绘制 SVG 图标时基于浏览器的不同结果

问题描述 投票:0回答:1

在 Safari(版本 18.0.1)中运行此代码时,生成的图像为:

Safari Version 18.0.1

但是,在Chrome(版本131.0.6778.139)中运行代码时,生成的图像是:

Chrome Version 131.0.6778.139

如果我在 svg 本身中定义宽度和高度,我可以让这两个匹配...

<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"...

但是,出于无关紧要的原因,修改原始 SVG 对于实际情况来说是不切实际的。

有没有办法将 OpenLayers 与 SVG 结合使用,这样无论浏览器如何,这些情况都会匹配?

const osm = new ol.source.OSM();

osm.setTileGridForProjection(
  "EPSG:4326",
  ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);

const tileLayer = new ol.layer.Tile({ source: osm });
const coordinate = [-97, 38];

const svg =
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 0c17.7 0 32 14.3 32 32l0 10.4c93.7 13.9 167.7 88 181.6 181.6l10.4 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-10.4 0c-13.9 93.7-88 167.7-181.6 181.6l0 10.4c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-10.4C130.3 455.7 56.3 381.7 42.4 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l10.4 0C56.3 130.3 130.3 56.3 224 42.4L224 32c0-17.7 14.3-32 32-32zM107.4 288c12.5 58.3 58.4 104.1 116.6 116.6l0-20.6c0-17.7 14.3-32 32-32s32 14.3 32 32l0 20.6c58.3-12.5 104.1-58.4 116.6-116.6L384 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l20.6 0C392.1 165.7 346.3 119.9 288 107.4l0 20.6c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-20.6C165.7 119.9 119.9 165.7 107.4 224l20.6 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-20.6 0zM256 224a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>';
console.log("svg", svg);

const svgPoint = new ol.Feature({
  geometry: new ol.geom.Point(coordinate),
  properties: {
    name: "svgPoint"
  }
});

const layer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [svgPoint]
  }),

  style: (feature) => {
    const properties = feature.getProperties();
    let style;

    if (properties.properties.name === "svgPoint") {
      style = new ol.style.Style({
        image: new ol.style.Icon({
          opacity: 1,
          src: "data:image/svg+xml;base64," + btoa(svg),
          width: 20,
          height: 20
        })
      });
    }

    return style;
  }
});

const map = new ol.Map({
  target: "map",
  layers: [tileLayer, layer],
  view: new ol.View({
    projection: "EPSG:4326",
    center: coordinate,
    zoom: 5
  }),
  controls: ol.control.defaults.defaults({ attribution: false, zoom: false })
});

ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);
#map {
  height: 256px;
  width: 256px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/dist/ol.min.js"></script>

<div id="map"></div>

svg openlayers
1个回答
0
投票

绘制到画布上的未调整大小的 SVG 的大小将取决于(地图)画布的大小。 在 Firefox 中它根本不起作用。 如果您不需要支持 Firefox,您可以在图标选项中添加

