social_cheesecake 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/app/assets/javascripts/kinetic.js +812 -432
  2. data/app/assets/javascripts/socialcheesecake/_header.js +1 -1
  3. data/app/assets/javascripts/socialcheesecake/actor.js +57 -32
  4. data/app/assets/javascripts/socialcheesecake/cheesecake.js +257 -280
  5. data/app/assets/javascripts/socialcheesecake/grid.js +168 -56
  6. data/app/assets/javascripts/socialcheesecake/sector.js +124 -70
  7. data/app/assets/javascripts/socialcheesecake/text.js +9 -4
  8. data/lib/social_cheesecake/version.rb +1 -1
  9. data/test/dummy/app/assets/images/images/ui-bg_diagonals-medium_20_d34d17_40x40.png +0 -0
  10. data/test/dummy/app/assets/images/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
  11. data/test/dummy/app/assets/images/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
  12. data/test/dummy/app/assets/images/images/ui-bg_gloss-wave_45_817865_500x100.png +0 -0
  13. data/test/dummy/app/assets/images/images/ui-bg_gloss-wave_60_fece2f_500x100.png +0 -0
  14. data/test/dummy/app/assets/images/images/ui-bg_gloss-wave_70_ffdd57_500x100.png +0 -0
  15. data/test/dummy/app/assets/images/images/ui-bg_gloss-wave_90_fff9e5_500x100.png +0 -0
  16. data/test/dummy/app/assets/images/images/ui-bg_highlight-soft_100_feeebd_1x100.png +0 -0
  17. data/test/dummy/app/assets/images/images/ui-bg_inset-soft_30_ffffff_1x100.png +0 -0
  18. data/test/dummy/app/assets/images/images/ui-icons_3d3d3d_256x240.png +0 -0
  19. data/test/dummy/app/assets/images/images/ui-icons_bd7b00_256x240.png +0 -0
  20. data/test/dummy/app/assets/images/images/ui-icons_d19405_256x240.png +0 -0
  21. data/test/dummy/app/assets/images/images/ui-icons_eb990f_256x240.png +0 -0
  22. data/test/dummy/app/assets/images/images/ui-icons_ed9f26_256x240.png +0 -0
  23. data/test/dummy/app/assets/images/images/ui-icons_fadc7a_256x240.png +0 -0
  24. data/test/dummy/app/assets/images/images/ui-icons_ffe180_256x240.png +0 -0
  25. data/test/dummy/app/assets/images/socialcheesecake_background.png +0 -0
  26. data/test/dummy/app/assets/images/soialcheesecake_icon.png +0 -0
  27. data/test/dummy/app/assets/images/soialcheesecake_icon_back.png +0 -0
  28. data/test/dummy/app/assets/images/under-construction.png +0 -0
  29. data/test/dummy/app/assets/javascripts/application.js +1 -0
  30. data/test/dummy/app/assets/javascripts/main.js +352 -0
  31. data/test/dummy/app/assets/stylesheets/jquery-ui-1.8.17.custom.css +565 -0
  32. data/test/dummy/app/assets/stylesheets/style.css +251 -0
  33. data/test/dummy/public/index.html +149 -119
  34. data/test/dummy/vendor/assets/javascripts/jquery-ui.js +356 -0
  35. metadata +29 -4
@@ -1,11 +1,11 @@
1
1
  /**
2
- * KineticJS JavaScript Library v3.4.0
2
+ * KineticJS JavaScript Library v3.6.2
3
3
  * http://www.kineticjs.com/
4
- * Copyright 2011, Eric Rowell
4
+ * Copyright 2012, Eric Rowell
5
5
  * Licensed under the MIT or GPL Version 2 licenses.
6
- * Date: Dec 31 2011
6
+ * Date: Jan 21 2012
7
7
  *
8
- * Copyright (C) 2011 by Eric Rowell
8
+ * Copyright (C) 2012 by Eric Rowell
9
9
  *
10
10
  * Permission is hereby granted, free of charge, to any person obtaining a copy
11
11
  * of this software and associated documentation files (the "Software"), to deal
@@ -27,39 +27,58 @@
27
27
  */
28
28
  var Kinetic = {};
29
29
 
30
- /****************************************
31
- * Layer
30
+ /*
31
+ * I know, globals suck. But since Shape objects
32
+ * and Layer objects can exist before adding them to
33
+ * the stage, a global shape id counter is necessary
32
34
  */
33
- Kinetic.Layer = function(stage, isInvisible){
35
+ Kinetic.GLOBALS = {
36
+ shapeIdCounter: 0
37
+ };
38
+
39
+ ///////////////////////////////////////////////////////////////////////
40
+ //// Link
41
+ ///////////////////////////////////////////////////////////////////////
42
+ ///////////////////////////////////////////////////////////////////////
43
+
44
+ Kinetic.Link = function(shape){
45
+ this.shape = shape;
46
+ shape.link = this;
47
+ this.id = shape.id;
48
+ this.index = undefined;
49
+
50
+ // thes params are string ids
51
+ this.nextId = undefined;
52
+ this.prevId = undefined;
53
+ };
54
+
55
+ ///////////////////////////////////////////////////////////////////////
56
+ //// Layer
57
+ ///////////////////////////////////////////////////////////////////////
58
+ ///////////////////////////////////////////////////////////////////////
59
+
60
+ Kinetic.Layer = function(name){
61
+ this.name = name;
62
+ this.shapeIndexCounter = 0;
63
+ this.isListening = true;
64
+ this.shapeNames = {};
34
65
  this.canvas = document.createElement('canvas');
35
66
  this.context = this.canvas.getContext('2d');
36
- this.canvas.width = stage.width;
37
- this.canvas.height = stage.height;
38
67
  this.canvas.style.position = 'absolute';
39
- this.shapes = [];
40
68
 
41
- if (isInvisible) {
42
- var that = this;
43
- this.context.stroke = function(){
44
- };
45
- this.context.fill = function(){
46
- };
47
- this.context.fillRect = function(x, y, width, height){
48
- that.context.rect(x, y, width, height);
49
- };
50
- this.context.strokeRect = function(x, y, width, height){
51
- that.context.rect(x, y, width, height);
52
- };
53
- this.context.drawImage = function(){
54
- };
55
- this.context.fillText = function(){
56
- };
57
- this.context.strokeText = function(){
58
- };
59
- }
69
+ //links is an array of links which point to event links
70
+ this.links = [];
71
+ this.linkHash = {};
60
72
 
61
- stage.container.appendChild(this.canvas);
62
- }
73
+ this.headId = undefined;
74
+ this.tailId = undefined;
75
+ };
76
+ /*
77
+ * listen or don't listen to events
78
+ */
79
+ Kinetic.Layer.prototype.listen = function(isListening){
80
+ this.isListening = isListening;
81
+ };
63
82
  /*
64
83
  * clear layer
65
84
  */
@@ -67,7 +86,7 @@ Kinetic.Layer.prototype.clear = function(){
67
86
  var context = this.getContext();
68
87
  var canvas = this.getCanvas();
69
88
  context.clearRect(0, 0, canvas.width, canvas.height);
70
- }
89
+ };
71
90
  /*
72
91
  * get layer canvas
73
92
  */
@@ -81,32 +100,142 @@ Kinetic.Layer.prototype.getContext = function(){
81
100
  return this.context;
82
101
  }
83
102
  /*
84
- * get layer shapes
103
+ * get shapes as an array
85
104
  */
