如何构建具有用户坐标的SVG场景以填充屏幕

时间:2015-01-16 00:58:59

标签: svg image-scaling

我正在使用SVG显示一个图表地图,它必须是成比例的(即不是x / y偏斜)。

图像填满整个屏幕,因此外部项目始终为100%/ 100%。换句话说,我希望视口始终填充浏览器窗口(在宽高比的约束范围内),例如:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events" >
    <defs>
        <solidColor xml:id="solidBlack" solid-color="black" />
        <solidColor xml:id="solidLightGray" solid-color="lightgrey" />
    </defs>
    <style>
        .Border { fill:none; stroke:red; stroke-width="2px" }
        .TitleBlock { fill:none; stroke:black; stroke-width="1px" }
    </style>
    <svg x="0" y="0" width="100%" height="100%" viewbox="0 0 1000 1000" >
        <rect x="2" y="2" width="99%" height="99%" class="Border" />
        <svg viewbox="500 500 500 500">
            <circle cx="30" cy="20" r="10px" fill="red" />
            <circle cx="450" cy="30" r="10px" fill="blue" />
            <circle cx="40" cy="490" r="10px" fill="green" />
        </svg>  
    </svg>
</svg>

当渲染时,值被解释为像素,而不是用户坐标。因此,例如,绿点应该靠近屏幕的底部(因为它位于视图框的底部),但实际上它位于屏幕的中间,因为它将490解释为490像素。

为了进一步说明,总地图区域的1000 x 1000维度是用户坐标。例如,假设我正在制作太空游戏,游戏区域为1000秒差距x 1000秒差距。此地图区域的任何特定视图都应填满屏幕。

更新

根据答案,一个基本问题是填充屏幕我需要在外部svg元素中使用100%。但是,即使执行此操作,图像也不会放大并使用用户坐标:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events" 
    width="100%" height="100%"
    viewBox="0 0 100000 100000" >
    <defs>
        <solidColor xml:id="solidBlack" solid-color="black" />
        <solidColor xml:id="solidLightGray" solid-color="lightgrey" />
    </defs>
    <style>
        .Border { fill:none; stroke:red; stroke-width="2px"; }
        .TitleBlock { fill:none; stroke:black; stroke-width="1px"; }
    }
    </style>
    <rect y="2" width="100%" height="100%" class="Border" />
    <svg viewBox="50000 50000 100000 100000" >
        <circle  cx="52000"  cy="52000" r="10px" fill="red" />
        <circle cx="95000"  cy="53000" r="10px" fill="blue" />
        <circle  cx="54000" cy="99000" r="10px" fill="green" />
    </svg>
</svg>

这根本不会出现,表明它使用的是PIXELS而不是用户坐标。

1 个答案:

答案 0 :(得分:1)

我认为你可能会对viewBox的工作方式感到困惑。它描述了应缩放以适合视口(宽度和高度)的文档边界。它没有进行转换。

您的viewBox&#34; 500 500 500 500&#34;描述了该区域(500,500) - &gt; (1000,1000)。所以你的坐标(10,490)通常会在视口外面结束。

话虽如此,但您实际上想要使用嵌套的<svg>元素集来实现目标并不清楚。

我会假设您想要显示1000x1000世界地图的一部分,以便填满屏幕?让&#39;首先简化原始SVG。

&#13;
&#13;
.Border { fill:none; stroke:red; stroke-width="2px" }
.TitleBlock { fill:none; stroke:black; stroke-width="1px" }
&#13;
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:ev="http://www.w3.org/2001/xml-events"
    width="100%" height="100%"
    viewBox="0 0 1000 1000">
    <defs>
        <solidColor xml:id="solidBlack" solid-color="black" />
        <solidColor xml:id="solidLightGray" solid-color="lightgrey" />
    </defs>
    <rect x="2" y="2" width="99%" height="99%" class="Border" />
    <circle cx="30" cy="20" r="10px" fill="red" />
    <circle cx="450" cy="30" r="10px" fill="blue" />
    <circle cx="40" cy="490" r="10px" fill="green" />
