Comparing version 0.6.1 to 0.6.2
@@ -121,4 +121,4 @@ #### Application | ||
#### Pinning | ||
Pinning is a top level concept, it specifies how a node is transformed relative to its parent. | ||
#### Pin | ||
Pin or pinning defines how a node is transformed relative to its parent. | ||
@@ -125,0 +125,0 @@ When `nameX` equals `nameY`, `name` shorthand can be used instead. |
@@ -11,4 +11,10 @@ /* | ||
require('../core')._load(function(stage, elem) { | ||
Mouse.subscribe(stage, elem); | ||
}); | ||
// TODO: capture mouse | ||
function Mouse() { | ||
}; | ||
} | ||
@@ -19,6 +25,8 @@ Mouse.CLICK = 'click'; | ||
Mouse.END = 'touchend mouseup'; | ||
Mouse.CANCEL = 'touchcancel'; | ||
Mouse.CANCEL = 'touchcancel mousecancel'; | ||
Mouse.subscribe = function(stage, elem) { | ||
var visitor = null, data = {}, abs = null, rel = null, clicked = []; | ||
var visitor = null, data = {}; | ||
var abs = null, rel = null; | ||
var clicklist = [], cancellist = []; | ||
@@ -39,20 +47,25 @@ elem = elem || document; | ||
document.addEventListener('mouseup', handleCancel); | ||
window.addEventListener("blur", handleCancel); | ||
function handleStart(event) { | ||
Mouse._xy(stage, elem, event, abs); | ||
event.preventDefault(); | ||
locate(elem, event, abs); | ||
DEBUG && console.log('Mouse Start: ' + event.type + ' ' + abs); | ||
event.preventDefault(); | ||
publish(event.type, event); | ||
findClicks(); | ||
lookup('click', clicklist); | ||
lookup('mousecancel', cancellist); | ||
} | ||
function handleEnd(event) { | ||
// New xy is not valid/available, last xy is used instead. | ||
event.preventDefault(); | ||
// up/end location is not available, last one is used instead | ||
DEBUG && console.log('Mouse End: ' + event.type + ' ' + abs); | ||
event.preventDefault(); | ||
publish(event.type, event); | ||
if (clicked.length) { | ||
DEBUG && console.log('Mouse Click: ' + clicked.length); | ||
fireClicks(event); | ||
if (clicklist.length) { | ||
DEBUG && console.log('Mouse Click: ' + clicklist.length); | ||
publish('click', event, clicklist); | ||
cancellist.length = 0; | ||
} | ||
@@ -62,53 +75,53 @@ } | ||
function handleCancel(event) { | ||
DEBUG && console.log('Mouse Cancel: ' + event.type); | ||
event.preventDefault(); | ||
publish(event.type, event); | ||
if (cancellist.length) { | ||
DEBUG && console.log('Mouse Cancel: ' + event.type); | ||
publish('mousecancel', event, cancellist); | ||
} | ||
} | ||
function handleMove(event) { | ||
Mouse._xy(stage, elem, event, abs); | ||
// DEBUG && console.log('Mouse Move: ' + event.type + ' ' + | ||
// abs); | ||
if (!stage._flag(event.type)) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
locate(elem, event, abs); | ||
publish(event.type, event); | ||
} | ||
function findClicks() { | ||
while (clicked.length) { | ||
clicked.pop(); | ||
} | ||
publish('click', null, clicked); | ||
} | ||
var ratio = stage.viewport().ratio || 1; | ||
function fireClicks(event) { | ||
data.event = event; | ||
data.type = 'click'; | ||
data.stage = stage; | ||
data.collect = false; | ||
stage.on('viewport', function(size) { | ||
ratio = size.ratio || ratio; | ||
}); | ||
var cancel = false; | ||
while (clicked.length) { | ||
var node = clicked.shift(); | ||
if (cancel) { | ||
continue; | ||
} | ||
cancel = visitor.end(node, data) ? true : cancel; | ||
} | ||
function locate(elem, event) { | ||
locateElevent(elem, event, abs); | ||
abs.x *= ratio; | ||
abs.y *= ratio; | ||
} | ||
function publish(type, event, collect) { | ||
rel.x = abs.x; | ||
rel.y = abs.y; | ||
data.event = event; | ||
function lookup(type, collect) { | ||
data.type = type; | ||
data.stage = /* stage._capture || */stage; | ||
data.root = stage; | ||
data.event = null; | ||
collect.length = 0; | ||
data.collect = collect; | ||
data.stage.visit(visitor, data); | ||
data.root.visit(visitor, data); | ||
} | ||
function publish(type, event, targets) { | ||
data.type = type; | ||
data.root = stage; | ||
data.event = event; | ||
data.collect = false; | ||
data.timeStamp = Date.now(); | ||
if (targets) { | ||
while (targets.length) | ||
if (visitor.end(targets.shift(), data)) | ||
break; | ||
targets.length = 0; | ||
} else { | ||
data.root.visit(visitor, data); | ||
} | ||
} | ||
visitor = { | ||
@@ -121,5 +134,7 @@ reverse : true, | ||
end : function(node, data) { | ||
// data: event, type, stage, collect | ||
// data: event, type, root, collect | ||
rel.raw = data.event; | ||
rel.type = data.type; | ||
rel.timeStamp = data.timeStamp; | ||
var listeners = node.listeners(data.type); | ||
@@ -129,5 +144,4 @@ if (!listeners) { | ||
} | ||
node.matrix().reverse().map(abs, rel); | ||
if (!(node === data.stage || node.attr('spy') || Mouse | ||
._isInside(node, rel))) { | ||
node.matrix().inverse().map(abs, rel); | ||
if (!(node === data.root || node.hitTest(rel))) { | ||
return; | ||
@@ -137,9 +151,10 @@ } | ||
data.collect.push(node); | ||
return; | ||
} | ||
var cancel = false; | ||
for (var l = 0; l < listeners.length; l++) { | ||
cancel = listeners[l].call(node, rel) ? true : cancel; | ||
if (data.event) { | ||
var cancel = false; | ||
for (var l = 0; l < listeners.length; l++) { | ||
cancel = listeners[l].call(node, rel) ? true : cancel; | ||
} | ||
return cancel; | ||
} | ||
return cancel; | ||
} | ||
@@ -153,2 +168,8 @@ }; | ||
return (this.x | 0) + 'x' + (this.y | 0); | ||
}, | ||
clone : function(clone) { | ||
clone = clone || {}; | ||
clone.x = this.x; | ||
clone.y = this.y; | ||
return clone; | ||
} | ||
@@ -160,4 +181,11 @@ }; | ||
y : 0, | ||
abs : abs, | ||
toString : function() { | ||
return abs + ' / ' + (this.x | 0) + 'x' + (this.y | 0); | ||
}, | ||
clone : function(clone) { | ||
clone = clone || {}; | ||
clone.x = this.x; | ||
clone.y = this.y; | ||
return clone; | ||
} | ||
@@ -168,55 +196,19 @@ }; | ||
Mouse._isInside = function(node, point) { | ||
return point.x >= 0 && point.x <= node._pin._width && point.y >= 0 | ||
&& point.y <= node._pin._height; | ||
}; | ||
Mouse._xy = function(stage, elem, event, point) { | ||
var isTouch = false; | ||
// touch screen events | ||
if (event.touches) { | ||
if (event.touches.length) { | ||
isTouch = true; | ||
point.x = event.touches[0].pageX; | ||
point.y = event.touches[0].pageY; | ||
} else { | ||
return; | ||
} | ||
function locateElevent(el, ev, loc) { | ||
// TODO: use pageX/Y if available? | ||
if (ev.touches && ev.touches.length) { | ||
loc.x = ev.touches[0].clientX; | ||
loc.y = ev.touches[0].clientY; | ||
} else { | ||
// mouse events | ||
point.x = event.clientX; | ||
point.y = event.clientY; | ||
// See http://goo.gl/JuVnF2 | ||
if (document.body.scrollLeft || document.body.scrollTop) { | ||
// body is added as offsetParent | ||
} else if (document.documentElement) { | ||
point.x += document.documentElement.scrollLeft; | ||
point.y += document.documentElement.scrollTop; | ||
} | ||
loc.x = ev.clientX; | ||
loc.y = ev.clientY; | ||
} | ||
// accounts for border | ||
point.x -= elem.clientLeft || 0; | ||
point.y -= elem.clientTop || 0; | ||
var par = elem; | ||
while (par) { | ||
point.x -= par.offsetLeft || 0; | ||
point.y -= par.offsetTop || 0; | ||
if (!isTouch) { | ||
// touch events offset scrolling with pageX/Y | ||
// so scroll offset not needed for them | ||
point.x += par.scrollLeft || 0; | ||
point.y += par.scrollTop || 0; | ||
} | ||
par = par.offsetParent; | ||
} | ||
point.x *= stage.viewport().ratio || 1; | ||
point.y *= stage.viewport().ratio || 1; | ||
var rect = el.getBoundingClientRect(); | ||
loc.x -= rect.left; | ||
loc.y -= rect.top; | ||
loc.x -= el.clientLeft | 0; | ||
loc.y -= el.clientTop | 0; | ||
return loc; | ||
}; | ||
module.exports = Mouse; |
@@ -8,2 +8,5 @@ /* | ||
if (typeof DEBUG === 'undefined') | ||
DEBUG = true; | ||
var Class = require('./core'); | ||
@@ -23,6 +26,4 @@ var Texture = require('./texture'); | ||
// TODO: return entire atlas as texture | ||
// TODO: select atlas itself, call texture function | ||
// TODO: print subquery not found error | ||
// TODO: cache and clone or index textures | ||
// TODO: index textures | ||
@@ -44,3 +45,3 @@ Class.atlas = function(def) { | ||
} else if (is.hash(def.image)) { | ||
url = def.image.url; | ||
url = def.image.src || def.image.url; | ||
ratio = def.image.ratio || ratio; | ||
@@ -150,2 +151,6 @@ } | ||
this.select = function(query) { | ||
if (!query) { | ||
// TODO: if `textures` is texture def, map or fn? | ||
return new Selection(this.pipe()); | ||
} | ||
var found = find(query); | ||
@@ -217,14 +222,17 @@ if (found) { | ||
var result = null; | ||
var result = null, atlas, i; | ||
var i = query.indexOf(':'); | ||
if (i > 0 && query.length > i + 1) { | ||
var atlas = _atlases_map[query.slice(0, i)]; | ||
if ((i = query.indexOf(':')) > 0 && query.length > i + 1) { | ||
atlas = _atlases_map[query.slice(0, i)]; | ||
result = atlas && atlas.select(query.slice(i + 1)); | ||
} | ||
for (var i = 0; !result && i < _atlases_arr.length; i++) { | ||
for (i = 0; !result && i < _atlases_arr.length; i++) { | ||
result = _atlases_arr[i].select(query); | ||
} | ||
if (!result && (atlas = _atlases_map[query])) { | ||
result = atlas.select(); | ||
} | ||
if (!result) { | ||
@@ -231,0 +239,0 @@ console.error('Texture not found: ' + query); |
@@ -37,2 +37,3 @@ /* | ||
texture.size = function(width, height, ratio) { | ||
ratio = ratio || 1; | ||
canvas.width = width * ratio; | ||
@@ -39,0 +40,0 @@ canvas.height = height * ratio; |
@@ -42,2 +42,8 @@ /* | ||
var _load = []; | ||
Class._load = function(fn) { | ||
_load.push(fn); | ||
}; | ||
var _config = {}; | ||
@@ -72,2 +78,5 @@ | ||
DEBUG && console.log('Initing app...'); | ||
for (var i = 0; i < _load.length; i++) { | ||
_load[i].call(this, stage, canvas); | ||
} | ||
app(stage, canvas); | ||
@@ -74,0 +83,0 @@ _stages.push(stage); |
@@ -1,76 +0,3 @@ | ||
/* | ||
* Stage.js | ||
* Copyright (c) 2015 Ali Shakiba, Piqnt LLC | ||
* Available under the MIT license | ||
* @license | ||
*/ | ||
var Class = require('./core'); | ||
var is = require('./util/is'); | ||
Class.prototype._listeners = null; | ||
Class.prototype.on = Class.prototype.listen = function(types, listener) { | ||
if (types = _check(this, types, listener, true)) { | ||
for (var i = 0; i < types.length; i++) { | ||
var type = types[i]; | ||
this._listeners[type] = this._listeners[type] || []; | ||
this._listeners[type].push(listener); | ||
this._flag(type, true); | ||
} | ||
} | ||
return this; | ||
}; | ||
Class.prototype.off = function(types, listener) { | ||
if (types = _check(this, types, listener, false)) { | ||
for (var i = 0; i < types.length; i++) { | ||
var type = types[i], all = this._listeners[type], index; | ||
if (all && (index = all.indexOf(listener)) >= 0) { | ||
all.splice(index, 1); | ||
if (!all.length) { | ||
delete this._listeners[type]; | ||
} | ||
this._flag(type, false); | ||
} | ||
} | ||
} | ||
return this; | ||
}; | ||
function _check(node, types, listener, create) { | ||
if (!types || !types.length || typeof listener !== 'function') { | ||
return false; | ||
} | ||
if (!(types = (is.array(types) ? types.join(' ') : types).match(/\S+/g))) { | ||
return false; | ||
} | ||
if (node._listeners === null) { | ||
if (create) { | ||
node._listeners = {}; | ||
} else { | ||
return false; | ||
} | ||
} | ||
return types; | ||
} | ||
Class.prototype.listeners = function(type) { | ||
return this._listeners && this._listeners[type]; | ||
}; | ||
Class.prototype.publish = function(name, args) { | ||
var listeners = this.listeners(name); | ||
if (!listeners || !listeners.length) { | ||
return 0; | ||
} | ||
for (var l = 0; l < listeners.length; l++) { | ||
listeners[l].apply(this, args); | ||
} | ||
return listeners.length; | ||
}; | ||
Class.prototype.trigger = function(name, args) { | ||
this.publish(name, args); | ||
return this; | ||
}; | ||
require('./util/event')(require('./core').prototype, function(obj, name, on) { | ||
obj._flag(name, on); | ||
}); |
@@ -15,3 +15,3 @@ /* | ||
Class.row = function(align) { | ||
return Class.create().row(align); | ||
return Class.create().row(align).label('Row'); | ||
}; | ||
@@ -25,3 +25,3 @@ | ||
Class.column = function(align) { | ||
return Class.create().column(align); | ||
return Class.create().column(align).label('Row'); | ||
}; | ||
@@ -35,3 +35,3 @@ | ||
Class.sequence = function(type, align) { | ||
return Class.create().sequence(type, align); | ||
return Class.create().sequence(type, align).label('Sequence'); | ||
}; | ||
@@ -44,4 +44,4 @@ | ||
this.untick(this._sequenceTicker); | ||
this.tick(this._sequenceTicker = function() { | ||
this.untick(this._layoutTiker); | ||
this.tick(this._layoutTiker = function() { | ||
if (this._mo_seq == this._ts_touch) { | ||
@@ -91,12 +91,10 @@ return; | ||
Class.box = function() { | ||
return Class.create().box(); | ||
return Class.create().box().label('Box'); | ||
}; | ||
Class.prototype.box = function() { | ||
if (this._boxTicker) | ||
return this; | ||
this._padding = this._padding || 0; | ||
this.tick(this._boxTicker = function() { | ||
this.untick(this._layoutTiker); | ||
this.tick(this._layoutTiker = function() { | ||
if (this._mo_box == this._ts_touch) { | ||
@@ -125,2 +123,25 @@ return; | ||
Class.layer = function() { | ||
return Class.create().layer().label('Layer'); | ||
}; | ||
Class.prototype.layer = function() { | ||
this.untick(this._layoutTiker); | ||
this.tick(this._layoutTiker = function() { | ||
var parent = this.parent(); | ||
if (parent) { | ||
var width = parent.pin('width'); | ||
if (this.pin('width') != width) { | ||
this.pin('width', width); | ||
} | ||
var height = parent.pin('height'); | ||
if (this.pin('height') != height) { | ||
this.pin('height', height); | ||
} | ||
} | ||
}, true); | ||
return this; | ||
}; | ||
// TODO: move padding to pin | ||
@@ -127,0 +148,0 @@ Class.prototype.padding = function(pad) { |
@@ -17,5 +17,2 @@ /* | ||
// TODO: don't hard-code this | ||
var Mouse = require('../addon/mouse'); | ||
if (typeof FastContext === 'undefined') { | ||
@@ -119,3 +116,2 @@ FastContext = window.FastContext; | ||
Mouse.subscribe(root, canvas); | ||
app(root, canvas); | ||
@@ -122,0 +118,0 @@ |
@@ -17,5 +17,2 @@ /* | ||
// TODO: don't hard-code this | ||
var Mouse = require('../addon/mouse'); | ||
window.addEventListener('load', function() { | ||
@@ -81,3 +78,2 @@ DEBUG && console.log('On load.'); | ||
Mouse.subscribe(root, canvas); | ||
app(root, canvas); | ||
@@ -84,0 +80,0 @@ |
@@ -150,15 +150,15 @@ /* | ||
Matrix.prototype.reverse = function() { | ||
Matrix.prototype.inverse = Matrix.prototype.reverse = function() { | ||
if (this._dirty) { | ||
this._dirty = false; | ||
this.reversed = this.reversed || new Matrix(); | ||
this.inversed = this.inversed || new Matrix(); | ||
var z = this.a * this.d - this.b * this.c; | ||
this.reversed.a = this.d / z; | ||
this.reversed.b = -this.b / z; | ||
this.reversed.c = -this.c / z; | ||
this.reversed.d = this.a / z; | ||
this.reversed.e = (this.c * this.f - this.e * this.d) / z; | ||
this.reversed.f = (this.e * this.b - this.a * this.f) / z; | ||
this.inversed.a = this.d / z; | ||
this.inversed.b = -this.b / z; | ||
this.inversed.c = -this.c / z; | ||
this.inversed.d = this.a / z; | ||
this.inversed.e = (this.c * this.f - this.e * this.d) / z; | ||
this.inversed.f = (this.e * this.b - this.a * this.f) / z; | ||
} | ||
return this.reversed; | ||
return this.inversed; | ||
}; | ||
@@ -174,2 +174,4 @@ | ||
Matrix.prototype.mapX = function(x, y) { | ||
if (typeof x === 'object') | ||
y = x.y, x = x.x; | ||
return this.a * x + this.c * y + this.e; | ||
@@ -179,2 +181,4 @@ }; | ||
Matrix.prototype.mapY = function(x, y) { | ||
if (typeof x === 'object') | ||
y = x.y, x = x.x; | ||
return this.b * x + this.d * y + this.f; | ||
@@ -181,0 +185,0 @@ }; |
@@ -401,2 +401,13 @@ /* | ||
/** | ||
* @private | ||
*/ | ||
Class.prototype.hitTest = function(hit) { | ||
if (this.attr('spy')) { | ||
return true; | ||
} | ||
return hit.x >= 0 && hit.x <= this._pin._width && hit.y >= 0 | ||
&& hit.y <= this._pin._height; | ||
}; | ||
function _ensure(obj) { | ||
@@ -403,0 +414,0 @@ if (obj && obj instanceof Class) { |
@@ -553,2 +553,49 @@ /* | ||
Class.prototype.size = function(w, h) { | ||
this.pin('width', w); | ||
this.pin('height', h); | ||
return this; | ||
}; | ||
Class.prototype.offset = function(a, b) { | ||
if (typeof a === 'object') | ||
b = a.y, a = a.x; | ||
this.pin('offsetX', a); | ||
this.pin('offsetY', b); | ||
return this; | ||
}; | ||
Class.prototype.rotate = function(a) { | ||
this.pin('rotation', a); | ||
return this; | ||
}; | ||
Class.prototype.skew = function(a, b) { | ||
if (typeof a === 'object') | ||
b = a.y, a = a.x; | ||
else if (typeof b === 'undefined') | ||
b = a; | ||
this.pin('skewX', a); | ||
this.pin('skewY', b); | ||
return this; | ||
}; | ||
Class.prototype.scale = function(a, b) { | ||
if (typeof a === 'object') | ||
b = a.y, a = a.x; | ||
else if (typeof b === 'undefined') | ||
b = a; | ||
this.pin('scaleX', a); | ||
this.pin('scaleY', b); | ||
return this; | ||
}; | ||
Class.prototype.alpha = function(a, ta) { | ||
this.pin('alpha', a); | ||
if (typeof ta !== 'undefined') { | ||
this.pin('textureAlpha', ta); | ||
} | ||
return this; | ||
}; | ||
module.exports = Pin; |
@@ -124,1 +124,13 @@ /* | ||
}; | ||
Class.prototype.timeout = function(fn, time) { | ||
this.tick(function timer(t) { | ||
if ((time -= t) < 0) { | ||
this.untick(timer); | ||
fn.call(this); | ||
} else { | ||
return true; | ||
} | ||
}); | ||
}; | ||
{ | ||
"name": "stage.js", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"description": "Lightweight and fast HTML5 2D rendering engine for cross-platform game development.", | ||
@@ -5,0 +5,0 @@ "homepage": "http://piqnt.com/stage.js/", |
@@ -6,27 +6,19 @@ var expect = require('./util/expect'); | ||
var Stage = require('../lib/node'); | ||
var Stage = require('../lib/'); | ||
it('Mouse', function() { | ||
var document = { | ||
body : {} | ||
}, window = { | ||
document : document | ||
}; | ||
var event, elem, elemOn, doc, docOn, win, winOn; | ||
var Mouse = sandboxed.require('../lib/addon/mouse', { | ||
locals : { | ||
window : window, | ||
document : document | ||
document : doc = { | ||
addEventListener : docOn = sinon.stub() | ||
}, | ||
window : win = { | ||
document : doc, | ||
addEventListener : winOn = sinon.stub() | ||
} | ||
} | ||
}); | ||
var elem, add, remove, event; | ||
Mouse._xy = sinon.spy(function(stage, el, ev, point) { | ||
expect(ev).equal(event); | ||
expect(el).equal(elem); | ||
point.x = ev.x; | ||
point.y = ev.y; | ||
}); | ||
var node = memo(function(id) { | ||
@@ -44,2 +36,8 @@ return Stage.create().label(id).pin({ | ||
stage.viewport = function() { | ||
return { | ||
ratio : 1 | ||
}; | ||
}; | ||
node(1).on(Mouse.CLICK, listener('click-' + 1)); | ||
@@ -51,12 +49,19 @@ node(1).on(Mouse.START, listener('start-' + 1)); | ||
Mouse.subscribe(stage, elem = { | ||
addEventListener : add = sinon.stub(), | ||
removeEventListener : remove = sinon.stub() | ||
addEventListener : elemOn = sinon.stub(), | ||
getBoundingClientRect : function() { | ||
return { | ||
left : 0, | ||
top : 0 | ||
}; | ||
}, | ||
clientLeft : 0, | ||
clientTop : 0 | ||
}); | ||
expect(add.args.pluck(0)).list( | ||
expect(elemOn.args.pluck(0)).list( | ||
[ 'touchstart', 'touchend', 'touchmove', 'touchcancel', 'mousedown', | ||
'mouseup', 'mousemove' ]); | ||
expect(add.alwaysCalledOn(elem)).ok(); | ||
expect(elemOn.alwaysCalledOn(elem)).ok(); | ||
var down = add.args[0][1], up = add.args[1][1], move; | ||
var down = elemOn.args[0][1], up = elemOn.args[1][1], move; | ||
@@ -78,3 +83,3 @@ down.call(elem, event = Event('mousedown', 40, 30)); | ||
down.call(elem, event = Event('mousedown', 40, 30)); | ||
move = add.lastCall.args[1]; | ||
move = elemOn.lastCall.args[1]; | ||
move.call(elem, event = Event('mousemove', 30, 20)); | ||
@@ -90,4 +95,4 @@ up.call(elem, event = Event('mouseup')); | ||
return { | ||
x : x, | ||
y : y, | ||
pageX : x, | ||
pageY : y, | ||
type : type, | ||
@@ -94,0 +99,0 @@ preventDefault : sinon.stub() |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
139465
50
4533