马黑黑 发表于 2023-11-18 08:40

svg基础变形: transform 之 scale

本帖最后由 马黑黑 于 2023-11-18 08:45 编辑 <br /><br /><style>
.papa > p { margin: 10px 0; }
.hCode { display: block; padding: 10px 10px 10px 50px; font: normal 15px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; background: #F7EFE6; overflow-x: auto; tab-size: 4; position: relative; }
.hCode::before { position: absolute; content: attr(data-line); min-width: 20px; left: 0; top: 0; padding: 10px; font: inherit; color: #999; text-align: right; border-right: 1px solid tan; }
.stage { display: grid; place-items: center; }
.rred { color: red; }
</style>

<div class="papa">


<h2>svg基础变形: transform 之 scale</h2>
<p>scale是svg画布内元素的放大或缩小属性,实现原理和CSS的一致,但变形的基点默认情况下总是在svg画布的左上角{0,0}。并且,不像rotate可以自带基点,scale只有xy参数值,即沿XY坐标放大几倍。下面,我们给出一个简单的示例,在200*200的画布上绘制一个位于左上角的小圆,小圆可以通过svg下方的单选按钮选择放大1~5倍,可以通过对其放大,观察其缩放基点:</p>

<p>svg代码:</p>

<pre class="hCode">
&lt;svg width="200" height="200" style="border: 1px solid gray;"&gt;
        &lt;circle id="Circle" cx="20" cy="20" r="20" fill="tan" <span class="rred">transform="scale(1)"</span> /&gt;
&lt;/svg&gt;
</pre>

<p>效果:</p>

<svg width="200" height="200" style="border: 1px solid gray;">
        <circle id="Circle" cx="20" cy="20" r="20" fill="tan" transform="scale(1)" />
</svg>
<p>
        <label>【伸缩倍数】</lable>
        <input id="rd1" type="radio" name="r_scale" value="1" checked="true" /><label for="rd1">原始</label>
        <input id="rd2" type="radio" name="r_scale" value="2" /><label for="rd2">2倍</label>
        <input id="rd3" type="radio" name="r_scale" value="3" /><label for="rd3">3倍</label>
        <input id="rd4" type="radio" name="r_scale" value="4" /><label for="rd4">4倍</label>
        <input id="rd5" type="radio" name="r_scale" value="5" /><label for="rd5">5倍</label>
</p>

<p>如果需要令元素以自己的中心为基点在原地缩放,虽然scale不提供实现方法,我们也不是无能为力。其中的巧妙方法是,先令元素移动(translate)到它的中心点,再缩放(scale),最后再反向移动(translate)先前移动的尺寸。以下示例我们绘制了四个圆,橙色的两个圆初始半径均为 10,然后它们分别按如此方式进行伸缩:scale(1,8)、scale(8,1),亦即一个垂直放大8倍、一个水平放大8倍;它们放大前放大后均使用 translate 移位处理。看代码和效果:</p>

<pre class="hCode">
&lt;svg width="200" height="200" style="border: 1px solid gray;"&gt;
        &lt;circle cx="100" cy="100" r="80" fill="lightsteelblue" /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="orange" <span class="rred">transform="translate(0,100) scale(1,8) translate(0,-100)"</span> /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="orange" <span class="rred">transform="translate(100,0) scale(8,1) translate(-100,0)"</span> /&gt;
        &lt;circle cx="100" cy="100" r="10" fill="steelblue" /&gt;
&lt;/svg&gt;
</pre>

<svg width="200" height="200" style="border: 1px solid gray;">
        <circle cx="100" cy="100" r="80" fill="lightsteelblue" />
        <circle cx="100" cy="100" r="10" fill="orange" transform="translate(0,100) scale(1,8) translate(0,-100)" />
        <circle cx="100" cy="100" r="10" fill="orange" transform="translate(100,0) scale(8,1) translate(-100,0)" />
        <circle cx="100" cy="100" r="10" fill="steelblue" />
</svg>

<p>从效果中我们可以看到,translate能够帮助我们让元素围绕自己的中心缩放。</p>

<p>【小结】scale只接收xy缩放倍数值,写成 scale(x,y) 或 scale(x),当 y 缺省时,y = x 。scale不带变形基点参数,若需要元素围绕自己的中心缩放,可以使用 translate 一前一后配套处理:先令元素移动到自己的中心点坐标(基于svg画布坐标体系),缩放后再反向移动回来。</p>

</div>

<script>

let btns = document.querySelectorAll('.btnok'),
        stages = document.querySelectorAll('.stage'),
        hCodes = document.querySelectorAll('.hCode'),
        hLineNums = document.querySelectorAll('.hLineNum');

hCodes.forEach((item,key) => {
        let lines = hCodes.innerText.trim().split('\n').length;
        let str = '';
        for(let i = 0; i < lines; i ++) {
                str += i + 1 + '\n';
        }
        item.dataset.line = str;
});

let rds = document.getElementsByName('r_scale');

rds.forEach((item) => {
        item.onchange = () => Circle.setAttribute('transform', 'scale(' + item.value + ')');
});
</script>

马黑黑 发表于 2023-11-18 08:49

和在 rotate 中的表现一样,scale 行为也是围绕svg左上角坐标{0,0}进行,当缩放对象左上角不在 svg 的左上角,那么,缩放对象也会绕svg左上角转圈。所以,要让示例二的橙色小圆缩在原地缩放,就需要配套 translate 进行。

红影 发表于 2023-11-18 10:06

这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放,就需要translate(100,100)了吧?

红影 发表于 2023-11-18 10:09

这个缩放后的图案还挺漂亮呢{:4_173:}

马黑黑 发表于 2023-11-18 10:43

红影 发表于 2023-11-18 10:09
这个缩放后的图案还挺漂亮呢

放大倍数大了一点,小一点的话会更好看

马黑黑 发表于 2023-11-18 10:44

红影 发表于 2023-11-18 10:06
这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放, ...

这是因为,不放大的方向,它不会在这个方向产生绕svg基点而绕圈圈的移位现象

马黑黑 发表于 2023-11-18 10:44

红影 发表于 2023-11-18 10:06
这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放, ...

是的

红影 发表于 2023-11-18 14:22

马黑黑 发表于 2023-11-18 10:43
放大倍数大了一点,小一点的话会更好看

单一方向的放大竟然有这样的效果,真不错。

红影 发表于 2023-11-18 14:23

马黑黑 发表于 2023-11-18 10:44
这是因为,不放大的方向,它不会在这个方向产生绕svg基点而绕圈圈的移位现象

又是个比较特殊的地方呢,需要记一下的。

红影 发表于 2023-11-18 14:24

马黑黑 发表于 2023-11-18 10:44
是的

嗯嗯,知道了{:4_204:}

马黑黑 发表于 2023-11-18 18:29

红影 发表于 2023-11-18 14:24
嗯嗯,知道了

谢花

马黑黑 发表于 2023-11-18 18:29

红影 发表于 2023-11-18 14:23
又是个比较特殊的地方呢,需要记一下的。

这个正常呀,没什么特殊

马黑黑 发表于 2023-11-18 18:29

红影 发表于 2023-11-18 14:22
单一方向的放大竟然有这样的效果,真不错。

擀面的时候你应该可以有这样的感受

红影 发表于 2023-11-19 13:30

马黑黑 发表于 2023-11-18 18:29
谢花

不客气啊。

红影 发表于 2023-11-19 13:30

马黑黑 发表于 2023-11-18 18:29
这个正常呀,没什么特殊

和我原本的想法不一样,所以就觉得它特殊。

红影 发表于 2023-11-19 13:31

马黑黑 发表于 2023-11-18 18:29
擀面的时候你应该可以有这样的感受

你这个就是把橙色往一个方向擀面的{:4_173:}

马黑黑 发表于 2023-11-19 19:38

红影 发表于 2023-11-19 13:31
你这个就是把橙色往一个方向擀面的

原理就是酱紫

马黑黑 发表于 2023-11-19 19:39

红影 发表于 2023-11-19 13:30
和我原本的想法不一样,所以就觉得它特殊。

想象有时候会影响人的理解能力

马黑黑 发表于 2023-11-19 19:39

红影 发表于 2023-11-19 13:30
不客气啊。

应该的应该的

红影 发表于 2023-11-19 22:59

马黑黑 发表于 2023-11-19 19:38
原理就是酱紫

这个比喻很好玩{:4_173:}
页: [1] 2
查看完整版本: svg基础变形: transform 之 scale