首页 > 代码库 > 小前端大能耐——Canvas与Javascript配合实现几个功能

小前端大能耐——Canvas与Javascript配合实现几个功能

1.粒子化

function Dot(X, Y, Z, R) {
                this.dx = X;
                this.dy = Y;
                this.dz = Z;

                this.tx = 0;
                this.ty = 0;
                this.tz = 0;

                this.z = Z;
                this.x = X;
                this.y = Y;
                this.r = R;

                this.paint = function() {
                    context.save();
                    context.beginPath();
                    var scale = 250 / (250 + this.z);
                    context.arc(canvas.width / 2 + (this.x - canvas.width / 2) * scale, canvas.height / 2 + (this.y - canvas.height / 2) * scale, this.r * scale, 0, 2 * Math.PI);
                    context.fillStyle = "rgba(50,50,50," + scale + ")";
                    context.fill();
                    context.restore();
                }
            }


            window.onload = function() {
                canvas = document.getElementsByTagName("canvas")[0];
                context = canvas.getContext(‘2d‘);

                var dots = getimgData(‘program‘);

                dots.forEach(function(dot) {
                    dot.tx = Math.random() * canvas.width;
                    dot.ty = Math.random() * canvas.height;
                    dot.tz = Math.random() * 250 * 2 - 250;

                    dot.x = dot.tx;
                    dot.y = dot.ty;
                    dot.z = dot.tz;
                    dot.paint();
                });

                var moving = false;
                var lastTime;
                var direction = true;
                function animate() {
                    animateRunning = true;
                    var thisTime = +new Date();
                    context.clearRect(0, 0, canvas.width, canvas.height);
                    dots.forEach(function(dot) {
                        if (direction) {
                            if (Math.abs(dot.dx - dot.x) < 0.1 && Math.abs(dot.dy - dot.y) < 0.1 && Math.abs(dot.dz - dot.z) < 0.1) {
                                if (thisTime - lastTime > 1000)
                                    direction = false;
                            } else {
                                dot.x += (dot.dx - dot.x) * 0.1;
                                dot.y += (dot.dy - dot.y) * 0.1;
                                dot.z += (dot.dz - dot.z) * 0.1;
                                lastTime = +new Date();
                            }
                        } else {
                            if (Math.abs(dot.tx - dot.x) < 0.1 && Math.abs(dot.ty - dot.y) < 0.1 && Math.abs(dot.tz - dot.z) < 0.1) {
                                moving = false;
                            } else {
                                dot.x += (dot.tx - dot.x) * 0.1;
                                dot.y += (dot.ty - dot.y) * 0.1;
                                dot.z += (dot.tz - dot.z) * 0.1;
                            }
                        }
                        dot.paint();
                    });
                    if (moving) {
                        if ("requestAnimationFrame" in window) {
                            requestAnimationFrame(animate);
                        } else if ("webkitRequestAnimationFrame" in window) {
                            webkitRequestAnimationFrame(animate);
                        }
                    }
                }


                document.getElementById(‘startBtn‘).onclick = function() {
                    if (moving)
                        return;
                    dots = getimgData(document.getElementById(‘name‘).value);
                    direction = true;
                    moving = true;
                    dots.forEach(function(dot) {
                        dot.tx = Math.random() * canvas.width;
                        dot.ty = Math.random() * canvas.height;
                        dot.tz = Math.random() * 250 * 2 - 250;

                        dot.x = dot.tx;
                        dot.y = dot.ty;
                        dot.z = dot.tz;
                        dot.paint();
                    });
                    animate();
                }
            }
            function getimgData(text) {
                context.save();
                context.font = "200px 微软雅黑 bold";
                context.fillStyle = "rgba(255,255,255,1)";
                context.textAlign = "center";
                context.textBaseline = "middle";
                context.fillText(text, canvas.width / 2, canvas.height / 2);
                context.restore();

                var imgData = http://www.mamicode.com/context.getImageData(0, 0, canvas.width, canvas.height);
                context.clearRect(0, 0, canvas.width, canvas.height);

                var dots = [];
                for (var y = 0; y < imgData.height; y += 6) {
                    for (var x = 0; x < imgData.width; x += 6) {
                        var i = (y * imgData.width + x) * 4;
                        if (imgData.data[i] >= 255) {
                            dots.push(new Dot(x - 3, y - 3, 0, 3));
                        }
                    }
                }
                return dots;
            }

 

