В настоящее время я работаю с SVG и зашел в тупик.
В SVG есть линии, которые должны масштабироваться вместе с масштабированием (чтобы они оставались в равновесии: например, 100% ширины 10 пикселей -> 10% ширины 1 пиксель)
я масштабирую все stroke-widths
с помощью этого кода:
var svgPath = this._svgContainer.find('svg [class* = "style"]');
for (var i = 0; i < svgPath.length; ++i) {
var newStrokeWidth = this._oldStrokeWidth[i] * (1 / (width / imgData.w));
$(svgPath[i]).css(
'stroke-width', newStrokeWidth
);
}
Где width
— новая ширина после масштабирования, а imgData.w
— исходная немасштабированная ширина.
Проблема в том, что если я увеличу слишком далеко. Штрих становится слишком маленьким и приводит к субпиксельному рендерингу. И якобы черные линии становятся серыми.
Моя идея заключалась в том, чтобы обрезать значение в определенный момент, чтобы предотвратить это. Но, насколько мне известно, я также должен учитывать соотношение пикселей устройства из-за разных экранов (настольный, мобильный, 4K).
Было бы неплохо, если бы кто-нибудь мог помочь мне с идеей, чтобы решить мою проблему
Одним из решений легкий вашей проблемы будет использование vector-effect = "non-scaling-stroke"
Цитата МДН: Значение non-scaling-stroke
— это ключевое слово для предопределенного векторного эффекта, вызывающего ширина штриха объекта не зависит от преобразований и масштабирования.
@Bacon Я управляю масштабированием через javascript. на основе уровня масштабирования и положения указателя рассчитывается ширина штриха. Я могу предоставить скрипку, но не раньше среды, потому что я сейчас в командировке...
может попробовать shape-rendering = "crispEdges"
?
var newStrokeWidth = this._oldStrokeWidth[i] * (1 / (width / imgData.w));
newStrokeWidth = (newStrokeWidth < 1) ? 1 : newStrokeWidth;
newStrokeWidth всегда будет 1 или больше
Это неправильный способ решить эту проблему: значение ширины обводки будет равно 1, но из-за того, что область просмотра находится между (0 0 0 0) и (inf inf inf inf), ширина обводки единицы не равна 1 пикселю на монитор.
Наконец-то мы нашли решение для этого, если у кого-то возникнут такие же проблемы:
1) Из-за панорамирования this._$svgElement
и вычисления vpx
в совершенно другом разделе кода элемент находится «между» пикселями. (100.88945px для x например). Это приводит к размытию линий.
Я исправил эту часть простым Мат.раунд().
this._hammerCanvas.on('panmove', (event: any) => {
const translate3d = 'translate3d(' + Math.round(this._oldDeltaX + ((vpx === imgData.x) ? 0 : vpx) + event.deltaX) + 'px, ' + Math.round(this._oldDeltaY + ((vpy === imgData.y) ? 0 : vpy) + event.deltaY) + 'px, 0)';
this._$svgElement.css({
transform: translate3d
});
}
2) Чтобы решить проблему между окном просмотра SVG и силой линии, мне пришлось реализовать метод для расчета ширины штриха, равной 1 «реальному» пикселю относительно размера svgs.
обновленный код выглядит так: (Это начальный код, после загрузки SVG с сервера. Внутри масштабирования старый код выше все тот же)
const pixelRatio = devicePixelRatio || 1;
const widthRatio = this._initSVGWidth / svgContainerWidth;
const heightRatio = this._initSVGHeight / svgContainerHeight;
this._svgZoomFactor = Math.max(widthRatio, heightRatio);
const strokeWidth1px = this.computeStrokeWidth1px(widthRatio, heightRatio);
for (let i = 0; i < svgPaths.length; ++i) {
this._initalStrokeWidth[i] = parseFloat($(svgPaths[i]).css('stroke-width'));
const newStrokeWidth = Math.max(strokeWidth1px / pixelRatio, this._svgZoomFactor * this._initalStrokeWidth[i]);
$(svgPaths[i])[0].setAttribute('style', 'stroke-width:' + newStrokeWidth);
this._oldStrokeWidth[i] = newStrokeWidth;
}
и вычисление:
protected computeStrokeWidth1px (widthRatio: number, heightRatio: number): number {
const viewBox = this._$svgElement[0].getAttribute('viewBox').split(' ');
const viewBoxWidthRatio = parseFloat(viewBox[2]) / this._$svgElement.width();
const viewBoxHeightRatio = parseFloat(viewBox[3]) / this._$svgElement.height();
return widthRatio > heightRatio ? viewBoxWidthRatio : viewBoxHeightRatio;
}
не могли бы вы предоставить скрипку в качестве примера? под масштабированием вы имеете в виду масштабирование в браузере или вы управляете масштабированием через javascript?