</svg>
&#13;
&#13;
&#13;

这里我们在一个100%x100%的SVG中显示整个世界地图。由于处理SVG的百分比宽度/高度值的方式,并且因为viewBox是方形的。这通常会导致SVG宽度为100%且高度等于宽度,从而导致SVG最终离开页面底部。

如果您希望SVG视口与屏幕完全匹配,则应使用宽度/高度(以像素为单位),而不是百分比。为了适应代码段窗口,让我们选择512x384的小屏幕(1024x768屏幕的1/2)。

&#13;
&#13;
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="512" height="384"
    viewBox="0 0 1000 1000">

    <rect x="-50%" y="-50" width="200%" height="200%" fill="#ffc"/>
    <rect x="2" y="2" width="99%" height="99%" fill="none" stroke="red" stroke-width="2" />
    <circle cx="30" cy="20" r="10px" fill="red" />
    <circle cx="450" cy="30" r="10px" fill="blue" />
    <circle cx="40" cy="490" r="10px" fill="green" />
</svg>
&#13;
&#13;
&#13;

在这里,我还添加了一个浅黄色矩形,以显示视口(屏幕)的尺寸以及viewBox如何产生&#34; world&#34;缩放以适应屏幕。

如果您希望世界填满屏幕并且左侧和右侧没有空白区域,则需要更改preserveAspectRatio属性。默认情况下,它设置为xMidYMid meet,这意味着将viewBox区域缩放到整齐地适合视口并使其居中。如果我们将其更改为xMidYMid slice,它会将其缩放以填充视口的最宽部分。这导致了你的世界的顶部和底部。离开屏幕。

&#13;
&#13;
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="512" height="384"
    viewBox="0 0 1000 1000"
    preserveAspectRatio="xMidYMid slice">

    <rect x="-50%" y="-50" width="200%" height="200%" fill="#ffc"/>
    <rect x="2" y="2" width="99%" height="99%" fill="none" stroke="red" stroke-width="2" />
    <circle cx="30" cy="20" r="10px" fill="red" />
    <circle cx="450" cy="30" r="10px" fill="blue" />
    <circle cx="40" cy="490" r="10px" fill="green" />
</svg>
&#13;
&#13;
&#13;

现在,如果您想查看&#34; world&#34;的一部分,例如左上角,您可以将viewBox设置为&#34; 0 0 500 500&#34;。如果你想看到整个区域,请使用`preserveAspectRatio =&#34; xMidYMid meet&#34;:

&#13;
&#13;
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="512" height="384"
    viewBox="0 0 500 500"
    preserveAspectRatio="xMidYMid meet">

    <rect x="-50%" y="-50" width="200%" height="200%" fill="#ffc"/>
    <rect x="2" y="2" width="99%" height="99%" fill="none" stroke="red" stroke-width="2" />
    <circle cx="30" cy="20" r="10px" fill="red" />
    <circle cx="450" cy="30" r="10px" fill="blue" />
    <circle cx="40" cy="490" r="10px" fill="green" />
</svg>
&#13;
&#13;
&#13;

如果您不希望在500x500区域之外看到世界上的某些地方,并且可以将部分内容放在屏幕外,请使用xMidYMid slice

&#13;
&#13;
<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="512" height="384"
    viewBox="0 0 500 500"
    preserveAspectRatio="xMidYMid slice">

    <rect x="-50%" y="-50" width="200%" height="200%" fill="#ffc"/>
    <rect x="2" y="2" width="99%" height="99%" fill="none" stroke="red" stroke-width="2" />
    <circle cx="30" cy="20" r="10px" fill="red" />
    <circle cx="450" cy="30" r="10px" fill="blue" />
    <circle cx="40" cy="490" r="10px" fill="green" />
</svg>
&#13;
&#13;
&#13;

在这里,您的三个圈子最终都在屏幕外。

这有帮助吗?