javascript - 无论位置如何,如何获得一致的笔画宽度?
问题描述
问题的本质是,当我移动 SVG 元素时,线条的宽度会发生变化。
我在浏览器环境中工作,我想要清晰的线条(没有抗锯齿),所以形状渲染设置为清晰边缘。例如,您可能有
“d M 0 0 L 10 0 L 10 10 L 0 10 z”
定义一个正方形,样式设置为
'填写:无;中风:黑色;笔画宽度:1px;形状渲染:crispEdges'
然后使用 translate() 用鼠标拖动它。它可以工作,但是随着正方形的移动,线条的粗细会跳动一个像素,我希望粗细保持不变。
我想我知道它为什么会发生,但我找不到任何方法来阻止它。它发生(我认为)是由于相对于 viewBox 的坐标映射到相对于物理监视器像素的坐标的方式。当一个像素宽(在 SVG 术语中)的线被映射到显示器时,它可能会或可能不会跨越多个像素,因此它最终可能会变得更厚或更薄(屏幕)像素。
我尝试弄乱 viewBox 大小与绘图区域大小的比率,将平移量四舍五入为整数或采用整数 + 0.50 的形式,但这样的解决方案似乎不太可能奏效,因为它来了缩小到浏览器中的缩放级别。矢量效果:非缩放笔画也不能修复它。
有没有办法告诉 SVG 将所有路径视为 1d 几何形状,并为所有路径使用特定的笔?换句话说,我希望用于绘制所有内容的笔“随缩放而缩放”,而不是在绘制线条后缩放线条。
拜托,只有香草JS。
您可以通过运行下面的代码来测试我的意思。单击正方形并将其拖动(无触摸设备)。请注意,在某些级别的浏览器缩放中,它可能表现得很好,而不是像我所描述的那样。
发生了一些奇怪的事情。svg 元素(正方形)一开始看起来很均匀,所有边缘的宽度都相同。它仅响应鼠标移动而移动,并且该事件(可能)在鼠标移动整个(绝不是分数)屏幕像素时发生。因此,如果它以这种方式开始,人们会期望正方形移动整个屏幕像素并保持与屏幕像素对齐。
跟进...问题不在屏幕CTM上。我测试了逆真的是逆;也就是说,CTM x CTM^{-1} 是我尝试的每个值的标识。并且 matrixTransform(getScreenCTM().inverse()) 提供的值在输入中是线性的(或与浮点数允许的一样线性)。
<html>
<body>
<svg xmlns="http://www.w3.org/2000/svg" id="svgtest"
style = "border: 1px solid; display: block; margin-left: auto; margin-right: auto; shape-rendering: crispEdges;"
width = "400" height = "400" viewBox = "0 0 100 100" >
</svg>
<script>
var theSquare = {
x : 10,
y : 10
};
var initialSquare = {
x : 10,
y : 10
};
var SideLength = 10;
var initialX = 0;
var initialY = 0;
var draggingSquare = 0;
function pointInRect(p, r) {
return p.x > r.xLeft && p.x < r.xRight && p.y > r.yTop && p.y < r.yBottom;
}
function mouseToLocal(theEvent) {
var screenPt = svgArea.createSVGPoint();
screenPt.x = theEvent.clientX;
screenPt.y = theEvent.clientY;
var svgPt = screenPt.matrixTransform(svgArea.getScreenCTM().inverse());
return {
x : svgPt.x,
y : svgPt.y
};
}
function doMouseDown(event) {
var localCoord = mouseToLocal(event);
initialX = localCoord.x;
initialY = localCoord.y;
var pt = {x: initialX, y: initialY};
var rect = {xLeft: theSquare.x, xRight: theSquare.x + SideLength,
yTop: theSquare.y, yBottom: theSquare.y + SideLength};
if (pointInRect(pt,rect))
{
draggingSquare = 1;
initialSquare.x = theSquare.x;
initialSquare.y = theSquare.y;
}
else
draggingSquare = 0;
}
function doMouseUp(event) {
draggingSquare = 0;
}
function doMouseMove(event) {
if (draggingSquare == 0)
return;
var localCoord = mouseToLocal(event);
zeroTranslate.setTranslate(initialSquare.x + localCoord.x - initialX,
+initialSquare.y + localCoord.y - initialY);
theSquare.x = initialSquare.x + localCoord.x - initialX;
theSquare.y = initialSquare.y + localCoord.y - initialY;
}
var svgArea = document.getElementById('svgtest');
var theSVGSquare = document.createElementNS("http://www.w3.org/2000/svg", 'path' );
theSVGSquare.setAttributeNS(null, "d", "M 0 0" +
" L " + SideLength + " 0" +
" L " + SideLength + " " + SideLength +
" L 0 " +SideLength +
" z");
theSVGSquare.setAttributeNS(null, 'style', 'fill: none; stroke: black; stroke-width: 0.5px; shape-rendering: crispEdges' );
var tforms = theSVGSquare.transform;
var zeroTranslate = svgArea.createSVGTransform();
zeroTranslate.setTranslate(initialSquare.x,initialSquare.y);
theSVGSquare.transform.baseVal.insertItemBefore(zeroTranslate,0);
svgArea.appendChild(theSVGSquare);
svgArea.addEventListener("mousedown",doMouseDown,false);
svgArea.addEventListener("mouseup",doMouseUp,false);
svgArea.addEventListener("mousemove",doMouseMove,false);
</script>
</body>
</html>
解决方案
推荐阅读
- amazon-simple-email-service - Amazon Simple Email Service 无法在端口 465 上运行
- python - 使用 Regex Python 搜索括号内的所有值
- c++ - 为什么可以向外部库添加函数以访问内部数据
- javascript - Yup & React Hook Form:如何验证 onChange 而不是 onSubmit
- google-apps-script - 使用脚本在 Gmail 主题行中搜索单元格值,然后转发电子邮件
- javascript - Nodemailer:无法发送嵌入图像
- r - 在 UTM 中创建具有混合区域的唯一对象
- java - 自定义异常未运行,抛出其他异常但未自定义。我应该为自定义异常做什么?
- python - 如何访问测试脚本之外的标记列表
- nestjs - NestJS & Multer 图像类型检查错误响应客户端