Суть проблемы в том, что когда я перемещаю элемент SVG, ширина линий меняется.
Я работаю в среде браузера и хочу четкие линии (без сглаживания) , так что рендеринг формы установлен в crispEdges. Например, у вас может быть
"d M 0 0 L 10 0 L 10 10 L 0 10 z"
для определения квадрата со стилем
' заполнить: нет; ход: черный; ширина хода: 1 пиксель; рендеринг формы: crispEdges '
Затем используйте translate (), чтобы перетащить его мышью. Это работает, но по мере движения квадрата толщина линий прыгает на пиксель, и я хочу, чтобы толщина оставалась постоянной.
Мне кажется, я знаю почему это происходит, но Я не могу найти способ предотвратить это. Это происходит (я думаю) из-за того, что координаты относительно viewBox отображаются на координаты относительно пикселей физического монитора. Когда линия шириной в один пиксель (в терминах SVG) отображается на мониторе, она может занимать или не перекрывать несколько пикселей, поэтому она может иметь (экранный) пиксель толще или тоньше.
Я пробовал возиться с отношением размера viewBox к размеру области рисования, округляя сумму перевода до целого числа или принимать целое число формы +0,50, но ни одно из подобных решений, похоже, не сработает, поскольку оно сводится к уровню зума в браузере. векторный эффект: не масштабирующий штрих тоже не исправляет это.
Есть ли способ заставить SVG рассматривать все пути как фигуры 1d геометрии c и использовать отдельное перо для всех их? Другими словами, я хочу, чтобы перо рисовало все в «масштабе с масштабированием», а не с масштабом линий после того, как они были нарисованы.
Пожалуйста, только ваниль 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>