| /* |
| * Copyright (C) 2015-2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| (function() { |
| |
| // === PAINT OBJECTS === |
| |
| CanvasLineSegment = Utilities.createClass( |
| function(stage) |
| { |
| var circle = Stage.randomInt(0, 3); |
| this._color = ["#e01040", "#10c030", "#744CBA", "#e05010"][circle]; |
| this._lineWidth = Math.pow(Pseudo.random(), 12) * 20 + 3; |
| this._omega = Pseudo.random() * 3 + 0.2; |
| var theta = Stage.randomAngle(); |
| this._cosTheta = Math.cos(theta); |
| this._sinTheta = Math.sin(theta); |
| this._startX = stage.circleRadius * this._cosTheta + stage.circleX[circle]; |
| this._startY = stage.circleRadius * this._sinTheta + stage.circleY[circle]; |
| this._length = Math.pow(Pseudo.random(), 8) * stage.lineLengthMaximum + stage.lineMinimum; |
| this._segmentDirection = Pseudo.random() > 0.5 ? -1 : 1; |
| }, { |
| |
| draw: function(context) |
| { |
| context.strokeStyle = this._color; |
| context.lineWidth = this._lineWidth; |
| |
| this._length += Math.sin(Stage.dateCounterValue(100) * this._omega); |
| |
| context.beginPath(); |
| context.moveTo(this._startX, this._startY); |
| context.lineTo(this._startX + this._segmentDirection * this._length * this._cosTheta, |
| this._startY + this._segmentDirection * this._length * this._sinTheta); |
| context.stroke(); |
| } |
| }); |
| |
| CanvasArc = Utilities.createClass( |
| function(stage) |
| { |
| var maxX = 6, maxY = 3; |
| var distanceX = stage.size.x / maxX; |
| var distanceY = stage.size.y / (maxY + 1); |
| var randY = Stage.randomInt(0, maxY); |
| var randX = Stage.randomInt(0, maxX - 1 * (randY % 2)); |
| |
| this._point = new Point(distanceX * (randX + (randY % 2) / 2), distanceY * (randY + .5)); |
| |
| this._radius = 20 + Math.pow(Pseudo.random(), 5) * (Math.min(distanceX, distanceY) / 1.8); |
| this._startAngle = Stage.randomAngle(); |
| this._endAngle = Stage.randomAngle(); |
| this._omega = (Pseudo.random() - 0.5) * 0.3; |
| this._counterclockwise = Stage.randomBool(); |
| var colors = ["#101010", "#808080", "#c0c0c0"]; |
| colors.push(["#e01040", "#10c030", "#e05010"][(randX + Math.ceil(randY / 2)) % 3]); |
| this._color = colors[Math.floor(Pseudo.random() * colors.length)]; |
| this._lineWidth = 1 + Math.pow(Pseudo.random(), 5) * 30; |
| this._doStroke = Stage.randomInt(0, 3) != 0; |
| }, { |
| |
| draw: function(context) |
| { |
| this._startAngle += this._omega; |
| this._endAngle += this._omega / 2; |
| |
| if (this._doStroke) { |
| context.strokeStyle = this._color; |
| context.lineWidth = this._lineWidth; |
| context.beginPath(); |
| context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise); |
| context.stroke(); |
| } else { |
| context.fillStyle = this._color; |
| context.beginPath(); |
| context.lineTo(this._point.x, this._point.y); |
| context.arc(this._point.x, this._point.y, this._radius, this._startAngle, this._endAngle, this._counterclockwise); |
| context.lineTo(this._point.x, this._point.y); |
| context.fill(); |
| } |
| } |
| }); |
| |
| // CanvasLinePoint contains no draw() method since it is either moveTo or |
| // lineTo depending on its index. |
| CanvasLinePoint = Utilities.createClass( |
| function(stage) |
| { |
| var colors = ["#101010", "#808080", "#c0c0c0", "#101010", "#808080", "#c0c0c0", "#e01040"]; |
| this.color = Stage.randomElementInArray(colors); |
| this.width = Math.pow(Pseudo.random(), 5) * 20 + 1; |
| this.isSplit = Pseudo.random() > 0.95; |
| |
| var nextPoint; |
| if (stage.objects.length) |
| nextPoint = this.randomPoint(stage, stage.objects[stage.objects.length - 1].coordinate); |
| else |
| nextPoint = this.randomPoint(stage, this.gridSize.center); |
| this.point = nextPoint.point; |
| this.coordinate = nextPoint.coordinate; |
| }, { |
| |
| gridSize: new Point(80, 40), |
| offsets: [ |
| new Point(-4, 0), |
| new Point(2, 0), |
| new Point(1, -2), |
| new Point(1, 2), |
| ], |
| |
| randomPoint: function(stage, startCoordinate) |
| { |
| var coordinate = startCoordinate; |
| if (stage.objects.length) { |
| var offset = Stage.randomElementInArray(this.offsets); |
| |
| coordinate = coordinate.add(offset); |
| if (coordinate.x < 0 || coordinate.x > this.gridSize.width) |
| coordinate.x -= offset.x * 2; |
| if (coordinate.y < 0 || coordinate.y > this.gridSize.height) |
| coordinate.y -= offset.y * 2; |
| } |
| |
| var x = (coordinate.x + .5) * stage.size.x / (this.gridSize.width + 1); |
| var y = (coordinate.y + .5) * stage.size.y / (this.gridSize.height + 1); |
| return { |
| point: new Point(x, y), |
| coordinate: coordinate |
| }; |
| }, |
| |
| draw: function(context) |
| { |
| context.lineTo(this.point.x, this.point.y); |
| } |
| }); |
| |
| CanvasQuadraticSegment = Utilities.createSubclass(CanvasLinePoint, |
| function(stage) |
| { |
| CanvasLinePoint.call(this, stage); |
| // The chosen point is instead the control point. |
| this._point2 = this.point; |
| |
| // Get another random point for the actual end point of the segment. |
| var nextPoint = this.randomPoint(stage, this.coordinate); |
| this.point = nextPoint.point; |
| this.coordinate = nextPoint.coordinate; |
| }, { |
| |
| draw: function(context) |
| { |
| context.quadraticCurveTo(this._point2.x, this._point2.y, this.point.x, this.point.y); |
| } |
| }); |
| |
| CanvasBezierSegment = Utilities.createSubclass(CanvasLinePoint, |
| function(stage) |
| { |
| CanvasLinePoint.call(this, stage); |
| // The chosen point is instead the first control point. |
| this._point2 = this.point; |
| var nextPoint = this.randomPoint(stage, this.coordinate); |
| this._point3 = nextPoint.point; |
| |
| nextPoint = this.randomPoint(stage, nextPoint.coordinate); |
| this.point = nextPoint.point; |
| this.coordinate = nextPoint.coordinate; |
| }, { |
| |
| draw: function(context, off) |
| { |
| context.bezierCurveTo(this._point2.x, this._point2.y, this._point3.x, this._point3.y, this.point.x, this.point.y); |
| } |
| }); |
| |
| // === STAGES === |
| |
| CanvasLineSegmentStage = Utilities.createSubclass(SimpleCanvasStage, |
| function() |
| { |
| SimpleCanvasStage.call(this, CanvasLineSegment); |
| }, { |
| |
| initialize: function(benchmark, options) |
| { |
| SimpleCanvasStage.prototype.initialize.call(this, benchmark, options); |
| this.context.lineCap = options["lineCap"] || "butt"; |
| this.lineMinimum = 20; |
| this.lineLengthMaximum = 40; |
| this.circleRadius = this.size.x / 8 - .4 * (this.lineMinimum + this.lineLengthMaximum); |
| this.circleX = [ |
| 5.5 / 32 * this.size.x, |
| 12.5 / 32 * this.size.x, |
| 19.5 / 32 * this.size.x, |
| 26.5 / 32 * this.size.x, |
| ]; |
| this.circleY = [ |
| 2.1 / 3 * this.size.y, |
| 0.9 / 3 * this.size.y, |
| 2.1 / 3 * this.size.y, |
| 0.9 / 3 * this.size.y |
| ]; |
| this.halfSize = this.size.multiply(.5); |
| this.twoFifthsSizeX = this.size.x * .4; |
| }, |
| |
| animate: function() |
| { |
| var context = this.context; |
| context.clearRect(0, 0, this.size.x, this.size.y); |
| |
| var angle = Stage.dateFractionalValue(3000) * Math.PI * 2; |
| var dx = this.twoFifthsSizeX * Math.cos(angle); |
| var dy = this.twoFifthsSizeX * Math.sin(angle); |
| |
| var gradient = context.createLinearGradient(this.halfSize.x + dx, this.halfSize.y + dy, this.halfSize.x - dx, this.halfSize.y - dy); |
| var gradientStep = 0.5 + 0.5 * Math.sin(Stage.dateFractionalValue(5000) * Math.PI * 2); |
| var colorStopStep = Utilities.lerp(gradientStep, -.1, .1); |
| var brightnessStep = Math.round(Utilities.lerp(gradientStep, 32, 64)); |
| var color1Step = "rgba(" + brightnessStep + "," + brightnessStep + "," + (brightnessStep << 1) + ",.4)"; |
| var color2Step = "rgba(" + (brightnessStep << 1) + "," + (brightnessStep << 1) + "," + brightnessStep + ",.4)"; |
| gradient.addColorStop(0, color1Step); |
| gradient.addColorStop(.2 + colorStopStep, color1Step); |
| gradient.addColorStop(.8 - colorStopStep, color2Step); |
| gradient.addColorStop(1, color2Step); |
| |
| context.lineWidth = 15; |
| for(var i = 0; i < 4; i++) { |
| context.strokeStyle = ["#e01040", "#10c030", "#744CBA", "#e05010"][i]; |
| context.fillStyle = ["#70051d", "#016112", "#2F0C6E", "#702701"][i]; |
| context.beginPath(); |
| context.arc(this.circleX[i], this.circleY[i], this.circleRadius, 0, Math.PI*2); |
| context.stroke(); |
| context.fill(); |
| context.fillStyle = gradient; |
| context.fill(); |
| } |
| |
| for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) |
| this.objects[i].draw(context); |
| } |
| }); |
| |
| CanvasLinePathStage = Utilities.createSubclass(SimpleCanvasStage, |
| function() |
| { |
| SimpleCanvasStage.call(this, [CanvasLinePoint, CanvasLinePoint, CanvasQuadraticSegment, CanvasBezierSegment]); |
| }, { |
| |
| initialize: function(benchmark, options) |
| { |
| SimpleCanvasStage.prototype.initialize.call(this, benchmark, options); |
| this.context.lineJoin = options["lineJoin"] || "bevel"; |
| this.context.lineCap = options["lineCap"] || "butt"; |
| }, |
| |
| animate: function() { |
| var context = this.context; |
| |
| context.clearRect(0, 0, this.size.x, this.size.y); |
| context.beginPath(); |
| for (var i = this.offsetIndex, length = this.objects.length; i < length; ++i) { |
| var object = this.objects[i]; |
| if (i == this.offsetIndex) { |
| context.lineWidth = object.width; |
| context.strokeStyle = object.color; |
| context.beginPath(); |
| context.moveTo(object.point.x, object.point.y); |
| } else { |
| object.draw(context); |
| |
| if (object.isSplit) { |
| context.stroke(); |
| |
| context.lineWidth = object.width; |
| context.strokeStyle = object.color; |
| context.beginPath(); |
| context.moveTo(object.point.x, object.point.y); |
| } |
| |
| if (Pseudo.random() > 0.995) |
| object.isSplit = !object.isSplit; |
| } |
| } |
| context.stroke(); |
| } |
| }); |
| |
| // === BENCHMARK === |
| |
| CanvasPathBenchmark = Utilities.createSubclass(Benchmark, |
| function(options) |
| { |
| var stage; |
| switch (options["pathType"]) { |
| case "line": |
| stage = new CanvasLineSegmentStage(); |
| break; |
| case "linePath": |
| stage = new CanvasLinePathStage(); |
| break; |
| case "arcs": |
| stage = new SimpleCanvasStage(CanvasArc); |
| break; |
| } |
| |
| Benchmark.call(this, stage, options); |
| } |
| ); |
| |
| window.benchmarkClass = CanvasPathBenchmark; |
| |
| })(); |