Canvas 文字拖拽排列组合

2,552 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

今天继续写写Canvas代码来练练手

做一个拖拽文字的小练习,可以传入一些文字,用鼠标拖拽的方式将这些文字排列组合起来。

对于文字的拖拽,如果是使用Dom去一个个定义文字元素,就只能使用绝对定位,不然就会影响到Dom树结构。所以我使用了画布。

第一步:先将canvas画布给定义好,后续就要在这上面开始写代码了

<canvas id="wordcanvas" ref="canvas"></canvas>

画布:

t1.png

第二步:在js中获取到canvas的dom元素,并且因为我之前只是使用%设置画布,很容易造成拉伸模糊,所以需要对canvas的宽高重新进行设置。

import { ref, reactive, onMounted } from "vue";
const canvas = ref(null), textAppear = ref(null);
let canvasDom;

const drawText = (word, color, initPos) => { 
    const fatherDom = textAppear.value;
    const size = fatherDom.getBoundingClientRect();
    // 不让画布模糊
    [canvasDom.width, canvasDom.height] = [size.width, size.height];
    // 画布
    let ctx = canvasDom.getContext("2d");
}

onMounted(()=>{ 
    canvasDom = canvas.value;
    drawText('拖拽文字', '#fff', { x: 100, y: 100 });
})

第三步:在获取到画布的Context后,先配置一下filltext文本的一些设置,然后将传入的word参数进行拆分,因为拖拽是以单个生词进行的,所以需要将其变成数组。在此数组中需要设置文字的位置和范围,文字大小因为是50px,所以文字宽50px,高大约66px

// 文字
ctx.font = "50px Arial";
ctx.fillStyle = color;
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom'
ctx.shadowColor = color;
ctx.shadowBlur = 5;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
// 文字拆分
wordArray = word.split('').map((item, index)=>{
    // 单个文字绘制
    let x = initPos.x + 50 * index;
    ctx.fillText(item, x, initPos.y);

    return {
        index: index,
        pos: { x: x, y: initPos.y },
        range: { w: [x, x + 50], h: [initPos.y - 66, initPos.y] },
        content: item
    }
})

此时在界面上就能出线之前传入的参数文本了

image.png

第四步:接下来就需要配合鼠标,将这些文字进行拖拽了。 这里我先创建了一个获取elementoffsetX/Y的方法

function getPointXY(e: any):xy {
    return { x: e.offsetX, y: e.offsetY };
}

在这一步中,就需要canvas绑定鼠标监听事件中按下抬起移动这三个事件

配置鼠标按下事件(具体代码可参考上面的代码片段),这样就能知道鼠标按下位置,以及是否是点击中了文字,并且确定点击的文字是哪一个

// 点击的文字  鼠标按下的位置
let clickWord, mouse = {mousedownpos: {x: 0, y: 0}, mouseFlag: false};
// 鼠标按下
canvasDom.onmousedown = (e) => {
    ...
}
// 鼠标移动
canvasDom.onmousemove = (e) => {
    ...
}
// 鼠标抬起
canvasDom.onmouseup = (e)=>{ 
    ...
}

onmousemove移动事件中,根据鼠标是否按下mouseFlag以及clickWord不为空,判断可以进行拖拽,然后让该文字跟随鼠标位置进行移动

这里要注意,文字的位置并不能与鼠标element位置相同,需要进行进行计算,我写了movexy方法。

之后就是清除画布,然后重新绘制文字的过程了。

鼠标抬起onmouseup事件当中,需要将mouseFlagclickWord重置,并且对之前的wordArray中移动的文字数据进行相应的修正。

这样一个简单的文字拖拽功能就实现啦。

虽然这次的拖拽比较简单,但是其实可以根据个人需求进行扩展,比如说做一个拼图游戏,原理大致也差不多吧?