canvas七巧板

使用canvas简单编写七巧板

最近在学习canvas,目前还只是简单的了解了一下canvas画图的原理和简单图形的绘画。看到网上有很多canvas画的七巧板,但是并没有实现可以移动、拖拽和旋转拼接的demo,所以自己就利用js加上简单的canvas来实现一下。


原理

七巧板说白了也就是七块不同的多边形,要么是三角形,要么是四边形:如下图
这里写图片描述

我们可以通过数组现将七巧板的每一块先画出来:
//把7个点的位置坐标和颜色存入一个数组
var points = [
{p: [{x: 0, y: 0}, {x: 200, y: 0}, {x: 100, y: 100}], color: “#caff67”, click: false, drag: false, types: 3},
{p: [{x: 0, y: 0}, {x: 100, y: 100}, {x: 0, y: 200}], color: “#67becf”, click: false, drag: false, types: 3},
{
p: [{x: 200, y: 0}, {x: 200, y: 100}, {x: 150, y: 150}, {x: 150, y: 50}],
color: “#ef3d61”,
click: false,
drag: false,
types: 4
},
{
p: [{x: 150, y: 50}, {x: 150, y: 150}, {x: 100, y: 100}],
color: “#f9f51a”,
click: false,
drag: false,
types: 3
},
{
p: [{x: 100, y: 100}, {x: 150, y: 150}, {x: 100, y: 200}, {x: 50, y: 150}],
color: “#a594c0”,
click: false,
drag: false,
types: 4
},
{
p: [{x: 50, y: 150}, {x: 100, y: 200}, {x: 0, y: 200}],
color: “#fa8ecc”,
click: false,
drag: false,
types: 3
},
{
p: [{x: 200, y: 100}, {x: 200, y: 200}, {x: 100, y: 200}],
color: “#f6ca29”,
click: false,
drag: false,
types: 3
}
];
然后我们只需要根据鼠标事件来改变相应的图形坐标,然后进行重新渲染就行了。
鼠标的事件具体为:
canvas.onmousedown
canvas.onmouseup
canvas.onmouseout
canvas.onmousemove
canvas.ondblclick
我们需要对相应的事件作出相应的操作
其中双击实现角度变换是需要用到数学公式为(自己数学太差了,只能从网上找了):
假设对图片上任意点(x,y),绕一个坐标点(rx0,ry0)逆时针旋转a角度后的新的坐标设为(x0, y0),有公式:

x0= (x - rx0)*cos(a) - (y - ry0)*sin(a) + rx0 ;

y0= (x - rx0)*sin(a) + (y - ry0)*cos(a) + ry0 ;

效果展示

这里写图片描述
鼠标按下后,即可对该模块进行拖拽。
这里写图片描述
对模块双击,即可对模块进行角度旋转,我这里是以图形的某一个点为参照点来旋转。
参照点和旋转角度可以自己设定。

代码

代码的实现很简单,主要是四个事件的处理函数,在代码中也已经很详细的添加了注释,很好理解

<div style="height: 100%;width: 100%;">
    <canvas id="canvas">
        <p>you brower is not support canvas</p>
    </canvas>

</div>
function draw() {
        // 清除画布,准备绘制
        context.clearRect(0, 0, canvas.width, canvas.height);
        //遍历数组,以每个点为起点画图
        for (var i = 0; i < points.length; i++) {
            context.beginPath();
            context.moveTo(points[i].p[0].x, points[i].p[0].y);
            for (var j = 0; j < points[i].p.length; j++) {
                context.lineTo(points[i].p[j].x, points[i].p[j].y);
            }
            context.lineTo(points[i].p[0].x, points[i].p[0].y);
            context.strokeStyle = "black";
            context.lineWidth = "3";
            context.fillStyle = points[i].color;
            context.stroke();
            context.fill();
            context.closePath();
        }
    }

    draw();
    var isDragging = false;

    function canvasClick(e) {
        // 取得画布上被单击的点
        var clickX = e.pageX - canvas.offsetLeft;
        var clickY = e.pageY - canvas.offsetTop;

        for (var i = 0; i < points.length; i++) {
            var flag = false;
            if (points[i].types == 3) {
                flag = anglecompult(points[i].p, clickX, clickY);
            } else if (points[i].types == 4) {
                flag = reactcompult(points[i].p, clickX, clickY);
            }
            if (flag == true) {
                isDragging = true;
                points[i].click = true;
                points[i].drag = true;
                select = i;
            } else {
                points[i].click = false;
                points[i].drag = false;
            }
        }

    }

    function dblik(e) {//双击一块转动45度角
        // 判断圆圈是否开始拖拽
        //if (isDragging == true) {
        // 判断拖拽对象是否存在

        // 取得鼠标位置
        var x = e.pageX - canvas.offsetLeft;
        var y = e.pageY - canvas.offsetTop;

        // 将圆圈移动到鼠标位置
        var changdu = points[select].p.length;

        var yuanX = points[select].p[0].x;
        var yuanY = points[select].p[0].y;

        var yuanX2 = points2[select].p[0].x;
        var yuanY2 = points2[select].p[0].y;
        var xianx;
        var xianx2;
        var xiany;
        var xiany2;
        var xiebian;
        for (var j = 1; j < changdu; j++) {
            xianx = (points[select].p[j].x - yuanX) * (Math.cos((2 * Math.PI / 360) * 45)) - (points[select].p[j].y - yuanY) * (Math.sin((2 * Math.PI / 360) * 45)) + yuanX;
            xiany = (points[select].p[j].x - yuanX) * (Math.sin((2 * Math.PI / 360) * 45)) + (points[select].p[j].y - yuanY) * (Math.cos((2 * Math.PI / 360) * 45)) + yuanY;
            points[select].p[j].x = xianx;
            points[select].p[j].y = xiany;

            xianx2 = (points2[select].p[j].x - yuanX2) * (Math.cos((2 * Math.PI / 360) * 45)) - (points2[select].p[j].y - yuanY2) * (Math.sin((2 * Math.PI / 360) * 45)) + yuanX2;
            xiany2 = (points2[select].p[j].x - yuanX2) * (Math.sin((2 * Math.PI / 360) * 45)) + (points2[select].p[j].y - yuanY2) * (Math.cos((2 * Math.PI / 360) * 45)) + yuanY2;
            points2[select].p[j].x = xianx2;
            points2[select].p[j].y = xiany2;
        }
        console.log(points[select].p);
        // 更新画布
        draw();

        //}
    }

    function drag(e) {
        // 判断圆圈是否开始拖拽
        if (isDragging == true) {
            // 判断拖拽对象是否存在

            // 取得鼠标位置
            var x = e.pageX - canvas.offsetLeft;
            var y = e.pageY - canvas.offsetTop;


            var changdu = points[select].p.length;

            var xx = x - points2[select].p[0].x;
            var yy = y - points2[select].p[0].y;
            for (var j = 0; j < changdu; j++) {//将图形拖动到鼠标相应位置
                points[select].p[j].x = points2[select].p[j].x + xx;
                points[select].p[j].y = points2[select].p[j].y + yy;
            }
            // 更新画布
            draw();

        }
    }

    function stopdrag() {
        isDragging = false;
    }

    function anglecompult(anglepostions, x, y) {//判断三角形内
        var first = anglepostions[0];
        var second = anglepostions[1];
        var third = anglepostions[2];

        var firstR = ((second.y - third.y) * (x - third.x) + (third.x - second.x) * (y - third.y)) / ((second.y - third.y) * (first.x - third.x) + (third.x - second.x) * (first.y - third.y));

        var secondR = ((third.y - first.y) * (x - third.x) + (first.x - third.x) * (y - third.y)) / ((second.y - third.y) * (first.x - third.x) + (third.x - second.x) * (first.y - third.y))

        var thirsR = 1 - firstR - secondR;

        if (firstR > 0 && firstR < 1 && secondR > 0 && secondR < 1 && thirsR > 0 && thirsR < 1) {
            return true;
        } else {
            return false;
        }
    }

    function reactcompult(reactpostions, x, y) {//判断鼠标是否在矩形区域内
        var xmin, xmax, ymin, ymax;
        xmin = xmax = reactpostions[0].x;
        ymin = ymax = reactpostions[0].y;
        for (var i = 0; i < reactpostions.length; i++) {
            if (reactpostions[i].x < xmin) {
                xmin = reactpostions[i].x;
            }
            if (reactpostions[i].x > xmax) {
                xmax = reactpostions[i].x;
            }
            if (reactpostions[i].y < ymin) {
                ymin = reactpostions[i].y;
            }
            if (reactpostions[i].y > ymax) {
                ymax = reactpostions[i].y;
            }
        }

        if (xmin < x && xmax > x && ymin < y && ymax > y) {
            return true;
        } else {
            return false;
        }
    }

总结

代码很简单,本人也是刚刚接触canvas,程序也有很多缺陷,主要是把自己理解的东西写出来而已,如果有错误的地方,希望大家能够指正。附上demo的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值