#google-chrome #d3.js #html5-canvas
Вопрос:
Я работаю над приложением D3 и столкнулся со странной проблемой масштабирования, которая возникает в Chrome, но не в Firefox (это единственные браузеры, в которых я тестировал свой код). Я свел проблему к приведенному ниже фрагменту кода.
В принципе, в определенных условиях обработчик масштабирования, который я определил, не вызывается при прокрутке элемента холста (с помощью кнопки прокрутки мыши или двух пальцев на трекпаде ноутбука). Однако щелчок и перетаскивание по холсту для его панорамирования успешно вызывают обработчик масштабирования.
Подробности вопроса:
- Масштабирование работает должным образом до тех пор, пока не будет вызван обработчик события «щелчок». Как только он будет вызван, масштабирование прокрутки не будет работать. И это как — то связано с вызовом
ctx.getImageData
в обработчике событий click. - Если я опущу
.call
вызывающий выбор в конце холстаclearRect
, проблема с масштабированием возникнет, даже если вы не запускали событие «щелчок». - Проблема возникает в других версиях D3, кроме v5. Я пробовал v6 и v7.
- Версия Chrome, которую я использую, 92.0.4515.159
- Я знаю несколько способов решить эту проблему:
- Проблема устраняется, если непрозрачность элемента canvas не установлена в 0.
- Это также можно решить, позвонив
window.addEventListener('wheel', () => {})
- Из того, что я помню, другим решением является определение поведения масштабирования на родительском элементе холста вместо этого.
Приведенный ниже код создает элемент canvas в левом верхнем углу (он не виден, так как его непрозрачность равна 0). При увеличении масштаба элемента на консоль будет выведено сообщение «масштабирование». При нажатии на холст будет выведено «нажмите». Вы обнаружите, что с кодом как есть, если вы нажмете на элемент, а затем попытаетесь прокрутить масштаб, «масштабирование» не будет напечатано. Вы также можете запустить код в JSFiddle: https://jsfiddle.net/yr3jdvhw/37/
Я хотел бы знать, в чем причина этой проблемы. Как я уже упоминал, я мог бы просто установить непрозрачность холста на ненулевое значение, чтобы избежать этой проблемы. Но я действительно хотел бы знать первопричину.
<html>
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<canvas class="my-canvas"></canvas>
<script>
const myCanvas = d3.select(".my-canvas")
.style('opacity', 0)
.on('click', function () {
console.log("click")
let ctx = this.getContext('2d')
const pixel = ctx.getImageData(0, 0, 1, 1)
})
.call(d3.zoom().on('zoom', () => {
console.log("zooming")
}))
.call(function (s) {
let ctx = s.node().getContext('2d')
ctx.clearRect(0, 0, s.node().width, s.node().height)
})
</script>
</body>
</html>
Ответ №1:
Это ошибка в Chrome, я только что открыл новую проблему по этому поводу, будем надеяться, что это скоро исправят.
Из моих исследований следует, что основные проблемы заключаются в том, что они обрабатывают события колеса на уровне составителя и что, когда ваш холст деакселерируется, он больше не проходит правильный путь в составителе и, следовательно, больше не рассматривается как «область обработчика событий колеса».
Вызов getImageData()
в настоящее время деакселерирует ваш холст, он переходит от графического процессора к процессору и остается там, поэтому вызов этого метода вызывает проблему. Аналогично, до тех пор, пока вы не выполните какую-либо операцию рисования, холст еще не перемещен на графический процессор, и, таким образом, здесь тоже воспроизводится ошибка.
Обратите внимание, что, надеюсь, в нескольких версиях { willReadFrequently }
будет доступно без флага, и что в этот момент большинство полотен всегда будут ускоряться.