html 用Javascript修改画布SVG图像

jxct1oxe  于 2023-02-02  发布在  Java
关注(0)|答案(2)|浏览(281)

我有一个svg图像,我可以用来绘制到画布:

image = new Image()
    image.src = "image.svg"

是否可以修改image,例如,更改元素的颜色?

p5fdfcr1

p5fdfcr11#

加载SVG

你可以使用fetch函数来代替直接将SVG加载到图像元素中。这里是一个数据URL,仅作为示例--它可以被URL替换。此时你可以将SVG存储在一个变量中。

解析SVG

要修改SVG,一种方法是使用XPath,这是在函数changeAttribute()中发生的,该函数接受SVG、XPath表达式和包含要修改内容的数据的对象。

将SVG加载到图像元素中并在画布中呈现

当我读到你的问题时,你已经明白了这一点。在函数insertIntoCanvas()中,通过使用FileReader将SVG(XML文档)转换为数据URL。之后,图像被创建并绘制在画布上。

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

fetch('data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAgMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTSA1IDAgTCAwIDUgTCA1IDEwIEwgMTAgNSBaIiAvPgo8L3N2Zz4=')
  .then(response => response.text())
  .then(text => {
    let xmlDoc = new DOMParser().parseFromString(text,'text/xml');
    changeAttribute(xmlDoc, '//svg:path', {fill:'red'});
    changeAttribute(xmlDoc, '//svg:svg', {width:100, height:100});
    insertIntoCanvas(xmlDoc);
  });

function insertIntoCanvas(xmlDoc){
  let file = new File([xmlDoc.rootElement.outerHTML], 'svg.svg', {
    type: "image/svg+xml"
  });
  // and a reader
  let reader = new FileReader();
  
  reader.addEventListener('load', e => {
    /* create a new image assign the result of the filereader
    to the image src */
    let img = new Image();
    // wait for it to got load
    img.addEventListener('load', e => {
      // update canvas with new image
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(e.target, 0, 0);
    });
    img.src = e.target.result;
  });
  // read the file as a data URL
  reader.readAsDataURL(file);
}

function changeAttribute(doc, xpath, obj) {
  let r = doc.evaluate(xpath, doc, nsResolver, XPathResult.ANY_TYPE, null);

  let nodes = [];
  let next = r.iterateNext();
  while (next) {
    nodes.push(next);
    next = r.iterateNext();
  }

  nodes.forEach(node => {
    Object.keys(obj).forEach(key => {
      node.setAttribute(key, obj[key]);
    });
  });
}

function nsResolver(prefix) {
  const ns = {
    'xhtml': 'http://www.w3.org/1999/xhtml',
    'svg': 'http://www.w3.org/2000/svg'
  };
  return ns[prefix] || null;
}
canvas {
  border: thin solid black;
}
<canvas id="canvas" width="300" height="200"></canvas>
z3yyvxxp

z3yyvxxp2#

您必须:

  • 外部SVG文件加载为 * 文本 *
  • 将其注入到shadowDOM中(浏览器将进行解析)
      • 添加**您的<style>元素
  • 解压缩SVG outerHTML
  • 替换无效的URI字符**"#**
  • 创建<canvas>
  • 将SVG作为XML写入canvas.img数据URI
  • <canvas>添加到shadowDOM

replaceWith执行此工作的Web组件

    • 本机JavaScript**Web组件<svg-to-canvas>,所有现代浏览器都支持,

它能为你做所有的事,所以你只写:

<svg-to-canvas src="//load-file.github.io/heart.svg">
  <style>
    svg  { background:green }
    path { fill:red }
  </style>
</svg-to-canvas>

JSF中间:https://jsfiddle.net/WebComponents/cosfrqyv/

StackOverflow代码段:

<style>
  svg-to-canvas { background: lightgreen }
  canvas { background:pink }
</style>
  <svg-to-canvas src="//load-file.github.io/heart.svg">
    <style>
      svg  { background:green }
      path { fill:red }
    </style>
  </svg-to-canvas>
  <svg-to-canvas replaceWith src="//load-file.github.io/heart.svg"></svg-to-canvas>
<script>
customElements.define("svg-to-canvas", class extends HTMLElement {
  async connectedCallback(svg,canvas,img) {
    this.style.display   = "inline-block";
    this.attachShadow({mode:"open"})
        .innerHTML = await (await fetch(this.getAttribute("src"))).text();
    svg = this.shadowRoot.querySelector("svg");
    svg.append(...this.querySelectorAll("*"));
    // stop here for an SVG inside shadowDOM
    canvas = document.createElement('canvas');
    img    = Object.assign(new Image(), {
               onload : () => {
                 canvas.width = img.width; canvas.height = img.height;
                 canvas.getContext('2d').drawImage(img, 0, 0);
               },
               src : "data:image/svg+xml;utf8,"
                     + svg.outerHTML.replace(/"/g, "'").replace(/#/g, "%23")
            });
    if (this.hasAttribute("replaceWith")) this.replaceWith(canvas);
    else { svg.remove();  this.shadowRoot.append(canvas) }
  }
})
</script>

相关问题