UNPKG

curvejs

Version:
1,452 lines (1,261 loc) 43.9 kB
/** * curvejs v0.3.3 By dntzhang * Github: https://github.com/AlloyTeam/curvejs * MIT Licensed. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.curvejs = factory()); }(this, (function () { 'use strict'; (function () { 'use strict'; if (!Date.now) Date.now = function () { return new Date().getTime(); }; var vendors = ['webkit', 'moz']; for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { var vp = vendors[i]; window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; window.cancelAnimationFrame = window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']; } if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy || !window.requestAnimationFrame || !window.cancelAnimationFrame) { var lastTime = 0; window.requestAnimationFrame = function (callback) { var now = Date.now(); var nextTime = Math.max(lastTime + 16, now); return setTimeout(function () { callback(lastTime = nextTime); }, nextTime - now); }; window.cancelAnimationFrame = clearTimeout; } })(); var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var Curve = function () { function Curve(option) { classCallCheck(this, Curve); this.points = option.points || [0, 0, 0, 0, 0, 0, 0, 0]; this.color = option.color || 'black'; this.x = option.x || 0; this.y = option.y || 0; this.vision = option.vision || []; this.visionMax = 720; this.visionInterval = option.visionInterval || 10; this._preDate = Date.now(); this._now = new Date(); this.data = option.data; this._noop = function () {}; this._ease = function (value) { return value; }; this._targetPoints = null; this.copyPoints = this.points.slice(0); this.motion = option.motion || this._noop; this.visionAlpha = option.visionAlpha === void 0 ? 0.2 : option.visionAlpha; if (option.initVision === void 0 || option.initVision) { this._initVision(option.visionCount || 80); } } createClass(Curve, [{ key: '_initVision', value: function _initVision() { var i = 0; for (; i < 80; i++) { this.tick(true); } } }, { key: 'tick', value: function tick(tickSelf) { this._now = Date.now(); if (this._now - this._preDate > this.visionInterval || tickSelf) { this.vision.push.apply(this.vision, this.points); this.vision.push(this.color); if (this.vision.length > this.visionMax) { this.vision.splice(0, 9); } this._preDate = this._now; } if (!this.pauseMotion) { this.motion.call(this, this.points, this.data); } if (this._targetPoints) { this._pointsTo(); } } }, { key: 'pause', value: function pause() { this.pauseMotion = true; } }, { key: 'play', value: function play() { this.pauseMotion = false; } }, { key: 'draw', value: function draw(ctx) { this.tick(); ctx.save(); ctx.translate(this.x, this.y); ctx.globalAlpha = 1; ctx.strokeStyle = this.color; var points = this.points; ctx.beginPath(); ctx.moveTo.call(ctx, points[0], points[1]); ctx.bezierCurveTo.call(ctx, points[2], points[3], points[4], points[5], points[6], points[7]); ctx.stroke(); var vision = this.vision; var i = 0, len = vision.length; for (; i < len; i += 9) { ctx.globalAlpha = i / this.visionMax * this.visionAlpha; ctx.strokeStyle = vision[i + 8]; ctx.beginPath(); ctx.moveTo.call(ctx, vision[i], vision[i + 1]); ctx.bezierCurveTo.call(ctx, vision[i + 2], vision[i + 3], vision[i + 4], vision[i + 5], vision[i + 6], vision[i + 7]); ctx.stroke(); } ctx.restore(); } }, { key: 'pointsTo', value: function pointsTo(points, time, option) { this.pause(); var ps = this.points; this._targetPoints = points; this._pto = option; this._ptStart = option.start || this._noop; this._ptProgress = option.progress || this._noop; this._ptEnd = option.end || this._noop; this._ptEase = option.ease || this._ease; this._ptTime = time; this._ptStartTime = Date.now(); this._ptCopyPoints = ps.slice(0); this._ptDistance = [points[0] - ps[0], points[1] - ps[1], points[2] - ps[2], points[3] - ps[3], points[4] - ps[4], points[5] - ps[5], points[6] - ps[6], points[7] - ps[7]]; this._ptStart.call(this, 0); } }, { key: 'translatePoints', value: function translatePoints(xy, time, option) { xy = Object.assign({ x: 0, y: 0 }, xy); var ps = this.points; this.pointsTo([ps[0] + xy.x, ps[1] + xy.y, ps[2] + xy.x, ps[3] + xy.y, ps[4] + xy.x, ps[5] + xy.y, ps[6] + xy.x, ps[7] + xy.y], time, option); } }, { key: 'scaleTo', value: function scaleTo(scale, time, option) { var scaleX = 1, scaleY = 1; if (typeof scale === 'number') { scaleX = scaleY = scale; } else { scale.scaleX !== void 0 && (scaleX = scale.scaleX)(scale.scaleY !== void 0) && (scaleY = scale.scaleX); } var points = this.points; var centerX = option.center !== void 0 ? option.center[0] : (points[0] + points[6]) / 2; var centerY = option.center !== void 0 ? option.center[1] : (points[1] + points[7]) / 2; this.pointsTo([scaleX * (points[0] - centerX) + centerX, scaleY * (points[1] - centerY) + centerY, scaleX * (points[2] - centerX) + centerX, scaleY * (points[3] - centerY) + centerY, scaleX * (points[4] - centerX) + centerX, scaleY * (points[5] - centerY) + centerY, scaleX * (points[6] - centerX) + centerX, scaleY * (points[7] - centerY) + centerY], time, option); } }, { key: 'rotateTo', value: function rotateTo(rotation, time, option) {} }, { key: '_pointsTo', value: function _pointsTo() { var _this = this; var ps = this.points; var dt = Date.now() - this._ptStartTime; if (dt < this._ptTime) { var progress = dt / this._ptTime; ps.forEach(function (v, i) { ps[i] = _this._ptCopyPoints[i] + _this._ptDistance[i] * _this._ptEase(progress); }); this._ptProgress.call(this, progress); } else { ps = this._targetPoints.slice(0); this._targetPoints = null; this._ptEnd.call(this, 1); } } }, { key: 'colorTo', value: function colorTo() {} }, { key: 'clone', value: function clone() {} }]); return Curve; }(); var Group = function () { function Group() { classCallCheck(this, Group); this.children = []; } createClass(Group, [{ key: "add", value: function add(line) { this.children.push(line); } }, { key: "remove", value: function remove(line) { var i = 0, len = this.children.length; for (; i < len; i++) { if (line === this.children[i]) { this.children.splice(i, 1); break; } } } }, { key: "draw", value: function draw(ctx) { this.children.forEach(function (child) { child.draw(ctx); }); } }]); return Group; }(); var Stage = function (_Group) { inherits(Stage, _Group); function Stage(width, height, renderTo) { classCallCheck(this, Stage); var _this = possibleConstructorReturn(this, (Stage.__proto__ || Object.getPrototypeOf(Stage)).call(this)); if (arguments.length === 1) { _this.canvas = width; _this.ctx = _this.canvas.getContext('2d'); _this.width = _this.canvas.width; _this.height = _this.canvas.height; } else if (arguments.length === 3) { _this.canvas = document.createElement('canvas'); _this.canvas.width = width; _this.canvas.height = height; _this.width = width; _this.height = height; _this.ctx = _this.canvas.getContext('2d'); document.querySelector(renderTo).appendChild(_this.canvas); } return _this; } createClass(Stage, [{ key: 'update', value: function update(notClear) { var _this2 = this; if (!notClear) { this.ctx.clearRect(0, 0, this.width, this.height); } this.children.forEach(function (child) { child.draw(_this2.ctx); }); } }, { key: 'addExistLine', value: function addExistLine(process) {} }, { key: 'sameAs', value: function sameAs(index) {} }]); return Stage; }(Group); /** * dance motion, spin around. * * @param {points} * @param {data} * data rule example: * { angle : 0, r : 5 , step : Math.PI / 50 } */ var dance = function (points, data) { var pre = this.copyPoints, theta = data.angle, r = data.r; var R = [[Math.cos(theta), -Math.sin(theta)], [Math.sin(theta), Math.cos(theta)]]; points[0] = pre[0] + R[0][0] * r; points[1] = pre[1] + R[1][0] * r; points[2] = pre[2] + R[0][0] * r; points[3] = pre[3] + R[1][0] * r; points[4] = pre[4] + R[0][0] * r; points[5] = pre[5] + R[1][0] * r; points[6] = pre[6] + R[0][0] * r; points[7] = pre[7] + R[1][0] * r; data.angle += data.step; }; /** * move motion. * * @param {points} * @param {data} * data rule example: * [1, 0.2, -3, 0.7, 0.5, 0.3, -1, 1] */ var move = function (points, data) { points.forEach(function (item, index) { points[index] += data[index]; }); }; /** * rotate motion. * * @param {points} * @param {data} * data rule example: * Math.PI/100 */ function _rotate(x1, y1, x2, y2, theta, index, points) { var v = { x: x1 - x2, y: y1 - y2 }; var R = [[Math.cos(theta), -Math.sin(theta)], [Math.sin(theta), Math.cos(theta)]]; points[index] = x2 + R[0][0] * v.x + R[0][1] * v.y; points[index + 1] = y2 + R[1][0] * v.x + R[1][1] * v.y; } function rotate(points, angle) { var centerX = (points[0] + points[6]) / 2; var centerY = (points[1] + points[7]) / 2; _rotate(points[0], points[1], centerX, centerY, angle, 0, points); _rotate(points[2], points[3], centerX, centerY, angle, 2, points); _rotate(points[4], points[5], centerX, centerY, angle, 4, points); _rotate(points[6], points[7], centerX, centerY, angle, 6, points); } function n(x, y) { var sum = x * x + y * y; if (sum === 0) return [0, 0]; var len = Math.sqrt(sum); return [x / len, y / len]; } function sl(x, y) { return x * x + y * y; } var vector2 = { n: n, sl: sl }; /** * close or open path motion. * * @param {points} */ function open(points) { var v = vector2.n(points[0] - points[6], points[1] - points[7]); points[0] += v[0]; points[1] += v[1]; points[6] -= v[0]; points[7] -= v[1]; } function close(points) { var v = vector2.n(points[0] - points[6], points[1] - points[7]); points[0] -= v[0]; points[1] -= v[1]; points[6] += v[0]; points[7] += v[1]; } function auto(points) {} var path = { close: close, open: open, auto: auto }; /** * to motion. * * @param {points} * @param {data} * data rule example: * [100,200, 150, 333, 200,11, 1, 1] */ function to(points, target) { var va1 = [points[2] - points[0], points[3] - points[1]]; var va2 = [points[4] - points[2], points[5] - points[3]]; var va3 = [points[6] - points[4], points[7] - points[5]]; var vb1 = [target[2] - target[0], target[3] - target[1]]; var vb2 = [target[4] - target[2], target[5] - target[3]]; var vb3 = [target[6] - target[4], target[7] - target[5]]; var v1 = vector2.n(vb1[0] - va1[0], vb1[1] - va1[1]); points[0] -= v1[0]; points[1] -= v1[1]; var v2 = vector2.n(vb2[0] - va2[0], vb2[1] - va2[1]); points[4] += v2[0]; points[5] += v2[1]; var v3 = vector2.n(vb3[0] - va3[0], vb3[1] - va3[1]); points[6] += v3[0]; points[7] += v3[1]; } function line(arr) { arr[2] += arr[2] > arr[0] ? -1 : 1; arr[3] += arr[3] > arr[1] ? -1 : 1; arr[4] += arr[4] > arr[6] ? -1 : 1; arr[5] += arr[5] > arr[7] ? -1 : 1; } function circle(points, data) { var R = [[Math.cos(data.angle), -Math.sin(data.angle)], [Math.sin(data.angle), Math.cos(data.angle)]]; this.data.angle += data.step; points[0] = points[0] + R[0][0]; points[1] = points[1] + R[1][0]; points[6] = points[6] + R[0][0]; points[7] = points[7] + R[1][0]; } function sliceBezier(p1, cp1, cp2, p2, t) { var x1 = p1.x, y1 = p1.y, x2 = cp1.x, y2 = cp1.y, x3 = cp2.x, y3 = cp2.y, x4 = p2.x, y4 = p2.y; var x12 = (x2 - x1) * t + x1; var y12 = (y2 - y1) * t + y1; var x23 = (x3 - x2) * t + x2; var y23 = (y3 - y2) * t + y2; var x34 = (x4 - x3) * t + x3; var y34 = (y4 - y3) * t + y3; var x123 = (x23 - x12) * t + x12; var y123 = (y23 - y12) * t + y12; var x234 = (x34 - x23) * t + x23; var y234 = (y34 - y23) * t + y23; var x1234 = (x234 - x123) * t + x123; var y1234 = (y234 - y123) * t + y123; return [x1, y1, x12, y12, x123, y123, x1234, y1234]; } var expand = function (points, data) { data.value -= data.step; if (data.value < 0) data.value = 0; var part1OfBezier = sliceBezier({ x: this.copyPoints[0], y: this.copyPoints[1] }, { x: this.copyPoints[2], y: this.copyPoints[3] }, { x: this.copyPoints[4], y: this.copyPoints[5] }, { x: this.copyPoints[6], y: this.copyPoints[7] }, data.value); points.forEach(function (value, index) { points[index] = part1OfBezier[index]; }); }; // from https://github.com/processing/p5.js/blob/master/src/math/noise.js ////////////////////////////////////////////////////////////// // http://mrl.nyu.edu/~perlin/noise/ // Adapting from PApplet.java // which was adapted from toxi // which was adapted from the german demo group farbrausch // as used in their demo "art": http://www.farb-rausch.de/fr010src.zip // someday we might consider using "improved noise" // http://mrl.nyu.edu/~perlin/paper445.pdf // See: https://github.com/shiffman/The-Nature-of-Code-Examples-p5.js/ // blob/master/introduction/Noise1D/noise.js /** * @module Math * @submodule Noise * @for p5 * @requires core */ var p5 = {}; var PERLIN_YWRAPB = 4; var PERLIN_YWRAP = 1 << PERLIN_YWRAPB; var PERLIN_ZWRAPB = 8; var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB; var PERLIN_SIZE = 4095; var perlin_octaves = 4; // default to medium smooth var perlin_amp_falloff = 0.5; // 50% reduction/octave var scaled_cosine = function scaled_cosine(i) { return 0.5 * (1.0 - Math.cos(i * Math.PI)); }; var perlin; // will be initialized lazily by noise() or noiseSeed() /** * Returns the Perlin noise value at specified coordinates. Perlin noise is * a random sequence generator producing a more natural ordered, harmonic * succession of numbers compared to the standard <b>random()</b> function. * It was invented by Ken Perlin in the 1980s and been used since in * graphical applications to produce procedural textures, natural motion, * shapes, terrains etc.<br /><br /> The main difference to the * <b>random()</b> function is that Perlin noise is defined in an infinite * n-dimensional space where each pair of coordinates corresponds to a * fixed semi-random value (fixed only for the lifespan of the program; see * the noiseSeed() function). p5.js can compute 1D, 2D and 3D noise, * depending on the number of coordinates given. The resulting value will * always be between 0.0 and 1.0. The noise value can be animated by moving * through the noise space as demonstrated in the example above. The 2nd * and 3rd dimension can also be interpreted as time.<br /><br />The actual * noise is structured similar to an audio signal, in respect to the * function's use of frequencies. Similar to the concept of harmonics in * physics, perlin noise is computed over several octaves which are added * together for the final result. <br /><br />Another way to adjust the * character of the resulting sequence is the scale of the input * coordinates. As the function works within an infinite space the value of * the coordinates doesn't matter as such, only the distance between * successive coordinates does (eg. when using <b>noise()</b> within a * loop). As a general rule the smaller the difference between coordinates, * the smoother the resulting noise sequence will be. Steps of 0.005-0.03 * work best for most applications, but this will differ depending on use. * * * @method noise * @param {Number} x x-coordinate in noise space * @param {Number} y y-coordinate in noise space * @param {Number} z z-coordinate in noise space * @return {Number} Perlin noise value (between 0 and 1) at specified * coordinates * @example * <div> * <code>var xoff = 0.0; * * function draw() { * background(204); * xoff = xoff + .01; * var n = noise(xoff) * width; * line(n, 0, n, height); * } * </code> * </div> * <div> * <code>var noiseScale=0.02; * * function draw() { * background(0); * for (var x=0; x < width; x++) { * var noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale); * stroke(noiseVal*255); * line(x, mouseY+noiseVal*80, x, height); * } * } * </code> * </div> * * @alt * vertical line moves left to right with updating noise values. * horizontal wave pattern effected by mouse x-position & updating noise values. * */ p5.noise = function (x, y, z) { y = y || 0; z = z || 0; if (perlin == null) { perlin = new Array(PERLIN_SIZE + 1); for (var i = 0; i < PERLIN_SIZE + 1; i++) { perlin[i] = Math.random(); } } if (x < 0) { x = -x; } if (y < 0) { y = -y; } if (z < 0) { z = -z; } var xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z); var xf = x - xi; var yf = y - yi; var zf = z - zi; var rxf, ryf; var r = 0; var ampl = 0.5; var n1, n2, n3; for (var o = 0; o < perlin_octaves; o++) { var of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB); rxf = scaled_cosine(xf); ryf = scaled_cosine(yf); n1 = perlin[of & PERLIN_SIZE]; n1 += rxf * (perlin[of + 1 & PERLIN_SIZE] - n1); n2 = perlin[of + PERLIN_YWRAP & PERLIN_SIZE]; n2 += rxf * (perlin[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n2); n1 += ryf * (n2 - n1); of += PERLIN_ZWRAP; n2 = perlin[of & PERLIN_SIZE]; n2 += rxf * (perlin[of + 1 & PERLIN_SIZE] - n2); n3 = perlin[of + PERLIN_YWRAP & PERLIN_SIZE]; n3 += rxf * (perlin[of + PERLIN_YWRAP + 1 & PERLIN_SIZE] - n3); n2 += ryf * (n3 - n2); n1 += scaled_cosine(zf) * (n2 - n1); r += n1 * ampl; ampl *= perlin_amp_falloff; xi <<= 1; xf *= 2; yi <<= 1; yf *= 2; zi <<= 1; zf *= 2; if (xf >= 1.0) { xi++;xf--; } if (yf >= 1.0) { yi++;yf--; } if (zf >= 1.0) { zi++;zf--; } } return r; }; /** * * Adjusts the character and level of detail produced by the Perlin noise * function. Similar to harmonics in physics, noise is computed over * several octaves. Lower octaves contribute more to the output signal and * as such define the overall intensity of the noise, whereas higher octaves * create finer grained details in the noise sequence. * <br><br> * By default, noise is computed over 4 octaves with each octave contributing * exactly half than its predecessor, starting at 50% strength for the 1st * octave. This falloff amount can be changed by adding an additional function * parameter. Eg. a falloff factor of 0.75 means each octave will now have * 75% impact (25% less) of the previous lower octave. Any value between * 0.0 and 1.0 is valid, however note that values greater than 0.5 might * result in greater than 1.0 values returned by <b>noise()</b>. * <br><br> * By changing these parameters, the signal created by the <b>noise()</b> * function can be adapted to fit very specific needs and characteristics. * * @method noiseDetail * @param {Number} lod number of octaves to be used by the noise * @param {Number} falloff falloff factor for each octave * @example * <div> * <code> * * var noiseVal; * var noiseScale=0.02; * * function setup() { * createCanvas(100,100); * } * * function draw() { * background(0); * for (var y = 0; y < height; y++) { * for (var x = 0; x < width/2; x++) { * noiseDetail(2,0.2); * noiseVal = noise((mouseX+x) * noiseScale, * (mouseY+y) * noiseScale); * stroke(noiseVal*255); * point(x,y); * noiseDetail(8,0.65); * noiseVal = noise((mouseX + x + width/2) * noiseScale, * (mouseY + y) * noiseScale); * stroke(noiseVal*255); * point(x + width/2, y); * } * } * } * </code> * </div> * * @alt * 2 vertical grey smokey patterns affected my mouse x-position and noise. * */ p5.noiseDetail = function (lod, falloff) { if (lod > 0) { perlin_octaves = lod; } if (falloff > 0) { perlin_amp_falloff = falloff; } }; /** * Sets the seed value for <b>noise()</b>. By default, <b>noise()</b> * produces different results each time the program is run. Set the * <b>value</b> parameter to a constant to return the same pseudo-random * numbers each time the software is run. * * @method noiseSeed * @param {Number} seed the seed value * @example * <div> * <code>var xoff = 0.0; * * function setup() { * noiseSeed(99); * stroke(0, 10); * } * * function draw() { * xoff = xoff + .01; * var n = noise(xoff) * width; * line(n, 0, n, height); * } * </code> * </div> * * @alt * vertical grey lines drawing in pattern affected by noise. * */ p5.noiseSeed = function (seed) { // Linear Congruential Generator // Variant of a Lehman Generator var lcg = function () { // Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes // m is basically chosen to be large (as it is the max period) // and for its relationships to a and c var m = 4294967296, // a - 1 should be divisible by m's prime factors a = 1664525, // c and m should be co-prime c = 1013904223, seed, z; return { setSeed: function setSeed(val) { // pick a random seed if val is undefined or null // the >>> 0 casts the seed to an unsigned 32-bit integer z = seed = (val == null ? Math.random() * m : val) >>> 0; }, getSeed: function getSeed() { return seed; }, rand: function rand() { // define the recurrence relationship z = (a * z + c) % m; // return a float in [0, 1) // if z = m then z / m = 0 therefore (z % m) / m < 1 always return z / m; } }; }(); lcg.setSeed(seed); perlin = new Array(PERLIN_SIZE + 1); for (var i = 0; i < PERLIN_SIZE + 1; i++) { perlin[i] = lcg.rand(); } }; /** * noise motion. * * @param {points} * @param {data} * data rule example: * { value : 0, step : 0.005 ,width : 600, height : 400} */ var noise = function (points, data) { data.value += data.step; points[0] = data.width * p5.noise(data.value + 15); points[1] = data.height * p5.noise(data.value + 25); points[2] = data.width * p5.noise(data.value + 35); points[3] = data.height * p5.noise(data.value + 45); points[4] = data.width * p5.noise(data.value + 55); points[5] = data.height * p5.noise(data.value + 65); points[6] = data.width * p5.noise(data.value + 75); points[7] = data.height * p5.noise(data.value + 85); }; var motion = { dance: dance, move: move, rotate: rotate, to: to, line: line, circle: circle, close: path.close, open: path.open, expand: expand, noise: noise }; var wordData = { 'c': [[70, 70, 12, 76, 12, 123, 70, 128]], 'u': [[25, 68, 23, 140, 80, 140, 74, 100], [73, 62, 72, 90, 75, 110, 93, 134]], 'r': [[21, 62, 21, 62, 21, 128, 21, 128], [21, 128, 17, 96, 17, 68, 65, 60]], 'v': [[12, 58, 41, 132, 61, 132, 96, 58]], 'e': [[44, 104, 112, 52, -20, 82, 77, 136]], 'j': [[52, 48, 53, 48, 54, 49, 52, 48], [8, 175, 24, 204, 60, 197, 56, 74]], 's': [[81, 72, 17, 42, 105, 145, 41, 120]], 'l': [[77, 27, 30, 114, 36, 126, 57, 126]], 'i': [[56, 71, 56, 72, 59, 70, 56, 73], [47, 93, 59, 81, 47, 121, 59, 111]] }; var Word = function (_Group) { inherits(Word, _Group); function Word(word, option) { classCallCheck(this, Word); var _this = possibleConstructorReturn(this, (Word.__proto__ || Object.getPrototypeOf(Word)).call(this)); option = Object.assign({ x: 0, y: 0, color: 'black' }, option); _this.x = option.x; _this.y = option.y; _this.color = option.color; _this.word = word; _this.data = option.data; _this.motion = option.motion; _this.points = wordData[word]; _this._init(); return _this; } createClass(Word, [{ key: '_init', value: function _init() { var _this2 = this; this.points.forEach(function (item) { _this2.add(new Curve({ x: _this2.x, y: _this2.y, points: item, color: _this2.color, data: _this2.data, motion: _this2.motion })); }); } }]); return Word; }(Group); var cache = {}; var cssColors = { aliceblue: 0xF0F8FF, antiquewhite: 0xFAEBD7, aqua: 0x00FFFF, aquamarine: 0x7FFFD4, azure: 0xF0FFFF, beige: 0xF5F5DC, bisque: 0xFFE4C4, black: 0x000000, blanchedalmond: 0xFFEBCD, blue: 0x0000FF, blueviolet: 0x8A2BE2, brown: 0xA52A2A, burlywood: 0xDEB887, cadetblue: 0x5F9EA0, chartreuse: 0x7FFF00, chocolate: 0xD2691E, coral: 0xFF7F50, cornflowerblue: 0x6495ED, cornsilk: 0xFFF8DC, crimson: 0xDC143C, cyan: 0x00FFFF, darkblue: 0x00008B, darkcyan: 0x008B8B, darkgoldenrod: 0xB8860B, darkgray: 0xA9A9A9, darkgrey: 0xA9A9A9, darkgreen: 0x006400, darkkhaki: 0xBDB76B, darkmagenta: 0x8B008B, darkolivegreen: 0x556B2F, darkorange: 0xFF8C00, darkorchid: 0x9932CC, darkred: 0x8B0000, darksalmon: 0xE9967A, darkseagreen: 0x8FBC8F, darkslateblue: 0x483D8B, darkslategray: 0x2F4F4F, darkslategrey: 0x2F4F4F, darkturquoise: 0x00CED1, darkviolet: 0x9400D3, deeppink: 0xFF1493, deepskyblue: 0x00BFFF, dimgray: 0x696969, dimgrey: 0x696969, dodgerblue: 0x1E90FF, firebrick: 0xB22222, floralwhite: 0xFFFAF0, forestgreen: 0x228B22, fuchsia: 0xFF00FF, gainsboro: 0xDCDCDC, ghostwhite: 0xF8F8FF, gold: 0xFFD700, goldenrod: 0xDAA520, gray: 0x808080, grey: 0x808080, green: 0x008000, greenyellow: 0xADFF2F, honeydew: 0xF0FFF0, hotpink: 0xFF69B4, indianred: 0xCD5C5C, indigo: 0x4B0082, ivory: 0xFFFFF0, khaki: 0xF0E68C, lavender: 0xE6E6FA, lavenderblush: 0xFFF0F5, lawngreen: 0x7CFC00, lemonchiffon: 0xFFFACD, lightblue: 0xADD8E6, lightcoral: 0xF08080, lightcyan: 0xE0FFFF, lightgoldenrodyellow: 0xFAFAD2, lightgray: 0xD3D3D3, lightgrey: 0xD3D3D3, lightgreen: 0x90EE90, lightpink: 0xFFB6C1, lightsalmon: 0xFFA07A, lightseagreen: 0x20B2AA, lightskyblue: 0x87CEFA, lightslategray: 0x778899, lightslategrey: 0x778899, lightsteelblue: 0xB0C4DE, lightyellow: 0xFFFFE0, lime: 0x00FF00, limegreen: 0x32CD32, linen: 0xFAF0E6, magenta: 0xFF00FF, maroon: 0x800000, mediumaquamarine: 0x66CDAA, mediumblue: 0x0000CD, mediumorchid: 0xBA55D3, mediumpurple: 0x9370D8, mediumseagreen: 0x3CB371, mediumslateblue: 0x7B68EE, mediumspringgreen: 0x00FA9A, mediumturquoise: 0x48D1CC, mediumvioletred: 0xC71585, midnightblue: 0x191970, mintcream: 0xF5FFFA, mistyrose: 0xFFE4E1, moccasin: 0xFFE4B5, navajowhite: 0xFFDEAD, navy: 0x000080, oldlace: 0xFDF5E6, olive: 0x808000, olivedrab: 0x6B8E23, orange: 0xFFA500, orangered: 0xFF4500, orchid: 0xDA70D6, palegoldenrod: 0xEEE8AA, palegreen: 0x98FB98, paleturquoise: 0xAFEEEE, palevioletred: 0xD87093, papayawhip: 0xFFEFD5, peachpuff: 0xFFDAB9, peru: 0xCD853F, pink: 0xFFC0CB, plum: 0xDDA0DD, powderblue: 0xB0E0E6, purple: 0x800080, red: 0xFF0000, rosybrown: 0xBC8F8F, royalblue: 0x4169E1, saddlebrown: 0x8B4513, salmon: 0xFA8072, sandybrown: 0xF4A460, seagreen: 0x2E8B57, seashell: 0xFFF5EE, sienna: 0xA0522D, silver: 0xC0C0C0, skyblue: 0x87CEEB, slateblue: 0x6A5ACD, slategray: 0x708090, slategrey: 0x708090, snow: 0xFFFAFA, springgreen: 0x00FF7F, steelblue: 0x4682B4, tan: 0xD2B48C, teal: 0x008080, thistle: 0xD8BFD8, tomato: 0xFF6347, turquoise: 0x40E0D0, violet: 0xEE82EE, wheat: 0xF5DEB3, white: 0xFFFFFF, whitesmoke: 0xF5F5F5, yellow: 0xFFFF00, yellowgreen: 0x9ACD32 }; function lerp(start, end, percent) { return makeGradientColor(hexToRgb(start), hexToRgb(end), percent); } var hexTriplet = "01".substr(-1) === "1" ? // pad 6 zeros to the left function (cssColor) { return "#" + ("00000" + cssColor.toString(16)).substr(-6); } : // IE doesn't support substr with negative numbers function (cssColor) { var str = cssColor.toString(16); return "#" + new Array(str.length < 6 ? 6 - str.length + 1 : 0).join("0") + str; }; function hexToRgb(hex) { if (cache[hex]) return cache[hex]; var cssColor = null; if (cssColors[hex]) { cssColor = hex; hex = hexTriplet(cssColors[hex]); } // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function (m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); var key = cssColor ? cssColor : hex; cache[key] = result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; return cache[key]; } function makeGradientColor(color1, color2, percent) { var newColor = {}; if (percent < 0) percent = 0; if (percent > 100) percent = 100; function makeChannel(a, b) { return a + Math.round((b - a) * (percent / 100)); } function makeColorPiece(num) { num = Math.min(num, 255); // not more than 255 num = Math.max(num, 0); // not less than 0 var str = num.toString(16); if (str.length < 2) { str = "0" + str; } return str; } newColor.r = makeChannel(color1.r, color2.r); newColor.g = makeChannel(color1.g, color2.g); newColor.b = makeChannel(color1.b, color2.b); newColor.cssColor = "#" + makeColorPiece(newColor.r) + makeColorPiece(newColor.g) + makeColorPiece(newColor.b); return newColor.cssColor; } var color = { lerp: lerp, hexToRgb: hexToRgb, makeGradientColor: makeGradientColor }; var SmoothCurve = function () { function SmoothCurve(option) { classCallCheck(this, SmoothCurve); this.points = option.points || [0, 0, 0, 0, 0, 0]; this.color = option.color || 'black'; this.x = option.x || 0; this.y = option.y || 0; this.vision = option.vision || []; this.visionMax = option.visionMax !== void 0 ? option.visionMax : 80; this.visionInterval = option.visionInterval || 10; this.disableVision = option.disableVision; this._preDate = Date.now(); this._now = new Date(); this.debug = option.debug; this.size = option.size || 1; this.data = option.data; var noop = function noop() {}; this._ease = function (value) { return value; }; this._targetPoints = null; this.copyPoints = this.points.slice(0); this.motion = option.motion || noop; this.visionAlpha = option.visionAlpha === void 0 ? 0.2 : option.visionAlpha; if (option.initVision === void 0 || option.initVision) { this._initVision(option.visionCount || 80); } this.beforeDraw = option.beforeDraw || noop; this.afterDraw = option.afterDraw || noop; } createClass(SmoothCurve, [{ key: '_initVision', value: function _initVision() { var i = 0; for (; i < 80; i++) { this.tick(true); } } }, { key: 'tick', value: function tick(tickSelf) { if (!this.disableVision) { this._now = Date.now(); if (this._now - this._preDate > this.visionInterval || tickSelf) { this.vision.push(this.points.slice(0)); if (this.vision.length > this.visionMax) { this.vision.splice(0, 1); } this._preDate = this._now; } } if (!this.pauseMotion) { this.motion.call(this, this.points, this.data); } if (this._targetPoints) { this._pointsTo(); } } }, { key: 'pause', value: function pause() { this.pauseMotion = true; } }, { key: 'play', value: function play() { this.pauseMotion = false; } }, { key: 'draw', value: function draw(ctx) { this.tick(); this.beforeDraw.call(this, ctx); ctx.save(); ctx.translate(this.x, this.y); ctx.lineWidth = this.size; ctx.globalAlpha = 1; ctx.strokeStyle = this.color; var points = this.points; ctx.beginPath(); ctx.moveTo(points[0], points[1]); for (var i = 2, len = points.length; i < len; i += 2) { if (i === points.length - 4) { ctx.quadraticCurveTo(points[i], points[i + 1], points[i + 2], points[i + 3]); } else { ctx.quadraticCurveTo(points[i], points[i + 1], (points[i] + points[i + 2]) / 2, (points[i + 1] + points[i + 3]) / 2); } } ctx.stroke(); if (this.debug) { ctx.beginPath(); ctx.globalAlpha = 0.3; ctx.moveTo(points[0], points[1]); for (var _i = 2, _len = points.length; _i < _len; _i += 2) { ctx.lineTo(points[_i], points[_i + 1]); } ctx.stroke(); } var vision = this.vision; for (var _i2 = 0, _len2 = vision.length; _i2 < _len2; _i2++) { ctx.globalAlpha = _i2 / this.visionMax * this.visionAlpha; var vp = vision[_i2]; ctx.beginPath(); ctx.moveTo(vp[0], vp[1]); for (var _i3 = 2, vlen = vp.length; _i3 < vlen; _i3 += 2) { if (_i3 === points.length - 4) { ctx.quadraticCurveTo(vp[_i3], vp[_i3 + 1], vp[_i3 + 2], vp[_i3 + 3]); } else { ctx.quadraticCurveTo(vp[_i3], vp[_i3 + 1], (vp[_i3] + vp[_i3 + 2]) / 2, (vp[_i3 + 1] + vp[_i3 + 3]) / 2); } } ctx.stroke(); } ctx.restore(); this.afterDraw.call(this, ctx); } }]); return SmoothCurve; }(); /** * Created by dntzhang on 2017/4/26. */ var SproutCurve = function () { function SproutCurve(option) { classCallCheck(this, SproutCurve); this.seeds = []; this.initAlpha = 0.2; this.startLife = 250; this.noise = { value: 0, step: 0.0008, scale: 2, interval: 10 }; this.color = option.color || '#65ffff'; } createClass(SproutCurve, [{ key: 'addSeed', value: function addSeed(x, y, vx, vy) { this.seeds.push({ x: x, y: y, vx: vx, vy: vy, px: x, py: y, life: this.startLife }); } }, { key: 'sprout', value: function sprout() { while (this.seeds.length && this.seeds[0].life === 0) { this.seeds.shift(); } var dx = 0, dy = 0; for (var i = 0, len = this.seeds.length; i < len; i++) { dx = dy = 0; var seed = this.seeds[i]; var nv = p5.noise(this.noise.value + i * this.noise.interval) * Math.PI * 5; this.noise.value += this.noise.step; dx += this.noise.scale * Math.cos(nv); dy += this.noise.scale * Math.sin(nv); seed.life--; var nx = seed.x + dx; var ny = seed.y + dy; seed.px = seed.x; seed.py = seed.y; seed.x = nx; seed.y = ny; //seed.x+=seed.vx*10 //seed.y+=seed.vy*10 } } }, { key: 'draw', value: function draw(ctx) { this.sprout(); if (this.seeds.length === 0) return; ctx.globalAlpha = this.initAlpha * (this.seeds[this.seeds.length - 1].life / this.startLife); this.points = []; for (var i = 0, _len = this.seeds.length; i < _len; i++) { this.points.push(this.seeds[i].x, this.seeds[i].y); } var points = this.points; var len = points.length; if (len > 5) { ctx.beginPath(); ctx.globalCompositeOperation = 'lighter'; ctx.strokeStyle = this.color; ctx.moveTo(points[0], points[1]); for (var _i = 2; _i < len; _i += 2) { if (_i === points.length - 4) { ctx.quadraticCurveTo(points[_i], points[_i + 1], points[_i + 2], points[_i + 3]); } else { ctx.quadraticCurveTo(points[_i], points[_i + 1], (points[_i] + points[_i + 2]) / 2, (points[_i + 1] + points[_i + 3]) / 2); } } ctx.stroke(); } } }]); return SproutCurve; }(); var index = { Curve: Curve, Group: Group, Stage: Stage, motion: motion, Word: Word, perlin: p5, color: color, SmoothCurve: SmoothCurve, SproutCurve: SproutCurve }; return index; })));