paper.js 开源的矢量图形的脚本,运行于HTM5的Canvas上

paper.js 开源的矢量图形的脚本,运行于HTM5的Canvas上

Paper.js是一个开源的矢量图形的脚本,运行于HTM5的Canvas上,所以仅仅支持现代的浏览器。它提供了一个干净的画布/文档对象和许多功能强大的函数给用户去创建矢量图形和贝塞尔曲线。所有这些功能都整齐地包在一个设计良好的,一致的和干净的接口里。

示例如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
    <script src="//repo.bfw.wiki/bfwrepo/js/jquery.17.js"></script>
    <script src="//repo.bfw.wiki/bfwrepo/js/paper.js"></script>
    <title>Paper.js — Tadpoles</title>
</head>
<body class="fullscreen">

    <article>
        <div class="paperscript">
           
            <script type="text/paperscript" canvas="canvas-1">
                // Adapted from Flocking Processing example by Daniel Schiffman:
                // http://processing.org/learning/topics/flocking.html

                var Boid = Base.extend({
                    initialize: function(position, maxSpeed, maxForce) {
                        var strength = Math.random() * 0.5;
                        this.acceleration = new Point();
                        this.vector = Point.random() * 2 - 1;
                        this.position = position.clone();
                        this.radius = 30;
                        this.maxSpeed = maxSpeed + strength;
                        this.maxForce = maxForce + strength;
                        this.amount = strength * 10 + 10;
                        this.count = 0;
                        this.createItems();
                    },

                    run: function(boids) {
                        this.lastLoc = this.position.clone();
                        if (!groupTogether) {
                            this.flock(boids);
                        } else {
                            this.align(boids);
                        }
                        this.borders();
                        this.update();
                        this.calculateTail();
                        this.moveHead();
                    },

                    calculateTail: function() {
                        var segments = this.path.segments,
                        shortSegments = this.shortPath.segments;
                        var speed = this.vector.length;
                        var pieceLength = 5 + speed / 3;
                        var point = this.position;
                        segments[0].point = shortSegments[0].point = point;
                        // Chain goes the other way than the movement
                        var lastVector = -this.vector;
                        for (var i = 1; i < this.amount; i++) {
                            var vector = segments[i].point - point;
                            this.count += speed * 10;
                            var wave = Math.sin((this.count + i * 3) / 300);
                            var sway = lastVector.rotate(90).normalize(wave);
                            point += lastVector.normalize(pieceLength) + sway;
                            segments[i].point = point;
                            if (i < 3)
                                shortSegments[i].point = point;
                            lastVector = vector;
                        }
                        this.path.smooth();
                    },

                    createItems: function() {
                        this.head = new Shape.Ellipse({
                            center: [0, 0],
                            size: [13, 8],
                            fillColor: 'white'
                        });

                        this.path = new Path({
                            strokeColor: 'white',
                            strokeWidth: 2,
                            strokeCap: 'round'
                        });
                        for (var i = 0; i < this.amount; i++)
                            this.path.add(new Point());

                        this.shortPath = new Path({
                            strokeColor: 'white',
                            strokeWidth: 4,
                            strokeCap: 'round'
                        });
                        for (var i = 0; i < Math.min(3, this.amount); i++)
                            this.shortPath.add(new Point());
                    },

                    moveHead: function() {
                        this.head.position = this.position;
                        this.head.rotation = this.vector.angle;
                    },

                    // We accumulate a new acceleration each time based on three rules
                    flock: function(boids) {
                        var separation = this.separate(boids) * 3;
                        var alignment = this.align(boids);
                        var cohesion = this.cohesion(boids);
                        this.acceleration += separation + alignment + cohesion;
                    },

                    update: function() {
                        // Update velocity
                        this.vector += this.acceleration;
                        // Limit speed (vector#limit?)
                        this.vector.length = Math.min(this.maxSpeed, this.vector.length);
                        this.position += this.vector;
                        // Reset acceleration to 0 each cycle
                        this.acceleration = new Point();
                    },

                    seek: function(target) {
                        this.acceleration += this.steer(target, false);
                    },

                    arrive: function(target) {
                        this.acceleration += this.steer(target, true);
                    },

                    borders: function() {
                        var vector = new Point();
                        var position = this.position;
                        var radius = this.radius;
                        var size = view.size;
                        if (position.x < -radius) vector.x = size.width + radius;
                        if (position.y < -radius) vector.y =  size.height + radius;
                        if (position.x > size.width + radius) vector.x = -size.width -radius;
                        if (position.y > size.height + radius) vector.y = -size.height -radius;
                        if (!vector.isZero()) {
                            this.position += vector;
                            var segments = this.path.segments;
                            for (var i = 0; i < this.amount; i++) {
                                segments[i].point += vector;
                            }
                        }
                    },

                    // A method that calculates a steering vector towards a target
                    // Takes a second argument, if true, it slows down as it approaches
                    // the target
                    steer: function(target, slowdown) {
                        var steer,
                        desired = target - this.position;
                        var distance = desired.length;
                        // Two options for desired vector magnitude
                        // (1 -- based on distance, 2 -- maxSpeed)
                        if (slowdown && distance < 100) {
                            // This damping is somewhat arbitrary:
                            desired.length = this.maxSpeed * (distance / 100);
                        } else {
                            desired.length = this.maxSpeed;
                        }
                        steer = desired - this.vector;
                        steer.length = Math.min(this.maxForce, steer.length);
                        return steer;
                    },

                    separate: function(boids) {
                        var desiredSeperation = 60;
                        var steer = new Point();
                        var count = 0;
                        // For every boid in the system, check if it's too close
                        for (var i = 0, l = boids.length; i < l; i++) {
                            var other = boids[i];
                            var vector = this.position - other.position;
                            var distance = vector.length;
                            if (distance > 0 && distance < desiredSeperation) {
                                // Calculate vector pointing away from neighbor
                                steer += vector.normalize(1 / distance);
                                count++;
                            }
                        }
                        // Average -- divide by how many
                        if (count > 0)
                            steer /= count;
                        if (!steer.isZero()) {
                            // Implement Reynolds: Steering = Desired - Velocity
                            steer.length = this.maxSpeed;
                            steer -= this.vector;
                            steer.length = Math.min(steer.length, this.maxForce);
                        }
                        return steer;
                    },

                    // Alignment
                    // For every nearby boid in the system, calculate the average velocity
                    align: function(boids) {
                        var neighborDist = 25;
                        var steer = new Point();
                        var count = 0;
                        for (var i = 0, l = boids.length; i < l; i++) {
                            var other = boids[i];
                            var distance = this.position.getDistance(other.position);
                            if (distance > 0 && distance < neighborDist) {
                                steer += other.vector;
                                count++;
                            }
                        }

                        if (count > 0)
                            steer /= count;
                        if (!steer.isZero()) {
                            // Implement Reynolds: Steering = Desired - Velocity
                            steer.length = this.maxSpeed;
                            steer -= this.vector;
                            steer.length = Math.min(steer.length, this.maxForce);
                        }
                        return steer;
                    },

                    // Cohesion
                    // For the average location (i.e. center) of all nearby boids,
                    // calculate steering vector towards that location
                    cohesion: function(boids) {
                        var neighborDist = 100;
                        var sum = new Point();
                        var count = 0;
                        for (var i = 0, l = boids.length; i < l; i++) {
                            var other = boids[i];
                            var distance = this.position.getDistance(other.position);
                            if (distance > 0 && distance < neighborDist) {
                                sum += other.position; // Add location
                                count++;
                            }
                        }
                        if (count > 0) {
                            sum /= count;
                            // Steer towards the location
                            return this.steer(sum, false);
                        }
                        return sum;
                    }
                });

                var heartPath = new Path('M514.69629,624.70313c-7.10205,-27.02441 -17.2373,-52.39453 -30.40576,-76.10059c-13.17383,-23.70703 -38.65137,-60.52246 -76.44434,-110.45801c-27.71631,-36.64355 -44.78174,-59.89355 -51.19189,-69.74414c-10.5376,-16.02979 -18.15527,-30.74951 -22.84717,-44.14893c-4.69727,-13.39893 -7.04297,-26.97021 -7.04297,-40.71289c0,-25.42432 8.47119,-46.72559 25.42383,-63.90381c16.94775,-17.17871 37.90527,-25.76758 62.87354,-25.76758c25.19287,0 47.06885,8.93262 65.62158,26.79834c13.96826,13.28662 25.30615,33.10059 34.01318,59.4375c7.55859,-25.88037 18.20898,-45.57666 31.95215,-59.09424c19.00879,-18.32178 40.99707,-27.48535 65.96484,-27.48535c24.7373,0 45.69531,8.53564 62.87305,25.5957c17.17871,17.06592 25.76855,37.39551 25.76855,60.98389c0,20.61377 -5.04102,42.08691 -15.11719,64.41895c-10.08203,22.33203 -29.54687,51.59521 -58.40723,87.78271c-37.56738,47.41211 -64.93457,86.35352 -82.11328,116.8125c-13.51758,24.0498 -23.82422,49.24902 -30.9209,75.58594z');

                var boids = [];
                var groupTogether = false;

                // Add the boids:
                for (var i = 0; i < 30; i++) {
                    var position = Point.random() * view.size;
                    boids.push(new Boid(position, 10, 0.05));
                }


                function onFrame(event) {
                    for (var i = 0, l = boids.length; i < l; i++) {
                        if (groupTogether) {
                            var length = ((i + event.count / 30) % l) / l * heartPath.length;
                            var point = heartPath.getPointAt(length);
                            if (point)
                                boids[i].arrive(point);
                        }
                        boids[i].run(boids);
                    }
                }

                // Reposition the heart path whenever the window is resized:
                function onResize(event) {
                    heartPath.fitBounds(view.bounds);
                    heartPath.scale(0.8);
                }

                function onMouseDown(event) {
                    groupTogether = !groupTogether;
                }

                function onKeyDown(event) {
                    if (event.key == 'space') {
                        var layer = project.activeLayer;
                        layer.selected = !layer.selected;
                        return false;
                    }
                }
            </script>
            <div class="canvas">
                <canvas width="640" height="480" resize="true" id="canvas-1" style="background:black"></canvas>
            </div>
        </div>
    </article>
</body>
</html>



立即下载paper.js查看所有js插件

网友评论0

程序员在线工具箱