86
105
  Kinetic.Layer.prototype.getShapes = function(){
87
- return this.shapes;
88
- }
106
+ var shapes = [];
107
+ for (var n = 0; n < this.links.length; n++) {
108
+ shapes.push(this.links[n].shape);
109
+ }
110
+ return shapes;
111
+ };
89
112
  /*
90
113
  * draw all shapes in layer
91
114
  */
92
115
  Kinetic.Layer.prototype.draw = function(){
93
116
  this.clear();
94
- var context = this.getContext();
117
+ var links = this.links;
118
+ for (var n = 0; n < links.length; n++) {
119
+ var shape = links[n].shape;
120
+ shape.draw(shape.layer);
121
+ }
122
+ };
123
+ /*
124
+ * add link to data structure
125
+ */
126
+ Kinetic.Layer.prototype.addLink = function(link){
127
+ var shape = link.shape;
128
+ shape.layer = this;
129
+ // add link to array
130
+ this.links.push(link);
131
+ // add link to hash
132
+ this.linkHash[link.id] = link;
133
+ link.index = this.links.length - 1;
95
134
 
96
- for (var n = 0; n < this.getShapes().length; n++) {
97
- this.getShapes()[n].draw(this);
135
+ if (shape.isListening) {
136
+ // if tail doesnt exist, add tail and head
137
+ if (this.tailId === undefined) {
138
+ this.tailId = link.id;
139
+ this.headId = link.id;
140
+ }
141
+ // if tail does exist, this means there's at least one link
142
+ else {
143
+ var tail = this.linkHash[this.tailId];
144
+ tail.nextId = link.id;
145
+ link.prevId = tail.id;
146
+ this.tailId = link.id;
147
+ }
148
+ }
149
+ };
150
+ /*
151
+ * add shape
152
+ */
153
+ Kinetic.Layer.prototype.add = function(shape){
154
+ if (shape.name) {
155
+ this.shapeNames[shape.name] = shape;
156
+ }
157
+ shape.id = Kinetic.GLOBALS.shapeIdCounter++;
158
+ var link = new Kinetic.Link(shape);
159
+ this.addLink(link);
160
+ };
161
+ /*
162
+ * get shape by name
163
+ */
164
+ Kinetic.Layer.prototype.getShape = function(name){
165
+ return this.shapeNames[name];
166
+ };
167
+ /*
168
+ * remove a shape from layer (link + shape deconstructor)
169
+ */
170
+ Kinetic.Layer.prototype.remove = function(shape){
171
+ var link = shape.link;
172
+ this.removeLink(link);
173
+ this.shape = null;
174
+ this.link = null;
175
+ };
176
+ /*
177
+ * remove link from layer. this does not deconstruct
178
+ * the link or the shape
179
+ */
180
+ Kinetic.Layer.prototype.removeLink = function(link){
181
+ link.shape.layer = undefined;
182
+ this.unlink(link);
183
+ this.links.splice(link.index, 1);
184
+ this.linkHash[link.id] = undefined;
185
+ this.setLinkIndices();
186
+ };
187
+
188
+ /*
189
+ * unlink link. This is different from removeLink because it
190
+ * keeps the link in the layer data structure
191
+ */
192
+ Kinetic.Layer.prototype.unlink = function(link){
193
+ // set head if needed
194
+ if (link.id === this.headId) {
195
+ this.headId = link.nextId;
196
+ }
197
+ // set tail if needed
198
+ if (link.id === this.tailId) {
199
+ this.tailId = link.prevId;
98
200
  }
201
+ // link prev to next
202
+ if (link.prevId !== undefined) {
203
+ this.linkHash[link.prevId].nextId = link.nextId;
204
+ }
205
+ if (link.nextId !== undefined) {
206
+ this.linkHash[link.nextId].prevId = link.prevId;
207
+ }
208
+ // clear pointers
209
+ link.prevId = undefined;
210
+ link.nextId = undefined;
99
211
  };
100
- /****************************************
101
- * Stage
212
+ /*
213
+ * set link indices
102
214
  */
215
+ Kinetic.Layer.prototype.setLinkIndices = function(){
216
+ for (var n = 0; n < this.links.length; n++) {
217
+ this.links[n].index = n;
218
+ }
219
+ };
220
+ ///////////////////////////////////////////////////////////////////////
221
+ //// Stage
222
+ ///////////////////////////////////////////////////////////////////////
223
+ ///////////////////////////////////////////////////////////////////////
224
+
103
225
  Kinetic.Stage = function(containerId, width, height){
104
226
  this.container = document.getElementById(containerId);
105
227
  this.width = width;
106
228
  this.height = height;
107
- this.zIndexCounter = 9999;
108
- this.idCounter = 0;
229
+ this.scale = {
230
+ x: 1,
231
+ y: 1
232
+ };
233
+ this.layerIdCounter = 0;
109
234
  this.dblClickWindow = 400;
235
+ this.targetShape = {};
236
+ this.clickStart = false;
237
+ this.layerNames = {};
238
+
110
239
  // desktop flags
111
240
  this.mousePos = null;
112
241
  this.mouseDown = false;
@@ -117,39 +246,119 @@ Kinetic.Stage = function(containerId, width, height){
117
246
  this.touchStart = false;
118
247
  this.touchEnd = false;
119
248
 
120
- // create layers
121
- this.bufferLayer = new Kinetic.Layer(this);
122
- this.backstageLayer = new Kinetic.Layer(this, true);
123
- this.stageLayer = new Kinetic.Layer(this);
124
- this.propsLayer = new Kinetic.Layer(this);
125
- this.actorsLayer = new Kinetic.Layer(this);
249
+ // user defined layers
250
+ this.layers = [];
251
+
252
+ /*
253
+ * Layer roles
254
+ *
255
+ * buffer - canvas compositing
256
+ * backstage - path detection
257
+ */
258
+ var that = this;
259
+ this.bufferLayer = new Kinetic.Layer();
260
+ this.backstageLayer = new Kinetic.Layer();
261
+
262
+ // customize back stage context
263
+ var backstageLayer = this.backstageLayer;
264
+ backstageLayer.context.stroke = function(){
265
+ };
266
+ backstageLayer.context.fill = function(){
267
+ };
268
+ backstageLayer.context.fillRect = function(x, y, width, height){
269
+ backstageLayer.context.rect(x, y, width, height);
270
+ };
271
+ backstageLayer.context.strokeRect = function(x, y, width, height){
272
+ that.context.rect(x, y, width, height);
273
+ };
274
+ backstageLayer.context.drawImage = function(){
275
+ };
276
+ backstageLayer.context.fillText = function(){
277
+ };
278
+ backstageLayer.context.strokeText = function(){
279
+ };
126
280
 
127
281
  this.bufferLayer.getCanvas().style.display = 'none';
128
282
  this.backstageLayer.getCanvas().style.display = 'none';
283
+
284
+ // add buffer layer
285
+ this.bufferLayer.stage = this;
286
+ this.bufferLayer.canvas.width = this.width;
287
+ this.bufferLayer.canvas.height = this.height;
288
+ this.container.appendChild(this.bufferLayer.canvas);
289
+
290
+ // add backstage layer
291
+ this.backstageLayer.stage = this;
292
+ this.backstageLayer.canvas.width = this.width;
293
+ this.backstageLayer.canvas.height = this.height;
294
+ this.container.appendChild(this.backstageLayer.canvas);
295
+
129
296
  this.listen();
130
297
 
131
298
  this.addEventListener("mouseout", function(evt){
132
299
  that.shapeDragging = undefined;
133
300
  }, false);
134
301
 
135
- // prepare stage for drag and drop
136
- var that = this;
137
- this.addEventListener("mousemove", function(evt){
138
- if (that.shapeDragging) {
139
- var mousePos = that.getMousePos();
140
- that.shapeDragging.x = mousePos.x - that.shapeDragging.offset.x;
141
- that.shapeDragging.y = mousePos.y - that.shapeDragging.offset.y;
142
- that.drawActors();
143
- }
144
- }, false);
145
- this.addEventListener("mouseup", function(evt){
302
+ /*
303
+ * prepare drag and drop
304
+ */
305
+ var types = [{
306
+ end: "mouseup",
307
+ move: "mousemove"
308
+ }, {
309
+ end: "touchend",
310
+ move: "touchmove"
311
+ }];
312
+
313
+ for (var n = 0; n < types.length; n++) {
314
+ var pubType = types[n];
315
+ (function(){
316
+ var type = pubType;
317
+ that.on(type.move, function(evt){
318
+ if (that.shapeDragging) {
319
+ var pos = type.move == "mousemove" ? that.getMousePosition() : that.getTouchPosition();
320
+ if (that.shapeDragging.drag.x) {
321
+ that.shapeDragging.x = pos.x - that.shapeDragging.offset.x;
322
+ }
323
+ if (that.shapeDragging.drag.y) {
324
+ that.shapeDragging.y = pos.y - that.shapeDragging.offset.y;
325
+ }
326
+ that.shapeDragging.layer.draw();
327
+
328
+ // execute user defined ondragend if defined
329
+ var dragmove = that.shapeDragging.eventListeners.ondragmove;
330
+ if (dragmove) {
331
+ var events = dragmove;
332
+ for (var i = 0; i < events.length; i++) {
333
+ events[i].handler.apply(that.shapeDragging, [evt]);
334
+ }
335
+ }
336
+ }
337
+ }, false);
338
+ that.on(type.end, function(evt){
339
+ // execute user defined ondragend if defined
340
+ if (that.shapeDragging) {
341
+ var dragend = that.shapeDragging.eventListeners.ondragend;
342
+ if (dragend) {
343
+ var events = dragend;
344
+ for (var i = 0; i < events.length; i++) {
345
+ events[i].handler.apply(that.shapeDragging, [evt]);
346
+ }
347
+ }
348
+ }
349
+ that.shapeDragging = undefined;
350
+ });
351
+ })();
352
+ }
353
+
354
+ this.on("touchend", function(evt){
146
355
  // execute user defined ondragend if defined
147
-
148
356
  if (that.shapeDragging) {
149
357
  var dragend = that.shapeDragging.eventListeners.ondragend;
150
358
  if (dragend) {
151
- for (var i = 0; i < dragend.length; i++) {
152
- dragend[i].func(evt);
359
+ var events = dragend;
360
+ for (var i = 0; i < events.length; i++) {
361
+ events[i].handler.apply(that.shapeDragging, [evt]);
153
362
  }
154
363
  }
155
364
  }
@@ -157,60 +366,41 @@ Kinetic.Stage = function(containerId, width, height){
157
366
  });
158
367
  };
159
368
  /*
160
- * get buffer layer
161
- */
162
- Kinetic.Stage.prototype.getBufferLayer = function(){
163
- return this.bufferLayer;
164
- };
165
- /*
166
- * get backstage layer
369
+ * set stage size
167
370
  */
168
- Kinetic.Stage.prototype.getBackstageLayer = function(){
169
- return this.backstageLayer;
170
- };
171
- /*
172
- * get stage layer
173
- */
174
- Kinetic.Stage.prototype.getStageLayer = function(){
175
- return this.stageLayer;
176
- };
177
- /*
178
- * get props layer
179
- */
180
- Kinetic.Stage.prototype.getPropsLayer = function(){
181
- return this.propsLayer;
182
- };
183
- /*
184
- * get actors layer
185
- */
186
- Kinetic.Stage.prototype.getActorsLayer = function(){
187
- return this.actorsLayer;
188
- };
189
- /*
190
- * clear stage
191
- */
192
- Kinetic.Stage.prototype.clear = function(){
193
- this.stageLayer.clear();
371
+ Kinetic.Stage.prototype.setSize = function(width, height){
372
+ var layers = this.layers;
373
+ for (n = 0; n < layers.length; n++) {
374
+ var layer = layers[n];
375
+ layer.getCanvas().width = width;
376
+ layer.getCanvas().height = height;
377
+ layer.draw();
378
+ }
379
+
380
+ // set stage dimensions
381
+ this.width = width;
382
+ this.height = height;
194
383
  };
195
384
  /*
196
- * clear all canvases
385
+ * scale stage
197
386
  */
198
- Kinetic.Stage.prototype.clearAll = function(){
199
- this.backstageLayer.clear();
200
- this.stageLayer.clear();
201
- this.propsLayer.clear();
202
- this.actorsLayer.clear();
387
+ Kinetic.Stage.prototype.setScale = function(scaleX, scaleY){
388
+ if (scaleY) {
389
+ this.scale.x = scaleX;
390
+ this.scale.y = scaleY;
391
+ }
392
+ else {
393
+ this.scale.x = scaleX;
394
+ this.scale.y = scaleX;
395
+ }
203
396
  };
204
397
  /*
205
398
  * Composite toDataURL
206
399
  */
207
400
  Kinetic.Stage.prototype.toDataURL = function(callback){
208
- var bufferLayer = this.getBufferLayer();
401
+ var bufferLayer = this.bufferLayer;
209
402
  var bufferContext = bufferLayer.getContext();
210
- var stageLayer = this.getStageLayer();
211
- var propsLayer = this.getPropsLayer();
212
- var actorsLayer = this.getActorsLayer();
213
- var layers = [stageLayer, propsLayer, actorsLayer];
403
+ var layers = this.layers;
214
404
 
215
405
  function addLayer(n){
216
406
  var dataURL = layers[n].getCanvas().toDataURL();
@@ -228,92 +418,59 @@ Kinetic.Stage.prototype.toDataURL = function(callback){
228
418
  imageObj.src = dataURL;
229
419
  }
230
420
 
421
+
231
422
  bufferLayer.clear();
232
423
  addLayer(0);
233
424
  };
425
+
234
426
  /*
235
- * draw actors layer
236
- */
237
- Kinetic.Stage.prototype.drawActors = function(){
238
- this.getActorsLayer().draw();
239
- };
240
- /*
241
- * draw props layer
242
- */
243
- Kinetic.Stage.prototype.drawProps = function(){
244
- this.getPropsLayer().draw();
245
- };
246
- /*
247
- * draw actors and props layer. This method should be used
248
- * in combination with makeActor() or makeProp()
427
+ * draw shapes
249
428
  */
250
429
  Kinetic.Stage.prototype.draw = function(){
251
- this.drawProps();
252
- this.drawActors();
253
- };
254
- /*
255
- * remove a shape from the stage
256
- */
257
- Kinetic.Stage.prototype.remove = function(shape){
258
- // remove from shapes array
259
- var shapes = this.getShapes();
260
- for (var n = 0; n < shapes.length; n++) {
261
- var id = shapes[n].id;
262
- if (id == shape.id) {
263
- shape.getLayer().getShapes().splice(n, 1);
264
- }
430
+ var layers = this.layers;
431
+ for (var n = 0; n < layers.length; n++) {
432
+ layers[n].draw();
265
433
  }
266
434
  };
267
435
  /*
268
- * remove all shapes from the stage
269
- */
270
- Kinetic.Stage.prototype.removeAll = function(){
271
- // remove all shapes
272
- this.getPropsLayer().shapes = [];
273
- this.getActorsLayer().shapes = [];
274
- };
275
- /*
276
- * get stage canvas
277
- */
278
- Kinetic.Stage.prototype.getCanvas = function(){
279
- return this.stageLayer.getCanvas();
280
- };
281
- /*
282
- * get stage context
436
+ * remove a layer from the stage
283
437
  */
284
- Kinetic.Stage.prototype.getContext = function(){
285
- return this.stageLayer.getContext();
438
+ Kinetic.Stage.prototype.remove = function(shape){
439
+ // TODO
286
440
  };
287
441
  /*
288
442
  * short-hand add event listener to stage (which is essentially
289
443
  * the container DOM)
290
444
  */
291
- Kinetic.Stage.prototype.on = function(type, func){
292
- this.container.addEventListener(type, func);
445
+ Kinetic.Stage.prototype.on = function(type, handler){
446
+ this.container.addEventListener(type, handler);
293
447
  };
294
448
  /*
295
449
  * long-hand add event listener to stage (which is essentially
296
450
  * the container DOM)
297
451
  */
298
- Kinetic.Stage.prototype.addEventListener = function(type, func){
299
- this.on(type, func);
452
+ Kinetic.Stage.prototype.addEventListener = function(type, handler){
453
+ this.on(type, handler);
300
454
  };
301
- /*
302
- * add shape to stage
455
+ /*
456
+ * add layer to stage
303
457
  */
304
- Kinetic.Stage.prototype.add = function(shape){
305
- shape.stage = this;
306
- if (shape.isProp) {
307
- shape.layer = this.propsLayer;
458
+ Kinetic.Stage.prototype.add = function(layer){
459
+ if (layer.name) {
460
+ this.layerNames[layer.name] = layer;
308
461
  }
309
- else {
310
- shape.layer = this.actorsLayer;
311
- }
312
-
313
- shape.getLayer().shapes.push(shape);
314
-
315
- shape.id = this.idCounter++;
316
- shape.draw(shape.layer);
462
+ layer.canvas.width = this.width;
463
+ layer.canvas.height = this.height;
464
+ layer.stage = this;
465
+ this.layers.push(layer);
466
+ layer.draw();
467
+ this.container.appendChild(layer.canvas);
468
+ };
469
+ /*
470
+ * get layer by name
471
+ */
472
+ Kinetic.Stage.prototype.getLayer = function(name){
473
+ return this.layerNames[name];
317
474
  };
318
475
  /*
319
476
  * handle incoming event
@@ -332,120 +489,180 @@ Kinetic.Stage.prototype.handleEvent = function(evt){
332
489
 
333
490
  backstageLayer.clear();
334
491
 
335
- for (var n = this.getShapes().length - 1; n >= 0; n--) {
336
- var pubShape = this.getShapes()[n];
337
- (function(){
338
- var shape = pubShape;
339
- shape.draw(backstageLayer);
340
- var pos = that.touchPos || that.mousePos;
341
- var el = shape.eventListeners;
492
+ /*
493
+ * loop through layers. If at any point an event
494
+ * is triggered, n is set to -1 which will break out of the
495
+ * three nested loops
496
+ */
497
+ for (var n = this.layers.length - 1; n >= 0; n--) {
498
+ var layer = this.layers[n];
499
+ if (n >= 0 && layer.isListening) {
500
+ var linkId = layer.tailId;
342
501
 
343
- if (shape.visible && pos !== null && backstageLayerContext.isPointInPath(pos.x, pos.y)) {
344
- // handle onmousedown
345
- if (that.mouseDown) {
346
- that.mouseDown = false;
347
- shape.clickStart = true;
502
+ // propapgate backwards through event links
503
+ while (n >= 0 && linkId !== undefined) {
504
+ //for (var n = this.getEventShapes().length - 1; n >= 0; n--) {
505
+ //var pubShape = this.getEventShapes()[n];
506
+ var link = layer.linkHash[linkId];
507
+ var pubShape = link.shape;
508
+ (function(){
509
+ var shape = pubShape;
510
+ shape.draw(backstageLayer);
511
+ var pos = that.getUserPosition();
512
+ var el = shape.eventListeners;
348
513
 
349
- if (el.onmousedown) {
350
- for (var i = 0; i < el.onmousedown.length; i++) {
351
- el.onmousedown[i].func(evt);
514
+ if (shape.visible && pos !== null && backstageLayerContext.isPointInPath(pos.x, pos.y)) {
515
+ // handle onmousedown
516
+ if (that.mouseDown) {
517
+ that.mouseDown = false;
518
+ that.clickStart = true;
519
+
520
+ if (el.onmousedown) {
521
+ var events = el.onmousedown;
522
+ for (var i = 0; i < events.length; i++) {
523
+ events[i].handler.apply(shape, [evt]);
524
+ }
525
+ }
526
+ n = -1;
352
527
  }
353
- }
354
- n = -1;
355
- }
356
- // handle onmouseup & onclick
357
- else if (that.mouseUp) {
358
- that.mouseUp = false;
359
- if (el.onmouseup) {
360
- for (var i = 0; i < el.onmouseup.length; i++) {
361
- el.onmouseup[i].func(evt);
528
+ // handle onmouseup & onclick
529
+ else if (that.mouseUp) {
530
+ that.mouseUp = false;
531
+ if (el.onmouseup) {
532
+ var events = el.onmouseup;
533
+ for (var i = 0; i < events.length; i++) {
534
+ events[i].handler.apply(shape, [evt]);
535
+ }
536
+ }
537
+
538
+ // detect if click or double click occurred
539
+ if (that.clickStart) {
540
+ if (el.onclick) {
541
+ var events = el.onclick;
542
+ for (var i = 0; i < events.length; i++) {
543
+ events[i].handler.apply(shape, [evt]);
544
+ }
545
+ }
546
+
547
+ if (el.ondblclick && shape.inDoubleClickWindow) {
548
+ var events = el.ondblclick;
549
+ for (var i = 0; i < events.length; i++) {
550
+ events[i].handler.apply(shape, [evt]);
551
+ }
552
+ }
553
+
554
+ shape.inDoubleClickWindow = true;
555
+
556
+ setTimeout(function(){
557
+ shape.inDoubleClickWindow = false;
558
+ }, that.dblClickWindow);
559
+ }
560
+ n = -1;
362
561
  }
363
- }
364
-
365
- // detect if click or double click occurred
366
- if (shape.clickStart) {
367
- if (el.onclick) {
368
- for (var i = 0; i < el.onclick.length; i++) {
369
- el.onclick[i].func(evt);
562
+
563
+ // handle touchstart
564
+ else if (that.touchStart) {
565
+ that.touchStart = false;
566
+ if (el.touchstart) {
567
+ var events = el.touchstart;
568
+ for (var i = 0; i < events.length; i++) {
569
+ events[i].handler.apply(shape, [evt]);
570
+ }
571
+ }
572
+
573
+ if (el.ondbltap && shape.inDoubleClickWindow) {
574
+ var events = el.ondbltap;
575
+ for (var i = 0; i < events.length; i++) {
576
+ events[i].handler.apply(shape, [evt]);
577
+ }
370
578
  }
579
+
580
+ shape.inDoubleClickWindow = true;
581
+
582
+ setTimeout(function(){
583
+ shape.inDoubleClickWindow = false;
584
+ }, that.dblClickWindow);
585
+ n = -1;
371
586
  }
372
587
 
373
- if (el.ondblclick && shape.inDoubleClickWindow) {
374
- for (var i = 0; i < el.ondblclick.length; i++) {
375
- el.ondblclick[i].func(evt);
588
+ // handle touchend
589
+ else if (that.touchEnd) {
590
+ that.touchEnd = false;
591
+ if (el.touchend) {
592
+ var events = el.touchend;
593
+ for (var i = 0; i < events.length; i++) {
594
+ events[i].handler.apply(shape, [evt]);
595
+ }
376
596
  }
597
+ n = -1;
377
598
  }
378
599
 
379
- shape.inDoubleClickWindow = true;
600
+ // handle touchmove
601
+ else if (el.touchmove) {
602
+ var events = el.touchmove;
603
+ for (var i = 0; i < events.length; i++) {
604
+ events[i].handler.apply(shape, [evt]);
605
+ }
606
+ n = -1;
607
+ }
380
608
 
381
- setTimeout(function(){
382
- shape.inDoubleClickWindow = false;
383
- }, that.dblClickWindow);
384
- }
385
- n = -1;
386
- }
387
-
388
- // handle touchstart
389
- else if (that.touchStart) {
390
- that.touchStart = false;
391
- if (el.touchstart) {
392
- for (var i = 0; i < el.touchstart.length; i++) {
393
- el.touchstart[i].func(evt);
609
+ /*
610
+ * this condition is used to identify a new target shape.
611
+ * A new target shape occurs if a target shape is not defined or
612
+ * if the current shape is different from the current target shape and
613
+ * the current shape is beneath the target
614
+ */
615
+ else if (that.targetShape.id === undefined || (that.targetShape.id != shape.id && that.targetShape.getZIndex() < shape.getZIndex())) {
616
+ /*
617
+ * check if old target has an onmouseout event listener
618
+ */
619
+ var oldEl = that.targetShape.eventListeners;
620
+ if (oldEl && oldEl.onmouseout) {
621
+ var events = oldEl.onmouseout;
622
+ for (var i = 0; i < events.length; i++) {
623
+ events[i].handler.apply(that.targetShape, [evt]);
624
+ }
625
+ }
626
+
627
+ // set new target shape
628
+ that.targetShape = shape;
629
+
630
+ // handle onmouseover
631
+ if (el.onmouseover) {
632
+ var events = el.onmouseover;
633
+ for (var i = 0; i < events.length; i++) {
634
+ events[i].handler.apply(shape, [evt]);
635
+ }
636
+ }
637
+ n = -1;
394
638
  }
395
- }
396
- n = -1;
397
- }
398
-
399
- // handle touchend
400
- else if (that.touchEnd) {
401
- that.touchEnd = false;
402
- if (el.touchend) {
403
- for (var i = 0; i < el.touchend.length; i++) {
404
- el.touchend[i].func(evt);
639
+
640
+ // handle onmousemove
641
+ else if (el.onmousemove) {
642
+ var events = el.onmousemove;
643
+ for (var i = 0; i < events.length; i++) {
644
+ events[i].handler.apply(shape, [evt]);
645
+ }
646
+ n = -1;
405
647
  }
406
648
  }
407
- n = -1;
408
- }
409
-
410
- // handle touchmove
411
- else if (el.touchmove) {
412
- for (var i = 0; i < el.touchmove.length; i++) {
413
- el.touchmove[i].func(evt);
414
- }
415
- n = -1;
416
- }
417
-
418
- // handle onmouseover
419
- else if (!shape.mouseOver) {
420
- shape.mouseOver = true;
421
- if (el.onmouseover) {
422
- for (var i = 0; i < el.onmouseover.length; i++) {
423
- el.onmouseover[i].func(evt);
649
+ // handle mouseout condition
650
+ else if (that.targetShape.id == shape.id) {
651
+ that.targetShape = {};
652
+ if (el.onmouseout) {
653
+ var events = el.onmouseout;
654
+ for (var i = 0; i < events.length; i++) {
655
+ events[i].handler.apply(shape, [evt]);
656
+ }
424
657
  }
658
+ n = -1;
425
659
  }
426
- n = -1;
427
- }
660
+ }());
428
661
 
429
- // handle onmousemove
430
- else if (el.onmousemove) {
431
- for (var i = 0; i < el.onmousemove.length; i++) {
432
- el.onmousemove[i].func(evt);
433
- }
434
- n = -1;
435
- }
436
- }
437
- // handle mouseout condition
438
- else if (shape.mouseOver) {
439
- shape.mouseOver = false;
440
- if (el.onmouseout) {
441
- for (var i = 0; i < el.onmouseout.length; i++) {
442
- el.onmouseout[i].func(evt);
443
- }
444
- }
445
- n = -1;
446
- }
447
- }());
448
- }
662
+ linkId = link.prevId;
663
+ } // end links loop
664
+ }
665
+ } // end layer loop
449
666
  };
450
667
  /*
451
668
  * begin listening for events by adding event handlers
@@ -471,10 +688,7 @@ Kinetic.Stage.prototype.listen = function(){
471
688
  that.mouseDown = false;
472
689
  that.handleEvent(evt);
473
690
 
474
- // clear all click starts
475
- for (var i = 0; i < that.getShapes().length; i++) {
476
- that.getShapes()[i].clickStart = false;
477
- }
691
+ that.clickStart = false;
478
692
  }, false);
479
693
 
480
694
  this.container.addEventListener("mouseover", function(evt){
@@ -505,21 +719,28 @@ Kinetic.Stage.prototype.listen = function(){
505
719
  /*
506
720
  * get mouse position for desktop apps
507
721
  */
508
- Kinetic.Stage.prototype.getMousePos = function(evt){
722
+ Kinetic.Stage.prototype.getMousePosition = function(evt){
509
723
  return this.mousePos;
510
724
  };
511
725
  /*
512
726
  * get touch position for mobile apps
513
727
  */
514
- Kinetic.Stage.prototype.getTouchPos = function(evt){
728
+ Kinetic.Stage.prototype.getTouchPosition = function(evt){
515
729
  return this.touchPos;
516
730
  };
731
+ /*
732
+ * get user position (mouse position or touch position)
733
+ *
734
+ */
735
+ Kinetic.Stage.prototype.getUserPosition = function(evt){
736
+ return this.getTouchPosition() || this.getMousePosition();
737
+ };
517
738
  /*
518
739
  * set mouse positon for desktop apps
519
740
  */
520
741
  Kinetic.Stage.prototype.setMousePosition = function(evt){
521
- var mouseX = evt.clientX - this.getContainerPos().left + window.pageXOffset;
522
- var mouseY = evt.clientY - this.getContainerPos().top + window.pageYOffset;
742
+ var mouseX = evt.clientX - this.getContainerPosition().left + window.pageXOffset;
743
+ var mouseY = evt.clientY - this.getContainerPosition().top + window.pageYOffset;
523
744
  this.mousePos = {
524
745
  x: mouseX,
525
746
  y: mouseY
@@ -533,8 +754,8 @@ Kinetic.Stage.prototype.setTouchPosition = function(evt){
533
754
  // one finger
534
755
  var touch = evt.touches[0];
535
756
  // Get the information for finger #1
536
- var touchX = touch.clientX - this.getContainerPos().left + window.pageXOffset;
537
- var touchY = touch.clientY - this.getContainerPos().top + window.pageYOffset;
757
+ var touchX = touch.clientX - this.getContainerPosition().left + window.pageXOffset;
758
+ var touchY = touch.clientY - this.getContainerPosition().top + window.pageYOffset;
538
759
 
539
760
  this.touchPos = {
540
761
  x: touchX,
@@ -545,11 +766,11 @@ Kinetic.Stage.prototype.setTouchPosition = function(evt){
545
766
  /*
546
767
  * get container position
547
768
  */
548
- Kinetic.Stage.prototype.getContainerPos = function(){
769
+ Kinetic.Stage.prototype.getContainerPosition = function(){
549
770
  var obj = this.container;
550
771
  var top = 0;
551
772
  var left = 0;
552
- while (obj.tagName != "BODY") {
773
+ while (obj && obj.tagName != "BODY") {
553
774
  top += obj.offsetTop;
554
775
  left += obj.offsetLeft;
555
776
  obj = obj.offsetParent;
@@ -565,18 +786,16 @@ Kinetic.Stage.prototype.getContainerPos = function(){
565
786
  Kinetic.Stage.prototype.getContainer = function(){
566
787
  return this.container;
567
788
  };
568
- /*
569
- * get all shapes
570
- */
571
- Kinetic.Stage.prototype.getShapes = function(){
572
- return (this.getPropsLayer().getShapes()).concat(this.getActorsLayer().getShapes());
573
- };
574
- /****************************************
575
- * Shape
576
- */
577
- Kinetic.Shape = function(drawFunc, isProp){
789
+
790
+ ///////////////////////////////////////////////////////////////////////
791
+ //// Shape
792
+ ///////////////////////////////////////////////////////////////////////
793
+ ///////////////////////////////////////////////////////////////////////
794
+
795
+ Kinetic.Shape = function(drawFunc, name){
796
+ this.isListening = true;
578
797
  this.drawFunc = drawFunc;
579
- this.isProp = isProp === undefined ? false : isProp;
798
+ this.name = name;
580
799
  this.x = 0;
581
800
  this.y = 0;
582
801
  this.scale = {
@@ -596,28 +815,68 @@ Kinetic.Shape = function(drawFunc, isProp){
596
815
  };
597
816
 
598
817
  this.eventListeners = {};
599
- this.mouseOver = false;
600
- this.clickStart = false;
601
- this.inDblClickWindow = false;
602
-
603
818
  this.visible = true;
819
+ this.drag = {
820
+ x: false,
821
+ y: false
822
+ };
823
+ };
824
+ /*
825
+ * listen or don't listen to events
826
+ */
827
+ Kinetic.Shape.prototype.listen = function(isListening){
828
+ // if shape is in layer
829
+ if (this.link) {
830
+ // if changing isListening
831
+ if (isListening != this.isListening) {
832
+ // is now listening
833
+ if (isListening) {
834
+ //TODO
835
+ }
836
+ // if now not listening
837
+ else {
838
+ //TODO
839
+ }
840
+ }
841
+ }
842
+
843
+ this.isListening = isListening;
844
+ };
845
+ /*
846
+ * get shape temp layer context
847
+ */
848
+ Kinetic.Shape.prototype.getContext = function(){
849
+ return this.tempLayer.getContext();
850
+ };
851
+ /*
852
+ * get shape temp layer canvas
853
+ */
854
+ Kinetic.Shape.prototype.getCanvas = function(){
855
+ return this.tempLayer.getCanvas();
604
856
  };
605
857
  /*
606
858
  * get stage
607
859
  */
608
860
  Kinetic.Shape.prototype.getStage = function(){
609
- return this.stage;
861
+ return this.layer.stage;
610
862
  };
611
863
  /*
612
864
  * draw shape
613
865
  */
614
866
  Kinetic.Shape.prototype.draw = function(layer){
615
867
  if (this.visible) {
616
- var stage = this.getStage();
868
+ //var layer = this.layer;
869
+ var stage = layer.stage;
617
870
  var context = layer.getContext();
618
871
 
872
+ // layer transform
619
873
  context.save();
874
+ if (stage.scale.x != 1 || stage.scale.y != 1) {
875
+ context.scale(stage.scale.x, stage.scale.y);
876
+ }
620
877
 
878
+ // shape transform
879
+ context.save();
621
880
  if (this.x !== 0 || this.y !== 0) {
622
881
  context.translate(this.x, this.y);
623
882
  }
@@ -628,51 +887,128 @@ Kinetic.Shape.prototype.draw = function(layer){
628
887
  context.scale(this.scale.x, this.scale.y);
629
888
  }
630
889
 
631
- this.drawFunc.call(layer);
890
+ this.tempLayer = layer;
891
+ this.drawFunc.call(this);
892
+
893
+ context.restore();
632
894
  context.restore();
633
895
  }
634
896
  };
635
897
  /*
636
- * enable/disable drag and drop
898
+ * initialize drag and drop
899
+ */
900
+ Kinetic.Shape.prototype.initDrag = function(){
901
+ var that = this;
902
+ var types = ["mousedown", "touchstart"];
903
+
904
+ for (var n = 0; n < types.length; n++) {
905
+ var pubType = types[n];
906
+ (function(){
907
+ var type = pubType;
908
+ that.on(type + ".initdrag", function(evt){
909
+ var stage = that.layer.stage;
910
+ var pos = stage.getUserPosition();
911
+
912
+ if (pos) {
913
+ stage.shapeDragging = that;
914
+ stage.shapeDragging.offset = {};
915
+ stage.shapeDragging.offset.x = pos.x - that.x;
916
+ stage.shapeDragging.offset.y = pos.y - that.y;
917
+
918
+ // execute dragstart events if defined
919
+ var dragstart = that.eventListeners.ondragstart;
920
+ if (dragstart) {
921
+ var events = dragstart;
922
+ for (var i = 0; i < events.length; i++) {
923
+ events[i].handler.apply(that, [evt]);
924
+ }
925
+ }
926
+ }
927
+ });
928
+ })();
929
+ }
930
+ };
931
+ /*
932
+ * remove drag and drop event listener
933
+ */
934
+ Kinetic.Shape.prototype.dragCleanup = function(){
935
+ if (!this.drag.x && !this.drag.y) {
936
+ this.off("mousedown.initdrag");
937
+ this.off("touchstart.initdrag");
938
+ }
939
+ };
940
+ /*
941
+ * enable/disable drag and drop for box x and y direction
637
942
  */
638
943
  Kinetic.Shape.prototype.draggable = function(setDraggable){
639
944
  if (setDraggable) {
640
- var that = this;
641
- this.addEventListener("mousedown.initdrag", function(evt){
642
- var stage = that.getStage();
643
- stage.shapeDragging = that;
644
- var mousePos = stage.getMousePos();
645
-
646
- stage.shapeDragging.offset = {};
647
- stage.shapeDragging.offset.x = mousePos.x - that.x;
648
- stage.shapeDragging.offset.y = mousePos.y - that.y;
649
-
650
- // execute dragstart events if defined
651
- var dragstart = that.eventListeners.ondragstart;
652
- if (dragstart) {
653
- for (var i = 0; i < dragstart.length; i++) {
654
- dragstart[i].func(evt);
655
- }
656
- }
657
- });
945
+ var needInit = !this.drag.x && !this.drag.y;
946
+ this.drag = {
947
+ x: true,
948
+ y: true
949
+ };
950
+ if (needInit) {
951
+ this.initDrag();
952
+ }
658
953
  }
659
954
  else {
660
- this.removeEventListener("mousedown.initdrag");
955
+ this.drag = {
956
+ x: false,
957
+ y: false
958
+ };
959
+ this.dragCleanup();
661
960
  }
662
961
  };
663
962
  /*
664
- * set shape scale
963
+ * enable/disable drag and drop for x only
665
964
  */
666
- Kinetic.Shape.prototype.setScale = function(scale){
667
- this.scale.x = scale;
668
- this.scale.y = scale;
965
+ Kinetic.Shape.prototype.draggableX = function(setDraggable){
966
+ if (setDraggable) {
967
+ var needInit = !this.drag.x && !this.drag.y;
968
+ this.drag.x = true;
969
+ if (needInit) {
970
+ this.initDrag();
971
+ }
972
+ }
973
+ else {
974
+ this.drag.x = false;
975
+ this.dragCleanup();
976
+ }
669
977
  };
670
978
  /*
671
- * scale shape
979
+ * enable/disable drag and drop for y only
672
980
  */
673
- Kinetic.Shape.prototype.scale = function(scale){
674
- this.scale.x *= scale;
675
- this.scale.y *= scale;
981
+ Kinetic.Shape.prototype.draggableY = function(setDraggable){
982
+ if (setDraggable) {
983
+ var needInit = !this.drag.x && !this.drag.y;
984
+ this.drag.y = true;
985
+ if (needInit) {
986
+ this.initDrag();
987
+ }
988
+ }
989
+ else {
990
+ this.drag.y = false;
991
+ this.dragCleanup();
992
+ }
993
+ };
994
+ /*
995
+ * get zIndex
996
+ */
997
+ Kinetic.Shape.prototype.getZIndex = function(){
998
+ return this.link.index;
999
+ };
1000
+ /*
1001
+ * set shape scale
1002
+ */
1003
+ Kinetic.Shape.prototype.setScale = function(scaleX, scaleY){
1004
+ if (scaleY) {
1005
+ this.scale.x = scaleX;
1006
+ this.scale.y = scaleY;
1007
+ }
1008
+ else {
1009
+ this.scale.x = scaleX;
1010
+ this.scale.y = scaleX;
1011
+ }
676
1012
  };
677
1013
  /*
678
1014
  * move shape to position
@@ -681,6 +1017,15 @@ Kinetic.Shape.prototype.setPosition = function(x, y){
681
1017
  this.x = x;
682
1018
  this.y = y;
683
1019
  };
1020
+ /*
1021
+ * get shape position
1022
+ */
1023
+ Kinetic.Shape.prototype.getPosition = function(){
1024
+ return {
1025
+ x: this.x,
1026
+ y: this.y
1027
+ };
1028
+ };
684
1029
  /*
685
1030
  * move shape by amount
686
1031
  */
@@ -703,26 +1048,35 @@ Kinetic.Shape.prototype.rotate = function(theta){
703
1048
  /*
704
1049
  * short-hand add event listener to shape
705
1050
  */
706
- Kinetic.Shape.prototype.on = function(type, func){
707
- var event = (type.indexOf('touch') == -1) ? 'on' + type : type;
708
- var parts = event.split(".");
709
- var baseEvent = parts[0];
710
- var name = parts.length > 1 ? parts[1] : "";
711
-
712
- if (!this.eventListeners[baseEvent]) {
713
- this.eventListeners[baseEvent] = [];
1051
+ Kinetic.Shape.prototype.on = function(typesStr, handler){
1052
+ var types = typesStr.split(" ");
1053
+ /*
1054
+ * loop through types and attach event listeners to
1055
+ * each one. eg. "click mouseover.namespace mouseout"
1056
+ * will create three event bindings
1057
+ */
1058
+ for (var n = 0; n < types.length; n++) {
1059
+ var type = types[n];
1060
+ var event = (type.indexOf('touch') == -1) ? 'on' + type : type;
1061
+ var parts = event.split(".");
1062
+ var baseEvent = parts[0];
1063
+ var name = parts.length > 1 ? parts[1] : "";
1064
+
1065
+ if (!this.eventListeners[baseEvent]) {
1066
+ this.eventListeners[baseEvent] = [];
1067
+ }
1068
+
1069
+ this.eventListeners[baseEvent].push({
1070
+ name: name,
1071
+ handler: handler
1072
+ });
714
1073
  }
715
-
716
- this.eventListeners[baseEvent].push({
717
- name: name,
718
- func: func
719
- });
720
1074
  };
721
1075
  /*
722
1076
  * long-hand add event listener to shape
723
1077
  */
724
- Kinetic.Shape.prototype.addEventListener = function(type, func){
725
- this.on(type, func);
1078
+ Kinetic.Shape.prototype.addEventListener = function(type, handler){
1079
+ this.on(type, handler);
726
1080
  };
727
1081
  /*
728
1082
  * short-hand remove event listener(s)
@@ -732,13 +1086,13 @@ Kinetic.Shape.prototype.off = function(type){
732
1086
  var parts = event.split(".");
733
1087
  var baseEvent = parts[0];
734
1088
 
735
- if (parts.length > 1) {
1089
+ if (this.eventListeners[baseEvent] && parts.length > 1) {
736
1090
  var name = parts[1];
737
1091
 
738
1092
  for (var i = 0; i < this.eventListeners[baseEvent].length; i++) {
739
1093
  if (this.eventListeners[baseEvent][i].name == name) {
740
1094
  this.eventListeners[baseEvent].splice(i, 1);
741
- if (this.eventListeners[baseEvent].length == 0) {
1095
+ if (this.eventListeners[baseEvent].length === 0) {
742
1096
  this.eventListeners[baseEvent] = undefined;
743
1097
  }
744
1098
  break;
@@ -771,115 +1125,141 @@ Kinetic.Shape.prototype.hide = function(){
771
1125
  * move shape to top
772
1126
  */
773
1127
  Kinetic.Shape.prototype.moveToTop = function(){
774
- var stage = this.stage;
775
- var layer = this.getLayer();
776
- var shapes = layer.getShapes();
777
-
778
- for (var n = 0; n < shapes.length; n++) {
779
- var shape = shapes[n];
780
- if (shape.id == this.id) {
781
- layer.shapes.splice(n, 1);
782
- layer.shapes.push(this);
783
- break;
1128
+ var link = this.link;
1129
+ var index = link.index;
1130
+ var layer = this.layer;
1131
+ this.layer.links.splice(index, 1);
1132
+ this.layer.links.push(link);
1133
+
1134
+ layer.setLinkIndices();
1135
+
1136
+ if (this.isListening) {
1137
+ // alter link structure if more than one link in the layer
1138
+ if (link.nextId !== undefined || link.prevId !== undefined) {
1139
+ layer.unlink(link);
1140
+ var tail = layer.linkHash[layer.tailId];
1141
+ tail.nextId = link.id;
1142
+ link.prevId = tail.id;
1143
+ layer.tailId = link.id;
784
1144
  }
785
1145
  }
786
1146
  };
787
1147
  /*
788
- * get shape layer
1148
+ * move shape up
789
1149
  */
790
- Kinetic.Shape.prototype.getLayer = function(){
791
- return this.layer;
792
- };
793
- /*
794
- * get shape layer
795
- */
796
- Kinetic.Shape.prototype.makeActor = function(){
797
- var stage = this.stage;
798
- var layer = this.getLayer();
799
- var propsLayer = stage.getPropsLayer();
800
- var actorsLayer = stage.getActorsLayer();
801
- var shapes = layer.getShapes();
802
-
803
- for (var n = 0; n < shapes.length; n++) {
804
- var shape = shapes[n];
805
- if (shape.id == this.id) {
806
- layer.shapes.splice(n, 1);
807
- actorsLayer.getShapes().push(this);
808
- break;
1150
+ Kinetic.Shape.prototype.moveUp = function(){
1151
+ var link = this.link;
1152
+ var index = link.index;
1153
+ var layer = this.layer;
1154
+ var nextLink = layer.linkHash[link.nextId];
1155
+
1156
+ // only do something if there's a link above
1157
+ if (nextLink) {
1158
+ // swap links
1159
+ this.layer.links.splice(index, 1);
1160
+ this.layer.links.splice(index + 1, 0, link);
1161
+
1162
+ layer.setLinkIndices();
1163
+
1164
+ nextLink.prevId = link.prevId;
1165
+ link.nextId = nextLink.nextId;
1166
+
1167
+ if (link.prevId !== undefined) {
1168
+ layer.linkHash[link.prevId].nextId = nextLink.id;
1169
+ }
1170
+ if (nextLink.nextId !== undefined) {
1171
+ layer.linkHash[nextLink.nextId].prevId = link.id;
1172
+ }
1173
+
1174
+ // link to eachother
1175
+ link.prevId = nextLink.id;
1176
+ nextLink.nextId = link.id;
1177
+
1178
+ // handle tail and head reassignment
1179
+ if (link.id == layer.headId) {
1180
+ layer.headId = nextLink.id;
1181
+ }
1182
+ if (nextLink.id == layer.tailId) {
1183
+ layer.tailId = link.id;
809
1184
  }
810
1185
  }
811
1186
  };
812
1187
  /*
813
- * make shape into an actor
1188
+ * move shape down
814
1189
  */
815
- Kinetic.Shape.prototype.makeActor = function(){
816
- var stage = this.stage;
817
- var layer = this.getLayer();
818
- var propsLayer = stage.getPropsLayer();
819
- var actorsLayer = stage.getActorsLayer();
820
- var shapes = layer.getShapes();
1190
+ Kinetic.Shape.prototype.moveDown = function(){
1191
+ var link = this.link;
1192
+ var index = link.index;
1193
+ var layer = this.layer;
1194
+ var prevLink = layer.linkHash[link.prevId];
821
1195
 
822
- for (var n = 0; n < shapes.length; n++) {
823
- var shape = shapes[n];
824
- if (shape.id == this.id) {
825
- layer.shapes.splice(n, 1);
826
- actorsLayer.getShapes().push(this);
827
- this.layer = stage.actorsLayer;
828
- break;
1196
+ // only do something if there's a link above
1197
+ if (prevLink) {
1198
+ // swap links
1199
+ this.layer.links.splice(index, 1);
1200
+ this.layer.links.splice(index - 1, 0, link);
1201
+
1202
+ layer.setLinkIndices();
1203
+
1204
+ link.prevId = prevLink.prevId;
1205
+ prevLink.nextId = link.nextId;
1206
+
1207
+ if (link.nextId !== undefined) {
1208
+ layer.linkHash[link.nextId].prevId = prevLink.id;
1209
+ }
1210
+ if (prevLink.prevId !== undefined) {
1211
+ layer.linkHash[prevLink.prevId].nextId = link.id;
1212
+ }
1213
+
1214
+ // link to eachother
1215
+ link.nextId = prevLink.id;
1216
+ prevLink.prevId = link.id;
1217
+
1218
+ // handle tail and head reassignment
1219
+ if (prevLink.id == layer.headId) {
1220
+ layer.headId = link.id;
1221
+ }
1222
+ if (link.id == layer.tailId) {
1223
+ layer.tailId = prevLink.id;
829
1224
  }
830
1225
  }
831
1226
  };
832
1227
  /*
833
- * make shape into a prop
1228
+ * move shape to bottom
834
1229
  */
835
- Kinetic.Shape.prototype.makeProp = function(){
836
- var stage = this.stage;
837
- var layer = this.getLayer();
838
- var propsLayer = stage.getPropsLayer();
839
- var actorsLayer = stage.getActorsLayer();
840
- var shapes = layer.getShapes();
841
- for (var n = 0; n < shapes.length; n++) {
842
- var shape = shapes[n];
843
- if (shape.id == this.id) {
844
- layer.shapes.splice(n, 1);
845
- propsLayer.getShapes().push(this);
846
- this.layer = stage.propsLayer;
847
- break;
1230
+ Kinetic.Shape.prototype.moveToBottom = function(){
1231
+ var link = this.link;
1232
+ var index = link.index;
1233
+ var layer = this.layer;
1234
+ this.layer.links.splice(index, 1);
1235
+ this.layer.links.unshift(link);
1236
+
1237
+ layer.setLinkIndices();
1238
+
1239
+ if (this.isListening) {
1240
+ // alter link structure if more than one link in the layer
1241
+ if (link.nextId !== undefined || link.prevId !== undefined) {
1242
+ layer.unlink(link);
1243
+ var head = layer.linkHash[layer.headId];
1244
+ head.prevId = link.id;
1245
+ link.nextId = head.id;
1246
+ layer.headId = link.id;
848
1247
  }
849
1248
  }
850
1249
  };
851
- /****************************************
852
- * Image constructor
1250
+ /*
1251
+ * get shape layer
853
1252
  */
854
- Kinetic.Image = function(config){
855
- var imageObj = config.imageObj;
856
- var x = config.x;
857
- var y = config.y;
858
- var width = config.width;
859
- var height = config.height;
860
- var isProp = config.isProp;
861
-
862
- if (!width) {
863
- width = imageObj.width;
864
- }
865
- if (!height) {
866
- height = imageObj.height;
867
- }
868
- var drawImage = function(){
869
- var context = this.getContext();
870
- context.drawImage(imageObj, x, y, width, height);
871
- context.beginPath();
872
- context.rect(x, y, width, height);
873
- context.closePath();
874
- };
875
-
876
- var shape = new Kinetic.Shape(drawImage, isProp);
877
-
878
- /*
879
- * copy shape methods and properties to
880
- * Image object
881
- */
882
- for (var key in shape) {
883
- this[key] = shape[key];
884
- }
1253
+ Kinetic.Shape.prototype.getLayer = function(){
1254
+ return this.layer;
885
1255
  };
1256
+ /*
1257
+ * move shape to another layer
1258
+ */
1259
+ Kinetic.Shape.prototype.moveToLayer = function(newLayer){
1260
+ var layer = this.layer;
1261
+ var link = this.link;
1262
+ layer.unlink(link);
1263
+ layer.removeLink(link);
1264
+ newLayer.addLink(link);
1265
+ };