likes
comments
collection
share

vue3 fabricjs自定义鼠标光标样式

作者站长头像
站长
· 阅读数 4

fabricjs绘制希望能实现笔刷在绘制中显示为半透明的圆圈光标,并且可以根据笔刷大小动态调整光标大小: vue3 fabricjs自定义鼠标光标样式

实现过程:

fabricjs中几个常用的光标样式:

// 鼠标在画布上悬停时的默认光标样式
hoverCursor: 'move' 
// 在画布上移动对象时使用的默认光标样式
moveCursor: 'move'
// 整个画布的默认光标样式
defaultCursor: 'default'
// 在自由绘图时的光标样式
freeDrawingCursor: 'crosshair'

显然我们需要使用freeDrawingCursor控制光标样式。

生成svg圆形做为自定义光标样式

由于系统默认样式中没有圆形,css提供了样式属性支持自定义光标dom.style.cursor = url(${imagePath}),正常填入对应的光标图片路径即可。但由于需求中要求光标可根据画笔大小动态改变,那么可以使用svg图动态控制,如一个20像素圆形的svg源码如下:

    <svg height="20" width="20" fill="#c6c6c6" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
      <circle cx="50%" cy="50%" r="20" opacity="0.5" />
    </svg>

设置一个动态变量,将svg用base64的方式嵌入光标样式中

将svg中圆形大小改为动态变量,使用canvas.freeDrawingCursor修改光标样式:

  state.cursor = encodeURIComponent(`
    <svg
      height="${state.size}"
      width="${state.size}"
      fill="#c6c6c6"
      viewBox="0 0 ${state.size * 2} ${state.size * 2}"
      xmlns="http://www.w3.org/2000/svg"
    >
      <circle
        cx="50%"
        cy="50%"
        r="${state.size}" 
        opacity="0.5"
      />
    </svg>
  `)
  canvas.freeDrawingCursor = `url('data:image/svg+xml;charset=utf-8,${state.cursor}') ${state.size / 2} ${state.size / 2}, crosshair`
  canvas.renderAll()

注:规范要求尽量把svg的内容encode,修改光标样式后,canvas需重新renderAll().

vue页面完整源码:

<template>
<div>
  <canvas width="800" height="600" id="canvas" ref="canvasEl"></canvas>
</div>
<button @click="updateConfig">change</button>
<button @click="clear" style="margin-left: 30px;">clear</button>
</template>

<script setup>
import { fabric } from 'fabric'
import { ref, reactive, onMounted } from 'vue'
const canvasEl = ref(null)

const state = reactive({
  canvas: null,
  cursor: '',
  size: 10,
  color: '#000'
})
onMounted(() => {
  // 初始化canvas
  state.canvas = new fabric.Canvas('canvas', {
    isDrawingMode: true,
  })
  updateConfig()
})

function updateConfig() {
  state.size = state.size + 10
  state.cursor = encodeURIComponent(`
    <svg
      height="${state.size}"
      width="${state.size}"
      fill="#c6c6c6"
      viewBox="0 0 ${state.size * 2} ${state.size * 2}"
      xmlns="http://www.w3.org/2000/svg"
    >
      <circle
        cx="50%"
        cy="50%"
        r="${state.size}" 
        opacity="0.5"
      />
    </svg>
  `)
  state.canvas.freeDrawingCursor = `url('data:image/svg+xml;charset=utf-8,${state.cursor}') ${state.size / 2} ${state.size / 2}, crosshair`
  state.canvas.freeDrawingBrush = new fabric.PencilBrush(state.canvas)
  state.canvas.freeDrawingBrush.width = state.size;
}
function clear() {
  state.canvas.clear()
}
</script>

<style>
#app {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>