Como todos sabemos, canvas é um bitmap. Em um bitmap podemos desenhar várias coisas nele, incluindo imagens, linhas, etc. Então, o que devemos fazer se quisermos adicionar um evento de clique a uma determinada imagem na tela. E js só pode monitorar eventos do canvas. Obviamente essa imagem não existe e as imagens no dom são apenas desenhadas no canvas. A seguir, simplesmente implementarei a vinculação de eventos para cada imagem dentro de uma tela.
Deixe-me primeiro falar sobre o princípio de implementação: na verdade, ele vincula eventos relacionados à tela. Ao registrar as coordenadas da tela onde a imagem está localizada, é julgado em qual imagem o evento atua. Dessa forma, parece um pouco semelhante ao agente de eventos. No entanto, ainda é um pouco complicado de implementar.
ps: Eu escrevi o seguinte código em ts. Você pode lê-lo como es6. Você pode verificar se é um pouco diferente.
Documentação do Typescript (o Typescript é muito fácil de usar, recomendo que você aprenda mais sobre ele).
1. Estabeleça uma conexão entre a imagem e a tela (aqui eu uso blocos de cores em vez de imagens)Aqui precisamos estabelecer uma certa conexão entre o bloco de cores e a tela, ao invés de apenas renderizar. Registre também as coordenadas, largura e altura do bloco de cores. Vamos implementá-lo passo a passo
Primeiro escreva uma página HTML básica para criar uma tela:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, escala inicial=1.0> <meta http-equiv=X-UA -Conteúdo compatível=ie=edge> <title>evento de tela</title> <style> html, body { height: 100% background: #eee } canvas { background: #fff; display: bloco; margem: 0 auto } </style></head><body> <canvas width=500 height=500 id=canvas></canvas></body>
A seguir, precisamos definir uma classe Canvas. Quais funções esta classe deve ter?
Como os blocos de cores também possuem alguns parâmetros próprios, para facilitar a expansão, definimos também uma classe para os blocos de cores. As funções necessárias para este tipo são:
Largura, altura, cor, coordenadas (x, y) e instância do Canvas, vamos decidir sobre isso inicialmente;
OK, comece a escrever
// Canvas class class Canvas { blockList: Block[] ctx: any canvas: any createBlock (option) { option.Canvas = this this.blockList.push(new Block(option)) this.painting() } renderização (bloco) { // Renderizar bloco de cores function this.ctx.fillStyle = block.color this.ctx.fillRect(block.x, block.y, block.w, block.h) } painting () { // Renderize todos os blocos de cores do contêiner na tela // Limpe a tela (a antiga deve ser limpa antes da renderização) this.ctx.fillStyle = '#fff' this.ctx.fillRect(0, 0, this.canvas. width, this .canvas.height) this.blockList.forEach(ele => { this.rendering(ele) }) } constructor (ele) { // Função de inicialização (a entrada é canvas) // Definir canvas this.canvas = ele this.ctx = this.canvas.getContext('2d') // Contêiner do bloco de cores this.blockList = [] }}class Block { w: número h: número x: número y: cor do número : string Canvas: Hierarquia do Canvas: construtor de número ({ w, h, x, y, color, Canvas }) { // Inicializa e define as propriedades relacionadas ao bloco de cores this.w = w this.h = h this.x = x this.y = y this.color = color this.Canvas = Canvas }}
Vamos tentar executar uma onda abaixo
// Crie uma instância do Canvas e adicione um bloco de cor azul com largura e altura de 100px, posição (100.100), (300.100) blocos de cores vermelho e azul var canvas = new Canvas(document.getElementById('canvas')) canvas. createBlock({ // vermelho x: 100, y: 100, w: 100, h: 100, cor: '#f00' }) canvas.createBlock({ // azul x: 100, y: 100, w: 300, h: 100, color: '#00f' })
Os resultados da execução são os seguintes:
2. Adicione um evento de clique ao bloco de coresAqui você não pode adicionar diretamente um evento de clique ao bloco de cores, então você precisa usar coordenadas para determinar qual bloco de cores está clicado no momento.
class Block { // ...Omite parte do código checkBoundary (x, y) { // Determina o método de limite return x > this.x && x < (this.x + this.w) && y > this.y && y < (this.y + this.h) } mousedownEvent () { // Evento de clique console.log(`Clicado no bloco de cores com cor ${this.color}`) }}class Canvas { // .. .construtor de código de parte omitido (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Vinculação de evento (há uma coisa a ser observada aqui. Usei o método bind aqui, que is Para mudar o ponteiro this no método mousedownEvent para Canvas) this.canvas.addEventListener('click', this.mousedownEvent.bind(this)) // Click event} mousedownEvent () { // Evento de clique const x = e.offsetX const y = e.offsetY // Aqui as coordenadas do clique são passadas para todos os blocos de cores e o método de julgamento de limite é usado para determinar se o clique está dentro. Se sim, execute o método de evento do bloco de cores. this.blockList.forEach(ele => { if (ele.checkBoundary(x, y)) ele.mousedownEvent(e) }) }}
Até agora, implementamos a vinculação de eventos de clique correspondentes a diferentes blocos de cores em diferentes telas. Porém, este evento de clique não é perfeito, pois até o momento não introduzimos o conceito de hierarquia, o que significa que se dois blocos de cores sobrepostos forem clicados, ambos serão acionados. Portanto, também precisamos adicionar atributos hierárquicos aos blocos de cores. Se você clicar em um bloco de cores para alterá-lo, o nível do bloco de cores será elevado ao nível mais alto.
class Block { // ...Omite parte do construtor de código ({ w, h, x, y, color, Canvas, hierarquia }) { // Inicializa e define as propriedades relacionadas ao bloco de cores this.w = w this .h = h this. x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = 0 }}class Canvas { // ...omitir parte do construtor de código (ele) { this .canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Vinculação de evento (há uma coisa a ser observada aqui. Usei o método bind aqui para mudar o ponteiro this no método mousedownEvent para Canvas) this .canvas .addEventListener('click', this.mousedownEvent.bind(this)) // Evento de clique this.nowBlock = null // Bloco de cores atualmente selecionado} createBlock (option) { // Criar função de bloco de cores (Bloco aqui é a classe do bloco de cores) option.Canvas = this // O nível de criação do bloco de cores mais recente deve ser o mais alto option.hierarchy = this.blockList.length this.blockList.push(new Block (opção)) this.rendering() } mousedownEvent (e) { // Evento de clique const x = e.offsetX const y = e.offsetY // Obtenha o bloco de cores de nível mais alto no ponto this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Se não houver nenhum bloco de cores capturado, saia diretamente se (!this .nowBlock) return // Aumenta o nível do bloco de cores clicado para o mais alto this.nowBlock.hierarchy = this.blockList.length // Reordena (de pequeno para grande) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Realoque a hierarquia de 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Reclassifique na ordem inversa e depois renderize novamente. this.painting() this.nowBlock.mousedownEvent(e) // Aciona apenas eventos para o bloco de cores selecionado}}// Aqui temos que adicionar um terceiro bloco de cores que se sobrepõe ao bloco de cores vermelho canvas.createBlock({ x: 150 , y: 150, w: 100, h: 100, cor: '#0f0'})
O código no método mousedownEvent no Canvas é um pouco complicado, principalmente porque é um pouco complicado.
O efeito após a corrida é o seguinte:
3. Arraste e solte blocos de cores diferentesAcima implementamos a obtenção de diferentes blocos de cores e a modificação de seus níveis. A seguir precisamos implementar o arrastamento dos blocos coloridos, principalmente para obter as mudanças nas coordenadas de posição durante o movimento do mouse e quando o mouse é clicado inicialmente. Este princípio é o mesmo da implementação comum de arrastar e soltar do DOM.
Obtenha o ponto onde o bloco de cores foi clicado e a distância (disX, disY) da esquerda e do topo do bloco de cores.
Quando o mouse se move, subtraia (disX, disY) da distância atual do mouse à esquerda e ao topo da tela. Estas são as coordenadas xey do bloco de cores.
class Block { // ...omite parte do código mousedownEvent (e: MouseEvent) { /* O método de cálculo de disX e disY aqui: e.offsetX obtém a distância entre o clique do mouse e o lado esquerdo da tela, isso .x é a distância do bloco de cores A distância à esquerda da tela. e.offsetX-this.x é a distância à esquerda do bloco de cores. Isso deve ser fácil de entender */ const disX = e.offsetX - this.x // A distância do lado esquerdo do bloco de cores quando clicado const disY = e.offsetY - this.y // A distância do topo do o bloco de cores quando clicado // Vincula o evento de deslizamento do mouse; aqui mouseEvent.offsetX também é a distância entre o mouse e o lado esquerdo da tela, mouseEvent.offsetX - disX é a coordenada x do bloco de cores. Da mesma forma, y é calculado da mesma maneira. Finalmente, basta renderizar novamente. document.onmousemove = (mouseEvent) => { this.x = mouseEvent.offsetX - disX this.y = mouseEvent.offsetY - disY this.Canvas.painting() } // Limpa todos os eventos quando o mouse é liberado document.onmouseup = ( ) => { document.onmousemove = document.onmousedown = null } // console.log(`O bloco de cores 22 com a cor ${this.color} foi clicado`) }}
O efeito é o seguinte:
O código completo está colado abaixo (o HTML e o método de chamada não serão incluídos). Este exemplo é apenas uma implementação simples de eventos de ligação ao conteúdo na tela. Você pode implementar outros mais complexos, como substituir blocos de cores por imagens. Além de arrastar, você pode ampliar, girar, excluir, etc.
class Canvas { blockList: Block[] ctx: any canvas: any nowBlock: Block createBlock (option) { option.hierarchy = this.blockList.length option.Canvas = this this.blockList.push(new Block(option)) this. pintura() } renderização (bloco) { this.ctx.fillStyle = block.color this.ctx.fillRect (block.x, block.y, block.w, block.h) } painting () { // Limpa a tela 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) { // Evento de clique const x = e.offsetX const y = e.offsetY // Obtenha o bloco de cores de nível mais alto no ponto this.nowBlock = (this.blockList.filter(ele => ele.checkBoundary(x, y))).pop() // Se não houver nenhum bloco de cores capturado, saia diretamente se (!this .nowBlock) return // Aumenta o nível do bloco de cores clicado para o mais alto this.nowBlock.hierarchy = this.blockList.length // Reordena (de pequeno para grande) this.blockList.sort((a, b) = > a.hierarchy - b.hierarchy) // Realoque a hierarquia de 0 this.blockList.forEach((ele, idx) => ele.hierarchy = idx) // Reclassifique na ordem inversa e depois renderize novamente. this.painting() this.nowBlock.mousedownEvent(e) // this.blockList.forEach(ele => { // if (ele.checkBoundary(x, y)) ele.clickEvent(e) // }) } construtor (ele) { this.canvas = ele this.ctx = this.canvas.getContext('2d') this.blockList = [] // Vinculação de evento this.canvas.addEventListener('mousedown', this.mousedownEvent.bind(this)) }}class Block { w: número h: número x: número y: número cor: string Canvas: Hierarquia de canvas: construtor de número ( { w, h, x, y, cor, Canvas, hierarquia }) { this.w = w this.h = h this.x = x this.y = y this.color = color this.Canvas = Canvas this.hierarchy = hierarquia } 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(`O bloco de cores 22 com a cor ${this.color} foi clicado`) }}
O texto acima é todo o conteúdo deste artigo. Espero que seja útil para o estudo de todos. Também espero que todos apoiem a Rede VeVb Wulin.