У меня есть 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.Обе зеленые области обозначают / seam как видео, при этом большая часть - это та, которую я хотел бы получить.
Почему это / Чего мне не хватает?
ОБНОВЛЕНИЕ
Поскольку это зашло слишком далеко, я создал этот простой 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`;