https://jsfiddle.net/ru8fzeya/5/
//polygon
function changeStrokePoly() {
var poly = document.getElementById("poly"),
isw = document.getElementById("isw-poly");
poly.setAttribute("stroke-width",isw.value);
};
function changeSizePoly(){
var poly = document.getElementById("poly"),
polyMask = document.getElementById("msk-poly"),
isz = document.getElementById("isz-poly");
var _getCoordinates = function(scale){
var viewBox = 400,
placeSize = 380 * (scale / 100),
h = placeSize * (Math.sqrt(3) / 2);
var offsetX = (viewBox - placeSize) / 2,
offsetY = (viewBox - h) / 2,
coordinates = [
{
x : (placeSize / 2 + offsetX),
y : offsetY
},
{
x : (offsetX),
y : (h + offsetY),
},
{
x : (placeSize + offsetX),
y : (h + offsetY)
}
];
return coordinates;
}
var coordinates = _getCoordinates(isz.value),
coordinatesString = coordinates[0].x + ' ' + coordinates[0].y + ' ' + coordinates[1].x + ' ' + coordinates[1].y + ' ' + coordinates[2].x + ' ' + coordinates[2].y;
poly.setAttribute('points', coordinatesString);
polyMask.setAttribute('points', coordinatesString);
};
//circle
function changeStrokeCircle() {
var circle = document.getElementById("circle"),
isw = document.getElementById("isw-circle");
circle.setAttribute("stroke-width",isw.value);
};
function changeSizeCircle(){
var circle = document.getElementById("circle"),
circleMask = document.getElementById("msk-circle"),
isz = document.getElementById("isz-circle");
circle.setAttribute('r', isz.value);
circleMask.setAttribute('r', isz.value);
};
//rect
function changeStrokeRect() {
var rect = document.getElementById("rect"),
isw = document.getElementById("isw-rect");
rect.setAttribute("stroke-width",isw.value);
};
function changeSizeRect(){
var rect = document.getElementById("rect"),
rectMask = document.getElementById("msk-rect"),
isz = document.getElementById("isz-rect"),
value = isz.value,
maxWidth = 300,
maxHeight = 100,
width = maxWidth * value / 100,
height = maxHeight * value / 100;
rect.setAttribute('width', width);
rect.setAttribute('height', height);
rectMask.setAttribute('width', width);
rectMask.setAttribute('height', height);
};
<div>
<div>
Polygon--
<input id="isw-poly" type="range" min="1" value="30" max="219" oninput="changeStrokePoly()"/>
<input id="isz-poly" type="range" min="10" value="100" max="100" oninput="changeSizePoly()"/>
</div>
<div>
Circle-----
<input id="isw-circle" type="range" min="1" value="30" max="360" oninput="changeStrokeCircle()"/>
<input id="isz-circle" type="range" min="10" value="180" max="180" oninput="changeSizeCircle()"/>
</div>
<div>
Rect-------
<input id="isw-rect" type="range" min="1" value="30" max="100" oninput="changeStrokeRect()"/>
<input id="isz-rect" type="range" min="10" value="100" max="100" oninput="changeSizeRect()"/>
</div>
</div>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="400" viewBox="0 0 800 400" >
<defs>
<mask id="msk1">
<polygon id="msk-poly" fill="#fff" points="200 35.5 10 364.5 390 364.5"></polygon>
</mask>
<mask id="msk2">
<circle id="msk-circle" fill="#fff" cx="600" cy="200" r="180"></circle>
</mask>
<mask id="msk3">
<rect id="msk-rect" fill="#fff" x="200" y="-100" width="300" height="100"></rect>
</mask>
</defs>
<polygon id="poly" mask="url(#msk1)" fill="none" stroke-width="30" stroke="red" points="200 35.5 10 364.5 390 364.5"></polygon>
<circle id="circle" mask="url(#msk2)" fill="none" stroke-width="30" stroke="green" cx="600" cy="200" r="180"></circle>
<rect id="rect" mask="url(#msk3)" fill="none" stroke-width="30" stroke="blue" x="200" y="-100" width="300" height="100"></rect>
</svg>
有 3 种形状:等边三角形、圆形和矩形。还有用于更改笔画粗细和调整形状大小的滑块。这些数字是相互独立的。正如您在示例中看到的,形状的轮廓仅向内变化。由于遮罩元素和@Alexandr_TT帮助我解决了这个问题,以及这个问题的替代解决方案,外部笔划被剪掉了。
但是由于 使用蒙版/剪辑路径并非一切都是完美的(在此处阅读有关该问题的更多信息),然后我正在寻找一种在方法方面可能更复杂但更通用的解决方案,该解决方案将基于数学和几何。
我希望能够分别使用一个多边形、一个矩形和一个圆形来解决每个形状的问题。没有蒙版,没有剪辑路径和其他外部元素。也就是只需要重新计算三角形的坐标,矩形的宽高和圆的半径。
附加限制:
- 三角形的坐标、初始半径或圆心的坐标,以及矩形的宽度和高度都是任意的。在示例中,它们的含义只是一个示例。三角形总是等边的(为简单起见)。
- 您不能更改 viewBox、使用 css、蒙版和剪辑路径。
- 在任何情况下,笔划都不会超出形状的边界。
- 描边可以完全“填充”形状内部的背景。
- 使用滑块调整形状的笔触和大小。
- SVG 本身可以有许多不同的其他形状和元素,这个决定不应该影响它们。
问题:如何做到这一点?
这是一个示例,其中所有不必要的内容都已删除:https ://jsfiddle.net/ru8fzeya/6/ 只剩下形状和更改笔触粗细/大小。但是 stroke 的默认行为是在两个方向上扩展,您需要获得与示例中使用遮罩但不使用遮罩相同的结果。
让我们尝试用
clipPath使用了问题中的代码。将遮罩更改为 clipPath。剪裁原理与遮罩相同 - 剪裁定义中指定的形状之外的所有内容都将被剪裁。将显示内部内容。因此,字符串只会向内增长。
添加了坐标网格以可视化更改。
该解决方案基于找到中心并计算偏移量的原理,尽管对于每个给定的数字,它的计算方式略有不同。
所以,比如有一种形状,我们想增加1个像素的笔画粗细,自然会增加
видимый размер形状,这正是需要补偿(减小形状)的地方,如图所示以上。由于需要计算补偿,将计算分成两个函数来计算线的大小和粗细是没有意义的。
对于圆,最简单的是:半径增加 1 个像素会导致直径增加 2 个像素:
радиус - толщина_обводки / 2;对于一个 rectangle ,它有点复杂:
начальная_позиция_x + толщина_обводки / 2начальная_позиция_x + толщина_обводки / 2ширина - толщина_обводкивысота - толщина_обводки对于多边形来说,这更加困难:
центр点会发散/收敛的地方расстояние от центра和угол в градусах对于每个点центр + (расстояние_от_центра - толшина_обводки + размер) * косинус(угла)центр + (расстояние_от_центра - толшина_обводки + размер) * синус(угла)下面是一个解决方案,代码不是很优化,但是我们看了下,唯一没解决的一点就是如果线粗大于半径,那么就重叠svg begin的特性,然后图形就被渲染或者“绘制”了,所以先最好设置笔画粗细为1像素的大小,然后加上粗细,一般情况下,我觉得根据图的大小加个取值范围的修正并不难so没有这样的覆盖。