Canvas同源页面多画布,事件分发隔离

需求产生背景

当我们日常编写图像操作编辑器代码时,可能会碰到一个需求,需要在一个网页里面同时显示多个画布,并且要做到鼠标聚焦到一个画布之上的时候,我们可以操作这个画布之上的元素,同时多画布存在的这个网页中的其他画布【同源页面多画布】,要取消事件操作带来的影响【事件分发隔离】。

实现效果

核心逻辑

为了在一个页面中,能够展示多个绘制图像的窗口,这些窗口我们使用canvas进行分别绘制。然后在不同的canvas中展示不同的图像,为了更加方便的编写代码操作这些canvas画布。我们引入了PaperJS工具。

PaperJS是一个能够非常方便的操作Canvas的JavaScript工具。在PaperJS中,用户能够非常方便的创建路径,注册多个事件工具。管理Canvas画布的多个图层。并且能够管理同一个页面中的多个Canvas画布。

paperJS官网链接

逻辑步骤整理

  1. 创建一个HTML页面,在HTML页面中创建多个画布。
  2. 将这些画布中的paperScope,paperProject,paperView,paperTool分别做状态管理保存下来。
  3. 当画布得到聚焦的时候,我们后续对于这个画布的操作影响到其他画布。

代码实现

首先创建一个Vue3+Vite项目,语言选择TypeScript.

缓存数据结构设计

typescript 复制代码
import {ref} from 'vue'

export const AppStore = ref({

    canvas1: {
        canvasPaperScope: null as any,
        canvasPaperProject: null as any,
        canvasPaperView: null as any,
    },
    canvas2: {
        canvasPaperScope: null as any,
        canvasPaperProject: null as any,
        canvasPaperView: null as any
    }
})

paperjs画布挂载

typescript 复制代码
export function registerCanvas(canvas: string) {
    AppStore.value[canvas].canvasPaperScope = new paper.PaperScope().setup(canvas)
    AppStore.value[canvas].canvasPaperProject = AppStore.value[canvas].canvasPaperScope.project
    AppStore.value[canvas].canvasPaperView = AppStore.value[canvas].canvasPaperScope.view
    // 闭包内部注册辅助工具
    const horizen = new paper.Path.Line({
        from: new paper.Point(0, 0),
        to: new paper.Point(0, 0),
        strokeColor: canvas == 'canvas1'?'grey':'red',
        dashArray: [5, 5]
    })
    const vertical = new paper.Path.Line({
        from: new paper.Point(0, 0),
        to: new paper.Point(0, 0),
        strokeColor: canvas == 'canvas1'?'grey':'red',
        dashArray: [5, 5]
    })
    const ruleLineText = new paper.PointText({
        content: '(1,1)',
        strokeColor: canvas == 'canvas1'?'grey':'red',
        fontSize: 18,
        point: new paper.Point(0, 0)
    })
    // 注册工具
    const tool = new paper.Tool()
    tool.onMouseMove = (event: paper.MouseEvent) => {
        console.log(`画布${canvas}的移动`)
        horizen.visible = true
        vertical.visible = true
        ruleLineText.visible = true
        const point = event.point
        // 改变水平线位置
        vertical.segments[0].point = new paper.Point(0, point.y)
        vertical.segments[1].point = new paper.Point(AppStore.value[canvas].canvasPaperView.size.width, point.y)
        // 改变垂直线的位置
        horizen.segments[0].point = new paper.Point(point.x, 0)
        horizen.segments[1].point = new paper.Point(point.x, AppStore.value[canvas].canvasPaperView.size.height)
        ruleLineText.content = `(${Math.ceil(point.x)},${Math.ceil(point.y)})`
        ruleLineText.point = point
    }
    tool.activate()
}

完整源码

vue 复制代码
<template>
  <div class="app-container">
    <div class="item">
      <canvas id="canvas1" ref="canvas1" resize></canvas>
    </div>
    <div class="item">
      <canvas id="canvas2" ref="canvas2" resize></canvas>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { registerCanvas } from './utils/index'
import { AppStore } from './store/index'

let currentSelect = ''


const canvas1 = ref<any>()

const canvas2 = ref<any>()

onMounted(() => {
  loadData()
})

const loadData = async () => {
  await registerCanvas('canvas1')
  await registerCanvas('canvas2')
}

</script>
<style lang="scss" scoped>
.app-container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: row;

  .item {
    width: 50%;
    height: 100%;

    #canvas1[resize] {
      width: 100%;
      height: 100%;

      &:hover {
        border: 1px solid red;
      }
    }

    #canvas2[resize] {
      width: 100%;
      height: 100%;
      &:hover {
        border: 1px solid red;
      }
    }
  }

}
</style>
相关推荐
confiself26 分钟前
前端代码渲染截图方案
前端
xkxnq36 分钟前
第二阶段:Vue 组件化开发(第 21天)
前端·javascript·vue.js
阿珊和她的猫1 小时前
深入理解 React 中的 Render Props 模式
前端·react.js·状态模式
IT_陈寒1 小时前
SpringBoot 3.0实战:10个高效开发技巧让你的启动时间减少50%
前端·人工智能·后端
im_AMBER1 小时前
前端 + agent 开发学习路线
前端·学习·agent
亿坊电商1 小时前
利于SEO优化的CMS系统都有哪些特点?
前端·数据库
juejin_cn2 小时前
使用 Codex SDK 轻松实现文字控制电脑
前端
CUYG2 小时前
Moment.js常用
前端
用户81274828151202 小时前
漏学Input知识系列之“偷”走了其他窗口的事件pilferPointers
前端