2.图片文字识别

<html>
    <head>
        <meta charset="UTF-8">
        <title>文字识别</title>
    </head>
    <body>
        <canvas id="canvas" width="880" height="1500"></canvas>
        <script type="text/javascript">
            var image = new Image();
            image.src = image.jpg;
            var stanData = {};
            var lineHeight = 24;
            var letters = 0123456789abcdefghijklmnopqrstuvwxyz;
            var context = document.getElementById(canvas).getContext(2d);
            context.font = 16px 微软雅黑;
            context.textBaseline = top;

            image.onload = function() {
                for (var i = 0; i < letters.length; i++) {
                    var letter = letters[i];
                    // 绘制白色背景,与图片背景对应
                    context.fillStyle = #fff;
                    context.fillRect(0, 0, width, 18);
                    // 绘制文字,以获取字型数据
                    context.fillStyle = #000;
                    context.fillText(letter, 0, 0);
                    // 获取字符绘制宽度
                    var width = context.measureText(letter).width;
                    stanData[letter] = {
                        width : width,
                        data : getBinary(context.getImageData(0, 0, width, 18).data)
                    };
                    // 清空该区域以获取下个字符字型数据
                    context.clearRect(0, 0, width, 18);
                }
                context.fillStyle = #000;
                context.fillText(512abcxyz, 0, 0);
                findLetter(0, 0, ‘‘);

                alert(result);
            };
            var result = ‘‘;
            function findLetter(x, y, str) {
                console.log(x, y, str);
                if (result != ‘‘)
                    return;
                var queue = [];
                for (var letter in stanData) {
                    if (y > lineHeight * 3) {
                        result = str;
                        break;
                    }
                    // 边界
                    var width = stanData[letter].width;
                    if (x + width > 440) {
                        continue;
                    }
                    // 获取该矩形区域下的灰度化0-1数据
                    var data = getBinary(context.getImageData(x, y, width, 18).data);
                    // 计算偏差
                    var deviation = 0, flag = true;
                    for (var i = 0; i < data.length; i++) {
                        if (data[i])
                            flag = false;
                        if (data[i] != stanData[letter].data[i])
                            deviation++;
                    }
                    if (letter == 0)
                        alert(deviation);
                    // 如果已经到了行末,重置匹配坐标
                    // if (flag) {
                    // findLetter(0, y + lineHeight, str + ‘\n‘);
                    // break;
                    // }
                    // 如果偏差量与宽度的比值小于3,则纳入匹配队列中
                    // 这里也是算法中的关键点,怎样的偏差量可以纳入匹配队列中
                    // 刚开始是直接用绝对偏差量判断,当偏差量小于某个值的时候则匹配成功,但调试过程中发现不妥之处
                    // 字符字型较小的绝对偏差量自然也小,这样l,i等较小的字型特别容易匹配成功
                    // 因此使用偏差量与字型宽度的比值作为判断依据较为合理
                    console.log(letter, deviation, deviation / width);
                    if (deviation / width < 3) {
                        queue.push({
                            letter : letter,
                            width : width,
                            deviation : deviation
                        });
                    }
                }
                // 如果匹配队列不为空
                if (queue.length) {
                    // 对队列进行排序,同样是根据偏差量与字符宽度的比例
                    queue.sort(compare);
                    console.log(str, queue, queue.length);
                    for (var i = 0; i < queue.length && !result; ++i) {
                        var item = queue[i];
                        findLetter(x + item.width, y, str + item.letter);
                    }
                } else {
                    return;
                }
            }

            // 两个匹配到的字符的比较方法,用于排序
            function compare(letter1, letter2) {
                return letter1.deviation / letter1.width - letter2.deviation / letter2.width;
            }

            // 图像数据的灰度化及0-1化
            function getBinary(data) {
                var binaryData = [];
                for (var i = 0; i < data.length; i += 4) {
                    binaryData[i / 4] = ((data[i] + data[i + 1] + data[i + 2]) / 3 < 200);
                }
                return binaryData;
            }
        </script>
    </body>
