我有一个SVG
,它具有如下简化的结构:
<svg viewbox="0 0 1000 2000">
<image width="1024" height="2048" transform="<matrix A>" … />
</svg>
我想用html5 <video>
元素替换图像,像这样使用<foreignObject>
:
<svg viewbox="0 0 1000 2000">
<g transform="<matrix A>">
<foreignObject x="0" y="0" width="100%" height="100%">
<video style="display:block; width: 100%; height: 100%;">
<source src="…" type="…">
</video>
</foreignObject>
</g>
<!--
<image width="1024" height="2048" transform="<matrix in here>" … />
-->
</svg>
因此我有以下代码:
[...document.querySelectorAll('image')].forEach(img => {
const
g = document.createElementNS('…', 'g'),
fo = g.appendChild(document.createElementNS('…', 'foreignObject')),
video = fo.appendChild(document.createElement('video')),
src = video.appendChild(document.createElement('source'))
;
g.setAttribute('transform', img.getAttribute('transform'));
fo.setAttribute('x', 0);
fo.setAttribute('y', 0);
fo.setAttribute('width', '100%');
fo.setAttribute('height', '100%');
video.style.cssText = `
position: absolute;
top: 100px;
left: 100px;
background-color: #00ff00;
`
video.setAttribute('width', 100);
video.setAttribute('height', 100);
img.parentNode.appendChild(g);
img.parentNode.removeChild(img);
});
到目前为止,基本上一切正常,但是我无法使<video>
出现在与图像大小相同的位置。规范说:
(I)
[…]包含的外部图形内容需要进行SVG转换,过滤器,剪切,遮罩和合成[…]
(II)
HTML解析器将'foreignObject'中的元素等同于HTML文档片段中的元素。 […]
考虑(I):通过用<g>
替换图像,该图像复制了图像中的所有变换,视频应“位于坐标空间中”,而不是“
考虑到(II),<video>
应该成为新文档片段的根节点,并适合给定区域。
但是结果看起来像这样:
其中:黑色区域代表整个SVG,白色区域代表整个HTML文档,其中包括SVG。这两个绿色区域/都将成为视频,而较大的区域就是我想要的视频。
为什么/我想念什么?
更新
由于这太过分了,我创建了这个基本的svg:
<svg
width="200"
height="200"
viewBox="0 0 200 200"
preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="clip">
<circle cx="100" cy="100" r="100" />
</clipPath>
</defs>
<rect
x="0"
y="0"
width="200"
height="200"
style="fill:#ff0000;stroke:none"
clip-path="url(#clip)" />
<g clip-path="url(#clip)">
<foreignObject x="0" y="0" width="200" height="200" >
<video
autoplay=""
width="100%" height="100%">
<source src="/path/to/a/video.mp4" type="video/mp4" />
</video>
</foreignObject>
</g>
<text x="100" y="100">Hello</text>
</svg>
什么在Firefox中完美运行,但在Chromium中却无法正常运行。我可以通过在视频中添加style="clip-path: url(#clip)"
来裁剪视频,但是<text>
并没有出现在视频的前面(铬)。
考虑视频的坐标,这可行:
const
{ top,
left,
width,
height } = foreignObject.getBoundingClientRect()
;
Object.entries({ width, height}).forEach(
([k,v]) => video.setAttribute(k,v)
);
video.style.left = `${left}px`;
video.style.top = `${top}px`;
答案 0 :(得分:-1)
您的视口是1000x2000,但图像是1024x2048。我认为这会剪辑您的图像。可能是混乱的一部分。
下一步:由于您通常希望保留视频的纵横比,因此图像比视频更自由地缩放。这就是为什么视频大小不适合容器时会出现黑色边框的原因。确保视频大小,图像大小和SVG视口都一致。
我也有点怀疑浏览器可以将所有SVG转换应用于视频。至少在过去,浏览器不会自己渲染视频,而是在页面中保留一个矩形区域,并将该区域的坐标发送到视频渲染器(可以使用覆盖窗口在另一个过程中进行)。如果无法正常使用,请尝试用视频替换整个SVG。
此外,不要在JavaScript中执行此操作,而是构建一个小的本地HTML文件,您可以快速对其进行调整,直到视频看起来正确为止。当它起作用时,然后从可以在两者之间转换的代码开始。否则,您将打开太多的蠕虫罐头。
[更新1]
欢迎来到地狱。待一会儿...
在这种情况下,您可以尝试使用开发人员工具找出Chromium正在做什么。也许创建第二个本地测试用例,您尝试在视频中放置一些文本的<div>
。如果这不起作用,则Chromium正在使用此类视频的外部渲染器。
这在屏幕上看起来相同,但在幕后,Chromium正在要求另一个进程在屏幕上放置另一个窗口,以使其看起来像是页面的一部分。如果您拥有一种可以在屏幕上显示所有应用程序窗口坐标的工具,则可以看到浏览器窗口上方有一个工具。点击进入该窗口,Chromium看不到它们,也无法在该窗口之前呈现任何内容,因为它是其他人的窗口(就像您不希望Chromium在恰好是在浏览器窗口中打开。)
选项: