在Chrome上,SVG中标记的上下文笔划和上下文填充不起作用,替代方案?

jtoj6r0c  于 2023-03-16  发布在  Go
关注(0)|答案(1)|浏览(148)

我正在为一个报告生成一些SVG,并且必须用匹配的开始和结束标记绘制不同颜色的线条。在Firefox中,他们似乎在14天前修复了这个问题,但是Chrome不理解SVG的def部分中标记上的stroke=“context-stroke”属性。我想知道是否有替代方法来解决这个问题,或者我只需要为我的线条可以是的每种颜色制作和管理一个标记。我甚至不确定我是否可以使用JavaScript更改样式,因为标记是在Defs部分定义的,并应用于所有使用它们的线条。
我试着用属性fill = context-stroke和stroke = context-stroke定义一个标记,这两个属性可以在Firefox上使用,但不能在chrome上使用。

2ul0zpep

2ul0zpep1#

从Erik Dahlström在2013年的回答中可以看出,用于继承颜色的context-strokecontext-fill值的概念在SVG 2草案中已经存在了相当长的一段时间。
不幸的是,大多数主流浏览器/引擎仍然没有实现它。
作为一种解决方法,您可以使用javaScript克隆具有不同填充或描边颜色的标记

let strokeMarkerEls = document.querySelectorAll(".strokeMarker");
let markerTemplate = document.querySelector("#marker");

// init
setMarkerColors(strokeMarkerEls, markerTemplate);

function setMarkerColors(strokeMarkerEls, markerTemplate) {
  strokeMarkerEls.forEach((el) => {

    // get element's stroke color
    let style = window.getComputedStyle(el);
    let stroke = style.stroke;

    // convert stroke color to hex value – used as an ID suffix for markers
    let strokeHex = rgbToHex(stroke);

    // define marker ID based on color
    let markerId = `${markerTemplate.id}_${strokeHex}`;
    let svg = el.closest("svg");
    let defs = svg.querySelector("defs");

    // check if marker of this color already exists
    let newMarker = defs.querySelector("#" + markerId);

    // otherwise append it
    if (!newMarker) {
      let markerClone = markerTemplate.cloneNode(true);
      markerClone.id = markerId;
      let markerEl = markerClone.children[0];
      markerEl.setAttribute("fill", "#" + strokeHex);
      defs.appendChild(markerClone);
    }
    // apply marker style
    el.style.markerEnd = `url(#${markerId})`;
    //el.setAttribute('marker-end', `url(#${markerId})`)
  });
}

// convert rgb(a) to hex code
function rgbToHex(color) {
  let colArray = color
    .replace(/[rgba(|rgb(|)]/g, "")
    .split(",")
    .map((val) => {
      return parseFloat(val);
    });
  let alpha = colArray[3] ? colArray[3] : "";
  if (alpha) {
    alpha = ((alpha * 255) | (1 << 8)).toString(16).slice(1);
  }
  let [r, g, b] = [colArray[0], colArray[1], colArray[2]];
  let hexColor =
    (r | (1 << 8)).toString(16).slice(1) +
    (g | (1 << 8)).toString(16).slice(1) +
    (b | (1 << 8)).toString(16).slice(1);
  return hexColor + alpha;
}
svg {
  width: 20em;
  overflow: visible;
}
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- reusable arrow path -->
    <path  id="markerPath" d="M 0 0 L 10 5 L 0 10 z" />
    <marker id="marker" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <use href="#markerPath" />
    </marker>
  </defs>
  <path class="strokeMarker" id="path0" d="M0 10 l 100 0" fill="none" stroke="rgba(0,0,0,0.5)" />
  <path class="strokeMarker" id="path1" d="M0 20 l 100 0" fill="none" stroke="red" />
  <path class="strokeMarker" id="path2" d="M0 30 l 100 0" fill="none" stroke="green" />
  <path class="strokeMarker" id="path3" d="M0 40 l 100 0" fill="none" stroke="orange" />
  <path class="strokeMarker" id="path3" d="M0 50 l 100 0" fill="none" stroke="blue" />
  <path class="strokeMarker" id="path4" d="M0 60 l 100 0" fill="none" stroke="blue" />
  <path class="strokeMarker" id="path5" d="M0 70 l 100 0" fill="none" stroke="orange" />
</svg>

这种方法基于这样的思想:创建一个标记模板,该模板可以通过更改实际标记元素的ID和填充属性来克隆:

<defs>
    <!-- reusable arrow path -->
    <path  id="markerPath" d="M 0 0 L 10 5 L 0 10 z" />
    <marker id="marker" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <use href="#markerPath" />
    </marker>
  </defs>

用于测试:codepen example

相关问题