一线大厂高级前端编写,前端初中阶面试题,帮助初学者应聘,需要联系微信:javadudu

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

需求产生背景

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

实现效果

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

核心逻辑

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

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

paperJS官网链接

逻辑步骤整理

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

代码实现

首先创建一个Vue3+Vite项目,语言选择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画布挂载

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()
}

完整源码

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

原文链接:https://juejin.cn/post/7261231205353472058 作者:threejs源码翻译官

(0)
上一篇 2023年7月28日 上午10:26
下一篇 2023年7月30日 上午10:05

相关推荐

发表评论

登录后才能评论