Как мы все знаем, холст — это растровое изображение. В растровом изображении мы можем рисовать различные объекты, включая изображения, линии и т. д. Итак, что нам делать, если мы хотим добавить событие щелчка к определенному изображению на холсте? А js может отслеживать только события холста. Очевидно, что этой картинки не существует, а картинка в dom просто нарисована на холсте. Далее я просто реализую привязку событий для каждого изображения внутри холста.
Сначала расскажу о принципе реализации: это фактически привязка связанных событий к холсту. По записи координат холста, на котором находится изображение, определяется, на какое изображение воздействует событие. В этом смысле он немного похож на агента событий. Тем не менее, это все еще немного сложно реализовать.
PS: Я написал следующий код в ts. Вы можете просто прочитать его как es6. Можете проверить, если он немного отличается.
Документация по машинописному тексту (машинописный текст действительно прост в использовании, я рекомендую вам узнать о нем больше).
1. Установите связь между картинкой и холстом (здесь вместо картинок я использую цветные блоки)Здесь нам нужно установить некую связь между цветовым блоком и холстом, а не просто рендеринг. Также запишите координаты, ширину и высоту цветового блока. Давайте реализуем это шаг за шагом
Сначала напишите простую HTML-страницу для создания холста:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, Initial-scale=1.0> <meta http-equiv=X-UA -Compatible content=ie=edge> <title>canvas event</title> <style> html, body { height: 100%; #fff; display: блок; поля: 0 авто } </style></head><body> <canvas width=500 height=500 id=canvas></canvas></body>
Далее нам нужно определить класс Canvas. Какие функции должен иметь этот класс?
Поскольку цветные блоки также имеют некоторые собственные параметры, для облегчения расширения мы также определяем класс для цветных блоков. Для этого типа необходимы следующие функции:
Давайте сначала определимся с шириной, высотой, цветом, координатами (x, y) и экземпляром Canvas;
ОК, начни писать
// Класс Canvas class Canvas {blockList: Block[] ctx: любой холст: любой createBlock (опция) { option.Canvas = this this.blockList.push(new Block(option)) this.painting() } рендеринг (блок) { // Функция рендеринга цветового блока this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, Block.y, Block.w, Block.h) } Painting () { // Рендеринг всех цветовых блоков в контейнере на холсте // Очистка холста (старый должен быть очищен перед рендерингом) this.ctx.fillStyle = '#fff' this.ctx.fillRect(0, 0, this.canvas. width, this .canvas.height) this.blockList.forEach(ele => { this.rendering(ele) }) } конструктор (ele) { // Функция инициализации (входные данные — холст) // Установить холст this.canvas = ele this.ctx = this.canvas.getContext('2d') // Контейнер цветового блока this.blockList = [] }}class Block { w: число h: число x: число y: цвет числа : string Canvas: Иерархия холста: числовой конструктор ({ w, h, x, y, color, Canvas }) { // Инициализируем и устанавливаем свойства, связанные с цветовым блоком this.w = w this.h = h this.x = x this.y = y this.color = цвет this.Canvas = Canvas }}
Давайте попробуем запустить волну ниже
//Создаем экземпляр Canvas и добавляем синий цветовой блок шириной и высотой 100 пикселей, положением (100,100), (300,100), красным и синим цветовыми блоками var Canvas = new Canvas(document.getElementById('canvas')) Canvas .createBlock({ // красный x: 100, y: 100, w: 100, h: 100, цвет: '#f00' }) Canvas.createBlock({ // синий x: 100, y: 100, w: 300, h: 100, цвет: '#00f' })
Результаты бега следующие:
2. Добавьте событие клика в цветовой блок.Здесь нельзя напрямую добавить событие щелчка к цветовому блоку, поэтому вам нужно использовать координаты, чтобы определить, по какому цветовому блоку в данный момент щелкают.
class Block { // ...опускаем часть кода checkBoundary (x, y) { // определяем метод границы return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent () { // Событие щелчка console.log(`Клик по цветному блоку с цветом ${this.color}`) }}class Canvas { // .. .опущен конструктор кода детали (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Привязка событий (здесь следует отметить одну вещь. Здесь я использовал метод привязки, который Чтобы переключить указатель this в методе mousedownEvent на Canvas) this.canvas.addEventListener('click', this.mousedownEvent.bind(this)) // Событие щелчка} mousedownEvent () { // Click event const x = e.offsetX const y = e.offsetY // Здесь координаты щелчка передаются всем цветным блокам, а метод оценки границы используется для определения того, находится ли щелчок внутри. Если да, выполните метод события цветового блока. this.blockList.forEach(ele => { if (ele.checkBoundary(x, y)) ele.mousedownEvent(e) }) }}
На данный момент мы реализовали привязку соответствующих событий кликов к разным цветным блокам на разных холстах. Однако это событие щелчка не идеально, поскольку до сих пор мы не ввели концепцию иерархии, а это означает, что если щелкнуть два перекрывающихся цветных блока, сработают оба. Поэтому нам также необходимо добавить иерархические атрибуты к цветным блокам. Если вы нажмете на цветовой блок, чтобы изменить цветовой блок, уровень цветового блока будет повышен до самого высокого уровня.
class Block { // ...Пропускаем часть конструктора кода ({ w, h, x, y, color, Canvas, иерархия }) { // Инициализируем и устанавливаем свойства, связанные с цветовым блоком this.w = w this .h = h this.x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = 0 }}class Canvas { // ...опустить часть конструктора кода (ele) { this .canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Привязка события (здесь следует отметить одну вещь. Здесь я использовал метод привязки, чтобы переключить указатель this в методе mousedownEvent на Canvas) this .canvas .addEventListener('click', this.mousedownEvent.bind(this)) // Событие щелчка this.nowBlock = null // Текущий выбранный цветовой блок} createBlock (опция) { // Создать функцию цветового блока (здесь Block — класс цветового блока) option.Canvas = this // Уровень создания последнего цветового блока должен быть самым высоким option.hierarchy = this.blockList.length this.blockList.push(new Block (опция)) this.rendering() } mousedownEvent (e) { // Событие щелчка const x = e.offsetX const y = e.offsetY // Получить цветовой блок самого высокого уровня в точке this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Если захваченного цветового блока нет, выходим напрямую, если (!this .nowBlock) return // Поднимите уровень выбранного цветового блока до максимального значения this.nowBlock.hierarchy = this.blockList.length // Измените порядок (от меньшего к большему) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Перераспределяем иерархию с 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Повторно сортируем в обратном порядке и затем повторно отображаем. this.painting() this.nowBlock.mousedownEvent(e) // События запускаются только для выбранного цветового блока}}// Здесь нам также нужно добавить третий цветовой блок, который перекрывает красный цветовой блок Canvas.createBlock({ x: 150, г: 150, ш: 100, ч: 100, цвет: '#0f0'})
Код метода mousedownEvent в Canvas немного сложен, главным образом потому, что он немного запутан.
Эффект после бега следующий:
3. Перетаскивайте блоки разных цветов.Выше мы реализовали получение блоков разных цветов и изменение их уровней. Далее нам необходимо реализовать перетаскивание цветных блоков, в основном для получения изменений координат положения во время движения мыши и при первоначальном щелчке мыши. Этот принцип такой же, как и в обычной реализации перетаскивания DOM.
Получите точку щелчка по цветовому блоку и расстояние (disX, disY) от левой и верхней части цветового блока.
Когда мышь перемещается, вычтите (disX, disY) из текущего расстояния мыши от левой и верхней части холста. Это координаты x и y цветового блока.
class Block { // ...опускаем часть кода mousedownEvent (e: MouseEvent) { /* Здесь используется метод расчета disX и disY: e.offsetX получает расстояние между щелчком мыши и левой стороной холста, и this.x — расстояние цветового блока. Расстояние слева от холста. e.offsetX-this.x — это расстояние слева от цветового блока. Это должно быть легко понять*/ const disX = e.offsetX - this.x // Расстояние от левой стороны цветового блока при нажатии const disY = e.offsetY - this.y // Расстояние от верха цветовой блок при нажатии // Привязываем событие скольжения мыши; здесь mouseEvent.offsetX — это также расстояние между мышью и левой стороной холста, mouseEvent.offsetX — disX — это координата x цветового блока. Точно так же рассчитывается и y. Наконец, просто перерисуйте. document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } // Очищаем все события при отпускании мыши document.onmouseup = ( ) => { document.onmousemove = document.onmousedown = null } // console.log(`Выбран цветной блок 22` с цветом ${this.color}) }}
Эффект следующий:
Полный код вставлен ниже (HTML и методы вызова не будут включены). Этот пример представляет собой простую реализацию привязки событий к содержимому холста. Вы можете реализовать более сложные, например, замену цветных блоков изображениями. Помимо перетаскивания, Вы можете масштабировать, вращать, удалять и т.д. фотографии.
класс Canvas {blockList: Block [] ctx: любой холст: любой nowBlock: Блок createBlock (опция) { option.hierarchy = this.blockList.length option.Canvas = this this.blockList.push (новый блок (опция)) this. Painting() } рендеринг (блок) { this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, Block.y, Block.w, Block.h) } Painting () { // Очищаем холст this.ctx.fillStyle = '#fff' this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) this.blockList.forEach(ele => { this.rendering(ele) }) } mousedownEvent (e: MouseEvent) { // Событие щелчка const x = e.offsetX const y = e.offsetY // Получить цветовой блок самого высокого уровня в точке this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Если захваченного цветового блока нет, выходим напрямую, если (!this .nowBlock) return // Поднимите уровень выбранного цветового блока до максимального значения this.nowBlock.hierarchy = this.blockList.length // Измените порядок (от меньшего к большему) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Перераспределяем иерархию с 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Повторно сортируем в обратном порядке и затем повторно отображаем. this.painting() this.nowBlock.mousedownEvent(e) // this.blockList.forEach(ele => { // if (ele.checkBoundary(x, y)) ele.clickEvent(e) // }) } конструктор (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Привязка события this.canvas.addEventListener('mousedown', this.mousedownEvent.bind(this)) }}class Block { w: число h: число x: число y: число цвет: строка Canvas: Иерархия холста: числовой конструктор ( { w, h, x, y, цвет, Canvas, иерархия }) { this.w = w this.h = h this.x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = иерархия } checkBoundary (x, y) { return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent (e: MouseEvent) { const disX = e.offsetX - this.x const disY = e.offsetY - this.y document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } document.onmouseup = () => { document.onmousemove = document.onmousedown = null } // console.log(`Нажат цветной блок 22 с цветом ${this.color}`) }}
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.