SVG ForeignObjects覆盖了Chrome中的所有其他元素 [英] SVG ForeignObjects draw over all other elements in Chrome

查看:103
本文介绍了SVG ForeignObjects覆盖了Chrome中的所有其他元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新,2016年4月22日:没什么新鲜事,我决定检查一下并发布快速代码更新. Firefox仍然表现出预期,IE则完全没有表现,Chrome 50.0.2661.87 m仍然表现与去年相同.下面的小提琴链接和代码已更新,以反映最新的工作版本(在Firefox中).

Update 22 April, 2016: Nothing new, I just decided to check up on this, and post a quick code update. Firefox still performs as expected, IE doesn't perform at all, and Chrome 50.0.2661.87 m still behaves the same as it did last year. The fiddle link and code below have been updated to reflect the latest working version (in Firefox).

背景: 我正在玩将canvas + HTML元素渲染为PNG.当然,这意味着要创建一个临时SVG,该SVG会将HTML托管为外部对象.

Background: I'm playing with rendering a canvas + HTML elements to PNG. Of course, this means creating an interim SVG which hosts the HTML as a foreignObject.

整个过程都是元素的分层.我有一个背景,一层元素,画布和另一层元素.您可以在下面的代码段中看到它的样子.

The whole thing is a layer-cake of elements. I have a background, a layer of elements, the canvas, and another layer of elements. You can see what it looks like in the snippet below.

我本可以通过两种方式解决这个问题:

I could have approached this in two ways:

  1. 将所有内容(包括图像)写入单个SVG,然后将其渲染到画布上.

  1. Write everything, including the image, to a single SVG, which will be rendered to a canvas.

编写两个SVG,一个用于背景和图像后面的项目,另一个用于图像前面的项目,然后绘制后部SVG,然后绘制图像,然后将前SVG绘制到目标画布.

Write two SVGs, one for the background and the items behind the image, and another for the items in front of the image, then draw the back SVG, then the image, then the front SVG to the target canvas.

我选择了选项1,因为它看起来简单明了.

I chose option 1 because it seemed straightforward and simple.

问题:SVG绘制顺序应该遵循DOM顺序,但对于Chrome(38和Canary)来说,它的作用就像是在之后渲染 呈现原始对象,完全覆盖了原始对象. (该代码在Firefox中按预期工作,而在IE11中却失败了.)那么,谁是正确的呢?这是Chrome,Firefox中的错误,还是它们都无法正确处理?还是我错过了一些用户错误?

The problem: SVG draw order is supposed to follow the DOM order, but in the case of Chrome (38 & Canary), it acts like it's rendering the foreignObjects after it renders the native objects, completely covering the native objects. (The code works as expected in Firefox, and fails miserably in IE11.) So who is correct? Is this a bug in Chrome, Firefox, or are neither of them handling this properly? Or is there some user error that I missed?

谢谢!

function putAnImageInTheCanvas() {
  var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  var svgNS = svg.namespaceURI;
  svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
  svg.setAttribute('height', '310');
  svg.setAttribute('width', '310');
  svg.setAttribute('version', '1.1');

  var svgRect = document.createElementNS(svgNS, 'rect');
  svgRect.setAttribute('x', '125');
  svgRect.setAttribute('y', '25');
  svgRect.setAttribute('height', '250');
  svgRect.setAttribute('width', '50');
  svgRect.setAttribute('fill', 'rgb(0,255,255)');

  svg.appendChild(svgRect);

  var dataSrc = 'data:image/svg+xml;base64,' + btoa(svg.outerHTML);

  var img = document.createElement('img');
  img.setAttribute('src', dataSrc);

  var c = document.getElementById('myCanvas');
  var ctx = c.getContext("2d");
  img.addEventListener('load', function() {
    ctx.drawImage(img, 0, 0, 310, 310, 0, 0, 310, 310);
  });
}