color: 'transparent
,` 以获得更一致的结果,但最好在运行时将真正的默认值注入 SVG - 可以获取 SVG,解析、添加或更改属性,然后序列化回 SVG 文本(您需要使代码异步)

  const svgDimensions = (text) => {
const xml = new DOMParser().parseFromString(text, 'application/xml');
const svg = xml.getElementsByTagName('svg')[0];
const defaultWidth = 300;
const defaultHeight = 150;
// extract any width or height values with 2 character units
const defaultUnit = '';
const ww = svg?.getAttribute('width');
const wUnit = ww?.match(/[a-z]{2}$/)?.[0] || defaultUnit;
let w = Number(ww?.replace(new RegExp(wUnit + '$'), ''));
const hh = svg?.getAttribute('height');
const hUnit = hh?.match(/[a-z]{2}$/)?.[0] || defaultUnit;
let h = Number(hh?.replace(new RegExp(hUnit + '$'), ''));
// disregard NaN percentage values
w = w > 0 ? w : 0;
h = h > 0 ? h : 0;
const absent = !(w > 0 && h > 0);
const viewBox = svg
  ?.getAttribute('viewBox')
  ?.split(/[\s,]+?/)
  .map(Number);
if (viewBox || absent) {
  const wView = viewBox?.[2];
  const hView = viewBox?.[3];
  if (absent && wView > 0 && hView > 0) {
    // calculate missing dimensions based on viewBox aspect ratio
    // and default height
    if (w > 0) {
      h = (w * hView) / wView;
      svg.setAttribute('height', h + wUnit);
    } else if (h > 0) {
      w = (h * wView) / hView;
      svg.setAttribute('width', w + hUnit);
    } else {
      h = defaultHeight;
      w = (h * wView) / hView;
      svg.setAttribute('width', w + defaultUnit);
      svg.setAttribute('height', h + defaultUnit);
    }
  } else {
    // if no valid viewBox use defaults for missing dimensions
    if (w === 0) {
      w = defaultWidth;
      svg.setAttribute('width', w + defaultUnit);
    }
    if (h === 0) {
      h = defaultHeight;
      svg.setAttribute('height', h + defaultUnit);
    }
  }
  svg.setAttribute('preserveAspectRatio', 'none');
  text = new XMLSerializer().serializeToString(xml) || text;
}
return text;
  }

  const injectDimensions = async (src) => {
const blob = await fetch(src)
  .then((response) => {
    if (response.headers.get('content-type').includes('image/svg+xml')) {
      return response.text().then((text) => {
        return new Blob([svgDimensions(text)], {type: 'image/svg+xml'});
      });
    }
    return response.blob();
  });
return URL.createObjectURL(blob);
  }

  (async () => {

const osm = new ol.source.OSM();

osm.setTileGridForProjection(
  "EPSG:4326",
  ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);

const tileLayer = new ol.layer.Tile({ source: osm });
const coordinate = [-97, 38];

const svg =
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 0c17.7 0 32 14.3 32 32l0 10.4c93.7 13.9 167.7 88 181.6 181.6l10.4 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-10.4 0c-13.9 93.7-88 167.7-181.6 181.6l0 10.4c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-10.4C130.3 455.7 56.3 381.7 42.4 288L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l10.4 0C56.3 130.3 130.3 56.3 224 42.4L224 32c0-17.7 14.3-32 32-32zM107.4 288c12.5 58.3 58.4 104.1 116.6 116.6l0-20.6c0-17.7 14.3-32 32-32s32 14.3 32 32l0 20.6c58.3-12.5 104.1-58.4 116.6-116.6L384 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l20.6 0C392.1 165.7 346.3 119.9 288 107.4l0 20.6c0 17.7-14.3 32-32 32s-32-14.3-32-32l0-20.6C165.7 119.9 119.9 165.7 107.4 224l20.6 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-20.6 0zM256 224a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>';
//console.log("svg", svg);

const svgPoint = new ol.Feature({
  geometry: new ol.geom.Point(coordinate),
  properties: {
    name: "svgPoint"
  }
});

const src = await injectDimensions("data:image/svg+xml;base64," + btoa(svg));
//const src = await injectDimensions('https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg');

const layer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [svgPoint]
  }),

  style: (feature) => {
    const properties = feature.getProperties();
    let style;

    if (properties.properties.name === "svgPoint") {
      style = new ol.style.Style({
        image: new ol.style.Icon({
          opacity: 1,
          src: src,
          width: 75,
          height: 50
        })
      });
    }

    return style;
  }
});

const map = new ol.Map({
  target: "map",
  layers: [tileLayer, layer],
  view: new ol.View({
    projection: "EPSG:4326",
    center: coordinate,
    zoom: 5
  }),
  controls: ol.control.defaults.defaults({ attribution: false, zoom: false })
});

ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);

  }) ();
#map {
  height: 256px;
  width: 256px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/dist/ol.min.js"></script>

<div id="map"></div>

© www.soinside.com 2019 - 2024. All rights reserved.