马黑黑 发表于 2023-10-31 13:17

svg : viewBox + preserveAspectRatio 属性演示

<style>
        .ma p { margin: 10px 0; }
        .ma svg { margin: 10px; border: 1px solid gray; }
        .ma fieldset { margin: 10px; width: 400px; }
        .ma input { margin: 10px 2px 10px 10px; }
        .rred { color: red; }
</style>

<div class="ma">
        <p>以下演示,左边的红色方框是 viewBox 属性的虚拟,具体值在演示下方有提供,右边是效果,不同的对齐参数和伸缩参数,连同 viewBox 的具体设置,均会影响 viewBox 的最终呈现效果。具体如何影响,请参阅 <a href="https://www.huachaowang.com/forum.php?mod=viewthread&tid=72139">理解 svg 的 viewBox 属性(二)</a>。</p>
        <svg width="300" height="240">
                <circle cx="100" cy="100" r="90" fill="olive" />
                <rect id="vbRect1" x="10" y="10" width="61" height="169" fill="none" stroke="red" />
                <circle cx="10" cy="10" r="5" fill="purple" />
                <circle cx="71" cy="100" r="5" fill="purple" />
        </svg>
        <svg id="vbSvg" width="300" height="240" viewBox="10 10 61 169" preserveAspectRatio="xMidYMid meet">
                <circle cx="100" cy="100" r="90" fill="olive" />
                <rect id="vbRect2" x="10" y="10" width="61" height="169" fill="none" stroke="red" />
                <circle cx="10" cy="10" r="5" fill="purple" />
                <circle cx="71" cy="100" r="5" fill="purple" />
        </svg>
        <p>viewBox 代码:viewBox="<span id="vbox" class="rred">10 10 61 169</span>" preserveAspectRatio="<span id="ratio" class="rred">xMidYMid meet</span>"</p>
        <fieldset>
                <legend>设置viewBox参数</legend>
                <input id="vb1" type="radio" value="10 10 61 169" name="vb" checked />
                <label for="vb1" class="rred">10 10 61 169</label>
                <input id="vb2" class="rdXym" type="radio" value="10 10 169 61" name="vb" />
                <label for="vb2">10 10 169 61</label>
        </fieldset>
        <fieldset>
                <legend>设置对齐参数</legend>
                <input id="xym1" type="radio" value="xMinYMin" name="xym" />
                <label for="xym1">xMinYMin</label>
                <input id="xym2" type="radio" value="xMinYMid" name="xym" />
                <label for="xym2">xMinYMid</label>
                <input id="xym3" type="radio" value="xMinYMax" name="xym" />
                <label for="xym3">xMinYMax</label>
                <br>
                <input id="xym4" type="radio" value="xMidYMin" name="xym" />
                <label for="xym4">xMidYMin</label>
                <input id="xym5" type="radio" value="xMidYMid" name="xym" checked />
                <label for="xym5" class="rred">xMidYMid</label>
                <input id="xym6" type="radio" value="xMidYMax" name="xym" />
                <label for="xym6">xMidYMax</label>
                <br>
                <input id="xym7" type="radio" value="xMaxYMin" name="xym" />
                <label for="xym7">xMaxYMin</label>
                <input id="xym8" type="radio" value="xMaxYMid" name="xym" />
                <label for="xym8">xMaxYMid</label>
                <input id="xym9" type="radio" value="xMaxYMax" name="xym" />
                <label for="xym9">xMaxYMax</label>
        </fieldset>
        <fieldset>
                <legend>设置伸缩参数</legend>
                <input id="rdMeet" name="meet" type="radio" value="meet" checked />
                <label for="rdMeet"> meet :按短边比例伸缩</label>
                <br>
                <input id="rdSlice" name="meet" type="radio" value="slice" />
                <label for="rdSlice"> slice :按长边比例裁剪</label>
        </fieldset>
        <p>【说明】</p>
        <pre>
<span class="rred">meet</span> (默认值):

宽高比将会被保留
整个SVG的viewbox在视图范围内是可见的
尽可能地放大SVG的viewbox,同时仍然满足其他的条件

在这种情况下,如果图形的宽高比和视图窗口不匹配,则某些视图将会超出viewbox范围,
即SVG的viewbox视图将会比可视窗口小

<span class="rred">slice</span>:

宽高比将会被保留
整个视图窗口将覆盖viewbox
SVG的viewbox属性将会被尽可能的缩小,但是仍然符合其他标准

在这种情况下,如果SVG的viewbox宽高比与可视区域不匹配,则viewbox的某些区域将
会延伸到视图窗口外部,即SVG的viewbox将会比可视窗口大
        </pre>
</div>

<script>

let rdXym = document.getElementsByName('xym'),
        rdMeet = document.getElementsByName('meet'),
        vbs = document.getElementsByName('vb');
let ratioNow = 'meet',
        alignNow = 'xMidYMid',
        vbNow = vb1.value;