</html>

 

3.3D云标签

<html>
    <head>
        <meta charset="UTF-8">
        <style>
            .tag {
                display: block;
                position: absolute;
                text-decoration: none;
            }
        </style>
    </head>
    <body>
        <div class="content" style="width: 800px;height: 800px;margin: 50px auto;    position: relative;">
            <a class="tag" href="javascript:void(0)">A</a>
            <a class="tag" href="javascript:void(0)">B</a>
            <a class="tag" href="javascript:void(0)">C</a>
            <a class="tag" href="javascript:void(0)">D</a>
            <a class="tag" href="javascript:void(0)">E</a>
            <a class="tag" href="javascript:void(0)">A</a>
            <a class="tag" href="javascript:void(0)">B</a>
            <a class="tag" href="javascript:void(0)">C</a>
            <a class="tag" href="javascript:void(0)">D</a>
            <a class="tag" href="javascript:void(0)">E</a>
        </div>
        <script>
            var tagEle = document.querySelectorAll(".tag"), paper = document.querySelector(".content");
            var R = 300, fallLength = 500;
            var tags = [];
            var angleX = Math.PI / 500, angleY = Math.PI / 500;
            var CX = paper.offsetWidth / 2, CY = paper.offsetHeight / 2, EX = paper.offsetLeft + document.body.scrollLeft + document.documentElement.scrollLeft, EY = paper.offsetTop + document.body.scrollTop + document.documentElement.scrollTop;

            function tag(ele, x, y, z) {
                this.ele = ele;
                this.x = x;
                this.y = y;
                this.z = z;
                this.print = function() {
                    var scale = fallLength / (fallLength - this.z);
                    var alpha = (this.z + R) / (2 * R);
                    this.ele.style.fontSize = 80 * scale + "px";
                    this.ele.style.opacity = alpha + 0.5;
                    this.ele.style.zIndex = parseInt(scale * 100);
                    this.ele.style.left = this.x + CX - this.ele.offsetWidth / 2 + "px";
                    this.ele.style.top = this.y + CY - this.ele.offsetHeight / 2 + "px";
                }
            }

            (function() {
                for (var i = 0; i < tagEle.length; i++) {
                    var k = (2 * (i + 1) - 1) / tagEle.length - 1;
                    var a = Math.acos(k);
                    var b = a * Math.sqrt(tagEle.length * Math.PI);

                    var x = R * Math.sin(a) * Math.cos(b);
                    var y = R * Math.sin(a) * Math.sin(b);
                    var z = R * Math.cos(a);

                    var t = new tag(tagEle[i], x, y, z);
                    tags.push(t);
                    t.print();
                }
            })();

            setInterval(function() {
                var cosX = Math.cos(angleX);
                var sinX = Math.sin(angleX);
                var cosY = Math.cos(angleY);
                var sinY = Math.sin(angleY);
                tags.forEach(function(tag) {
                    tag.y = tag.y * cosX - tag.z * sinX;
                    tag.z = tag.z * cosX + tag.y * sinX;
                    tag.x = tag.x * cosY - tag.z * sinY;
                    tag.z = tag.z * cosY + tag.x * sinY;

                    tag.print();
                })
            }, 20);

            paper.addEventListener("mousemove", function(event) {
                var x = event.clientX - EX - CX;
                var y = event.clientY - EY - CY;
                angleY = x * 0.0001;
                angleX = y * 0.0001;
            });
        </script>
    </body>
</html>