function render(darwBackground) {
  var myCanvas = document.getElementById('myCanvas');

  var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  var svgNS = svg.namespaceURI;
  svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
  svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
  svg.setAttribute('height', '310');
  svg.setAttribute('width', '310');
  svg.setAttribute('version', '1.1');

  var background = document.getElementById('main').cloneNode();
  background.setAttribute("xmlns", document.documentElement.namespaceURI);
  var svgFO_BG = document.createElementNS(svgNS, 'foreignObject');
  svgFO_BG.setAttribute('height', '310');
  svgFO_BG.setAttribute('width', '310');
  svgFO_BG.setAttribute('x', '0');
  svgFO_BG.setAttribute('y', '0');
  svgFO_BG.innerHTML = background.outerHTML.replace(/(\r\n|\n|\r|\t|[\s]{2,})/gm, '');

  var back = document.getElementById('back').cloneNode(true);
  back.setAttribute("xmlns", document.documentElement.namespaceURI);
  var svgFO_AB = document.createElementNS(svgNS, 'foreignObject');
  svgFO_AB.setAttribute('height', '310');
  svgFO_AB.setAttribute('width', '310');
  svgFO_AB.setAttribute('x', '0');
  svgFO_AB.setAttribute('y', '0');
  svgFO_AB.innerHTML = back.outerHTML.replace(/(\r\n|\n|\r|\t|[\s]{2,})/gm, '');

  var front = document.getElementById('front').cloneNode(true);
  front.setAttribute("xmlns", document.documentElement.namespaceURI);
  var svgFO_AA = document.createElementNS(svgNS, 'foreignObject');
  svgFO_AA.setAttribute('height', '310');
  svgFO_AA.setAttribute('width', '310');
  svgFO_AA.setAttribute('x', '0');
  svgFO_AA.setAttribute('y', '0');
  svgFO_AA.innerHTML = front.outerHTML.replace(/(\r\n|\n|\r|\t|[\s]{2,})/gm, '');

  var svgImage = document.createElementNS(svgNS, 'image');
  svgImage.setAttribute('xlink:href', myCanvas.toDataURL());
  svgImage.setAttribute('x', '0');
  svgImage.setAttribute('y', '0');
  svgImage.setAttribute('height', '310');
  svgImage.setAttribute('width', '310');

  var g = document.createElementNS(svgNS, 'g');
  if (darwBackground) {
    g.appendChild(svgFO_BG);
    svg.appendChild(g);
  }

  g = document.createElementNS(svgNS, 'g');
  g.appendChild(svgFO_AB);
  svg.appendChild(g);

  g = document.createElementNS(svgNS, 'g');
  g.appendChild(svgImage);
  svg.appendChild(g);

  g = document.createElementNS(svgNS, 'g');
  g.appendChild(svgFO_AA);
  svg.appendChild(g);

  var data = svg.outerHTML;

  document.getElementById('renderOutput').innerHTML = data;
}

<input type="button" value="load canvas image" onclick="putAnImageInTheCanvas();" />
<input type="button" value="render with background" onclick="render(true);" />
<input type="button" value="render without background" onclick="render(false);" />
<h2>Preview:</h2>
<div id="main" style="border: 5px blue solid; width: 300px; height: 300px; background: yellow; position: relative; top: 0; left: 0; overflow: hidden;">
  <canvas id="myCanvas" height="300px" width="300px" style="display: block; position: absolute; top: 0; left: 0; z-index: 1;"></canvas>
  <div id="back" style="position: relative; top: 0; left: 0;">
    <div style=" width: 100px; position: absolute; top: 75px; left: 75px; font-size: 20px; font-family: times; z-index: 0;">
      <div style="background: orange;">BACK</div>
    </div>
  </div>
  <div id="front" style="position: relative; top: 0; left: 0;">
    <div style=" width: 100px; position: absolute; top: 150px; left: 150px; font-size: 20px; font-family: times; z-index: 2;">
      <div style="background: lime;">FRONT</div>
    </div>
  </div>
</div>
<h2>Render Result:</h2>
<div id="renderOutput">

</div>

推荐答案

万岁!我不确定更改何时发生,但到目前为止,

Hooray! I'm not sure when the change came to be, but as of now, the Chrome bug mentioned in the comments above has been resolved, which seems to have resolved the issue.

我的演示现在可以在所有主流浏览器中使用

My demo now works in all major browsers:

  • Chrome(69.0.3497.100)
  • Firefox(62.0.2)
  • 边缘(38.14393.2068.0)

这篇关于SVG ForeignObjects覆盖了Chrome中的所有其他元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