let setAttr = () => {
        vbSvg.setAttribute('viewBox',vbNow);
        vbSvg.setAttribute('preserveAspectRatio', alignNow + ' ' + ratioNow);
        ratio.innerText = alignNow + ' ' + ratioNow;
};

rdXym.forEach((item,key) => {
        item.onclick = () => {
                alignNow = item.value;
                setAttr();
        };
});

rdMeet.forEach((item,key) =>{
        item.onclick = () => {
                ratioNow = item.value;
                setAttr();
        };
});

vbs.forEach((item) => {
        item.onclick = () => {
                vbNow = item.value;
                let vals = vbNow.split(' ');
                let attrs = ['x','y','width','height'];
                attrs.forEach((v,k) => {
                        vbRect1.setAttribute(v,vals);
                        vbRect2.setAttribute(v,vals);
                });
                setAttr();
        };
});

</script>

红影 发表于 2023-10-31 14:04

这个在线演示好,可以直接看到不同设置的结果了{:4_199:}

红影 发表于 2023-10-31 14:07

在设置meet或slice,会让某一个方向被充满的,这时再调这个方向的大中小是没反应的。

山人 发表于 2023-10-31 16:05

红影 发表于 2023-10-31 14:07
在设置meet或slice,会让某一个方向被充满的,这时再调这个方向的大中小是没反应的。
当一个方向充满了,该方向的对齐调整就不会有响应。想一想在 Word 里,如果一行文字刚好占满整行,这时,对齐调整它会有响应吗?

红影 发表于 2023-10-31 16:25

山人 发表于 2023-10-31 16:05
当一个方向充满了,该方向的对齐调整就不会有响应。想一想在 Word 里,如果一行文字刚好占满整行,这时, ...

是的,这个比喻很恰当。谢谢山人{:4_187:}

马黑黑 发表于 2023-10-31 17:06

红影 发表于 2023-10-31 14:07
在设置meet或slice,会让某一个方向被充满的,这时再调这个方向的大中小是没反应的。

原理:一个方向拉满了,该方向的任意一种对齐方式都一样

红影 发表于 2023-10-31 20:45

马黑黑 发表于 2023-10-31 17:06
原理:一个方向拉满了,该方向的任意一种对齐方式都一样

是的,所有的变化在没拉满的方向起作用。

马黑黑 发表于 2023-10-31 22:04

红影 发表于 2023-10-31 20:45
是的,所有的变化在没拉满的方向起作用。

这是道理

红影 发表于 2023-10-31 22:25

马黑黑 发表于 2023-10-31 22:04
这是道理

这个帖子需要学的东西很多。

马黑黑 发表于 2023-11-1 07:20

红影 发表于 2023-10-31 22:25
这个帖子需要学的东西很多。

多倒是不多,值的个数多但有规律,一弄懂就不用记了

红影 发表于 2023-11-1 13:08

马黑黑 发表于 2023-11-1 07:20
多倒是不多,值的个数多但有规律,一弄懂就不用记了

那个容易,是meet和slice理解透了不容易。

马黑黑 发表于 2023-11-1 19:35

红影 发表于 2023-11-1 13:08
那个容易,是meet和slice理解透了不容易。

严格说说,meet和slice都伸缩,不同的是它们两个正好相反,meet保证短边完整,不剪裁,slice保证长边完整,剪裁多出的部分以充满对象

红影 发表于 2023-11-1 22:54

马黑黑 发表于 2023-11-1 19:35
严格说说,meet和slice都伸缩,不同的是它们两个正好相反,meet保证短边完整,不剪裁,slice保证长边完整 ...

嗯,都是充满,一个裁一个不裁,这样记最容易。

马黑黑 发表于 2023-11-2 07:36

红影 发表于 2023-11-1 22:54
嗯,都是充满,一个裁一个不裁,这样记最容易。

充满不是绝对的,像 meet,以短边伸缩,保证viewBox选区在渲染目标上都可见,它不一定充满目标区域,且,选区以外的内容可能也可见

红影 发表于 2023-11-2 10:34

马黑黑 发表于 2023-11-2 07:36
充满不是绝对的,像 meet,以短边伸缩,保证viewBox选区在渲染目标上都可见,它不一定充满目标区域,且, ...

我说的是按选择参数的充满,不是图案的充满啊。

马黑黑 发表于 2023-11-2 11:54

红影 发表于 2023-11-2 10:34
我说的是按选择参数的充满,不是图案的充满啊。

红影 发表于 2023-11-2 14:00

马黑黑 发表于 2023-11-2 11:54


这个好像是这样吧{:4_173:}

马黑黑 发表于 2023-11-2 20:01

红影 发表于 2023-11-2 14:00
这个好像是这样吧

大约吧,我也不清楚

红影 发表于 2023-11-2 21:44

马黑黑 发表于 2023-11-2 20:01
大约吧,我也不清楚

我是跟着感觉走{:4_173:}

马黑黑 发表于 2023-11-2 21:44

红影 发表于 2023-11-2 21:44
我是跟着感觉走

挺好呢
页: [1] 2 3
查看完整版本: svg : viewBox + preserveAspectRatio 属性演示