2014-09-30 12 views
3

在本文件:可以转义SVG视图吗? (或如何定位在缩放/ SVG转换HTML DIV?)

html, body { 
 
    height: 100%; 
 
    margin: 0; 
 
    padding: 0; 
 
    overflow: hidden 
 
} 
 
#content { 
 
    width: 100%; 
 
    height: 100% 
 
}
<div id="content"> 
 
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="90%" viewBox="0 0 1920 1080" preserveAspectRatio="xMidYMid meet"> 
 
    <rect style="fill:none;stroke:black" width="540" height="157" x="690" y="26"></rect> 
 
    <text style="font-size:148px;text-align:center;text-anchor:middle;fill:black;stroke:none" x="960" y="145">Test</text> 
 
    <text style="font-size:112px;text-align:center;text-anchor:middle;fill:black;stroke:none" x="960" y="340">Lorem ipsum etc etc</text> 
 
    <foreignObject x="10" y="726" width="1901" height="347"> 
 
     <div xmlns="http://www.w3.org/1999/xhtml" style="width:99.6%;height:97.7%;border:4px solid blue"> 
 
     <p style="text-align:center">Hello World, from HTML inside SVG.</p> 
 
     </div> 
 
    </foreignObject> 
 
    </svg> 
 
    <div style="width:99%;border:4px solid blue"> 
 
    <p style="text-align:center">Hello World, from HTML outside SVG.</p> 
 
    </div> 
 
</div>

我使用视框,使其充满重新调整为任意大小的SVG浏览器窗口(通常svg的90%高度是100%;为了便于说明,我在此将其缩小)。在那个SVG中是一个包含一些HTML呈现的外部对象。

现在,呈现的HTML输出正在重新调整以适应viewBox坐标;请注意内部svg内容的边框宽度和文字大小与外部大小不同,并且在窗口大小调整时它会发生变化。

我想要foreignObject的位置和大小来定义内部div的边界框,但我不希望它实际重新调整内容,只是为了重新排列它们。有没有办法做到这一点?

(在顶部的文本还重新调整与窗口,但是这需要在这种情况下)。

请注意,我不能移动或删除视框。我可以把内部div的svg以外,并使用JavaScript来调整它的大小,但我不知道如何设置它的边界框(但不是比例),如果它在里面,它会。

(我不明白的是,我必须指定div的宽度/高度小于100%,否则会在内部和外部裁剪边框,这可能只是一个Chrome的事情。但也不是真正重要的,我只是好奇)


编辑AmeliaBR's answer之后,这是我的代码已经出来:

function svgTransform(x, y, matrix, svg) { 
 
    var p = svg.createSVGPoint(); 
 
    p.x = x; 
 
    p.y = y; 
 
    return p.matrixTransform(matrix); 
 
} 
 

 
function svgScreenBounds(svgElement) { 
 
    var matrix = svgElement.getScreenCTM(); 
 
    var r = svgElement.getBBox(); 
 
    var leftTop = svgTransform(r.x, r.y, matrix, svgElement.ownerSVGElement); 
 
    var rightBottom = svgTransform(r.x + r.width, r.y + r.height, matrix, svgElement.ownerSVGElement); 
 
    return { 
 
    x: leftTop.x, 
 
    y: leftTop.y, 
 
    width: rightBottom.x - leftTop.x, 
 
    height: rightBottom.y - leftTop.y 
 
    }; 
 
} 
 

 
function adjustOverlay() { 
 
    var placeholder = document.getElementById('placeholder'); 
 
    var overlay = document.getElementById('overlay'); 
 
    var bounds = svgScreenBounds(placeholder); 
 
    overlay.style.left = bounds.x + 'px'; 
 
    overlay.style.top = bounds.y + 'px'; 
 
    overlay.style.width = bounds.width + 'px'; 
 
    overlay.style.height = bounds.height + 'px'; 
 
    overlay.style.display = 'block'; 
 
}
html,body { height: 100%; margin: 0; padding: 0; overflow: hidden } 
 
#content { width: 100%; height: 100% } 
 
