Предотвратить субпиксельный рендеринг с помощью svg

В настоящее время я работаю с 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).

Было бы неплохо, если бы кто-нибудь мог помочь мне с идеей, чтобы решить мою проблему

не могли бы вы предоставить скрипку в качестве примера? под масштабированием вы имеете в виду масштабирование в браузере или вы управляете масштабированием через javascript?

Bacon 03.06.2019 09:46

Одним из решений легкий вашей проблемы будет использование vector-effect = "non-scaling-stroke"Цитата МДН: Значение non-scaling-stroke — это ключевое слово для предопределенного векторного эффекта, вызывающего ширина штриха объекта не зависит от преобразований и масштабирования.

enxaneta 04.06.2019 17:13

@Bacon Я управляю масштабированием через javascript. на основе уровня масштабирования и положения указателя рассчитывается ширина штриха. Я могу предоставить скрипку, но не раньше среды, потому что я сейчас в командировке...

breezertwo 04.06.2019 17:25

может попробовать shape-rendering = "crispEdges" ?

Flash Thunder 31.07.2019 15:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
13
4
1 419
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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 пикселю на монитор.

breezertwo 06.08.2019 16:02
Ответ принят как подходящий

Наконец-то мы нашли решение для этого, если у кого-то возникнут такие же проблемы:

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;
  }

Другие вопросы по теме