mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Merge branch 'master' of https://github.com/paperjs/paper.js
This commit is contained in:
commit
a28b20dac8
10 changed files with 648 additions and 42 deletions
571
examples/Games/Paperoids.html
Normal file
571
examples/Games/Paperoids.html
Normal file
|
@ -0,0 +1,571 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<title>Paperoids</title>
|
||||
<script type="text/javascript" src="../../dist/paper.js"></script>
|
||||
<script type="text/javascript" src="../../lib/stats.js"></script>
|
||||
<script type="text/paperscript" canvas="canvas">
|
||||
|
||||
//
|
||||
//
|
||||
// Paperoids - an Asteroids clone for paper.js
|
||||
//
|
||||
// Sorry nerds, no enemy ships or sound just yet.
|
||||
//
|
||||
// Version: 1.2.1
|
||||
// Author: David Hirmes (@hirmes)
|
||||
// Date: 2011-08-09
|
||||
//
|
||||
// Revision History:
|
||||
// 1.0 - 2011-07-13 - Initial release
|
||||
// 1.1 - 2011-07-13 - Optimizations by Jonathan Puckey (@jonathanpuckey)
|
||||
// 1.2 - 2011-07-16 - Refactored with closures (@jonathanpuckey)
|
||||
// 1.2.1- 2011-08-09 - bug fixes
|
||||
//
|
||||
|
||||
var presets = {
|
||||
speed: 0.2,
|
||||
maxRockSpeed: 4.5,
|
||||
rockCount: 6,
|
||||
lives: 3,
|
||||
freeShipScore: 10000,
|
||||
freeShipIncrement: 10000
|
||||
};
|
||||
|
||||
function initialize() {
|
||||
Rocks.add(presets.rockCount);
|
||||
Score.update();
|
||||
Lives.initialize();
|
||||
document.getElementById('statholder').style.display = 'block';
|
||||
}
|
||||
|
||||
function onKeyUp(event) {
|
||||
if (event.key == 'space') {
|
||||
Ship.moveTo(Point.random() * view.size);
|
||||
Ship.stop();
|
||||
}
|
||||
if (event.key == 'z') {
|
||||
Ship.fire();
|
||||
}
|
||||
// Show stats:
|
||||
if (event.key == 'f') {
|
||||
var statHolder = document.getElementById('statholder');
|
||||
statHolder.style.display = (statHolder.style.display == 'block')
|
||||
? 'none' : 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function onFrame() {
|
||||
Bullets.move();
|
||||
Rocks.iterateExplosions();
|
||||
Ship.checkCollisions();
|
||||
if (Key.isDown('left')) {
|
||||
Ship.turnLeft();
|
||||
}
|
||||
if (Key.isDown('right')) {
|
||||
Ship.turnRight();
|
||||
}
|
||||
if (Key.isDown('up')) {
|
||||
Ship.thrust();
|
||||
} else {
|
||||
Ship.coast();
|
||||
}
|
||||
Ship.move();
|
||||
Game.updateStats();
|
||||
}
|
||||
|
||||
project.currentStyle.strokeColor = 'white';
|
||||
|
||||
var Game = {
|
||||
roundDelay: false,
|
||||
over: function() {
|
||||
document.getElementById('gameover').style.display = 'block';
|
||||
},
|
||||
newRound: function() {
|
||||
Game.roundDelay = false;
|
||||
Rocks.add(presets.rockCount);
|
||||
},
|
||||
// Stats.js by Mr. Doob - https://github.com/mrdoob/stats.js
|
||||
updateStats: new function() {
|
||||
var stats = new Stats();
|
||||
|
||||
// Align top-left
|
||||
stats.domElement.style.position = 'absolute';
|
||||
stats.domElement.style.left = '0px';
|
||||
stats.domElement.style.top = '0px';
|
||||
|
||||
document.getElementById('statholder').appendChild( stats.domElement );
|
||||
document.getElementById('statholder').style.display = "none";
|
||||
return stats.update;
|
||||
}
|
||||
};
|
||||
|
||||
var assets = {
|
||||
destroyedShip: new function() {
|
||||
var group = new Group(
|
||||
new Path([-10, -8], [10, 0]),
|
||||
new Path([10, 0], [-10, 8]),
|
||||
new Path([-8, 4], [-8, -4])
|
||||
);
|
||||
group.visible = false;
|
||||
return group;
|
||||
},
|
||||
explosion: new function() {
|
||||
var explosionPath = new Path.Circle(new Point(), 1);
|
||||
explosionPath.fillColor = 'white';
|
||||
explosionPath.strokeColor = null;
|
||||
return new Symbol(explosionPath);
|
||||
}
|
||||
};
|
||||
|
||||
var Ship = new function() {
|
||||
var path = new Path([-10, -8], [10, 0], [-10, 8], [-8, 4], [-8, -4]);
|
||||
path.closed = true;
|
||||
var thrust = new Path([-8, -4], [-14, 0], [-8, 4]);
|
||||
var group = new Group(path, thrust);
|
||||
group.position = view.bounds.center;
|
||||
return {
|
||||
item: group,
|
||||
|
||||
angle: 0,
|
||||
|
||||
vector: new Point({
|
||||
angle: 0.2,
|
||||
length: 1
|
||||
}),
|
||||
|
||||
turnLeft: function() {
|
||||
group.rotate(-3);
|
||||
this.angle -= 3;
|
||||
},
|
||||
|
||||
turnRight: function() {
|
||||
group.rotate(3);
|
||||
this.angle += 3;
|
||||
},
|
||||
|
||||
thrust: function() {
|
||||
thrust.visible = true;
|
||||
this.vector += new Point({
|
||||
angle: this.angle,
|
||||
length: presets.speed
|
||||
});
|
||||
if (this.vector.length > 8) {
|
||||
this.vector.length = 8;
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this.vector.length = 0;
|
||||
},
|
||||
|
||||
fire: function() {
|
||||
if (!this.dying)
|
||||
Bullets.fire(this.item.position, this.angle);
|
||||
},
|
||||
|
||||
coast: function() {
|
||||
thrust.visible = false;
|
||||
this.vector *= .992;
|
||||
},
|
||||
|
||||
move: function() {
|
||||
group.position += this.vector;
|
||||
keepInView(group);
|
||||
},
|
||||
|
||||
moveTo: function(position) {
|
||||
group.position = position;
|
||||
keepInView(group);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.destroyedShip = assets.destroyedShip.clone();
|
||||
this.destroyedShip.position = this.item.position;
|
||||
this.destroyedShip.visible = true;
|
||||
this.item.visible = false;
|
||||
this.stop();
|
||||
this.item.position = view.center;
|
||||
this.dying = true;
|
||||
},
|
||||
|
||||
destroyed: function() {
|
||||
this.item.visible = true;
|
||||
this.stop();
|
||||
this.item.position = view.center;
|
||||
this.dying = false;
|
||||
this.destroyedShip.visible = false;
|
||||
},
|
||||
|
||||
checkCollisions: function() {
|
||||
var crash = -1;
|
||||
|
||||
// move rocks and do a hit test
|
||||
// between bounding rect of rocks and ship
|
||||
for (var i = 0; i < Rocks.children.length; i++) {
|
||||
var rock = Rocks.children[i];
|
||||
rock.position += rock.vector;
|
||||
if (rock.bounds.intersects(this.item.bounds)) {
|
||||
crash = i;
|
||||
}
|
||||
keepInView(rock);
|
||||
}
|
||||
|
||||
if (this.dying) {
|
||||
var children = this.destroyedShip.children;
|
||||
children[0].position.x++;
|
||||
children[1].position.x--;
|
||||
children[2].position.x--;
|
||||
children[2].position.y++;
|
||||
children[0].rotate(1);
|
||||
children[1].rotate(-1);
|
||||
children[2].rotate(1);
|
||||
this.destroyedShip.opacity *= 0.98;
|
||||
|
||||
// don't update anything else if the ship is already dead.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// if bounding rect collision, do a line intersection test
|
||||
if (crash > -1) {
|
||||
var hit = false;
|
||||
var pos = Rocks.children[crash].position;
|
||||
var shipSegments = this.item.firstChild.segments;
|
||||
var index = Rocks.children[crash].typeIndex;
|
||||
var tempRock = Rocks.shapes[index].clone();
|
||||
tempRock.transform(Rocks.children[crash].matrix);
|
||||
tempRock.remove();
|
||||
var rockSegments = tempRock.segments;
|
||||
// This code should be able to be simplified alot very soon,
|
||||
// when Paper.js implements Path#intersects(path);
|
||||
for (var i = 0; i < rockSegments.length - 1; i++) {
|
||||
var rockLine = new Line(rockSegments[i].point,
|
||||
rockSegments[i + 1].point, false);
|
||||
var shipLine = new Line(shipSegments[0].point,
|
||||
shipSegments[1].point, false);
|
||||
var lineHit = shipLine.intersect(rockLine);
|
||||
if (lineHit) {
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hit) Lives.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var Bullets = new function() {
|
||||
var group = new Group();
|
||||
var children = group.children;
|
||||
return {
|
||||
fire: function(position, angle) {
|
||||
if (children.length > 4) return;
|
||||
var bullet = new Path.Circle(position, 0.5);
|
||||
bullet.fillColor = 'white';
|
||||
bullet.strokeWidth = 0;
|
||||
bullet.data = {
|
||||
vector: new Point({
|
||||
angle: angle,
|
||||
length: 10
|
||||
}),
|
||||
timeToDie: 58
|
||||
};
|
||||
bullet.position += bullet.data.vector;
|
||||
group.addChild(bullet);
|
||||
},
|
||||
move: function() {
|
||||
// check for bullet hit
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var bullet = children[i];
|
||||
bullet.data.timeToDie--;
|
||||
if (bullet.data.timeToDie < 1) {
|
||||
bullet.remove();
|
||||
} else {
|
||||
bullet.position += bullet.data.vector;
|
||||
for (var r = 0; r < Rocks.children.length; r++) {
|
||||
var rock = Rocks.children[r];
|
||||
if (rock.bounds.contains(bullet.position) ) {
|
||||
Score.update(rock.type);
|
||||
Rocks.explode(rock);
|
||||
if (rock.type < Rocks.TYPE_SMALL ) {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
Rocks.add(1, rock.type + 4, rock.position);
|
||||
}
|
||||
}
|
||||
rock.remove();
|
||||
bullet.remove();
|
||||
}
|
||||
}
|
||||
keepInView(bullet);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var Rocks = new function() {
|
||||
var group = new Group();
|
||||
var shapes = [
|
||||
new Path(
|
||||
[-23, -40.5], [0, -30.5], [24, -40.5], [45, -21.5], [25, -12.5],
|
||||
[46, 9.5], [22, 38.5], [-10, 30.5], [-22, 40.5], [-46, 18.5],
|
||||
[-33, 0.5], [-44, -21.5], [-23, -40.5]),
|
||||
new Path(
|
||||
[-45, -9.5], [-12, -40.5], [24, -40.5], [46, -11.5], [45, 10.5],
|
||||
[24, 40.5], [0, 40.5], [0, 10.5], [-23, 38.5], [-46, 9.5], [-25, 0.5],
|
||||
[-45, -9.5]),
|
||||
new Path([-21.5, -39.5], [11.5, -39.5], [45.5, -20.5],
|
||||
[45.5, -8.5], [9.5, 0.5], [44.5, 21.5], [22.5, 39.5], [9.5, 31.5],
|
||||
[-20.5, 39.5], [-45.5, 10.5], [-45.5, -20.5], [-11.5, -21.5],
|
||||
[-21.5, -39.5]),
|
||||
new Path(
|
||||
[-22.5, -40.5], [-0.5, -19.5], [23.5, -39.5], [44.5, -21.5],
|
||||
[33.5, 0.5], [46.5, 19.5], [13.5, 40.5], [-22.5, 39.5], [-46.5, 18.5],
|
||||
[-46.5, -18.5], [-22.5, -40.5])
|
||||
];
|
||||
|
||||
// medium rocks
|
||||
for (var i = 4; i < 8; i++) {
|
||||
shapes[i] = shapes[i - 4].clone();
|
||||
shapes[i].scale(0.5);
|
||||
}
|
||||
|
||||
// small rocks
|
||||
for (var i = 8; i < 12; i++) {
|
||||
shapes[i] = shapes[i - 4].clone();
|
||||
shapes[i].scale(0.4);
|
||||
}
|
||||
|
||||
var rockSymbols = [];
|
||||
for (var i = 0; i < shapes.length; i++) {
|
||||
rockSymbols[i] = new Symbol(shapes[i]);
|
||||
}
|
||||
|
||||
var explosions = new Group();
|
||||
|
||||
return {
|
||||
shapes: shapes,
|
||||
children: group.children,
|
||||
make: function(type, pos) {
|
||||
var randomRock = type + Math.floor(4 * Math.random());
|
||||
var rock = rockSymbols[randomRock].place();
|
||||
rock.position = pos ? pos : Point.random() * view.size;
|
||||
rock.vector = new Point({
|
||||
angle: 360 * Math.random(),
|
||||
length: presets.maxRockSpeed * Math.random() + 0.1
|
||||
});
|
||||
rock.typeIndex = randomRock;
|
||||
rock.type = type;
|
||||
return rock;
|
||||
},
|
||||
add: function(amount, type, position) {
|
||||
for (var i = 0; i < amount; i++) {
|
||||
var rock = this.make(type || this.TYPE_BIG, position);
|
||||
group.addChild(rock);
|
||||
}
|
||||
},
|
||||
explode: function(rock) {
|
||||
var boomRock = shapes[rock.typeIndex].clone();
|
||||
boomRock.position = rock.position;
|
||||
for (var i = 0; i < boomRock.segments.length; i++) {
|
||||
var segmentPoint = boomRock.segments[i].point;
|
||||
var placed = assets.explosion.place(segmentPoint);
|
||||
placed.vector = (placed.position - rock.position) * 0.1;
|
||||
explosions.addChild(placed);
|
||||
}
|
||||
boomRock.remove();
|
||||
},
|
||||
iterateExplosions: function() {
|
||||
for (var i = 0; i < explosions.children.length; i++) {
|
||||
var explosion = explosions.children[i];
|
||||
explosion.vector.length *= .7;
|
||||
explosion.position += explosion.vector;
|
||||
explosion.opacity = explosion.vector.length;
|
||||
if (explosion.vector.length < 0.05 ) {
|
||||
explosion.remove();
|
||||
// if no more rocks, wait a second and start a new round
|
||||
if (this.children.length < 1 && !Game.roundDelay) {
|
||||
Game.roundDelay = true;
|
||||
presets.rockCount += 2;
|
||||
setTimeout(Game.newRound, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
TYPE_BIG: 0,
|
||||
TYPE_MEDIUM: 4,
|
||||
TYPE_SMALL: 8
|
||||
};
|
||||
};
|
||||
|
||||
var Score = new function() {
|
||||
var numberGroup = new Group(
|
||||
new Path([0, 0], [20, 0], [20, 27], [0, 27], [0, 0]),
|
||||
new Path([10, 0], [10, 27]),
|
||||
new Path([0, 0], [20, 0], [20, 14], [0, 14], [0, 27], [20, 27]),
|
||||
new Path([0, 0], [20, 0], [20, 14], [0, 14], [20, 14], [20, 27], [0, 27]),
|
||||
new Path([0, 0], [0, 14], [20, 14], [20, 0], [20, 27]),
|
||||
new Path([20, 0], [0, 0], [0, 14], [20, 14], [20, 27], [0, 27]),
|
||||
new Path([20, 0], [0, 0], [0, 27], [20, 27], [20, 14], [0, 14]),
|
||||
new Path([0, 0], [20, 0], [0, 27]),
|
||||
new Path([0, 0], [20, 0], [20, 27], [0, 27], [0, 0], [0, 14], [20, 14]),
|
||||
new Path([20, 14], [0, 14], [0, 0], [20, 0], [20, 27])
|
||||
);
|
||||
numberGroup.visible = false;
|
||||
var scoreDisplay = new Group();
|
||||
var score = 0;
|
||||
return {
|
||||
update: function(type) {
|
||||
if (type == Rocks.TYPE_BIG) score += 20;
|
||||
if (type == Rocks.TYPE_MEDIUM) score += 50;
|
||||
if (type == Rocks.TYPE_SMALL) score += 100;
|
||||
if (score >= presets.freeShipScore) {
|
||||
Lives.add(1);
|
||||
presets.freeShipScore += presets.freeShipIncrement;
|
||||
}
|
||||
scoreDisplay.removeChildren();
|
||||
|
||||
var scoreString = score + '';
|
||||
for (var i = 0; i < scoreString.length; i++) {
|
||||
var n = parseInt(scoreString[i], 10);
|
||||
scoreDisplay.addChild(numberGroup.children[n].clone());
|
||||
scoreDisplay.lastChild.position = [22 + i * 24, 22];
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var Lives = new function() {
|
||||
var currentLives;
|
||||
var shipPath = Ship.item.firstChild.clone();
|
||||
project.activeLayer.addChild(shipPath);
|
||||
shipPath.visible = false;
|
||||
Ship.visible = false;
|
||||
var group = new Group();
|
||||
return {
|
||||
initialize: function() {
|
||||
currentLives = presets.lives;
|
||||
this.display();
|
||||
},
|
||||
add: function() {
|
||||
currentLives++;
|
||||
this.display();
|
||||
},
|
||||
remove: function() {
|
||||
currentLives--;
|
||||
this.display();
|
||||
Ship.destroy();
|
||||
setTimeout( function() {
|
||||
if (currentLives == 0) {
|
||||
Game.over();
|
||||
} else {
|
||||
Ship.destroyed();
|
||||
}
|
||||
}, 1200);
|
||||
},
|
||||
display: function() {
|
||||
group.removeChildren();
|
||||
for (var i=0;i<currentLives-1;i++) {
|
||||
var copy = shipPath.clone();
|
||||
copy.rotate(-90);
|
||||
copy.visible = true;
|
||||
group.addChild(copy);
|
||||
copy.position = [22+ i * copy.bounds.width, 53];
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
initialize();
|
||||
|
||||
// Stop left and right keyboard events from propagating.
|
||||
function onKeyDown(event) {
|
||||
if (event.key == 'left' || event.key == 'right') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function keepInView(item) {
|
||||
var position = item.position;
|
||||
var itemBounds = item.bounds;
|
||||
var bounds = view.bounds;
|
||||
|
||||
if (itemBounds.left > bounds.width) {
|
||||
position.x = -item.bounds.width;
|
||||
}
|
||||
|
||||
if (position.x < -itemBounds.width) {
|
||||
position.x = bounds.width;
|
||||
}
|
||||
|
||||
if (itemBounds.top > view.size.height) {
|
||||
position.y = -itemBounds.height;
|
||||
}
|
||||
|
||||
if (position.y < -itemBounds.height) {
|
||||
position.y = bounds.height + itemBounds.height / 2;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
font-family:Helvetica,Arial;
|
||||
}
|
||||
.footer {
|
||||
position:absolute;
|
||||
bottom:0;
|
||||
color:#ff0000;
|
||||
background-color: rgba(60,60,60,0.8);
|
||||
font-size:0.75em;
|
||||
padding:0.5em;
|
||||
color:#ddd;
|
||||
width: 100%
|
||||
}
|
||||
.footer a {
|
||||
color: #fff;
|
||||
font-weight:
|
||||
bold; text-decoration: none;
|
||||
border-bottom: 1px solid #555;
|
||||
}
|
||||
.footer b {
|
||||
background-color: #660000;
|
||||
padding-left: 0.25em;
|
||||
padding-right: 0.25em; }
|
||||
.gameover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: 40%;
|
||||
color: #fff;
|
||||
background-color: rgba(60,60,60,0.8);
|
||||
padding: 32px;
|
||||
-moz-border-radius: 12px;
|
||||
-webkit-border-radius: 12px;
|
||||
border-radius: 12px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.gameover a {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background:black">
|
||||
<canvas style="position:absolute" id="canvas" resize></canvas>
|
||||
|
||||
<div style="position:absolute;right:51px;color:#ff0000;" id="statholder">FPS</div>
|
||||
|
||||
<div id="footer" class="footer"><a href=#">Paperoids</a>. To Play: <b>←</b> and <b>→</b> to rotate. <b>↑</b> for thrust. <b>Z</b> to fire. <b>F</b> to show FPS. Follow @<a href="http://twitter.com/#/hirmes">hirmes</a> for updates. Made with the amazing <a href="http://paperjs.org">Paper.js</a></div>
|
||||
|
||||
<div id="gameover" class="gameover">Game Over. <a href="Paperoids.html">Play again</a>?</div>
|
||||
</body>
|
||||
</html>
|
|
@ -422,7 +422,10 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* @return {Number} The determinant of this transform
|
||||
* The determinant of this transform.
|
||||
*
|
||||
* @type Number
|
||||
* @bean
|
||||
*/
|
||||
getDeterminant: function() {
|
||||
return this._a * this._d - this._b * this._c;
|
||||
|
@ -439,11 +442,12 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Returns the rotation angle of the matrix. If a non-uniform
|
||||
* rotation is applied as a result of a shear() or scale() command,
|
||||
* undefined is returned, as the resulting transformation cannot be
|
||||
* expressed in one rotation angle
|
||||
* @return {Number} The rotation angle of the matrix
|
||||
* The rotation angle of the matrix. If a non-uniform rotation is applied as
|
||||
* a result of a shear() or scale() command, undefined is returned, as the
|
||||
* resulting transformation cannot be expressed in one rotation angle.
|
||||
*
|
||||
* @type Number
|
||||
* @bean
|
||||
*/
|
||||
getRotation: function() {
|
||||
var angle1 = -Math.atan2(this._b, this._d),
|
||||
|
|
|
@ -949,7 +949,12 @@ var LinkedPoint = Point.extend({
|
|||
},
|
||||
|
||||
statics: {
|
||||
create: function(owner, setter, x, y) {
|
||||
create: function(owner, setter, x, y, dontLink) {
|
||||
// Support creation of normal Points rather than LinkedPoints
|
||||
// through an optional parameter that can be passed to the getters.
|
||||
// See e.g. Rectangle#getPoint(true).
|
||||
if (dontLink)
|
||||
return Point.create(x, y);
|
||||
var point = new LinkedPoint(LinkedPoint.dont);
|
||||
point._x = x;
|
||||
point._y = y;
|
||||
|
|
|
@ -145,7 +145,10 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
* @bean
|
||||
*/
|
||||
getPoint: function() {
|
||||
return LinkedPoint.create(this, 'setPoint', this.x, this.y);
|
||||
// Pass on the optional argument dontLink which tells LinkedPoint to
|
||||
// produce a normal point instead. Used internally for speed reasons.
|
||||
return LinkedPoint.create(this, 'setPoint', this.x, this.y,
|
||||
arguments[0]);
|
||||
},
|
||||
|
||||
setPoint: function(point) {
|
||||
|
@ -162,7 +165,9 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
* @bean
|
||||
*/
|
||||
getSize: function() {
|
||||
return LinkedSize.create(this, 'setSize', this.width, this.height);
|
||||
// See Rectangle#getPoint() about arguments[0]
|
||||
return LinkedSize.create(this, 'setSize', this.width, this.height,
|
||||
arguments[0]);
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
|
@ -282,7 +287,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
*/
|
||||
getCenter: function() {
|
||||
return LinkedPoint.create(this, 'setCenter',
|
||||
this.getCenterX(), this.getCenterY());
|
||||
this.getCenterX(), this.getCenterY(), arguments[0]);
|
||||
},
|
||||
|
||||
setCenter: function(point) {
|
||||
|
@ -665,7 +670,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
set = 'set' + part;
|
||||
this[get] = function() {
|
||||
return LinkedPoint.create(this, set,
|
||||
this[getX](), this[getY]());
|
||||
this[getX](), this[getY](), arguments[0]);
|
||||
};
|
||||
this[set] = function(point) {
|
||||
point = Point.read(arguments);
|
||||
|
|
|
@ -535,13 +535,16 @@ var LinkedSize = Size.extend({
|
|||
},
|
||||
|
||||
statics: {
|
||||
create: function(owner, setter, width, height) {
|
||||
var point = new LinkedSize(LinkedSize.dont);
|
||||
point._width = width;
|
||||
point._height = height;
|
||||
point._owner = owner;
|
||||
point._setter = setter;
|
||||
return point;
|
||||
create: function(owner, setter, width, height, dontLink) {
|
||||
// See LinkedPoint.create() for an explanation about dontLink.
|
||||
if (dontLink)
|
||||
return Size.create(width, height);
|
||||
var size = new LinkedSize(LinkedSize.dont);
|
||||
size._width = width;
|
||||
size._height = height;
|
||||
size._owner = owner;
|
||||
size._setter = setter;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -148,14 +148,15 @@ var Color = this.Color = Base.extend(new function() {
|
|||
max = Math.max(r, g, b),
|
||||
min = Math.min(r, g, b),
|
||||
delta = max - min,
|
||||
h = delta == 0 ? 0
|
||||
achromatic = delta == 0,
|
||||
h = achromatic ? 0
|
||||
: ( max == r ? (g - b) / delta + (g < b ? 6 : 0)
|
||||
: max == g ? (b - r) / delta + 2
|
||||
: (r - g) / delta + 4) * 60, // max == b
|
||||
l = (max + min) / 2,
|
||||
s = l < 0.5
|
||||
? delta / (max + min)
|
||||
: delta / (2 - max - min);
|
||||
s = achromatic ? 0 : l < 0.5
|
||||
? delta / (max + min)
|
||||
: delta / (2 - max - min);
|
||||
return new HSLColor(h, s, l, color._alpha);
|
||||
},
|
||||
|
||||
|
|
|
@ -95,13 +95,17 @@ Path.inject({ statics: new function() {
|
|||
*/
|
||||
Rectangle: function(rect) {
|
||||
rect = Rectangle.read(arguments);
|
||||
var path = new Path(),
|
||||
corners = ['getBottomLeft', 'getTopLeft', 'getTopRight',
|
||||
'getBottomRight'],
|
||||
segments = new Array(4);
|
||||
for (var i = 0; i < 4; i++)
|
||||
segments[i] = new Segment(rect[corners[i]]());
|
||||
path._add(segments);
|
||||
var left = rect.x,
|
||||
top = rect.y
|
||||
right = left + rect.width,
|
||||
bottom = top + rect.height,
|
||||
path = new Path();
|
||||
path._add([
|
||||
new Segment(Point.create(left, bottom)),
|
||||
new Segment(Point.create(left, top)),
|
||||
new Segment(Point.create(right, top)),
|
||||
new Segment(Point.create(right, bottom))
|
||||
]);
|
||||
path._closed = true;
|
||||
return path;
|
||||
},
|
||||
|
@ -128,13 +132,13 @@ Path.inject({ statics: new function() {
|
|||
rect = Rectangle.read(arguments, 0, 4);
|
||||
size = Size.read(arguments, 4, 2);
|
||||
}
|
||||
size = Size.min(size, rect.getSize().divide(2));
|
||||
size = Size.min(size, rect.getSize(true).divide(2));
|
||||
var path = new Path(),
|
||||
uSize = size.multiply(kappa * 2),
|
||||
bl = rect.getBottomLeft(),
|
||||
tl = rect.getTopLeft(),
|
||||
tr = rect.getTopRight(),
|
||||
br = rect.getBottomRight();
|
||||
bl = rect.getBottomLeft(true),
|
||||
tl = rect.getTopLeft(true),
|
||||
tr = rect.getTopRight(true),
|
||||
br = rect.getBottomRight(true);
|
||||
path._add([
|
||||
new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]),
|
||||
new Segment(bl.subtract(0, size.height), [0, uSize.height], null),
|
||||
|
@ -172,13 +176,13 @@ Path.inject({ statics: new function() {
|
|||
Oval: function(rect) {
|
||||
rect = Rectangle.read(arguments);
|
||||
var path = new Path(),
|
||||
topLeft = rect.getTopLeft(),
|
||||
size = new Size(rect.width, rect.height),
|
||||
point = rect.getPoint(true),
|
||||
size = rect.getSize(true),
|
||||
segments = new Array(4);
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var segment = ovalSegments[i];
|
||||
segments[i] = new Segment(
|
||||
segment._point.multiply(size).add(topLeft),
|
||||
segment._point.multiply(size).add(point),
|
||||
segment._handleIn.multiply(size),
|
||||
segment._handleOut.multiply(size)
|
||||
);
|
||||
|
@ -206,7 +210,7 @@ Path.inject({ statics: new function() {
|
|||
center = Point.read(arguments, 0, 1);
|
||||
}
|
||||
return Path.Oval(new Rectangle(center.subtract(radius),
|
||||
new Size(radius * 2, radius * 2)));
|
||||
Size.create(radius * 2, radius * 2)));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1286,10 +1286,10 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
|||
// objects that were read from segments. This is because the SegmentPoint
|
||||
// class overrides the plain x / y properties with getter / setters and
|
||||
// stores the values in these private properties internally. To avoid
|
||||
// of getter functions all the time we directly access these private
|
||||
// calling of getter functions all the time we directly access these private
|
||||
// properties here. The distinction between normal Point objects and
|
||||
// SegmentPoint objects maybe seem a bit tedious but is worth the
|
||||
// performance benefit.
|
||||
// SegmentPoint objects maybe seem a bit tedious but is worth the benefit in
|
||||
// performance.
|
||||
|
||||
function drawHandles(ctx, segments) {
|
||||
for (var i = 0, l = segments.length; i < l; i++) {
|
||||
|
@ -2028,7 +2028,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
|||
return this._handleBounds;
|
||||
var coords = new Array(6),
|
||||
stroke = arguments[1] / 2 || 0, // Stroke padding
|
||||
join = arguments[2] / 2 || 0, // Join padding, for miterLimiet
|
||||
join = arguments[2] / 2 || 0, // Join padding, for miterLimit
|
||||
open = !this._closed,
|
||||
x1 = Infinity,
|
||||
x2 = -x1,
|
||||
|
|
|
@ -47,6 +47,13 @@ var SegmentPoint = Point.extend({
|
|||
this._owner._changed(this);
|
||||
},
|
||||
|
||||
isZero: function() {
|
||||
// Provide our own version of Point#isZero() that does not use the x / y
|
||||
// accessors but the internal properties directly, for performance
|
||||
// reasons, since it is used a lot internally.
|
||||
return this._x == 0 && this._y == 0;
|
||||
},
|
||||
|
||||
setSelected: function(selected) {
|
||||
this._owner._setSelected(this, selected);
|
||||
},
|
||||
|
|
|
@ -196,4 +196,10 @@ test('Color#convert', function() {
|
|||
equals(function() {
|
||||
return converted.equals(color);
|
||||
}, true);
|
||||
});
|
||||
|
||||
test('Saturation from black rgb', function() {
|
||||
equals(function() {
|
||||
return new RGBColor(0, 0, 0).saturation == 0;
|
||||
}, true);
|
||||
});
|
Loading…
Reference in a new issue