#overlay { 
 
    display: none; 
 
    position: absolute; 
 
    border:4px solid blue; 
 
    box-sizing: border-box; 
 
}
<body onload="adjustOverlay()" onresize="adjustOverlay()"> 
 
    <div id="content"> 
 
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1920 1080" preserveAspectRatio="xMidYMid meet"> 
 
     <rect style="fill:none;stroke:black" width="540" height="157" x="690" y="26"></rect> 
 
     <text style="font-size:148px;text-align:center;text-anchor:middle;fill:black;stroke:none" x="960" y="145">Test</text> 
 
     <text style="font-size:112px;text-align:center;text-anchor:middle;fill:black;stroke:none" x="960" y="340">Lorem ipsum etc etc</text> 
 
     <rect style="fill:yellow;stroke:black" width="1901" height="100" x="10" y="618" rx="20" ry="20"></rect> 
 
     <text style="font-size:64px;text-align:center;text-anchor:middle;fill:black;stroke:none" x="960" y="685">Bottom banner text</text> 
 
     <rect style="visibility:hidden" x="10" y="726" width="1901" height="347" id="placeholder"></rect> 
 
    </svg> 
 
    </div> 
 
    <div id="overlay"> 
 
    <p style="text-align:center">Hello World, from HTML outside SVG.</p> 
 
    </div> 
 
</body>

它似乎表现得如预期。 (并且宽度小于100%的原因是因为我需要box-sizing: border-box - 在提问之前我曾尝试过html元素的样式,但它在那里没有影响;显然它需要直接应用而不是继承。)

+0

viewBox不是一个窗口,它不是一个“移动”或“移除”或“改变或”覆盖“的东西,它是一种坐标系,对于SVG元素来说是固定的和绝对的 – 2014-09-30 07:37:20

+0

** viewBox属性**是可以被移动或移除的东西,并且可能是可能的答案的一部分,除非我不能做到这一点,而不会破坏我希望以他们的方式工作的其他事物,这就是为什么我说 – Miral 2014-09-30 23:51:43

+0

感谢您添加详细的代码来帮助其他人。非常好地组织到逻辑函数 – AmeliaBR 2014-10-01 15:54:05

回答

2

不幸的是,你的问题的答案是“不”。 viewBox会为其所有子项更改整个坐标系,包括px或pt单位的定义。

<foreignObject>中的内容渲染到屏幕缓冲区(临时图像),px中的宽度和高度与foreignObject的宽度和高度在本地SVG坐标系中相同,然后将结果转换为适合屏幕,就像您在变换后的SVG坐标系中绘制(JPEG或PNG)图像一样。

如果使用Javascript是一个选项,最好的解决方案是有可读的文本和响应图形,将绝对定位在SVG上的元素叠加在<div>之间。 This CodePen I put together about tooltips应该帮助您开始如何在SVG坐标系和页面坐标系之间进行转换。特别是,您需要阅读SVGPoint对象和getScreenCTM()函数。

虽然做了更多的工作,但这种方法也会绕过foreignObject的跨浏览器问题,这些问题在IE中根本不被支持,而且在其他浏览器中很不稳定(例如,并不总是获得所需的滚动条)。

+0

'getScreenCTM'要求将SVG添加到“真实”文档模型中。尽管我可以这样做,但目前我正试图在SVG模型不在树上时对其进行基于脚本的更改,以便在我最终将其添加到树而不是更新时立即显示所有内容零碎。那么有没有类似于'getScreenCTM'的东西可以在树外运行? – Miral 2014-09-30 23:49:27

+0

在viewBox中没有什么相似之处 - 你可以使用常规的getCTM方法计算父SVG和任何元素之间的净变换,但是你需要弄清楚viewBox的缩放以转换为父HTML坐标系统。我不确定是否需要过多担心重绘多个布局任务的性能 - 但您仍然可以在同一批次中添加SVG,然后绝对定位的div不会创建任何布局重新计算。 – AmeliaBR 2014-10-01 02:55:57

+0

请记住,当您的窗口(因此您的响应SVG)调整大小时,您需要重新调用Javascript函数来设置div的位置和大小,因此您无法预先设置窗口的大小,计算一切。 – AmeliaBR 2014-10-01 02:58:16

1

另一种解决方案是将较低的DIV(SVG外部)放置在SVG区域上。

<div style="width:99%;border:4px solid blue; position:relative;top:-100px;">

foreignObject内部SVG的比例是正确的。当你可以简化它时,在SVG内部的DIV里面放入HTML(编码恕我直言编码的复杂方式)仍然没有意义。或者,如果您想在SVG内部控制文本大小,请使用<text...>标签。

+0

这就是我在我的问题中提出的另一种选择,但只是说如果不知道如何计算位置应该是什么就没有用处。它不能是静态CSS,它必须通过脚本以某种方式从SVG内容中进行计算。 – Miral 2014-09-30 23:46:55