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">
<svg width="200" height="200" style="border: 1px solid gray;">
<circle id="Circle" cx="20" cy="20" r="20" fill="tan" <span class="rred">transform="scale(1)"</span> />
</svg>
</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">
<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" <span class="rred">transform="translate(0,100) scale(1,8) translate(0,-100)"</span> />
<circle cx="100" cy="100" r="10" fill="orange" <span class="rred">transform="translate(100,0) scale(8,1) translate(-100,0)"</span> />
<circle cx="100" cy="100" r="10" fill="steelblue" />
</svg>
</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>
和在 rotate 中的表现一样,scale 行为也是围绕svg左上角坐标{0,0}进行,当缩放对象左上角不在 svg 的左上角,那么,缩放对象也会绕svg左上角转圈。所以,要让示例二的橙色小圆缩在原地缩放,就需要配套 translate 进行。 这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放,就需要translate(100,100)了吧? 这个缩放后的图案还挺漂亮呢{:4_173:} 红影 发表于 2023-11-18 10:09
这个缩放后的图案还挺漂亮呢
放大倍数大了一点,小一点的话会更好看 红影 发表于 2023-11-18 10:06
这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放, ...
这是因为,不放大的方向,它不会在这个方向产生绕svg基点而绕圈圈的移位现象 红影 发表于 2023-11-18 10:06
这个好奇怪,以为要移动到小圆中心进行缩放,结果如果缩放y,则只移动translate(0,100)
如果xy同步缩放, ...
是的 马黑黑 发表于 2023-11-18 10:43
放大倍数大了一点,小一点的话会更好看
单一方向的放大竟然有这样的效果,真不错。 马黑黑 发表于 2023-11-18 10:44
这是因为,不放大的方向,它不会在这个方向产生绕svg基点而绕圈圈的移位现象
又是个比较特殊的地方呢,需要记一下的。 马黑黑 发表于 2023-11-18 10:44
是的
嗯嗯,知道了{:4_204:} 红影 发表于 2023-11-18 14:24
嗯嗯,知道了
谢花 红影 发表于 2023-11-18 14:23
又是个比较特殊的地方呢,需要记一下的。
这个正常呀,没什么特殊 红影 发表于 2023-11-18 14:22
单一方向的放大竟然有这样的效果,真不错。
擀面的时候你应该可以有这样的感受 马黑黑 发表于 2023-11-18 18:29
谢花
不客气啊。 马黑黑 发表于 2023-11-18 18:29
这个正常呀,没什么特殊
和我原本的想法不一样,所以就觉得它特殊。 马黑黑 发表于 2023-11-18 18:29
擀面的时候你应该可以有这样的感受
你这个就是把橙色往一个方向擀面的{:4_173:} 红影 发表于 2023-11-19 13:31
你这个就是把橙色往一个方向擀面的
原理就是酱紫 红影 发表于 2023-11-19 13:30
和我原本的想法不一样,所以就觉得它特殊。
想象有时候会影响人的理解能力 红影 发表于 2023-11-19 13:30
不客气啊。
应该的应该的 马黑黑 发表于 2023-11-19 19:38
原理就是酱紫
这个比喻很好玩{:4_173:}
页:
[1]
2