infogra 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8ad51160672a5160a2b0087da0d5bc97e5de1b79
4
+ data.tar.gz: 5344ee729c6776e86b28bce9f58f9514e0bc434a
5
+ SHA512:
6
+ metadata.gz: 9d3c697386fb25d1c9f104b28ee22396157004c76fbd0398ec032d455dba0f320e55e4600684acdc36a8b48a005696fbfa32a8e1a20e5ea811f7e365dd95a735
7
+ data.tar.gz: b7d095aa61535f6c86a224f1a316ea095754cc69c800a2c27f9af596684405109f6a2eba7398a61dfef3ab1736085d4b04da1636d31fe72a1fc6b14164084089
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Hearty, Oh.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ infogra
2
+ =======
3
+
4
+ Infographic Modeller & Viewer
5
+
6
+ ## Features
7
+ * Canvas base
8
+ * Barcode Symbols
9
+ * Rectangle
10
+ * Circle
11
+ * Line
12
+ * Text
13
+ * Image
14
+
15
+ ## Usage
16
+
17
+ ```js
18
+ var infogra = require('infogra');
19
+
20
+ var modeler = infogra.createModeler(canvas, {
21
+ keydown : onKeyDownHandler,
22
+ selectionchange : onSelectionChange,
23
+ propertychange : onPropertyChange
24
+ });
25
+
26
+ var viewer = infogra.createViewer(canvas, {
27
+ keydown : onKeyDownHandler
28
+ });
29
+ ```
30
+
31
+ ## API
32
+
33
+ ### Objects
34
+ * modeler / viewer
35
+ * symbol (model)
36
+
37
+ ### Modeler(Viewer) Properties
38
+ * get / set
39
+ * edit mode
40
+ * width
41
+ * height
42
+ * root model
43
+ * symbol : get symbol
44
+
45
+ ### Symbols (Models) Manipulation
46
+ * add : add symbol(s)
47
+ * remove : remove symbol(s)
48
+ * get : get child symbol(s)
49
+
50
+ ### Selections
51
+ * selected : get or set selected symbol
52
+
53
+ ### Move
54
+ * move : move delta or move to
55
+
56
+ ### Editing
57
+ * undo
58
+ * redo
59
+ * cut
60
+ * copy
61
+ * paste
62
+
63
+ ### Align
64
+ * align : top, bottom, left, right, vcenter, hcenter
65
+
66
+ ### Arrange Z-Order
67
+ * arrange : front, back, forward, backward
68
+
69
+ ### Scale
70
+ * scale : enlarge, reduce or set scale
71
+
72
+ ## Events
73
+
74
+ ### Modeler(Viewer) Property Change
75
+ * before / after property change
76
+ * before / after close
77
+
78
+ ### Symbols Structure Change
79
+ * When symbols structure is changed
80
+ * It means some symbol is added, removed or moved on their symbol hierarchy
81
+
82
+ ### Symbol(Model) Property Change
83
+
84
+
85
+ ## License
86
+ Copyright (c) 2014 Hearty, Oh. Licensed under the MIT license.
@@ -0,0 +1,5 @@
1
+ require 'infogra/engine' if ::Rails.version >= '3.1'
2
+ require 'infogra/version'
3
+
4
+ module Infogra
5
+ end
@@ -0,0 +1,4 @@
1
+ module Infogra
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Infogra
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,2 @@
1
+ !function(){"use strict";function a(b,c){var e=d(this,b,c);return e.extend=a,e}var b=window.Toolbox={},c=function(){},d=function(a,b,d){var e;return e=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)},_.extend(e,a),c.prototype=a.prototype,e.prototype=new c,b&&_.extend(e.prototype,b),d&&_.extend(e,d),e.prototype.constructor=e,e.__super__=a.prototype,e};b.Base=function(){},b.Base.extend=a}();var Delo=function(){return{}}();Delo.EDITMODE={SELECT:0,CREATE:1,PANE:2},Delo.Command=Toolbox.Base.extend({constructor:function(a){this._params=a},execute:function(){},unexecute:function(){}}),Delo.ModeManager=function(a){this.mode=a.mode,this.context=a.context,this.onmodechange=a.onmodechange},Delo.ModeManager.prototype={get:function(){return{mode:this.mode,context:this.context}},set:function(a,b){if(this.mode!=a||this.context!=b){var c=this.mode,d=this.context;this.mode=a,this.context=b,this.onmodechange&&this.onmodechange({beforeMode:c,afterMode:this.mode,beforeContext:d,afterContext:this.context})}}},Delo.CommandManager=function(){this._executed=[],this._unexecuted=[]},Delo.CommandManager.prototype={execute:function(a){a instanceof Delo.Command&&(a.execute(),this._executed.push(a),this._unexecuted=[])},undo:function(){var a=this._executed.pop();void 0!==a&&(a.unexecute(),this._unexecuted.push(a))},redo:function(){var a=this._unexecuted.pop();void 0!==a&&(a.execute(),this._executed.push(a))},undoable:function(){return this._executed.length>0},redoable:function(){return this._unexecuted.length>0},reset:function(){this._executed=[],this._unexecuted=[]}},Delo.SelectionManager=function(a){this.onselectionchange=a.onselectionchange,this.selections=[]},Delo.SelectionManager.prototype={get:function(){return _.clone(this.selections)},toggle:function(a){var b=_.clone(this.selections),c=[],d=[];this.selections.indexOf(a)>=0?(d.push(a),this.selections=_.without(this.selections,a)):(c.push(a),this.selections.push(a)),this.onselectionchange&&this.onselectionchange({added:c,removed:d,selected:this.selections,before:b})},select:function(a){var b=_.clone(this.selections);a instanceof Array||(a=a?[a]:[]),this.selections=a;var c=_.difference(this.selections,b),d=_.difference(b,this.selections);this.onselectionchange&&this.onselectionchange({added:c,removed:d,selected:this.selections,before:b})},reset:function(){this.selections=[]}},Delo.AlignManager=function(a){this.command_manager=a.command_manager},Delo.AlignManager.prototype={top:function(a){if(!(a.length<2)){for(var b=null,c=0;c<a.length;c++){var d=a[c].getBound();b=null!==b?Math.min(b,d.y):d.y}for(var e=[],c=0;c<a.length;c++){var f=a[c],g=f.getAttr("model"),d=f.getBound(),h=d.y,i=b;i!==h&&e.push({model:g,property:"y",before:h,after:i})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:e}))}},bottom:function(a){if(!(a.length<2)){for(var b=null,c=0;c<a.length;c++){var d=a[c].getBound();b=null!==b?Math.max(b,d.y+d.height):d.y+d.height}for(var e=[],c=0;c<a.length;c++){var f=a[c],g=f.getAttr("model"),d=f.getBound(),h=d.y,i=d.y+(b-(d.y+d.height));i!==h&&e.push({model:g,property:"y",before:h,after:i})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:e}))}},vcenter:function(a){if(!(a.length<2)){for(var b=null,c=null,d=0;d<a.length;d++){var e=a[d].getBound();null!==b?(b=Math.min(b,e.y),c=Math.max(c,e.y+e.height)):(b=e.y,c=e.y+e.height)}for(var f=b+(c-b)/2,g=[],d=0;d<a.length;d++){var h=a[d],i=h.getAttr("model"),e=h.getBound(),j=e.y,k=e.y+(f-(e.y+e.height/2));k!==j&&g.push({model:i,property:"y",before:j,after:k})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:g}))}},left:function(a){if(!(a.length<2)){for(var b=null,c=0;c<a.length;c++){var d=a[c].getBound();b=null!==b?Math.min(b,d.x):d.x}for(var e=[],c=0;c<a.length;c++){var f=a[c],g=f.getAttr("model"),d=f.getBound(),h=d.x,i=b;i!==h&&e.push({model:g,property:"x",before:h,after:i})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:e}))}},right:function(a){if(!(a.length<2)){for(var b=null,c=0;c<a.length;c++){var d=a[c].getBound();b=null!==b?Math.max(b,d.x+d.width):d.x+d.width}for(var e=[],c=0;c<a.length;c++){var f=a[c],g=f.getAttr("model"),d=f.getBound(),h=d.x,i=d.x+(b-(d.x+d.width));i!==h&&e.push({model:g,property:"x",before:h,after:i})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:e}))}},hcenter:function(a){if(!(a.length<2)){for(var b=null,c=null,d=0;d<a.length;d++){var e=a[d].getBound();null!==b?(b=Math.min(b,e.x),c=Math.max(c,e.x+e.width)):(b=e.x,c=e.x+e.width)}for(var f=b+(c-b)/2,g=[],d=0;d<a.length;d++){var h=a[d],i=h.getAttr("model"),e=h.getBound(),j=e.x,k=e.x+(f-(e.x+e.width/2));k!==j&&g.push({model:i,property:"x",before:j,after:k})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:g}))}}},Delo.ClipboardManager=function(a){this.document=a.document,this.command_manager=a.command_manager,this.selection_manager=a.selection_manager,this.reset()},Delo.ClipboardManager.prototype={cut:function(a){if(this.copiable(a)){!a instanceof Array&&(a=[a]),this.reset(-1);for(var b=[],c=0;c<a.length;c++){var d=a[c];if(d.getAttr instanceof Function){var e=d.getAttr("model");b.push(e),this._copied.push(e.clone())}}this.command_manager.execute(new Delo.CommandRemove({collection:this.document,model:b})),this.selection_manager.select()}},copy:function(a){if(this.copiable(a)){!a instanceof Array&&(a=[a]),this.reset();for(var b=0;b<a.length;b++)a[b].getAttr instanceof Function&&this._copied.push(a[b].getAttr("model").clone())}},paste:function(){if(!(this._copied.length<=0)){this._turn++;for(var a=[],b=0;b<this._copied.length;b++){var c=this._copied[b].clone();c.set("x",c.get("x")+20*this._turn),c.set("y",c.get("y")+20*this._turn),a.push(c)}return this.command_manager.execute(new Delo.CommandAdd({collection:this.document,model:a})),a}},copiable:function(a){if(!a)return!1;if(a instanceof Array){if(a.length<=0)return!1;for(var b=0;b<a.length;b++){var c=a[b];if(c.getAttr instanceof Function)return!0}}else if(a.getAttr instanceof Function)return!0;return!1},reset:function(a){this._copied=[],this._turn=void 0!==a?a:0}},Delo.Part=Backbone.Model.extend({defaults:{x:0,y:0,width:100,height:100,fill:"blue",stroke:"black",strokeWidth:3,rotationDeg:0},getPosition:function(){return{x:this.get("x"),y:this.get("y")}},getBound:function(){return this.adjustAttrs({x:this.get("x"),y:this.get("y"),width:this.get("width")||0,height:this.get("height")||0})},adjustAttrs:function(a){return a},serialize:function(){return'{"type":"'+this.constructor.partType+'","attrs":'+JSON.stringify(this)+"}"}},{partType:"Delo.Part"}),Delo.Document=Backbone.Collection.extend({model:Delo.Part,width:800,height:600,load:function(data){var collection={components:[],width:1024,height:768};try{data&&(collection=JSON.parse(data))}catch(e){console.log(e)}void 0!==collection.width&&(this.width=collection.width),void 0!==collection.height&&(this.height=collection.height),this.reset(),collection.components.forEach(function(component){this.add(new(eval(component.type))(component.attrs))},this)},serialize:function(){return'{"width":'+this.width+',"height":'+this.height+',"components":['+this.models.map(function(a){return a.serialize()}).join(",")+"]}"}}),Delo.PartView=function(){},Delo.PartView.prototype={handleset:[1,1,1,1,1,1,1,1,1,1],onChangePost:function(){},_remove:function(){this.remove()},_change:function(a){this.set(a.changed),this.getLayer().draw()},getBound:function(){return{x:this.getX(),y:this.getY(),width:this.getWidth(),height:this.getHeight()}},adjust:function(a){return a},set:function(){if(0==arguments.length)arguments.callee.call(null,{});else if(arguments.length>1&&"string"==typeof arguments[0]){var a={};a[arguments[0]]=arguments[1],arguments.callee.call(null,a)}var b=arguments[0],c=this.adjust(b),d={};for(var e in c)d[e]=this.getAttr(e);this.setAttrs(c);var f=!1,g={};for(var e in b){var h=this.getAttr(e);h!=d[e]?(g[e]=this.getAttr(e),f=!0):delete d[e]}f&&this.fire("change",{before:d,after:g},!0)}},Delo.Handle=function(a){this._initHandle(a)},Delo.Handle.prototype={_rotateImage:null,getRotateImage:function(){if(!this._rotateImage){this._rotateImage=new Image,this._rotateImage.src="assets/modeler/iconModelerAngle.png";var a=this;this._rotateImage.onload=function(){a.getLayer().draw()}}return this._rotateImage},_initHandle:function(a){this.target=a.target;var b=this.target.getBound();a.x=b.x,a.y=b.y,a.width=b.width,a.height=b.height,a.rotation=this.target.getAttr("rotation"),Kinetic.Group.call(this,a),this.shapeType="Handle",this.addHandles(),this.on("removed",this._removed)},_removed:function(){},getHandleDelta:function(a){var b=this.getChildren().toArray(),c=b[0],d=b[1],e=b[2],f=b[3],g=b[4],h=b[5],i=b[6],j=b[7],k=b[8],l=b[9];switch(a){case e:return{x:e.getAttr("x"),y:e.getAttr("y"),width:-e.getAttr("x"),height:-e.getAttr("y")};case f:return{y:f.getAttr("y"),width:f.getAttr("x")-this.getAttr("width"),height:-f.getAttr("y")};case g:return{width:g.getAttr("x")-this.getAttr("width"),height:g.getAttr("y")-this.getAttr("height")};case h:return{x:h.getAttr("x"),width:-h.getAttr("x"),height:h.getAttr("y")-this.getAttr("height")};case i:return{y:i.getAttr("y"),height:-i.getAttr("y")};case j:return{height:j.getAttr("y")-this.getAttr("height")};case k:return{x:k.getAttr("x"),width:-k.getAttr("x")};case l:return{width:l.getAttr("x")-this.getAttr("width")};case d:var m=this.getAttr("width")/2,n=-16,o=d.getAttr("x"),p=d.getAttr("y"),q=Math.acos((m*o+n*p)/(Math.sqrt(m*m+n*n)*Math.sqrt(o*o+p*p)));(0==m||n/m>p/o)&&(q=-1*q);var r=((this.getAttr("rotationDeg")||0)+(q?q*(180/Math.PI):0))%360;return{rotationDeg:r-(this.getAttr("rotationDeg")||0)};case c:return{x:c.getAttr("x"),y:c.getAttr("y")}}},getModelDelta:function(){var a=this.target,b=a.getAttr("model"),c=b.getBound(),d=a.getBound();c.rotationDeg=b.get("rotationDeg")||0,d.rotationDeg=a.getAttr("rotationDeg")||0;var e={};return d=b.adjustAttrs(d),_.each(["x","y","width","height","rotationDeg"],function(a){var b=d[a]-(c[a]||0);b&&(e[a]=b)}),e},setHandlePositions:function(){var a=this.getChildren().toArray(),b=this.target.handleset[0]?a[0]:null;a[0];var c=this.target.handleset[1]?a[1]:null,d=this.target.handleset[2]?a[2]:null,e=this.target.handleset[3]?a[3]:null,f=this.target.handleset[4]?a[4]:null,g=this.target.handleset[5]?a[5]:null,h=this.target.handleset[6]?a[6]:null,i=this.target.handleset[7]?a[7]:null,j=this.target.handleset[8]?a[8]:null,k=this.target.handleset[9]?a[9]:null,l=this.getAttr("width"),m=this.getAttr("height");d&&d.setAttrs({x:0,y:0}),e&&e.setAttrs({x:l,y:0}),g&&g.setAttrs({x:0,y:m}),f&&f.setAttrs({x:l,y:m}),h&&h.setAttrs({x:l/2,y:0,width:Math.abs(l)>40?8:0,height:Math.abs(l)>40?8:0}),i&&i.setAttrs({x:l/2,y:m,width:Math.abs(l)>40?8:0,height:Math.abs(l)>40?8:0}),j&&j.setAttrs({x:0,y:m/2,width:Math.abs(m)>40?8:0,height:Math.abs(m)>40?8:0}),k&&k.setAttrs({x:l,y:m/2,width:Math.abs(m)>40?8:0,height:Math.abs(m)>40?8:0}),c&&c.setAttrs({x:l/2,y:-16}),b&&b.setAttrs({x:0,y:0,width:l,height:m})},addHandles:function(){this.add(this.target.handleset[0]?new Kinetic.Rect({stroke:"#7f7f7f",dashArray:[3,3],strokeWidth:1,draggable:!0}):new Kinetic.Rect({stroke:"#7f7f7f",fill:"white",strokeWidth:0,width:0,height:0,draggable:!1})),this.add(this.target.handleset[1]?new Kinetic.Image({image:this.getRotateImage(),offset:{x:5},draggable:!0}):new Kinetic.Ellipse({stroke:"black",fill:"white",radius:[0,0],strokeWidth:0,draggable:!1}));for(var a=2;6>a;a++)this.add(this.target.handleset[a]?new Kinetic.Ellipse({stroke:"black",fill:"white",radius:[4,4],strokeWidth:1,draggable:!0}):new Kinetic.Ellipse({stroke:"black",fill:"white",radius:[0,0],strokeWidth:1,draggable:!1}));for(var a=6;10>a;a++)this.add(this.target.handleset[a]?new Kinetic.Rect({stroke:"black",width:8,height:8,offset:{x:4,y:4},fill:"white",strokeWidth:1,draggable:!0}):new Kinetic.Rect({stroke:"black",fill:"white",strokeWidth:0,width:0,height:0,draggable:!1}));this.setHandlePositions()}},Kinetic.Util.extend(Delo.Handle,Kinetic.Group),Delo.DragTracker=Toolbox.Base.extend({constructor:function(a){this._init(a),this._onopen=_.bind(this._open,this),this._onclose=_.bind(this._close,this)},_init:function(a){this.config=a||{},this.config.self||(this.config.self=this.target),this.config.ondragstart||(this.config.ondragstart=this._ondragstart),this.config.ondragmove||(this.config.ondragmove=this._ondragmove),this.config.ondragend||(this.config.ondragend=this._ondragend),this.config.ondragstart=_.bind(this.config.ondragstart,this.config.self),this.config.ondragmove=_.bind(this.config.ondragmove,this.config.self),this.config.ondragend=_.bind(this.config.ondragend,this.config.self)},on:function(a,b){this.off(),this.target=a,b&&this._init(b),this.target.on("dragstart",this._onopen)},off:function(){this.target&&this.target.off("dragstart",this._onopen)},_ondragstart:function(){},_ondragmove:function(){},_ondragend:function(){},_open:function(a){this.target.on("dragmove",this.config.ondragmove),this.target.on("dragend",this.config.ondragend),this.target.on("dragend",this._onclose),this.config.ondragstart.call(this.config.self,a)},_close:function(){this.target.off("dragmove",this.config.ondragmove),this.target.off("dragend",this.config.ondragend),this.target.off("dragend",this._onclose)}}),Delo.Viewer=Backbone.View.extend({initialize:function(){this.stage=new Kinetic.Stage({container:this.el,width:this.collection.width,height:this.collection.height});this.partsLayer=new Delo.PartsLayer({target_stage:this.stage,document:this.collection,mode:"view"}),this.stage.add(this.partsLayer),this.register("Delo.Part",Delo.PartView),this.register("Delo.Line",Delo.LineView),this.register("Delo.Box",Delo.BoxView),this.register("Delo.Ellipse",Delo.EllipseView),this.register("Delo.Image",Delo.ImageView),this.register("Delo.Text",Delo.TextView),this.register("Barcode",BarcodeView),this.collection.bind("reset",this._reset,this)},register:function(a,b){this.partsLayer.register(a,b)},_reset:function(){this.stage.setSize(this.collection.width,this.collection.height)},toDataUrl:function(a){this.stage.toDataURL({callback:a})}}),Delo.DocumentView=Backbone.View.extend({stage:null,partsLayer:null,initialize:function(config){this.stage=new Kinetic.Stage({container:this.el,width:this.collection.width,height:this.collection.height});var self=this;this.command_manager=new Delo.CommandManager,this.editmode_manager=new Delo.ModeManager({mode:Delo.EDITMODE.SELECT,onmodechange:function(a){self.trigger("editmodechange",a)}}),this.selection_manager=new Delo.SelectionManager({onselectionchange:function(a){self.trigger("selectionchange",a)}}),this.align_manager=new Delo.AlignManager({command_manager:this.command_manager}),this.clipboard_manager=new Delo.ClipboardManager({document:this.collection,command_manager:this.command_manager,selection_manager:this.selection_manager}),this.partsLayer=new Delo.PartsLayer({document:this.collection,mode:"edit",offset:[-14,-14]}),this.stage.add(new Delo.SelectionLayer({document:this.collection,parts_layer:this.partsLayer,selection_manager:this.selection_manager})),this.stage.add(this.partsLayer),this.stage.add(new Delo.RulerLayer({target_stage:this.stage,document:this.collection,offset:[-14,-14]})),this.stage.add(new Delo.HandleLayer({docview:this,document:this.collection,command_manager:this.command_manager,editmode_manager:this.editmode_manager,selection_manager:this.selection_manager,parts_layer:this.partsLayer,offset:[-14,-14]})),this.register("Delo.Part",Delo.PartView),this.register("Delo.Line",Delo.LineView),this.register("Delo.Box",Delo.BoxView),this.register("Delo.Ellipse",Delo.EllipseView),this.register("Delo.Image",Delo.ImageView),this.register("Delo.Text",Delo.TextView),this.register("Barcode",BarcodeView),this.collection.bind("reset",this._reset,this),this.focusLayer=new Delo.FocusLayer({keydown_handler:config.keydown_handler}),this.stage.add(this.focusLayer),this.stage.on("click",_.bind(function(e){var editmode=this.editmode_manager.get();if(editmode.mode===Delo.EDITMODE.CREATE){var modelType=editmode.context,model=new(eval(modelType))({x:e.offsetX,y:e.offsetY});this.addNode(model)}},this))},movedelta:function(a){for(var b=this.selection_manager.get(),c=[],d=0;d<b.length;d++){var e=b[d],f=e.getAttr("model"),g={},h={};for(var i in a)g[i]=f.get(i),h[i]=f.get(i)+a[i];c.push({model:f,before:g,after:h})}this.command_manager.execute(new Delo.CommandPropertyChange({changes:c}))},register:function(a,b){this.partsLayer.register(a,b)},execute:function(a){this.command_manager.execute(a)},redo:function(){this.command_manager.redo()},undo:function(){this.command_manager.undo()},alignTop:function(){this.align_manager.top(this.selection_manager.get())},alignBottom:function(){this.align_manager.bottom(this.selection_manager.get())},alignVCenter:function(){this.align_manager.vcenter(this.selection_manager.get())},alignLeft:function(){this.align_manager.left(this.selection_manager.get())},alignRight:function(){this.align_manager.right(this.selection_manager.get())},alignHCenter:function(){this.align_manager.hcenter(this.selection_manager.get())},cut:function(){this.clipboard_manager.cut(this.selection_manager.get())},copy:function(){this.clipboard_manager.copy(this.selection_manager.get())},paste:function(){var a=this.clipboard_manager.paste();this.selection_manager.select(this.partsLayer.findByModel(a))},arrange_front:function(){for(var a=this.selection_manager.get(),b=0;b<a.length;b++)a[b].moveToTop();this.partsLayer.draw()},arrange_back:function(){for(var a=this.selection_manager.get(),b=0;b<a.length;b++)a[b].moveToBottom();this.partsLayer.draw()},arrange_forward:function(){for(var a=this.selection_manager.get(),b=0;b<a.length;b++)a[b].moveUp();this.partsLayer.draw()},arrange_backward:function(){for(var a=this.selection_manager.get(),b=0;b<a.length;b++)a[b].moveDown();this.partsLayer.draw()},set_size:function(a,b){this.collection.width=a,this.collection.height=b,this.stage.setSize(a,b),this.stage.draw()},set_scale:function(a){var b=this.collection.width,c=this.collection.height;this.stage.setWidth(b*a),this.stage.setHeight(c*a),this.stage.setScale({x:a,y:a}),this.stage.draw()},scale_enlarge:function(){var a=this.stage.getScale().x;this.set_scale(a+1>8?8:a+1)},scale_reduce:function(){var a=this.stage.getScale().x;this.set_scale(1>a-1?1:a-1)},addNode:function(a){this.execute(new Delo.CommandAdd({collection:this.collection,model:a})),this.selection_manager.select(this.partsLayer.findByModel(a))},setModelProperty:function(a,b,c){this.execute(new Delo.CommandPropertyChange({changes:[{model:a,property:b,before:a.get(b),after:c}]}))},setDocumentProperty:function(a,b){this.execute(new Delo.CommandDocPropertyChange({docview:this,document:this.collection,changes:[{property:a,before:document[a],after:b}]}))},getSelections:function(){return this.selection_manager.get()},_reset:function(){this.command_manager.reset(),this.clipboard_manager.reset(),this.selection_manager.reset(),this.stage.setScale(1),this.stage.setSize(this.collection.width,this.collection.height)},setEditMode:function(a,b){this.editmode_manager.set(a,b)},getFocusTarget:function(){return this.focusLayer.getFocusTarget()},toDataUrl:function(a){this.stage.toDataURL({callback:a})}}),Delo.CommandAdd=Delo.Command.extend({execute:function(){if(this._params.model instanceof Array)for(var a=0;a<this._params.model.length;a++)this._params.collection.add(this._params.model[a]);else this._params.collection.add(this._params.model)},unexecute:function(){if(this._params.model instanceof Array)for(var a=0;a<this._params.model.length;a++)this._params.collection.remove(this._params.model[a]);else this._params.collection.remove(this._params.model)}}),Delo.CommandDocPropertyChange=Delo.Command.extend({execute:function(){for(var a=this._params.changes,b=this._params.document,c=this._params.docview,d=0;d<a.length;d++){var e=a[d],f=e.property,g=e.after;switch(b[f]=g,f){case"width":case"height":c.set_size(b.width,b.height)}}},unexecute:function(){for(var a=this._params.changes,b=this._params.document,c=this._params.docview,d=0;d<a.length;d++){var e=a[d],f=e.property,g=e.before;switch(b[f]=g,f){case"width":case"height":c.set_size(b.width,b.height)}}}}),Delo.CommandMove=Delo.Command.extend({execute:function(){this._params.newx,this._params.newy;this._params.collection.add(this._params.model)},unexecute:function(){this._params.collection.remove(this._params.model)}}),Delo.CommandPropertyChange=Delo.Command.extend({execute:function(){for(var a=this._params.changes,b=0;b<a.length;b++){var c=a[b],d=c.property,e=c.after;d?c.model.set(d,e):c.model.set(e)}},unexecute:function(){for(var a=this._params.changes,b=0;b<a.length;b++){var c=a[b],d=c.property,e=c.before;d?c.model.set(d,e):c.model.set(e)}}}),Delo.CommandRemove=Delo.Command.extend({execute:function(){if(this._params.model instanceof Array)for(var a=0;a<this._params.model.length;a++)this._params.collection.remove(this._params.model[a]);else this._params.collection.remove(this._params.model)},unexecute:function(){if(this._params.model instanceof Array)for(var a=0;a<this._params.model.length;a++)this._params.collection.add(this._params.model[a]);else this._params.collection.add(this._params.model)}}),Delo.CommandResize=Delo.Command.extend({execute:function(){},unexecute:function(){}}),Barcode=Delo.Part.extend({defaults:{x:0,y:0,symbol:"code128",text:"1234567890",alttext:"1234567890",scale_h:2,scale_w:2,rotation:"N",includetext:!0,includecheckintext:!0,includecheck:!0,parsefnc:!0,segments:4,showborder:!0,version:"iata",barcolor:"#FF0000",rows:32,columns:8,height:64,width:64,backgroundcolor:"DD000011",format:"full",ccversion:"b",cccolumns:4,numeric:!0,guardwhitespace:!0}},{partType:"Barcode"}),Delo.Box=Delo.Part.extend({defaults:{x:0,y:0,width:100,height:100,stroke:"black",fill:"red",strokeWidth:3,rotationDeg:0}},{partType:"Delo.Box"}),Delo.Ellipse=Delo.Part.extend({defaults:{x:0,y:0,radius:[50,70],width:100,height:140,stroke:"black",fill:"red",strokeWidth:3,rotationDeg:0},adjustAttrs:function(a){return void 0!==a.x&&(a.x-=this.get("width")/2),void 0!==a.y&&(a.y-=this.get("height")/2),a}},{partType:"Delo.Ellipse"}),Delo.Image=Delo.Part.extend({defaults:{x:0,y:0,width:100,height:100,stroke:"black",strokeWidth:3,rotationDeg:0,url:"http://www.html5canvastutorials.com/demos/assets/yoda.jpg"}},{partType:"Delo.Image"}),Delo.Line=Delo.Part.extend({defaults:{x:0,y:0,width:100,height:100,stroke:"black",strokeWidth:10}},{partType:"Delo.Line"}),Delo.Text=Delo.Part.extend({defaults:{x:0,y:0,fontSize:30,fontFamily:"Calibri",fill:"black",stroke:"black",text:"ABCDEFG",rotationDeg:0}},{partType:"Delo.Text"}),Delo.FocusLayer=function(a){this._initFocusLayer(a)},Delo.FocusLayer.prototype={_initFocusLayer:function(a){a.id="focus_layer",Kinetic.Layer.call(this,a);var b=this.getFocusTarget();b.setAttribute("tabindex",0),b.addEventListener("click",function(){b.focus()}),a.keydown_handler&&b.addEventListener("keydown",a.keydown_handler)},getFocusTarget:function(){return this.getCanvas()._canvas}},Kinetic.Util.extend(Delo.FocusLayer,Kinetic.Layer),Delo.HandleLayer=function(a){this._initHandleLayer(a)},Delo.HandleLayer.prototype={_initHandleLayer:function(a){a.id="handle_layer",Kinetic.Layer.call(this,a);var b=this.getAttr("docview"),c=this.getAttr("document"),d=this.getAttr("command_manager"),e=this.getAttr("editmode_manager"),f=this.getAttr("selection_manager"),g=this.getAttr("parts_layer");b.on("selectionchange",_.bind(this._select,this)),c.bind("reset",this._reset,this),g.on("click",_.bind(function(a){e.get().mode===Delo.EDITMODE.SELECT&&(a.shiftKey?f.toggle(a.targetNode):f.select(a.targetNode))},this)),this.on("click",_.bind(function(a){var b=a.targetNode.getParent();e.get().mode===Delo.EDITMODE.SELECT&&(a.shiftKey?f.toggle(b.target):f.select(b.target))},this)),new Delo.DragTracker({ondragstart:function(a){var b=a.targetNode.getAttr("model");b&&(this.findHandleByPart(a.targetNode)||(a.shiftKey?f.toggle(a.targetNode):f.select(a.targetNode)))},ondragmove:function(a){for(var b=a.targetNode,c=b.getAttr("model"),d=b.getAttr("x")-c.get("x"),e=b.getAttr("y")-c.get("y"),g=f.get(),h={x:d,y:e},i=0;i<g.length;i++){var j=g[i],k=this.findHandleByPart(j),c=g[i].getAttr("model");if(k){var l={};for(var m in h)l[m]=c.get(m)+h[m];j.setAttrs(l),k.setAttrs(l),k.setHandlePositions()}}},ondragend:function(a){var b=a.targetNode,c=a.targetNode.getAttr("model");if(c){var e=b.getAttr("x")-c.get("x"),g=b.getAttr("y")-c.get("y"),h=f.get(),i=this.buildPropertyChangeSet(h,{x:e,y:g});d.execute(new Delo.CommandPropertyChange({changes:i}))}},self:this}).on(g),new Delo.DragTracker({ondragmove:function(a){for(var b=a.targetNode.getParent(),c=(b.target.getAttr("model"),b.getHandleDelta(a.targetNode)),d=f.get(),e=0;e<d.length;e++){var g=d[e],b=this.findHandleByPart(g);if(b){var h={};for(var i in c)h[i]=g.getAttr(i)+c[i];g.setAttrs(h),b.setAttrs(h),b.setHandlePositions()}}},ondragend:function(a){var b=a.targetNode.getParent(),c=(a.targetNode.getAttr("model"),b.getModelDelta(a.targetNode)),e=f.get();d.execute(new Delo.CommandPropertyChange({changes:this.buildPropertyChangeSet(e,c)}))},self:this}).on(this),g.on("change",_.bind(function(a){var b=a.targetNode,c=a.after,d=this.findHandleByPart(b);if(d){var e={};_.each(["x","y","width","height","rotation","rotationDeg"],function(a){void 0!==c[a]&&(e[a]=c[a])}),0!=_.keys(e).length&&(d.setAttrs(e),d.setHandlePositions(),this.draw())}},this))},_reset:function(){for(var a=this.getChildren().toArray(),b=0;b<a.length;b++)a[b].fire("removed"),a[b].destroy();this.draw()},_select:function(a){var b=this;a.removed.every(function(a){return b.removeHandleByPart(a),!0}),a.added.every(function(a){return b.add(new Delo.Handle({target:a})),!0}),this.draw()},buildPropertyChangeSet:function(a,b){for(var c=[],d=0;d<a.length;d++){var e=a[d],f=e.getAttr("model"),g={},h={};for(var i in b)g[i]=f.get(i),h[i]=f.get(i)+b[i];c.push({model:f,before:g,after:h})}return c},findHandleByPart:function(a){for(var b=this.getChildren().toArray(),c=0;c<b.length;c++)if(b[c].getAttr("target")===a)return b[c]},removeHandleByPart:function(a){var b=this.findHandleByPart(a);b&&(b.fire("removed"),b.destroy())}},Kinetic.Util.extend(Delo.HandleLayer,Kinetic.Layer),Delo.PartsLayer=function(a){this._initPartsLayer(a)},Delo.PartsLayer.prototype={_initPartsLayer:function(a){this.partMap={},a.id="parts_layer",Kinetic.Layer.call(this,a);{var b=this.getAttr("document");this.getAttr("mode")}b.bind("add",this._add,this),b.bind("remove",this._remove,this),b.bind("reset",this._reset,this),this._reset()},register:function(a,b){this.partMap[a]=b},findByModel:function(a){if(!a)return null;!a instanceof Array&&(a=[a]);for(var b=this.getChildren().toArray(),c=[],d=0;d<a.length;d++)for(var e=a[d],f=0;f<b.length;f++)b[f].getAttr("model")===e&&c.push(b[f]);return c},_reset:function(){this.removeChildren(),this.draw()},_add:function(a){var b=this.partMap[a.constructor.partType],c=new b({model:a,mode:this.getAttr("mode")});this.add(c),this.draw()},_remove:function(){this.draw()}},Kinetic.Util.extend(Delo.PartsLayer,Kinetic.Layer),Delo.RulerLayer=function(a){this._initRulerLayer(a)},Delo.RulerLayer.prototype={mmPixel:3.779527559,_initRulerLayer:function(a){this.partMap={},a.id="ruler_layer",Kinetic.Layer.call(this,a);var b=this.getAttr("target_stage"),c=this.getAttr("document");this.add(new Kinetic.Rect({offset:[14,14],fill:"#f3f4f6",x:0,y:0,width:b.getWidth(),height:14})),this.add(this.makeHRuler()),this.add(new Kinetic.Rect({offset:[14,14],fill:"#f3f4f6",x:0,y:0,width:14,height:b.getHeight()})),this.add(this.makeVRuler());var d=new Kinetic.Line({offset:[14,14],points:[0,0,0,15],stroke:"#ff0000",strokeWidth:2,opacity:1,draggable:!1});this.add(d);var e=new Kinetic.Line({offset:[14,14],points:[0,0,15,0],stroke:"#ff0000",strokeWidth:2,opacity:1,draggable:!1});this.add(e),new Delo.DragTracker({ondragmove:function(a){d.setPosition(a.layerX,0),e.setPosition(0,a.layerY),this.draw()},self:this}).on(b),b.on("mousemove",function(a){d.setPosition(a.layerX,0),e.setPosition(0,a.layerY),this.draw()}),c.bind("reset",this._reset,this)},_reset:function(){this.draw()},makeHRuler:function(){var a=this.mmPixel;return new Kinetic.Shape({offset:[0,14],drawFunc:function(b){var c=0,d=b.getCanvas().width-c,e=Math.ceil(d/a);b.beginPath(),b.moveTo(c,0),b.fillStyle="#848586",b.font="8px Verdana";for(var f=0;e>f;f++)f%10==0?(b.moveTo(c+f*a,0),b.lineTo(c+f*a,15),b.fillText(f/10+"",c+f*a+2,11,12)):f%5==0?(b.moveTo(c+f*a,9),b.lineTo(c+f*a,15)):(b.moveTo(c+f*a,12),b.lineTo(c+f*a,15));var g=c,h=Math.floor(g/a);b.moveTo(c,0);for(var i=1;h>i&&!(15>c-i*a);i++)i%10==0?(b.moveTo(c-i*a,0),b.lineTo(c-i*a,15),b.fillText("-"+i/10,c-i*a+2,11,12)):i%5==0?(b.moveTo(c-i*a,9),b.lineTo(c-i*a,15)):(b.moveTo(c-i*a,12),b.lineTo(c-i*a,15));b.closePath(),b.fillStrokeShape(this)},fill:"#FAF602",stroke:"#c2c3c5",strokeWidth:.5,x:0})},makeVRuler:function(){var a=this.mmPixel;return new Kinetic.Shape({offset:[14,0],drawFunc:function(b){var c=0,d=b.getCanvas().height-c,e=Math.ceil(d/a);b.beginPath(),b.moveTo(0,c),b.fillStyle="#848586",b.font="8px Verdana";for(var f=0;e>f;f++)f%10==0?(b.moveTo(0,c+f*a),b.lineTo(15,c+f*a),b.fillText(f/10+"",1,c+f*a+12,12)):f%5==0?(b.moveTo(9,c+f*a),b.lineTo(15,c+f*a)):(b.moveTo(12,c+f*a),b.lineTo(15,c+f*a));var g=c,h=Math.floor(g/a);b.moveTo(0,c);for(var i=1;h>i&&!(15>c-i*a);i++)i%10==0?(b.moveTo(0,c-i*a),b.lineTo(15,c-i*a),b.fillText("-"+i/10,1,c-i*a+12,12)):i%5==0?(b.moveTo(9,c-i*a),b.lineTo(15,c-i*a)):(b.moveTo(12,c-i*a),b.lineTo(15,c-i*a));b.closePath(),b.fillStrokeShape(this)},fill:"#FAF602",stroke:"#c2c3c5",strokeWidth:.5,x:0})}},Kinetic.Util.extend(Delo.RulerLayer,Kinetic.Layer),Delo.ScrollLayer=function(a){this._initScrollLayer(a)},Delo.ScrollLayer.prototype={_initScrollLayer:function(a){this.partMap={},a.id="scroll_layer",Kinetic.Layer.call(this,a);var b=this.getStage(),c=this.getAttr("document"),d=new Kinetic.Group,e=new Kinetic.Group,f=new Kinetic.Rect({x:0,y:b.getHeight()-20,width:b.getWidth(),height:20,fill:"black",opacity:.3}),g=new Kinetic.Rect({x:0,y:b.getHeight()-20,width:140,height:20,fill:"#9f005b",draggable:!0,dragBoundFunc:function(a){var c=a.x;return 0>c?c=0:c>b.getWidth()-160&&(c=b.getWidth()-160),{x:c,y:this.getAbsolutePosition().y}},opacity:.9,stroke:"black",strokeWidth:1}),h=new Kinetic.Rect({x:b.getWidth()-20,y:0,width:20,height:b.getHeight(),fill:"black",opacity:.3}),i=new Kinetic.Rect({x:b.getWidth()-20,y:0,width:20,height:80,fill:"#9f005b",draggable:!0,dragBoundFunc:function(a){var c=a.y;return 0>c?c=0:c>b.getHeight()-100&&(c=b.getHeight()-100),{x:this.getAbsolutePosition().x,y:c}},opacity:.9,stroke:"black",strokeWidth:1});e.on("mouseover",function(){c.body.style.cursor="pointer"}),e.on("mouseout",function(){c.body.style.cursor="default"});var j=function(){var a=-1*g.getPosition().x,b=-1*i.getPosition().y;targetLayer.setOffset(-a,-b),targetLayer.draw()};g.on("dragmove",j),i.on("dragmove",j),d.add(f),d.add(h),e.add(g),e.add(i),this.add(d),this.add(e)},_reset:function(){}},Kinetic.Util.extend(Delo.ScrollLayer,Kinetic.Layer),Delo.SelectionLayer=function(a){this._initSelectionLayer(a)},Delo.SelectionLayer.prototype={_initSelectionLayer:function(a){a.id="selection_layer",Kinetic.Layer.call(this,a);var b=(this.getStage(),this.getAttr("document"));b.bind("reset",this._reset,this),this._reset()},_reset:function(){function a(a,b){var c=Math.min(a.x,a.x+a.width),d=Math.min(b.x,b.x+b.width);if(c>d)return!1;var e=Math.max(a.x,a.x+a.width),f=Math.max(b.x,b.x+b.width);if(f>e)return!1;var g=Math.min(a.y,a.y+a.height),h=Math.min(b.y,b.y+b.height);if(g>h)return!1;var i=Math.max(a.y,a.y+a.height),j=Math.max(b.y,b.y+b.height);return j>i?!1:!0}this.removeChildren();var b=new Kinetic.Rect({width:this.getAttr("document").width,height:this.getAttr("document").height,fill:"white",stroke:"black",strokeWidth:1,name:"background",x:0,y:0,draggable:!0,dragBoundFunc:function(){return{x:this.getX(),y:this.getY()}}});this.add(b),b.on("click",_.bind(function(a){a.shiftKey||this.getAttr("selection_manager").select()
2
+ },this)),new Delo.DragTracker({ondragstart:function(a){this._selectbox&&(this._selectbox.remove(),this._selectbox=void 0),this._selectbox=new Kinetic.Rect({x:a.offsetX,y:a.offsetY,stroke:"black",strokeWidth:1,dashArray:[3,3],name:"selectbox",opacity:.5,width:0,height:0}),this.add(this._selectbox)},ondragmove:function(b){var c={};c.x=this._selectbox.getX(),c.y=this._selectbox.getY(),c.width=b.offsetX-this._selectbox.getX(),c.height=b.offsetY-this._selectbox.getY(),this._selectbox.setAttrs({width:c.width,height:c.height});var d=[];this.getAttr("parts_layer").getChildren().each(function(b){a(c,{x:b.getX(),y:b.getY(),width:b.getWidth(),height:b.getHeight()})&&d.push(b)}),this.getAttr("selection_manager").select(d)},ondragend:function(){this._selectbox.remove(),this._selectbox=void 0,this.draw()},self:this}).on(b),this.draw()}},Kinetic.Util.extend(Delo.SelectionLayer,Kinetic.Layer);var bwip=require("bwip");BarcodeView=function(a){this.build(a)},BarcodeView.prototype={handleset:[1,0,0,0,0,0,0,0,0,0],build:function(a){var b=a.model,c={name:"image",draggable:"view"!=a.mode,x:b.get("x"),y:b.get("y")};Kinetic.Image.call(this,c),this.setAttr("model",b);var d=this;this.imageObj=new Image,this.imageObj.onload=function(){d.setImage(d.imageObj),b.set({width:d.imageObj.width,height:d.imageObj.height}),d.getLayer().draw()},this.imageObj.src=this.buildImageUrl(),b.bind("remove",this._remove,this),b.bind("change",this._change,this)},buildImageUrl:function(){var a=this.getAttr("model");return global.bwip.base64({symbol:a.get("symbol"),text:a.get("text"),alttext:a.get("alttext"),scale_h:a.get("scale_h"),scale_w:a.get("scale_w"),rotation:a.get("rotation")})},_change:function(a){var b=a.changed;b.x||b.y||(this.imageObj.src=this.buildImageUrl()),Delo.PartView.prototype._change.call(this,a)}},Kinetic.Util.extend(BarcodeView,Delo.PartView),Kinetic.Util.extend(BarcodeView,Kinetic.Image),Delo.BoxView=function(a){this.build(a)},Delo.BoxView.prototype={build:function(a){var b=a.model;Kinetic.Rect.call(this,a.model.attributes),this.setDraggable("view"!=a.mode),this.setAttr("model",b),b.bind("remove",this._remove,this),b.bind("change",this._change,this)}},Kinetic.Util.extend(Delo.BoxView,Delo.PartView),Kinetic.Util.extend(Delo.BoxView,Kinetic.Rect),Delo.EllipseView=function(a){this.build(a)},Delo.EllipseView.prototype={build:function(a){var b=a.model,c={width:b.get("width"),height:b.get("height"),fill:b.get("fill"),stroke:b.get("stroke"),strokeWidth:b.get("strokeWidth"),rotationDeg:b.get("rotationDeg"),draggable:"view"!=a.mode,x:b.get("x"),y:b.get("y"),radius:[b.get("width")/2,b.get("height")/2],offset:{x:-b.get("width")/2,y:-b.get("height")/2}};Kinetic.Ellipse.call(this,c),this.setAttr("model",b),b.bind("remove",this._remove,this),b.bind("change",this._change,this)},adjust:function(a){if(void 0!==a.x||void 0!==a.y||void 0!==a.width||void 0!==a.height){var b=void 0===a.width?this.getAttr("width"):a.width,c=void 0===a.height?this.getAttr("height"):a.height;a.radius=[Math.abs(b/2),Math.abs(c/2)],a.offset=[-b/2,-c/2]}return a}},Kinetic.Util.extend(Delo.EllipseView,Delo.PartView),Kinetic.Util.extend(Delo.EllipseView,Kinetic.Ellipse),Delo.ImageView=function(a){this.build(a)},Delo.ImageView.prototype={build:function(a){var b=a.model,c={x:b.get("x"),y:b.get("y"),width:b.get("width"),height:b.get("height"),rotationDeg:b.get("rotationDeg"),draggable:"view"!=a.mode};Kinetic.Image.call(this,c),this.setAttr("model",b);var d=this,e=new Image;e.onload=function(){d.setImage(e),d.getLayer().draw()},e.src=b.get("url"),b.bind("remove",this._remove,this),b.bind("change",this._change,this)}},Kinetic.Util.extend(Delo.ImageView,Delo.PartView),Kinetic.Util.extend(Delo.ImageView,Kinetic.Image),Delo.LineView=function(a){this.build(a)},Delo.LineView.prototype={handleset:[0,0,1,0,1,0,0,0,0,0],build:function(a){var b=a.model,c={points:[[0,0],[b.get("width"),b.get("height")]],fill:b.get("fill"),stroke:b.get("stroke"),strokeWidth:b.get("strokeWidth"),x:b.get("x"),y:b.get("y"),width:b.get("width"),height:b.get("height"),draggable:"view"!=a.mode};Kinetic.Line.call(this,c),this.setAttr("model",b),b.bind("remove",this._remove,this),b.bind("change",this._change,this)},adjust:function(a){return(void 0!==a.x||void 0!==a.y||void 0!==a.width||void 0!==a.height)&&(a.width=void 0===a.width?this.getAttr("width"):a.width,a.height=void 0===a.height?this.getAttr("height"):a.height,a.points=[[0,0],[a.width,a.height]]),a}},Kinetic.Util.extend(Delo.LineView,Delo.PartView),Kinetic.Util.extend(Delo.LineView,Kinetic.Line),Delo.TextView=function(a){this.build(a)},Delo.TextView.prototype={build:function(a){var b=a.model;Kinetic.Text.call(this,a.model.attributes),this.setDraggable("view"!=a.mode),this.setAttr("model",b),b.bind("remove",this._remove,this),b.bind("change",this._change,this)},onChangePost:function(){}},Kinetic.Util.extend(Delo.TextView,Delo.PartView),Kinetic.Util.extend(Delo.TextView,Kinetic.Text);
@@ -0,0 +1,3037 @@
1
+ /*! infogra - v0.0.0 - 2014-02-01
2
+ * https://github.com/heartyoh/infogra
3
+ * Copyright (c) 2014 Hearty, Oh.; Licensed MIT */
4
+ //refer to http://blog.usefunnel.com/2011/03/js-inheritance-with-backbone/
5
+ (function () {
6
+ "use strict";
7
+
8
+ var Toolbox = window.Toolbox = {};
9
+
10
+ // `ctor` and `inherits` are from Backbone (with some modifications):
11
+ // http://documentcloud.github.com/backbone/
12
+
13
+ // Shared empty constructor function to aid in prototype-chain creation.
14
+ var ctor = function () {};
15
+
16
+ // Helper function to correctly set up the prototype chain, for subclasses.
17
+ // Similar to `goog.inherits`, but uses a hash of prototype properties and
18
+ // class properties to be extended.
19
+ var inherits = function (parent, protoProps, staticProps) {
20
+ var child;
21
+
22
+ // The constructor function for the new subclass is either defined by you
23
+ // (the "constructor" property in your `extend` definition), or defaulted
24
+ // by us to simply call `super()`.
25
+ if (protoProps && protoProps.hasOwnProperty('constructor')) {
26
+ child = protoProps.constructor;
27
+ } else {
28
+ child = function () { return parent.apply(this, arguments); };
29
+ }
30
+
31
+ // Inherit class (static) properties from parent.
32
+ _.extend(child, parent);
33
+
34
+ // Set the prototype chain to inherit from `parent`, without calling
35
+ // `parent`'s constructor function.
36
+ ctor.prototype = parent.prototype;
37
+ child.prototype = new ctor();
38
+
39
+ // Add prototype properties (instance properties) to the subclass,
40
+ // if supplied.
41
+ if (protoProps) _.extend(child.prototype, protoProps);
42
+
43
+ // Add static properties to the constructor function, if supplied.
44
+ if (staticProps) _.extend(child, staticProps);
45
+
46
+ // Correctly set child's `prototype.constructor`.
47
+ child.prototype.constructor = child;
48
+
49
+ // Set a convenience property in case the parent's prototype is needed later.
50
+ child.__super__ = parent.prototype;
51
+
52
+ return child;
53
+ };
54
+
55
+ // Self-propagating extend function.
56
+ // Create a new class that inherits from the class found in the `this` context object.
57
+ // This function is meant to be called in the context of a constructor function.
58
+ function extendThis(protoProps, staticProps) {
59
+ var child = inherits(this, protoProps, staticProps);
60
+ child.extend = extendThis;
61
+ return child;
62
+ }
63
+
64
+ // A primitive base class for creating subclasses.
65
+ // All subclasses will have the `extend` function.
66
+ // Example:
67
+ // var MyClass = Toolbox.Base.extend({
68
+ // someProp: 'My property value',
69
+ // someMethod: function () { ... }
70
+ // });
71
+ // var instance = new MyClass();
72
+ Toolbox.Base = function () {}
73
+ Toolbox.Base.extend = extendThis;
74
+ })();
75
+
76
+ // Namespace for Delo
77
+ var Delo = (function(){
78
+ return {};
79
+ })();
80
+ Delo.EDITMODE = {
81
+ SELECT : 0x00,
82
+ CREATE : 0x01,
83
+ PANE : 0x02
84
+ }
85
+ Delo.Command = Toolbox.Base.extend({
86
+ constructor : function(params) {
87
+ this._params = params;
88
+ },
89
+
90
+ execute : function() {
91
+ },
92
+
93
+ unexecute : function() {
94
+ }
95
+ });
96
+
97
+ Delo.ModeManager = function(config) {
98
+ this.mode = config.mode;
99
+ this.context = config.context;
100
+ this.onmodechange = config.onmodechange;
101
+ }
102
+
103
+ Delo.ModeManager.prototype = {
104
+ get : function() {
105
+ return {
106
+ mode : this.mode,
107
+ context : this.context
108
+ };
109
+ },
110
+
111
+ set : function(mode, context) {
112
+ if(this.mode == mode && this.context == context)
113
+ return;
114
+ var oldMode = this.mode;
115
+ var oldContext = this.context;
116
+ this.mode = mode;
117
+ this.context = context;
118
+
119
+ if(this.onmodechange) {
120
+ this.onmodechange({
121
+ beforeMode : oldMode,
122
+ afterMode : this.mode,
123
+ beforeContext : oldContext,
124
+ afterContext : this.context
125
+ })
126
+ }
127
+ }
128
+ }
129
+
130
+ Delo.CommandManager = function() {
131
+ this._executed = [];
132
+ this._unexecuted = [];
133
+ }
134
+
135
+ Delo.CommandManager.prototype = {
136
+ execute : function(cmd) {
137
+ if(!(cmd instanceof Delo.Command))
138
+ return;
139
+
140
+ cmd.execute();
141
+
142
+ this._executed.push(cmd);
143
+ this._unexecuted = [];
144
+ },
145
+
146
+ undo : function() {
147
+ var cmd = this._executed.pop();
148
+
149
+ if(cmd !== undefined) {
150
+ cmd.unexecute();
151
+ this._unexecuted.push(cmd);
152
+ }
153
+ },
154
+
155
+ redo : function() {
156
+ var cmd = this._unexecuted.pop();
157
+
158
+ if(cmd !== undefined) {
159
+ cmd.execute();
160
+ this._executed.push(cmd);
161
+ }
162
+ },
163
+
164
+ undoable : function() {
165
+ return this._executed.length > 0;
166
+ },
167
+
168
+ redoable : function() {
169
+ return this._unexecuted.length > 0;
170
+ },
171
+
172
+ reset : function() {
173
+ this._executed = [];
174
+ this._unexecuted = [];
175
+ }
176
+ }
177
+
178
+ Delo.SelectionManager = function(config) {
179
+ this.onselectionchange = config.onselectionchange;
180
+ this.selections = [];
181
+ }
182
+
183
+ Delo.SelectionManager.prototype = {
184
+ get : function() {
185
+ return _.clone(this.selections);
186
+ },
187
+
188
+ toggle : function(target) {
189
+ /*
190
+ target : 대상이 있는 경우는 Object. 없는 경우는 falsy
191
+ toggle : 기존 선택된 것들을 기반으로 하면 true, 새로운 선택이면 false 또는 falsy
192
+ */
193
+
194
+ // 1 단계 : 현재 선택된 리스트를 별도로 보관한다.
195
+ var old_sels = _.clone(this.selections);
196
+
197
+ // 2 단계 : 현재 선택된 리스트를 별도로 보관한다.
198
+ var added = [];
199
+ var removed = [];
200
+
201
+ // 3 단계 : target이 현재 선택된 것인지 확인한다.
202
+ if(this.selections.indexOf(target) >= 0) {
203
+ removed.push(target);
204
+ this.selections = _.without(this.selections, target);
205
+ } else {
206
+ added.push(target);
207
+ this.selections.push(target);
208
+ };
209
+
210
+ if(this.onselectionchange) {
211
+ this.onselectionchange({
212
+ added : added,
213
+ removed : removed,
214
+ selected : this.selections,
215
+ before : old_sels
216
+ });
217
+ }
218
+ },
219
+
220
+ select : function(target) {
221
+ /*
222
+ target : 복수개가 선택된 경우는 Array, 하나인 경우는 Object. 없는 경우는 falsy
223
+ append : 기존 선택된 것들에 추가이면 true, 새로운 선택이면 false 또는 falsy
224
+ */
225
+
226
+ // 1 단계 : 현재 선택된 리스트를 별도로 보관한다.
227
+ var old_sels = _.clone(this.selections);
228
+
229
+ // 2 단계 : target 타입을 Array로 통일한다.
230
+ if(!(target instanceof Array)) {
231
+ if(!target) {
232
+ target = []
233
+ } else {
234
+ target = [target];
235
+ }
236
+ }
237
+
238
+ // 3 단계 : 새로운 선택 리스트를 만든다.
239
+ this.selections = target;
240
+
241
+ // 4 단계 : 변화된 리스트를 찾는다.(선택리스트에서 빠진 것 찾기)
242
+ var added = _.difference(this.selections, old_sels);
243
+ var removed = _.difference(old_sels, this.selections);
244
+
245
+ if(this.onselectionchange) {
246
+ this.onselectionchange({
247
+ added : added,
248
+ removed : removed,
249
+ selected : this.selections,
250
+ before : old_sels
251
+ });
252
+ }
253
+ },
254
+
255
+ reset : function() {
256
+ this.selections = [];
257
+ }
258
+ }
259
+
260
+ Delo.AlignManager = function(config) {
261
+ this.command_manager = config.command_manager;
262
+ }
263
+
264
+ Delo.AlignManager.prototype = {
265
+
266
+ top : function(nodes) {
267
+
268
+ if(nodes.length < 2) {
269
+ return;
270
+ }
271
+
272
+ var top = null;
273
+
274
+ for(var i = 0;i < nodes.length;i++) {
275
+ var bound = nodes[i].getBound();
276
+ if(top !== null) {
277
+ top = Math.min(top, bound.y);
278
+ } else {
279
+ top = bound.y
280
+ }
281
+ }
282
+
283
+ var changes = [];
284
+
285
+ for(var i = 0;i < nodes.length;i++) {
286
+ var node = nodes[i];
287
+ var model = node.getAttr('model');
288
+
289
+ var bound = node.getBound();
290
+ var oldval = bound.y;
291
+ var newval = top;
292
+
293
+ if(newval !== oldval) {
294
+ changes.push({
295
+ model : model,
296
+ property : 'y',
297
+ before : oldval,
298
+ after : newval
299
+ });
300
+ }
301
+ }
302
+
303
+ this.command_manager.execute(new Delo.CommandPropertyChange({
304
+ changes : changes
305
+ }));
306
+ },
307
+
308
+ bottom : function(nodes) {
309
+
310
+ if(nodes.length < 2) {
311
+ return;
312
+ }
313
+
314
+ var bottom = null;
315
+
316
+ for(var i = 0;i < nodes.length;i++) {
317
+ var bound = nodes[i].getBound();
318
+ if(bottom !== null) {
319
+ bottom = Math.max(bottom, bound.y + bound.height);
320
+ } else {
321
+ bottom = bound.y + bound.height
322
+ }
323
+ }
324
+
325
+ var changes = [];
326
+
327
+ for(var i = 0;i < nodes.length;i++) {
328
+ var node = nodes[i];
329
+ var model = node.getAttr('model');
330
+
331
+ var bound = node.getBound();
332
+ var oldval = bound.y;
333
+ var newval = bound.y + (bottom - (bound.y + bound.height));
334
+
335
+ if(newval !== oldval) {
336
+ changes.push({
337
+ model : model,
338
+ property : 'y',
339
+ before : oldval,
340
+ after : newval
341
+ });
342
+ }
343
+ }
344
+
345
+ this.command_manager.execute(new Delo.CommandPropertyChange({
346
+ changes : changes
347
+ }));
348
+ },
349
+
350
+ vcenter : function(nodes) {
351
+
352
+ if(nodes.length < 2) {
353
+ return;
354
+ }
355
+
356
+ var top = null;
357
+ var bottom = null;
358
+
359
+ for(var i = 0;i < nodes.length;i++) {
360
+ var bound = nodes[i].getBound();
361
+ if(top !== null) {
362
+ top = Math.min(top, bound.y);
363
+ bottom = Math.max(bottom, bound.y + bound.height);
364
+ } else {
365
+ top = bound.y;
366
+ bottom = bound.y + bound.height
367
+ }
368
+ }
369
+
370
+ var center = top + (bottom - top) / 2;
371
+ var changes = [];
372
+
373
+ for(var i = 0;i < nodes.length;i++) {
374
+ var node = nodes[i];
375
+ var model = node.getAttr('model');
376
+
377
+ var bound = node.getBound();
378
+ var oldval = bound.y;
379
+ var newval = bound.y + (center - (bound.y + bound.height / 2));
380
+
381
+ if(newval !== oldval) {
382
+ changes.push({
383
+ model : model,
384
+ property : 'y',
385
+ before : oldval,
386
+ after : newval
387
+ });
388
+ }
389
+ }
390
+
391
+ this.command_manager.execute(new Delo.CommandPropertyChange({
392
+ changes : changes
393
+ }));
394
+ },
395
+
396
+ left : function(nodes) {
397
+
398
+ if(nodes.length < 2) {
399
+ return;
400
+ }
401
+
402
+ var left = null;
403
+
404
+ for(var i = 0;i < nodes.length;i++) {
405
+ var bound = nodes[i].getBound();
406
+ if(left !== null) {
407
+ left = Math.min(left, bound.x);
408
+ } else {
409
+ left = bound.x
410
+ }
411
+ }
412
+
413
+ var changes = [];
414
+
415
+ for(var i = 0;i < nodes.length;i++) {
416
+ var node = nodes[i];
417
+ var model = node.getAttr('model');
418
+
419
+ var bound = node.getBound();
420
+ var oldval = bound.x;
421
+ var newval = left;
422
+
423
+ if(newval !== oldval) {
424
+ changes.push({
425
+ model : model,
426
+ property : 'x',
427
+ before : oldval,
428
+ after : newval
429
+ });
430
+ }
431
+ }
432
+
433
+ this.command_manager.execute(new Delo.CommandPropertyChange({
434
+ changes : changes
435
+ }));
436
+ },
437
+
438
+ right : function(nodes) {
439
+
440
+ if(nodes.length < 2) {
441
+ return;
442
+ }
443
+
444
+ var right = null;
445
+
446
+ for(var i = 0;i < nodes.length;i++) {
447
+ var bound = nodes[i].getBound();
448
+ if(right !== null) {
449
+ right = Math.max(right, bound.x + bound.width);
450
+ } else {
451
+ right = bound.x + bound.width
452
+ }
453
+ }
454
+
455
+ var changes = [];
456
+
457
+ for(var i = 0;i < nodes.length;i++) {
458
+ var node = nodes[i];
459
+ var model = node.getAttr('model');
460
+
461
+ var bound = node.getBound();
462
+ var oldval = bound.x;
463
+ var newval = bound.x + (right - (bound.x + bound.width));
464
+
465
+ if(newval !== oldval) {
466
+ changes.push({
467
+ model : model,
468
+ property : 'x',
469
+ before : oldval,
470
+ after : newval
471
+ });
472
+ }
473
+ }
474
+
475
+ this.command_manager.execute(new Delo.CommandPropertyChange({
476
+ changes : changes
477
+ }));
478
+ },
479
+
480
+ hcenter : function(nodes) {
481
+
482
+ if(nodes.length < 2) {
483
+ return;
484
+ }
485
+
486
+ var left = null;
487
+ var right = null;
488
+
489
+ for(var i = 0;i < nodes.length;i++) {
490
+ var bound = nodes[i].getBound();
491
+ if(left !== null) {
492
+ left = Math.min(left, bound.x);
493
+ right = Math.max(right, bound.x + bound.width);
494
+ } else {
495
+ left = bound.x;
496
+ right = bound.x + bound.width
497
+ }
498
+ }
499
+
500
+ var center = left + (right - left) / 2;
501
+ var changes = [];
502
+
503
+ for(var i = 0;i < nodes.length;i++) {
504
+ var node = nodes[i];
505
+ var model = node.getAttr('model');
506
+
507
+ var bound = node.getBound();
508
+ var oldval = bound.x;
509
+ var newval = bound.x + (center - (bound.x + bound.width / 2));
510
+
511
+ if(newval !== oldval) {
512
+ changes.push({
513
+ model : model,
514
+ property : 'x',
515
+ before : oldval,
516
+ after : newval
517
+ });
518
+ }
519
+ }
520
+
521
+ this.command_manager.execute(new Delo.CommandPropertyChange({
522
+ changes : changes
523
+ }));
524
+ }
525
+ }
526
+
527
+ Delo.ClipboardManager = function(config) {
528
+ this.document = config.document;
529
+ this.command_manager = config.command_manager;
530
+ this.selection_manager = config.selection_manager;
531
+ this.reset();
532
+ }
533
+
534
+ Delo.ClipboardManager.prototype = {
535
+ cut : function(nodes) {
536
+ if(!this.copiable(nodes)) {
537
+ return;
538
+ }
539
+
540
+ if(!nodes instanceof Array) {
541
+ nodes = [nodes];
542
+ }
543
+
544
+ this.reset(-1);
545
+ var models = [];
546
+
547
+ for(var i = 0;i < nodes.length;i++) {
548
+ var node = nodes[i];
549
+ if(node.getAttr instanceof Function) {
550
+ var model = node.getAttr('model');
551
+ models.push(model);
552
+ this._copied.push(model.clone());
553
+ }
554
+ }
555
+
556
+ this.command_manager.execute(new Delo.CommandRemove({
557
+ collection : this.document,
558
+ model : models
559
+ }));
560
+
561
+ this.selection_manager.select();
562
+ },
563
+
564
+ copy : function(nodes) {
565
+ if(!this.copiable(nodes)) {
566
+ return;
567
+ }
568
+
569
+ if(!nodes instanceof Array) {
570
+ nodes = [nodes];
571
+ }
572
+
573
+ this.reset();
574
+ for(var i = 0;i < nodes.length;i++) {
575
+ if(nodes[i].getAttr instanceof Function) {
576
+ this._copied.push(nodes[i].getAttr('model').clone());
577
+ }
578
+ }
579
+ },
580
+
581
+ paste : function(config) {
582
+ if(this._copied.length <= 0) {
583
+ return;
584
+ }
585
+
586
+ this._turn++;
587
+
588
+ var models = [];
589
+ for(var i = 0;i < this._copied.length;i++) {
590
+ var model = this._copied[i].clone();
591
+
592
+ model.set('x', model.get('x') + this._turn * 20);
593
+ model.set('y', model.get('y') + this._turn * 20);
594
+
595
+ models.push(model);
596
+ }
597
+
598
+ this.command_manager.execute(new Delo.CommandAdd({
599
+ collection : this.document,
600
+ model : models
601
+ }));
602
+
603
+ return models;
604
+ },
605
+
606
+ copiable : function(nodes) {
607
+ if(!nodes) {
608
+ return false;
609
+ }
610
+
611
+ if(nodes instanceof Array) {
612
+ if(nodes.length <= 0) {
613
+ return false;
614
+ }
615
+
616
+ /* Nodes Element 중에 하나라도 PartView이면 카피 가능 대상으로 본다. */
617
+ for(var i = 0;i < nodes.length;i++) {
618
+ var node = nodes[i];
619
+ if(node.getAttr instanceof Function) {
620
+ return true;
621
+ }
622
+ }
623
+ } else {
624
+ if(nodes.getAttr instanceof Function) {
625
+ return true;
626
+ }
627
+ }
628
+
629
+ return false;
630
+ },
631
+
632
+ reset : function(initturn) {
633
+ this._copied = [];
634
+
635
+ this._turn = (initturn !== undefined) ? initturn : 0;
636
+ }
637
+ }
638
+
639
+ Delo.Part = Backbone.Model.extend({
640
+ defaults : {
641
+ x : 0,
642
+ y : 0,
643
+ width : 100,
644
+ height : 100,
645
+ fill : 'blue',
646
+ stroke : 'black',
647
+ strokeWidth : 3,
648
+ rotationDeg : 0
649
+ },
650
+
651
+ getPosition : function() {
652
+ return {
653
+ x : this.get('x'),
654
+ y : this.get('y')
655
+ }
656
+ },
657
+
658
+ getBound : function() {
659
+ return this.adjustAttrs({
660
+ x : this.get('x'),
661
+ y : this.get('y'),
662
+ width : this.get('width') || 0,
663
+ height : this.get('height') || 0
664
+ });
665
+ },
666
+
667
+ adjustAttrs : function(attrs) {
668
+ return attrs;
669
+ },
670
+
671
+ serialize : function() {
672
+ return '{"type":"' + this.constructor.partType + '","attrs":' + JSON.stringify(this) + '}'
673
+ }
674
+ }, {
675
+ partType : 'Delo.Part',
676
+ });
677
+ // TODO Document를 Collection을 사용하지 말고, Model을 사용하는 것이 좋겠다.
678
+ Delo.Document = Backbone.Collection.extend({
679
+ model : Delo.Part,
680
+ width : 800,
681
+ height : 600,
682
+
683
+ load : function(data) {
684
+ var collection = {
685
+ components : [],
686
+ width : 1024,
687
+ height : 768
688
+ };
689
+
690
+ try {
691
+ if(data) {
692
+ collection = JSON.parse(data);
693
+ }
694
+ } catch(e) {
695
+ console.log(e);
696
+ // TODO Invalid Diagram.
697
+ }
698
+
699
+ if(collection.width !== undefined) {
700
+ this.width = collection.width;
701
+ }
702
+ if(collection.height !== undefined) {
703
+ this.height = collection.height;
704
+ }
705
+
706
+ this.reset();
707
+
708
+ collection.components.forEach(function(component) {
709
+ this.add(new (eval(component.type))(component.attrs));
710
+ }, this);
711
+
712
+ },
713
+
714
+ serialize : function() {
715
+ return '{"width":' + this.width + ',"height":' + this.height + ',"components":[' +
716
+ this.models.map(function(model) {
717
+ return model.serialize();
718
+ }).join(',') + ']}';
719
+ }
720
+
721
+ });
722
+ Delo.PartView = function(config) {
723
+ // this.build(config);
724
+ };
725
+
726
+ Delo.PartView.prototype = {
727
+ handleset : [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
728
+
729
+ onChangePost : function(e) {
730
+ // 모델이 변경되었을 때, 특별히 해당 뷰모델에서 추가로 할 작업을 정의한다.
731
+ return;
732
+ },
733
+
734
+ _remove : function(e) {
735
+ this.remove();
736
+ },
737
+
738
+ _change : function(e) {
739
+ this.set(e.changed);
740
+
741
+ this.getLayer().draw();
742
+ },
743
+
744
+ getBound : function() {
745
+ return {
746
+ x : this.getX(),
747
+ y : this.getY(),
748
+ width : this.getWidth(),
749
+ height : this.getHeight()
750
+ }
751
+ },
752
+
753
+ adjust : function(attrs) {
754
+ return attrs;
755
+ },
756
+
757
+ set : function() {
758
+ if(arguments.length == 0) {
759
+ arguments.callee.call(null, {});
760
+ } else if(arguments.length > 1 && typeof(arguments[0]) == 'string') {
761
+ var obj = {};
762
+ obj[arguments[0]] = arguments[1];
763
+ arguments.callee.call(null, obj);
764
+ }
765
+
766
+ var arg0 = arguments[0];
767
+ var attrs = this.adjust(arg0);
768
+
769
+ var before = {};
770
+ for(var key in attrs) {
771
+ before[key] = this.getAttr(key);
772
+ }
773
+
774
+ this.setAttrs(attrs);
775
+
776
+ var changed = false;
777
+
778
+ var after = {};
779
+
780
+ for(var key in arg0) {
781
+ var val = this.getAttr(key);
782
+ if(val != before[key]) {
783
+ after[key] = this.getAttr(key);
784
+ changed = true;
785
+ } else {
786
+ delete before[key];
787
+ }
788
+ }
789
+
790
+ if(changed) {
791
+ this.fire('change', {
792
+ before : before,
793
+ after : after
794
+ }, true);
795
+ }
796
+ }
797
+ };
798
+
799
+ Delo.Handle = function(config) {
800
+ this._initHandle(config);
801
+ };
802
+
803
+ Delo.Handle.prototype = {
804
+ _rotateImage : null,
805
+
806
+ getRotateImage : function() {
807
+ if(!this._rotateImage) {
808
+ this._rotateImage = new Image();
809
+ /* TODO 로테이션 핸들의 이미지 리소스를 설정할 수 있도록 해야한다. 직접 그리면 제일 좋다. */
810
+ this._rotateImage.src = 'assets/modeler/iconModelerAngle.png';
811
+
812
+ var self = this;
813
+ this._rotateImage.onload = function() {
814
+ self.getLayer().draw();
815
+ };
816
+ }
817
+ return this._rotateImage;
818
+ },
819
+
820
+ _initHandle: function(config) {
821
+ this.target = config.target;
822
+ var bound = this.target.getBound();
823
+
824
+ config.x = bound.x;
825
+ config.y = bound.y;
826
+ config.width = bound.width;
827
+ config.height = bound.height;
828
+ config.rotation = this.target.getAttr('rotation');
829
+
830
+ // call super constructor
831
+ Kinetic.Group.call(this, config);
832
+ this.shapeType = 'Handle';
833
+
834
+ this.addHandles();
835
+
836
+ this.on('removed', this._removed);
837
+ },
838
+
839
+ _removed : function(e) {
840
+ },
841
+
842
+ /* 현재의 노드 디멘션 정보와 이벤트가 발생한 핸들의 정보와의 차이를 계산해서 제공한다. */
843
+ getHandleDelta : function(handle) {
844
+ var children = this.getChildren().toArray();
845
+
846
+ var bh = children[0]; // bound handle
847
+ var rh = children[1]; // rotation handle
848
+ var lt = children[2];
849
+ var rt = children[3];
850
+ var rb = children[4];
851
+ var lb = children[5];
852
+ var ct = children[6]; // center top
853
+ var cb = children[7]; // center bottom
854
+ var lc = children[8]; // left center
855
+ var rc = children[9]; // right center
856
+
857
+ switch(handle) {
858
+ case lt :
859
+ return {
860
+ x : lt.getAttr('x'),
861
+ y : lt.getAttr('y'),
862
+ width : -lt.getAttr('x'),
863
+ height : -lt.getAttr('y')
864
+ }
865
+ break;
866
+ case rt :
867
+ return {
868
+ y : rt.getAttr('y'),
869
+ width : rt.getAttr('x') - this.getAttr('width'),
870
+ height : -rt.getAttr('y')
871
+ }
872
+ break;
873
+ case rb :
874
+ return {
875
+ width : rb.getAttr('x') - this.getAttr('width'),
876
+ height : rb.getAttr('y') - this.getAttr('height')
877
+ }
878
+ break;
879
+ case lb :
880
+ return {
881
+ x : lb.getAttr('x'),
882
+ width : -lb.getAttr('x'),
883
+ height : lb.getAttr('y') - this.getAttr('height')
884
+ }
885
+ break;
886
+ case ct : // center top
887
+ return {
888
+ y : ct.getAttr('y'),
889
+ height : -ct.getAttr('y')
890
+ }
891
+ break;
892
+ case cb : // center bottom
893
+ return {
894
+ height : cb.getAttr('y') - this.getAttr('height')
895
+ }
896
+ break;
897
+ case lc : // left center
898
+ return {
899
+ x : lc.getAttr('x'),
900
+ width : -lc.getAttr('x')
901
+ }
902
+ break;
903
+ case rc : // right center
904
+ return {
905
+ width : rc.getAttr('x') - this.getAttr('width')
906
+ }
907
+ break;
908
+ case rh : // rotation handle
909
+ /* 벡터의 내적을 적용한, 두 벡터 사이의 각도 구하기 */
910
+ var x = this.getAttr('width') / 2;
911
+ var y = -16;
912
+ var x2 = rh.getAttr('x');
913
+ var y2 = rh.getAttr('y');
914
+
915
+ var theta = Math.acos((x * x2 + y * y2) / (Math.sqrt(x * x + y * y) * Math.sqrt(x2 * x2 + y2 * y2)));
916
+ if(x == 0 || (y / x) > (y2 / x2)) {
917
+ theta = theta * -1;
918
+ }
919
+
920
+ var rtdegree = ((this.getAttr('rotationDeg') || 0) + (theta ? theta * (180 / Math.PI) : 0)) % 360;
921
+
922
+ return {
923
+ rotationDeg : rtdegree - (this.getAttr('rotationDeg') || 0)
924
+ }
925
+ break;
926
+ case bh : // bound handle
927
+ return {
928
+ x : bh.getAttr('x'),
929
+ y : bh.getAttr('y')
930
+ }
931
+ }
932
+ },
933
+
934
+ /* 현재의 노드 디멘션 정보와 이벤트가 발생한 핸들의 정보와의 차이를 계산해서 제공한다. */
935
+ getModelDelta : function(handle) {
936
+ var node = this.target;
937
+ var model = node.getAttr('model');
938
+
939
+ var before = model.getBound();
940
+ var after = node.getBound();
941
+
942
+ before['rotationDeg'] = model.get('rotationDeg') || 0;
943
+ after['rotationDeg'] = node.getAttr('rotationDeg') || 0;
944
+
945
+ var delta = {};
946
+
947
+ after = model.adjustAttrs(after);
948
+
949
+ _.each(['x', 'y', 'width', 'height', 'rotationDeg'], function(attr) {
950
+ var diff = after[attr] - (before[attr] || 0);
951
+ if(diff) {
952
+ delta[attr] = diff;
953
+ }
954
+ });
955
+
956
+ return delta;
957
+ },
958
+
959
+ setHandlePositions : function() {
960
+ var children = this.getChildren().toArray();
961
+
962
+ var bound = this.target.handleset[0] ? children[0] : null;children[0]; // bound
963
+ var rotation = this.target.handleset[1] ? children[1] : null; // rotation handle
964
+ var lt = this.target.handleset[2] ? children[2] : null; // left top
965
+ var rt = this.target.handleset[3] ? children[3] : null; // right top
966
+ var rb = this.target.handleset[4] ? children[4] : null; // right bottom
967
+ var lb = this.target.handleset[5] ? children[5] : null; // left bottom
968
+ var ct = this.target.handleset[6] ? children[6] : null; // center top
969
+ var cb = this.target.handleset[7] ? children[7] : null; // center bottom
970
+ var lc = this.target.handleset[8] ? children[8] : null; // left center
971
+ var rc = this.target.handleset[9] ? children[9] : null; // right center
972
+
973
+ var w = this.getAttr('width');
974
+ var h = this.getAttr('height');
975
+
976
+ if(lt) {
977
+ lt.setAttrs({
978
+ x : 0,
979
+ y : 0
980
+ });
981
+ }
982
+
983
+ if(rt) {
984
+ rt.setAttrs({
985
+ x : w,
986
+ y : 0
987
+ });
988
+ }
989
+
990
+ if(lb) {
991
+ lb.setAttrs({
992
+ x : 0,
993
+ y : h
994
+ });
995
+ }
996
+
997
+ if(rb) {
998
+ rb.setAttrs({
999
+ x : w,
1000
+ y : h
1001
+ });
1002
+ }
1003
+
1004
+ if(ct) {
1005
+ ct.setAttrs({
1006
+ x : w / 2,
1007
+ y : 0,
1008
+ width : Math.abs(w) > 40 ? 8 : 0,
1009
+ height : Math.abs(w) > 40 ? 8 : 0
1010
+ });
1011
+ }
1012
+
1013
+ if(cb) {
1014
+ cb.setAttrs({
1015
+ x : w / 2,
1016
+ y : h,
1017
+ width : Math.abs(w) > 40 ? 8 : 0,
1018
+ height : Math.abs(w) > 40 ? 8 : 0
1019
+ });
1020
+ }
1021
+
1022
+ if(lc) {
1023
+ lc.setAttrs({
1024
+ x : 0,
1025
+ y : h / 2,
1026
+ width : Math.abs(h) > 40 ? 8 : 0,
1027
+ height : Math.abs(h) > 40 ? 8 : 0
1028
+ });
1029
+ }
1030
+
1031
+ if(rc) {
1032
+ rc.setAttrs({
1033
+ x : w,
1034
+ y : h / 2,
1035
+ width : Math.abs(h) > 40 ? 8 : 0,
1036
+ height : Math.abs(h) > 40 ? 8 : 0
1037
+ });
1038
+ }
1039
+
1040
+ if(rotation) {
1041
+ rotation.setAttrs({
1042
+ x : w / 2,
1043
+ y : -16
1044
+ });
1045
+ }
1046
+
1047
+ if(bound) {
1048
+ bound.setAttrs({
1049
+ x : 0,
1050
+ y : 0,
1051
+ width : w,
1052
+ height : h
1053
+ });
1054
+ }
1055
+ },
1056
+
1057
+ addHandles : function() {
1058
+ // 경계를 그린다.
1059
+ if(this.target.handleset[0]) {
1060
+ this.add(new Kinetic.Rect({
1061
+ stroke : '#7f7f7f',
1062
+ dashArray : [3, 3],
1063
+ strokeWidth : 1,
1064
+ draggable : true
1065
+ }));
1066
+ } else {
1067
+ this.add(new Kinetic.Rect({
1068
+ stroke : '#7f7f7f',
1069
+ fill : 'white',
1070
+ strokeWidth : 0,
1071
+ width : 0,
1072
+ height : 0,
1073
+ draggable : false
1074
+ }));
1075
+ }
1076
+
1077
+ // 회전 핸들을 만든다.
1078
+ if(this.target.handleset[1]) {
1079
+ this.add(new Kinetic.Image({
1080
+ image : this.getRotateImage(),
1081
+ offset : {
1082
+ x : 5
1083
+ },
1084
+ draggable: true
1085
+ }));
1086
+ } else {
1087
+ this.add(new Kinetic.Ellipse({
1088
+ stroke : 'black',
1089
+ fill : 'white',
1090
+ radius : [0, 0],
1091
+ strokeWidth : 0,
1092
+ draggable : false
1093
+ }));
1094
+ }
1095
+
1096
+ // 네 귀퉁이 핸들을 만든다.
1097
+ for(var i = 2;i < 6;i++) {
1098
+ if(this.target.handleset[i]) {
1099
+ this.add(new Kinetic.Ellipse({
1100
+ stroke : 'black',
1101
+ fill : 'white',
1102
+ radius : [4, 4],
1103
+ strokeWidth : 1,
1104
+ draggable : true
1105
+ }));
1106
+ } else {
1107
+ this.add(new Kinetic.Ellipse({
1108
+ stroke : 'black',
1109
+ fill : 'white',
1110
+ radius : [0, 0],
1111
+ strokeWidth : 1,
1112
+ draggable : false
1113
+ }));
1114
+ }
1115
+ }
1116
+
1117
+ // 상하좌우 핸들을 만든다.
1118
+ for(var i = 6;i < 10;i++) {
1119
+ if(this.target.handleset[i]) {
1120
+ this.add(new Kinetic.Rect({
1121
+ stroke : 'black',
1122
+ width : 8,
1123
+ height : 8,
1124
+ offset : {
1125
+ x : 4,
1126
+ y : 4
1127
+ },
1128
+ fill : 'white',
1129
+ strokeWidth : 1,
1130
+ draggable : true
1131
+ }));
1132
+ } else {
1133
+ this.add(new Kinetic.Rect({
1134
+ stroke : 'black',
1135
+ fill : 'white',
1136
+ strokeWidth : 0,
1137
+ width : 0,
1138
+ height : 0,
1139
+ draggable : false
1140
+ }));
1141
+ }
1142
+ }
1143
+
1144
+ this.setHandlePositions();
1145
+ }
1146
+ };
1147
+
1148
+ Kinetic.Util.extend(Delo.Handle, Kinetic.Group);
1149
+
1150
+ Delo.DragTracker = Toolbox.Base.extend({
1151
+ constructor : function(config) {
1152
+ this._init(config);
1153
+
1154
+ this._onopen = _.bind(this._open, this);
1155
+ this._onclose = _.bind(this._close, this);
1156
+ },
1157
+
1158
+ _init : function(config) {
1159
+ this.config = config || {};
1160
+
1161
+ if(!this.config.self) {
1162
+ this.config.self = this.target;
1163
+ }
1164
+
1165
+ if(!this.config.ondragstart) {
1166
+ this.config.ondragstart = this._ondragstart;
1167
+ }
1168
+ if(!this.config.ondragmove) {
1169
+ this.config.ondragmove = this._ondragmove;
1170
+ }
1171
+ if(!this.config.ondragend) {
1172
+ this.config.ondragend = this._ondragend;
1173
+ }
1174
+
1175
+ this.config.ondragstart = _.bind(this.config.ondragstart, this.config.self)
1176
+ this.config.ondragmove = _.bind(this.config.ondragmove, this.config.self)
1177
+ this.config.ondragend = _.bind(this.config.ondragend, this.config.self)
1178
+ },
1179
+
1180
+ on : function(target, config) {
1181
+ this.off();
1182
+
1183
+ this.target = target;
1184
+
1185
+ /* 만약, 트래커를 재 사용하고 싶으면, config 옵션을 갱신한다. */
1186
+ if(config) {
1187
+ this._init(config);
1188
+ }
1189
+
1190
+ this.target.on('dragstart', this._onopen);
1191
+ },
1192
+
1193
+ off : function() {
1194
+ if(this.target) {
1195
+ this.target.off('dragstart', this._onopen);
1196
+ }
1197
+ },
1198
+
1199
+ _ondragstart : function(e) {
1200
+ // console.log('dragstart', this.target, e);
1201
+ },
1202
+
1203
+ _ondragmove : function(e) {
1204
+ // console.log('dragmove', this.target, e);
1205
+ },
1206
+
1207
+ _ondragend : function(e) {
1208
+ // console.log('dragend', this.target, e);
1209
+ },
1210
+
1211
+ _open : function(e) {
1212
+ this.target.on('dragmove', this.config.ondragmove);
1213
+ this.target.on('dragend', this.config.ondragend);
1214
+ this.target.on('dragend', this._onclose);
1215
+
1216
+ this.config.ondragstart.call(this.config.self, e);
1217
+ },
1218
+
1219
+ _close : function(e) {
1220
+ this.target.off('dragmove', this.config.ondragmove);
1221
+ this.target.off('dragend', this.config.ondragend);
1222
+ this.target.off('dragend', this._onclose);
1223
+ }
1224
+ });
1225
+
1226
+ Delo.Viewer = Backbone.View.extend({
1227
+ initialize: function(config) {
1228
+
1229
+ this.stage = new Kinetic.Stage({
1230
+ container: this.el,
1231
+ width: this.collection.width,
1232
+ height: this.collection.height,
1233
+ });
1234
+
1235
+ var self = this;
1236
+
1237
+ this.partsLayer = new Delo.PartsLayer({
1238
+ target_stage : this.stage,
1239
+ document : this.collection,
1240
+ mode : 'view'
1241
+ });
1242
+
1243
+ this.stage.add(this.partsLayer);
1244
+
1245
+ this.register('Delo.Part', Delo.PartView);
1246
+ this.register('Delo.Line', Delo.LineView);
1247
+ this.register('Delo.Box', Delo.BoxView);
1248
+ this.register('Delo.Ellipse', Delo.EllipseView);
1249
+ this.register('Delo.Image', Delo.ImageView);
1250
+ this.register('Delo.Text', Delo.TextView);
1251
+ this.register('Barcode', BarcodeView);
1252
+
1253
+ this.collection.bind('reset', this._reset, this);
1254
+ },
1255
+
1256
+ register: function(modelType, editpartClass) {
1257
+ // 레이어에 있는 것을 옮길 방안 필요함.
1258
+ this.partsLayer.register(modelType, editpartClass);
1259
+ },
1260
+
1261
+ _reset : function() {
1262
+ this.stage.setSize(this.collection.width, this.collection.height);
1263
+ },
1264
+
1265
+ toDataUrl : function(callback) {
1266
+ this.stage.toDataURL({
1267
+ callback : callback
1268
+ });
1269
+ }
1270
+ });
1271
+
1272
+ Delo.DocumentView = Backbone.View.extend({
1273
+ stage: null,
1274
+
1275
+ partsLayer: null,
1276
+
1277
+ initialize: function(config) {
1278
+
1279
+ this.stage = new Kinetic.Stage({
1280
+ container: this.el,
1281
+ width: this.collection.width,
1282
+ height: this.collection.height,
1283
+ });
1284
+
1285
+ var self = this;
1286
+
1287
+ this.command_manager = new Delo.CommandManager();
1288
+ this.editmode_manager = new Delo.ModeManager({
1289
+ mode : Delo.EDITMODE.SELECT,
1290
+ onmodechange : function(e) {
1291
+ self.trigger('editmodechange', e);
1292
+ }
1293
+ });
1294
+ this.selection_manager = new Delo.SelectionManager({
1295
+ onselectionchange : function(e) {
1296
+ self.trigger('selectionchange', e);
1297
+ }
1298
+ });
1299
+ this.align_manager = new Delo.AlignManager({
1300
+ command_manager : this.command_manager
1301
+ });
1302
+ this.clipboard_manager = new Delo.ClipboardManager({
1303
+ document : this.collection,
1304
+ command_manager : this.command_manager,
1305
+ selection_manager : this.selection_manager
1306
+ });
1307
+
1308
+ this.partsLayer = new Delo.PartsLayer({
1309
+ document : this.collection,
1310
+ mode : 'edit',
1311
+ offset : [-14, -14]
1312
+ });
1313
+
1314
+ this.stage.add(new Delo.SelectionLayer({
1315
+ document : this.collection,
1316
+ parts_layer : this.partsLayer,
1317
+ selection_manager : this.selection_manager
1318
+ }));
1319
+
1320
+ this.stage.add(this.partsLayer);
1321
+
1322
+ this.stage.add(new Delo.RulerLayer({
1323
+ target_stage : this.stage,
1324
+ document : this.collection,
1325
+ offset : [-14, -14]
1326
+ }));
1327
+
1328
+ this.stage.add(new Delo.HandleLayer({
1329
+ docview : this,
1330
+ document : this.collection,
1331
+ command_manager : this.command_manager,
1332
+ editmode_manager : this.editmode_manager,
1333
+ selection_manager : this.selection_manager,
1334
+ parts_layer : this.partsLayer,
1335
+ offset : [-14, -14]
1336
+ }));
1337
+
1338
+ this.register('Delo.Part', Delo.PartView);
1339
+ this.register('Delo.Line', Delo.LineView);
1340
+ this.register('Delo.Box', Delo.BoxView);
1341
+ this.register('Delo.Ellipse', Delo.EllipseView);
1342
+ this.register('Delo.Image', Delo.ImageView);
1343
+ this.register('Delo.Text', Delo.TextView);
1344
+ this.register('Barcode', BarcodeView);
1345
+
1346
+ this.collection.bind('reset', this._reset, this);
1347
+
1348
+ /* FocusLayer 맨 나중에 추가되어야 한다. */
1349
+ this.focusLayer = new Delo.FocusLayer({
1350
+ keydown_handler : config.keydown_handler
1351
+ });
1352
+ this.stage.add(this.focusLayer);
1353
+
1354
+ /* 모델러 특징의 이벤트 핸들러들 - 이 핸들러들이 한곳으로 모이면 좋겠는데... */
1355
+ this.stage.on('click', _.bind(function(e) {
1356
+ var editmode = this.editmode_manager.get();
1357
+
1358
+ if(editmode.mode === Delo.EDITMODE.CREATE) {
1359
+ var modelType = editmode.context;
1360
+ var model = new (eval(modelType))({
1361
+ x : e.offsetX,
1362
+ y : e.offsetY
1363
+ });
1364
+
1365
+ this.addNode(model);
1366
+ }
1367
+ }, this));
1368
+ },
1369
+
1370
+ movedelta : function(delta) {
1371
+ var sels = this.selection_manager.get();
1372
+ var changes = [];
1373
+
1374
+ for(var i = 0;i < sels.length;i++) {
1375
+ var node = sels[i];
1376
+ var model = node.getAttr('model');
1377
+
1378
+ var before = {};
1379
+ var after = {};
1380
+
1381
+ for(var attr in delta) {
1382
+ before[attr] = model.get(attr);
1383
+ after[attr] = model.get(attr) + delta[attr];
1384
+ }
1385
+
1386
+ changes.push({
1387
+ model : model,
1388
+ before : before,
1389
+ after : after
1390
+ });
1391
+ }
1392
+
1393
+ this.command_manager.execute(new Delo.CommandPropertyChange({
1394
+ changes : changes
1395
+ }));
1396
+ },
1397
+
1398
+ register: function(modelType, editpartClass) {
1399
+ // 레이어에 있는 것을 옮길 방안 필요함.
1400
+ this.partsLayer.register(modelType, editpartClass);
1401
+ },
1402
+
1403
+ execute : function(command) {
1404
+ this.command_manager.execute(command);
1405
+ },
1406
+
1407
+ redo : function() {
1408
+ this.command_manager.redo();
1409
+ },
1410
+
1411
+ undo : function() {
1412
+ this.command_manager.undo();
1413
+ },
1414
+
1415
+ alignTop : function() {
1416
+ this.align_manager.top(this.selection_manager.get());
1417
+ },
1418
+
1419
+ alignBottom : function() {
1420
+ this.align_manager.bottom(this.selection_manager.get());
1421
+ },
1422
+
1423
+ alignVCenter : function() {
1424
+ this.align_manager.vcenter(this.selection_manager.get());
1425
+ },
1426
+
1427
+ alignLeft : function() {
1428
+ this.align_manager.left(this.selection_manager.get());
1429
+ },
1430
+
1431
+ alignRight : function() {
1432
+ this.align_manager.right(this.selection_manager.get());
1433
+ },
1434
+
1435
+ alignHCenter : function() {
1436
+ this.align_manager.hcenter(this.selection_manager.get());
1437
+ },
1438
+
1439
+ cut : function() {
1440
+ this.clipboard_manager.cut(this.selection_manager.get());
1441
+ },
1442
+
1443
+ copy : function() {
1444
+ this.clipboard_manager.copy(this.selection_manager.get());
1445
+ },
1446
+
1447
+ paste : function() {
1448
+ var models = this.clipboard_manager.paste();
1449
+
1450
+ this.selection_manager.select(this.partsLayer.findByModel(models));
1451
+ },
1452
+
1453
+ arrange_front : function() {
1454
+ var nodes = this.selection_manager.get();
1455
+ for(var i = 0;i < nodes.length;i++) {
1456
+ nodes[i].moveToTop();
1457
+ }
1458
+
1459
+ this.partsLayer.draw();
1460
+ },
1461
+
1462
+ arrange_back : function() {
1463
+ var nodes = this.selection_manager.get();
1464
+ for(var i = 0;i < nodes.length;i++) {
1465
+ nodes[i].moveToBottom();
1466
+ }
1467
+
1468
+ this.partsLayer.draw();
1469
+ },
1470
+
1471
+ arrange_forward : function() {
1472
+ var nodes = this.selection_manager.get();
1473
+ for(var i = 0;i < nodes.length;i++) {
1474
+ nodes[i].moveUp();
1475
+ }
1476
+
1477
+ this.partsLayer.draw();
1478
+ },
1479
+
1480
+ arrange_backward : function() {
1481
+ var nodes = this.selection_manager.get();
1482
+ for(var i = 0;i < nodes.length;i++) {
1483
+ nodes[i].moveDown();
1484
+ }
1485
+
1486
+ this.partsLayer.draw();
1487
+ },
1488
+
1489
+ set_size : function(width, height) {
1490
+ this.collection.width = width;
1491
+ this.collection.height = height;
1492
+
1493
+ this.stage.setSize(width, height);
1494
+ this.stage.draw();
1495
+ },
1496
+
1497
+ set_scale : function(scale) {
1498
+ var width = this.collection.width;
1499
+ var height = this.collection.height;
1500
+
1501
+ this.stage.setWidth(width * scale);
1502
+ this.stage.setHeight(height * scale);
1503
+ this.stage.setScale({
1504
+ x : scale,
1505
+ y : scale
1506
+ });
1507
+
1508
+ this.stage.draw();
1509
+ },
1510
+
1511
+ scale_enlarge : function() {
1512
+ var scale = this.stage.getScale().x;
1513
+
1514
+ this.set_scale((scale + 1 > 8) ? 8 : scale + 1);
1515
+ },
1516
+
1517
+ scale_reduce : function() {
1518
+ var scale = this.stage.getScale().x;
1519
+
1520
+ this.set_scale((scale - 1 < 1) ? 1 : scale - 1);
1521
+ },
1522
+
1523
+ addNode : function(model) {
1524
+ this.execute(new Delo.CommandAdd({
1525
+ collection : this.collection,
1526
+ model : model
1527
+ }));
1528
+
1529
+ /* TODO 복수개 추가 경우를 커버하라. */
1530
+ this.selection_manager.select(this.partsLayer.findByModel(model));
1531
+ },
1532
+
1533
+ // removeNode : function(model) {
1534
+ // this.execute(new Delo.CommandRemove({
1535
+ // collection : this.collection,
1536
+ // model : model
1537
+ // }));
1538
+ //
1539
+ // this.selection_manager.select();
1540
+ // },
1541
+ //
1542
+ // removeSelections : function() {
1543
+ // var sels = this.selection_manager.get();
1544
+ //
1545
+ // var model = [];
1546
+ // for(var i = 0;i < sels.length;i++) {
1547
+ // model.push(sels[i].getAttr('model'));
1548
+ // }
1549
+ //
1550
+ // this.removeNode(model);
1551
+ // },
1552
+
1553
+ setModelProperty : function(model, property, value) {
1554
+ this.execute(new Delo.CommandPropertyChange({
1555
+ changes : [{
1556
+ model : model,
1557
+ property : property,
1558
+ before : model.get(property),
1559
+ after : value
1560
+ }]
1561
+ }));
1562
+ },
1563
+
1564
+ setDocumentProperty : function(property, value) {
1565
+ this.execute(new Delo.CommandDocPropertyChange({
1566
+ docview : this,
1567
+ document : this.collection,
1568
+ changes : [{
1569
+ property : property,
1570
+ before : document[property],
1571
+ after : value
1572
+ }]
1573
+ }));
1574
+ },
1575
+
1576
+ getSelections : function() {
1577
+ return this.selection_manager.get();
1578
+ },
1579
+
1580
+ _reset : function() {
1581
+ this.command_manager.reset();
1582
+ this.clipboard_manager.reset();
1583
+ this.selection_manager.reset();
1584
+
1585
+ this.stage.setScale(1);
1586
+ this.stage.setSize(this.collection.width, this.collection.height);
1587
+ },
1588
+
1589
+ setEditMode : function(mode, context) {
1590
+ this.editmode_manager.set(mode, context);
1591
+ },
1592
+
1593
+ getFocusTarget : function() {
1594
+ return this.focusLayer.getFocusTarget();
1595
+ },
1596
+
1597
+ toDataUrl : function(callback) {
1598
+ this.stage.toDataURL({
1599
+ callback : callback
1600
+ });
1601
+ }
1602
+ });
1603
+
1604
+ Delo.CommandAdd = Delo.Command.extend({
1605
+ execute : function() {
1606
+ if(this._params.model instanceof Array) {
1607
+ for(var i = 0;i < this._params.model.length;i++) {
1608
+ this._params.collection.add(this._params.model[i]);
1609
+ }
1610
+ } else {
1611
+ this._params.collection.add(this._params.model);
1612
+ }
1613
+ },
1614
+
1615
+ unexecute : function() {
1616
+ if(this._params.model instanceof Array) {
1617
+ for(var i = 0;i < this._params.model.length;i++) {
1618
+ this._params.collection.remove(this._params.model[i]);
1619
+ }
1620
+ } else {
1621
+ this._params.collection.remove(this._params.model);
1622
+ }
1623
+ }
1624
+ });
1625
+
1626
+
1627
+ Delo.CommandDocPropertyChange = Delo.Command.extend({
1628
+ execute : function() {
1629
+ var changes = this._params.changes;
1630
+ var document = this._params.document;
1631
+ var docview = this._params.docview;
1632
+
1633
+ for(var i = 0;i < changes.length;i++) {
1634
+ var change = changes[i];
1635
+ var property = change.property;
1636
+ var after = change.after;
1637
+
1638
+ document[property] = after;
1639
+
1640
+ switch(property) {
1641
+ case 'width' :
1642
+ case 'height' :
1643
+ docview.set_size(document.width, document.height);
1644
+ break;
1645
+ }
1646
+ }
1647
+ },
1648
+
1649
+ unexecute : function() {
1650
+ var changes = this._params.changes;
1651
+ var document = this._params.document;
1652
+ var docview = this._params.docview;
1653
+
1654
+ for(var i = 0;i < changes.length;i++) {
1655
+ var change = changes[i];
1656
+ var property = change.property;
1657
+ var before = change.before;
1658
+
1659
+ document[property] = before;
1660
+
1661
+ switch(property) {
1662
+ case 'width' :
1663
+ case 'height' :
1664
+ docview.set_size(document.width, document.height);
1665
+ break;
1666
+ }
1667
+ }
1668
+ }
1669
+ });
1670
+
1671
+ Delo.CommandMove = Delo.Command.extend({
1672
+ execute : function() {
1673
+ var x = this._params.newx;
1674
+ var y = this._params.newy;
1675
+
1676
+ this._params.collection.add(this._params.model);
1677
+ },
1678
+
1679
+ unexecute : function() {
1680
+ this._params.collection.remove(this._params.model);
1681
+ }
1682
+ });
1683
+
1684
+ Delo.CommandPropertyChange = Delo.Command.extend({
1685
+ execute : function() {
1686
+ var changes = this._params.changes;
1687
+
1688
+ for(var i = 0;i < changes.length;i++) {
1689
+ var change = changes[i];
1690
+ var property = change.property;
1691
+ var after = change.after;
1692
+
1693
+ if(property) {
1694
+ change.model.set(property, after);
1695
+ } else {
1696
+ change.model.set(after);
1697
+ }
1698
+ }
1699
+ },
1700
+
1701
+ unexecute : function() {
1702
+ var changes = this._params.changes;
1703
+
1704
+ for(var i = 0;i < changes.length;i++) {
1705
+ var change = changes[i];
1706
+ var property = change.property;
1707
+ var before = change.before;
1708
+
1709
+ if(property) {
1710
+ change.model.set(property, before);
1711
+ } else {
1712
+ change.model.set(before);
1713
+ }
1714
+ }
1715
+ }
1716
+ });
1717
+
1718
+ // TODO 빼고 넣는 Index를 고려해야 한다.
1719
+ Delo.CommandRemove = Delo.Command.extend({
1720
+ execute : function() {
1721
+ if(this._params.model instanceof Array) {
1722
+ for(var i = 0;i < this._params.model.length;i++) {
1723
+ this._params.collection.remove(this._params.model[i]);
1724
+ }
1725
+ } else {
1726
+ this._params.collection.remove(this._params.model);
1727
+ }
1728
+ },
1729
+
1730
+ unexecute : function() {
1731
+ if(this._params.model instanceof Array) {
1732
+ for(var i = 0;i < this._params.model.length;i++) {
1733
+ this._params.collection.add(this._params.model[i]);
1734
+ }
1735
+ } else {
1736
+ this._params.collection.add(this._params.model);
1737
+ }
1738
+ }
1739
+ });
1740
+
1741
+ Delo.CommandResize = Delo.Command.extend({
1742
+ execute : function() {
1743
+ // this._params.collection.add(this._params.model);
1744
+ },
1745
+
1746
+ unexecute : function() {
1747
+ // this._params.collection.remove(this._params.model);
1748
+ }
1749
+ });
1750
+
1751
+ Barcode = Delo.Part.extend({
1752
+ defaults : {
1753
+ x : 0,
1754
+ y : 0,
1755
+ symbol : 'code128',
1756
+ text : '1234567890',
1757
+ alttext : '1234567890',
1758
+ scale_h : 2,
1759
+ scale_w : 2,
1760
+ rotation : 'N',
1761
+ includetext : true,
1762
+ includecheckintext : true,
1763
+ includecheck : true,
1764
+ parsefnc : true,
1765
+ segments : 4,
1766
+ showborder : true,
1767
+ version : 'iata',
1768
+ barcolor : '#FF0000',
1769
+ rows : 32,
1770
+ columns : 8,
1771
+ // height : 0.5,
1772
+ height : 64,
1773
+ width : 64,
1774
+ backgroundcolor : 'DD000011',
1775
+ format : 'full',
1776
+ ccversion : 'b',
1777
+ cccolumns : 4,
1778
+ numeric : true,
1779
+ guardwhitespace : true
1780
+ }
1781
+ }, {
1782
+ partType : 'Barcode'
1783
+ });
1784
+
1785
+ Delo.Box = Delo.Part.extend({
1786
+ defaults : {
1787
+ x : 0,
1788
+ y : 0,
1789
+ width : 100,
1790
+ height : 100,
1791
+ stroke : 'black',
1792
+ fill : 'red',
1793
+ strokeWidth : 3,
1794
+ rotationDeg : 0
1795
+ }
1796
+ }, {
1797
+ partType : 'Delo.Box'
1798
+ });
1799
+ Delo.Ellipse = Delo.Part.extend({
1800
+ defaults : {
1801
+ x : 0,
1802
+ y : 0,
1803
+ radius : [50, 70],
1804
+ width : 100,
1805
+ height : 140,
1806
+ stroke : 'black',
1807
+ fill : 'red',
1808
+ strokeWidth : 3,
1809
+ rotationDeg : 0
1810
+ },
1811
+
1812
+ adjustAttrs : function(attrs) {
1813
+ if(attrs.x !== undefined) {
1814
+ attrs.x -= this.get('width') / 2
1815
+ }
1816
+ if(attrs.y !== undefined) {
1817
+ attrs.y -= this.get('height') / 2
1818
+ }
1819
+
1820
+ return attrs;
1821
+ }
1822
+
1823
+ }, {
1824
+ partType : 'Delo.Ellipse'
1825
+ });
1826
+ Delo.Image = Delo.Part.extend({
1827
+ defaults : {
1828
+ x : 0,
1829
+ y : 0,
1830
+ width : 100,
1831
+ height : 100,
1832
+ stroke : 'black',
1833
+ strokeWidth : 3,
1834
+ rotationDeg : 0,
1835
+ url : 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
1836
+ }
1837
+ }, {
1838
+ partType : 'Delo.Image'
1839
+ });
1840
+ Delo.Line = Delo.Part.extend({
1841
+ defaults : {
1842
+ x : 0,
1843
+ y : 0,
1844
+ width : 100,
1845
+ height : 100,
1846
+ stroke : 'black',
1847
+ strokeWidth : 10
1848
+ }
1849
+ }, {
1850
+ partType : 'Delo.Line'
1851
+ });
1852
+ Delo.Text = Delo.Part.extend({
1853
+ defaults : {
1854
+ x : 0,
1855
+ y : 0,
1856
+ fontSize : 30,
1857
+ fontFamily : 'Calibri',
1858
+ fill : 'black',
1859
+ stroke : 'black',
1860
+ text : 'ABCDEFG',
1861
+ rotationDeg : 0
1862
+ }
1863
+ }, {
1864
+ partType : 'Delo.Text'
1865
+ });
1866
+
1867
+ Delo.FocusLayer = function(config) {
1868
+ this._initFocusLayer(config);
1869
+ };
1870
+
1871
+ Delo.FocusLayer.prototype = {
1872
+ _initFocusLayer : function(config) {
1873
+ config.id = 'focus_layer';
1874
+
1875
+ // call super constructor
1876
+ Kinetic.Layer.call(this, config);
1877
+
1878
+ var target = this.getFocusTarget(); /* 문서화되지 않은 접근 */
1879
+ target.setAttribute('tabindex', 0);
1880
+ target.addEventListener("click", function(e) {
1881
+ target.focus();
1882
+ });
1883
+
1884
+ if(config.keydown_handler) {
1885
+ target.addEventListener('keydown', config.keydown_handler);
1886
+ }
1887
+
1888
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
1889
+ },
1890
+
1891
+ getFocusTarget : function() {
1892
+ return this.getCanvas()._canvas;
1893
+ }
1894
+ };
1895
+
1896
+ Kinetic.Util.extend(Delo.FocusLayer, Kinetic.Layer);
1897
+
1898
+ Delo.HandleLayer = function(config) {
1899
+ this._initHandleLayer(config);
1900
+ };
1901
+
1902
+ Delo.HandleLayer.prototype = {
1903
+ _initHandleLayer : function(config) {
1904
+ config.id = 'handle_layer';
1905
+
1906
+ // call super constructor
1907
+ Kinetic.Layer.call(this, config);
1908
+
1909
+ /* set event handlers */
1910
+ var docview = this.getAttr('docview');
1911
+ var document = this.getAttr('document');
1912
+ var command_manager = this.getAttr('command_manager');
1913
+ var editmode_manager = this.getAttr('editmode_manager');
1914
+ var selection_manager = this.getAttr('selection_manager');
1915
+ var partsLayer = this.getAttr('parts_layer');
1916
+
1917
+ docview.on('selectionchange', _.bind(this._select, this));
1918
+ document.bind('reset', this._reset, this);
1919
+
1920
+ /* 핸들이 없는 노드에 클릭 이벤트가 발생했을 때의 동작을 정의한다. */
1921
+ partsLayer.on('click', _.bind(function(e) {
1922
+ if(editmode_manager.get().mode !== Delo.EDITMODE.SELECT) {
1923
+ return;
1924
+ }
1925
+
1926
+ if(e.shiftKey) {
1927
+ selection_manager.toggle(e.targetNode);
1928
+ } else {
1929
+ selection_manager.select(e.targetNode);
1930
+ }
1931
+ }, this));
1932
+
1933
+ /* 이미 존재하는 핸들에 클릭 이벤트가 발생했을 때의 동작을 정의한다. */
1934
+ this.on('click', _.bind(function(e) {
1935
+ var handle = e.targetNode.getParent();
1936
+
1937
+ if(editmode_manager.get().mode !== Delo.EDITMODE.SELECT) {
1938
+ return;
1939
+ }
1940
+
1941
+ if(e.shiftKey) {
1942
+ selection_manager.toggle(handle.target);
1943
+ } else {
1944
+ selection_manager.select(handle.target);
1945
+ }
1946
+ }, this));
1947
+
1948
+ /*
1949
+ PartsLayer에서 Part의 드래깅이 발생한 경우에 대한 처리이다.
1950
+ 1. 드래깅이 시작될 때는 해당 파트를 선택되도록 한다.
1951
+ 2. 드래깅이 진행될 때는 해당 파트의 핸들들이 따라오도록 한다.
1952
+ 3. 드리깅이 완료되면, 모델의 위치 정보를 수정한다.
1953
+ */
1954
+ new Delo.DragTracker({
1955
+ ondragstart : function(e) {
1956
+
1957
+ var model = e.targetNode.getAttr('model');
1958
+ if(!model)
1959
+ return;
1960
+
1961
+ if(!this.findHandleByPart(e.targetNode)) {
1962
+ if(e.shiftKey) {
1963
+ selection_manager.toggle(e.targetNode);
1964
+ } else {
1965
+ selection_manager.select(e.targetNode);
1966
+ }
1967
+ }
1968
+ },
1969
+
1970
+ ondragmove : function(e) {
1971
+
1972
+ var part = e.targetNode;
1973
+ var model = part.getAttr('model');
1974
+
1975
+ var dx = part.getAttr('x') - model.get('x');
1976
+ var dy = part.getAttr('y') - model.get('y');
1977
+
1978
+ var sels = selection_manager.get();
1979
+
1980
+ var delta = {
1981
+ x : dx,
1982
+ y : dy
1983
+ };
1984
+
1985
+ for(var i = 0;i < sels.length;i++) {
1986
+ var node = sels[i];
1987
+ var handle = this.findHandleByPart(node);
1988
+ var model = sels[i].getAttr('model');
1989
+
1990
+ if(handle) {
1991
+ var attrs = {};
1992
+
1993
+ for(var attr in delta) {
1994
+ attrs[attr] = model.get(attr) + delta[attr];
1995
+ }
1996
+
1997
+ node.setAttrs(attrs);
1998
+ handle.setAttrs(attrs);
1999
+ handle.setHandlePositions();
2000
+ }
2001
+ }
2002
+ },
2003
+
2004
+ ondragend : function(e) {
2005
+
2006
+ var node = e.targetNode;
2007
+ var model = e.targetNode.getAttr('model');
2008
+
2009
+ if(!model)
2010
+ return;
2011
+
2012
+ var dx = node.getAttr('x') - model.get('x');
2013
+ var dy = node.getAttr('y') - model.get('y');
2014
+
2015
+ var sels = selection_manager.get();
2016
+
2017
+ var changes = this.buildPropertyChangeSet(sels, {
2018
+ x : dx,
2019
+ y : dy
2020
+ });
2021
+
2022
+ command_manager.execute(new Delo.CommandPropertyChange({
2023
+ changes : changes
2024
+ }));
2025
+ },
2026
+
2027
+ self : this
2028
+ }).on(partsLayer);
2029
+
2030
+ /*
2031
+ HandleLayer에서 Handle의 드래깅이 발생한 경우에 대한 처리이다.
2032
+ 1. 드래깅이 시작될 때는 해당 파트를 선택되도록 한다.
2033
+ 2. 드래깅이 진행될 때는 해당 파트의 핸들들이 따라오도록 한다.
2034
+ 3. 드리깅이 완료되면, 모델의 위치 정보를 수정한다.
2035
+ */
2036
+
2037
+ new Delo.DragTracker({
2038
+ ondragmove : function(e) {
2039
+ var handle = e.targetNode.getParent();
2040
+ var model = handle.target.getAttr('model');
2041
+
2042
+ var delta = handle.getHandleDelta(e.targetNode);
2043
+ var sels = selection_manager.get();
2044
+
2045
+ for(var i = 0;i < sels.length;i++) {
2046
+ var node = sels[i];
2047
+ var handle = this.findHandleByPart(node);
2048
+
2049
+ if(handle) {
2050
+ var attrs = {};
2051
+
2052
+ for(var attr in delta) {
2053
+ attrs[attr] = node.getAttr(attr) + delta[attr];
2054
+ }
2055
+
2056
+ node.setAttrs(attrs);
2057
+ handle.setAttrs(attrs);
2058
+ handle.setHandlePositions();
2059
+ }
2060
+ }
2061
+ },
2062
+
2063
+ ondragend : function(e) {
2064
+ var handle = e.targetNode.getParent();
2065
+ var model = e.targetNode.getAttr('model');
2066
+
2067
+ var delta = handle.getModelDelta(e.targetNode);
2068
+ var sels = selection_manager.get();
2069
+
2070
+ command_manager.execute(new Delo.CommandPropertyChange({
2071
+ changes : this.buildPropertyChangeSet(sels, delta)
2072
+ }));
2073
+ },
2074
+
2075
+ self : this
2076
+ }).on(this);
2077
+
2078
+ /*
2079
+ Handle의 타겟의 변화를 감지하여 핸들을 리프레쉬하도록 한다.
2080
+ */
2081
+
2082
+ partsLayer.on('change', _.bind(function(e) {
2083
+ var part = e.targetNode;
2084
+ var changed = e.after;
2085
+
2086
+ var handle = this.findHandleByPart(part);
2087
+
2088
+ if(!handle) {
2089
+ return;
2090
+ }
2091
+
2092
+ var attrs = {};
2093
+
2094
+ _.each(['x', 'y', 'width', 'height', 'rotation', 'rotationDeg'], function(attr) {
2095
+ if(changed[attr] !== undefined) {
2096
+ attrs[attr] = changed[attr];
2097
+ }
2098
+ });
2099
+
2100
+ if(_.keys(attrs).length == 0) {
2101
+ return;
2102
+ }
2103
+
2104
+ handle.setAttrs(attrs);
2105
+ handle.setHandlePositions();
2106
+ this.draw();
2107
+ }, this));
2108
+
2109
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
2110
+ },
2111
+
2112
+ _reset : function() {
2113
+ var handles = this.getChildren().toArray();
2114
+ for(var i = 0;i < handles.length;i++) {
2115
+ handles[i].fire('removed');
2116
+ handles[i].destroy();
2117
+ }
2118
+ this.draw();
2119
+ },
2120
+
2121
+ _select : function(e) {
2122
+
2123
+ var self = this;
2124
+
2125
+ e.removed.every(function(node) {
2126
+ self.removeHandleByPart(node);
2127
+ return true;
2128
+ });
2129
+
2130
+ e.added.every(function(node) {
2131
+ self.add(new Delo.Handle({
2132
+ target : node
2133
+ }));
2134
+ return true;
2135
+ });
2136
+
2137
+ this.draw();
2138
+ },
2139
+
2140
+ buildPropertyChangeSet : function(sels, delta) {
2141
+
2142
+ var changes = [];
2143
+
2144
+ for(var i = 0;i < sels.length;i++) {
2145
+ var node = sels[i];
2146
+ var model = node.getAttr('model');
2147
+
2148
+ var before = {};
2149
+ var after = {};
2150
+
2151
+ for(var attr in delta) {
2152
+ before[attr] = model.get(attr);
2153
+ after[attr] = model.get(attr) + delta[attr];
2154
+ }
2155
+
2156
+ changes.push({
2157
+ model : model,
2158
+ before : before,
2159
+ after : after
2160
+ });
2161
+ }
2162
+
2163
+ return changes;
2164
+ },
2165
+
2166
+ findHandleByPart : function(t) {
2167
+ var handles = this.getChildren().toArray();
2168
+ for(var i = 0;i < handles.length;i++) {
2169
+ if(handles[i].getAttr('target') === t) {
2170
+ return handles[i];
2171
+ }
2172
+ }
2173
+ },
2174
+
2175
+ removeHandleByPart : function(part) {
2176
+ var handle = this.findHandleByPart(part);
2177
+ if(handle) {
2178
+ handle.fire('removed');
2179
+ handle.destroy();
2180
+ }
2181
+ }
2182
+ };
2183
+
2184
+ Kinetic.Util.extend(Delo.HandleLayer, Kinetic.Layer);
2185
+
2186
+ Delo.PartsLayer = function(config) {
2187
+ this._initPartsLayer(config);
2188
+ };
2189
+
2190
+ Delo.PartsLayer.prototype = {
2191
+ _initPartsLayer : function(config) {
2192
+ this.partMap = {};
2193
+
2194
+ config.id = 'parts_layer';
2195
+
2196
+ // call super constructor
2197
+ Kinetic.Layer.call(this, config);
2198
+
2199
+ /* set event handlers */
2200
+ var document = this.getAttr('document');
2201
+ var mode = this.getAttr('mode');
2202
+
2203
+ document.bind('add', this._add, this);
2204
+ document.bind('remove', this._remove, this);
2205
+ document.bind('reset', this._reset, this);
2206
+
2207
+ this._reset();
2208
+
2209
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
2210
+ },
2211
+
2212
+ register: function(modelType, editpartClass) {
2213
+ this.partMap[modelType] = editpartClass;
2214
+ },
2215
+
2216
+ findByModel : function(models) {
2217
+ if(!models) {
2218
+ return null;
2219
+ }
2220
+
2221
+ if(!models instanceof Array) {
2222
+ models = [models];
2223
+ }
2224
+
2225
+ var nodes = this.getChildren().toArray();
2226
+ var selnodes = [];
2227
+
2228
+ for(var i = 0;i < models.length;i++) {
2229
+ var model = models[i];
2230
+ for(var j = 0;j < nodes.length;j++) {
2231
+ if(nodes[j].getAttr('model') === model) {
2232
+ selnodes.push(nodes[j]);
2233
+ }
2234
+ }
2235
+ }
2236
+
2237
+ return selnodes;
2238
+ },
2239
+
2240
+ _reset : function() {
2241
+ // 뷰를 클리어하기 전에 리소스들을 해제할 수 있는 기회를 제공해야 한다. removed 이벤트 fire
2242
+ this.removeChildren();
2243
+ this.draw();
2244
+ },
2245
+
2246
+ _add : function(m) {
2247
+ var editPartClass = this.partMap[m.constructor.partType];
2248
+
2249
+ var node = new editPartClass({
2250
+ model: m,
2251
+ mode : this.getAttr('mode')
2252
+ });
2253
+ this.add(node);
2254
+
2255
+ this.draw();
2256
+ },
2257
+
2258
+ _remove : function(m) {
2259
+ this.draw();
2260
+ }
2261
+ };
2262
+
2263
+ Kinetic.Util.extend(Delo.PartsLayer, Kinetic.Layer);
2264
+
2265
+ Delo.RulerLayer = function(config) {
2266
+ this._initRulerLayer(config);
2267
+ };
2268
+
2269
+ Delo.RulerLayer.prototype = {
2270
+ mmPixel: 3.779527559,
2271
+
2272
+ _initRulerLayer : function(config) {
2273
+ this.partMap = {};
2274
+
2275
+ config.id = 'ruler_layer';
2276
+
2277
+ // call super constructor
2278
+ Kinetic.Layer.call(this, config);
2279
+
2280
+ /* set event handlers */
2281
+ var stage = this.getAttr('target_stage');
2282
+ var document = this.getAttr('document');
2283
+
2284
+ this.add(new Kinetic.Rect({
2285
+ offset : [14, 14],
2286
+ fill : '#f3f4f6',
2287
+ x : 0,
2288
+ y : 0,
2289
+ width : stage.getWidth(),
2290
+ height : 14
2291
+ }));
2292
+
2293
+ this.add(this.makeHRuler());
2294
+
2295
+ this.add(new Kinetic.Rect({
2296
+ offset : [14, 14],
2297
+ fill : '#f3f4f6',
2298
+ x : 0,
2299
+ y : 0,
2300
+ width : 14,
2301
+ height : stage.getHeight()
2302
+ }));
2303
+
2304
+ this.add(this.makeVRuler());
2305
+
2306
+ var hpoint = new Kinetic.Line({
2307
+ offset : [14, 14],
2308
+ points: [0, 0, 0, 15],
2309
+ stroke: '#ff0000',
2310
+ strokeWidth: 2,
2311
+ opacity: 1,
2312
+ draggable: false
2313
+ });
2314
+ this.add(hpoint);
2315
+
2316
+ var vpoint = new Kinetic.Line({
2317
+ offset : [14, 14],
2318
+ points: [0, 0, 15, 0],
2319
+ stroke: '#ff0000',
2320
+ strokeWidth: 2,
2321
+ opacity: 1,
2322
+ draggable: false
2323
+ });
2324
+ this.add(vpoint);
2325
+
2326
+ new Delo.DragTracker({
2327
+ ondragmove : function(evt) {
2328
+ hpoint.setPosition(evt.layerX, 0);
2329
+ vpoint.setPosition(0, evt.layerY);
2330
+
2331
+ this.draw();
2332
+ },
2333
+ self : this
2334
+ }).on(stage);
2335
+
2336
+ stage.on('mousemove', function(evt) {
2337
+ hpoint.setPosition(evt.layerX, 0);
2338
+ vpoint.setPosition(0, evt.layerY);
2339
+
2340
+ this.draw();
2341
+ });
2342
+
2343
+ document.bind('reset', this._reset, this);
2344
+
2345
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
2346
+ },
2347
+
2348
+ _reset : function() {
2349
+ this.draw();
2350
+ },
2351
+
2352
+ makeHRuler: function() {
2353
+ var mmPixel = this.mmPixel;
2354
+
2355
+ return new Kinetic.Shape({
2356
+ offset : [0, 14],
2357
+ drawFunc: function(context) {
2358
+ var startX = 0;
2359
+ var plusWidth = context.getCanvas().width - startX;
2360
+ var plusCount = Math.ceil(plusWidth / mmPixel);
2361
+
2362
+ context.beginPath();
2363
+ context.moveTo(startX, 0);
2364
+
2365
+ context.fillStyle = '#848586';
2366
+ context.font = '8px Verdana';
2367
+
2368
+ for (var i = 0; i < plusCount; i++) {
2369
+ if (i % 10 == 0) {
2370
+ context.moveTo(startX + i * mmPixel, 0);
2371
+ context.lineTo(startX + i * mmPixel, 15);
2372
+ context.fillText(i / 10 + '', startX + i * mmPixel + 2, 11, 12);
2373
+ } else if (i % 5 == 0) {
2374
+ context.moveTo(startX + i * mmPixel, 9);
2375
+ context.lineTo(startX + i * mmPixel, 15);
2376
+ } else {
2377
+ context.moveTo(startX + i * mmPixel, 12);
2378
+ context.lineTo(startX + i * mmPixel, 15);
2379
+ }
2380
+ }
2381
+ var minusWidth = startX;
2382
+ var minusCount = Math.floor(minusWidth / mmPixel);
2383
+ context.moveTo(startX, 0);
2384
+ for (var j = 1; j < minusCount; j++) {
2385
+ if (startX - j * mmPixel < 15) {
2386
+ break;
2387
+ }
2388
+ if (j % 10 == 0) {
2389
+ context.moveTo(startX - j * mmPixel, 0);
2390
+ context.lineTo(startX - j * mmPixel, 15);
2391
+ context.fillText('-' + j / 10, startX - j * mmPixel + 2, 11, 12);
2392
+ } else if (j % 5 == 0) {
2393
+ context.moveTo(startX - j * mmPixel, 9);
2394
+ context.lineTo(startX - j * mmPixel, 15);
2395
+ } else {
2396
+ context.moveTo(startX - j * mmPixel, 12);
2397
+ context.lineTo(startX - j * mmPixel, 15);
2398
+ }
2399
+ }
2400
+ context.closePath();
2401
+ context.fillStrokeShape(this);
2402
+ },
2403
+ fill: '#FAF602',
2404
+ stroke: '#c2c3c5',
2405
+ strokeWidth: 0.5,
2406
+ x: 0
2407
+ });
2408
+ },
2409
+
2410
+ makeVRuler: function() {
2411
+ var mmPixel = this.mmPixel;
2412
+
2413
+ return new Kinetic.Shape({
2414
+ offset : [14, 0],
2415
+ drawFunc: function(context) {
2416
+ var startY = 0;
2417
+ var plusHeight = context.getCanvas().height - startY;
2418
+ var plusCount = Math.ceil(plusHeight / mmPixel);
2419
+
2420
+ context.beginPath();
2421
+ context.moveTo(0, startY);
2422
+
2423
+ context.fillStyle = '#848586';
2424
+ context.font = '8px Verdana';
2425
+
2426
+ for (var i = 0; i < plusCount; i++) {
2427
+ if (i % 10 == 0) {
2428
+ context.moveTo(0, startY + i * mmPixel);
2429
+ context.lineTo(15, startY + i * mmPixel);
2430
+ context.fillText(i / 10 + '', 1, startY + i * mmPixel + 12, 12)
2431
+ } else if (i % 5 == 0) {
2432
+ context.moveTo(9, startY + i * mmPixel);
2433
+ context.lineTo(15, startY + i * mmPixel);
2434
+ } else {
2435
+ context.moveTo(12, startY + i * mmPixel);
2436
+ context.lineTo(15, startY + i * mmPixel);
2437
+ }
2438
+ }
2439
+ var minusHeight = startY;
2440
+ var minusCount = Math.floor(minusHeight / mmPixel);
2441
+ context.moveTo(0, startY);
2442
+ for (var j = 1; j < minusCount; j++) {
2443
+ if (startY - j * mmPixel < 15) {
2444
+ break;
2445
+ }
2446
+ if (j % 10 == 0) {
2447
+ context.moveTo(0, startY - j * mmPixel);
2448
+ context.lineTo(15, startY - j * mmPixel);
2449
+ context.fillText('-' + j / 10, 1, startY - j * mmPixel + 12, 12);
2450
+ } else if (j % 5 == 0) {
2451
+ context.moveTo(9, startY - j * mmPixel);
2452
+ context.lineTo(15, startY - j * mmPixel);
2453
+ } else {
2454
+ context.moveTo(12, startY - j * mmPixel);
2455
+ context.lineTo(15, startY - j * mmPixel);
2456
+ }
2457
+ }
2458
+ context.closePath();
2459
+ context.fillStrokeShape(this);
2460
+ },
2461
+ fill: '#FAF602',
2462
+ stroke: '#c2c3c5',
2463
+ strokeWidth: 0.5,
2464
+ x: 0
2465
+ });
2466
+ return shape;
2467
+ }
2468
+ };
2469
+
2470
+ Kinetic.Util.extend(Delo.RulerLayer, Kinetic.Layer);
2471
+
2472
+
2473
+ Delo.ScrollLayer = function(config) {
2474
+ this._initScrollLayer(config);
2475
+ };
2476
+
2477
+ Delo.ScrollLayer.prototype = {
2478
+ _initScrollLayer : function(config) {
2479
+ this.partMap = {};
2480
+
2481
+ config.id = 'scroll_layer';
2482
+
2483
+ // call super constructor
2484
+ Kinetic.Layer.call(this, config);
2485
+
2486
+ /* set event handlers */
2487
+ var stage = this.getStage();
2488
+ var document = this.getAttr('document');
2489
+
2490
+ var areas = new Kinetic.Group();
2491
+ var scrollbars = new Kinetic.Group();
2492
+
2493
+ var hscrollArea = new Kinetic.Rect({
2494
+ x: 0,
2495
+ y: stage.getHeight() - 20,
2496
+ width: stage.getWidth(),
2497
+ height: 20,
2498
+ fill: 'black',
2499
+ opacity: 0.3
2500
+ });
2501
+
2502
+ var hscroll = new Kinetic.Rect({
2503
+ x: 0,
2504
+ y: stage.getHeight() - 20,
2505
+ width: 140,
2506
+ height: 20,
2507
+ fill: '#9f005b',
2508
+ draggable: true,
2509
+
2510
+ dragBoundFunc: function(pos) {
2511
+ var newX = pos.x;
2512
+ if (newX < 0) {
2513
+ newX = 0;
2514
+ } else if (newX > stage.getWidth() - 160) {
2515
+ newX = stage.getWidth() - 160;
2516
+ }
2517
+ return {
2518
+ x: newX,
2519
+ y: this.getAbsolutePosition().y
2520
+ }
2521
+ },
2522
+ opacity: 0.9,
2523
+ stroke: 'black',
2524
+ strokeWidth: 1
2525
+ });
2526
+
2527
+ var vscrollArea = new Kinetic.Rect({
2528
+ x: stage.getWidth() - 20,
2529
+ y: 0,
2530
+ width: 20,
2531
+ height: stage.getHeight(),
2532
+ fill: 'black',
2533
+ opacity: 0.3
2534
+ });
2535
+
2536
+ var vscroll = new Kinetic.Rect({
2537
+ x: stage.getWidth() - 20,
2538
+ y: 0,
2539
+ width: 20,
2540
+ height: 80,
2541
+ fill: '#9f005b',
2542
+ draggable: true,
2543
+ dragBoundFunc: function(pos) {
2544
+ var newY = pos.y;
2545
+ if (newY < 0) {
2546
+ newY = 0;
2547
+ } else if (newY > stage.getHeight() - 100) {
2548
+ newY = stage.getHeight() - 100;
2549
+ }
2550
+ return {
2551
+ x: this.getAbsolutePosition()
2552
+ .x,
2553
+ y: newY
2554
+ }
2555
+ },
2556
+ opacity: 0.9,
2557
+ stroke: 'black',
2558
+ strokeWidth: 1
2559
+ });
2560
+
2561
+ scrollbars.on('mouseover', function() {
2562
+ document.body.style.cursor = 'pointer';
2563
+ });
2564
+
2565
+ scrollbars.on('mouseout', function() {
2566
+ document.body.style.cursor = 'default';
2567
+ });
2568
+
2569
+ var updateBackgroundPos = function() {
2570
+ var x = -1 * (hscroll.getPosition().x);
2571
+ var y = -1 * (vscroll.getPosition().y);
2572
+
2573
+ targetLayer.setOffset(-x, -y);
2574
+ targetLayer.draw();
2575
+ // container.style.backgroundPosition = x + 'px ' + y + 'px';
2576
+ };
2577
+
2578
+ hscroll.on('dragmove', updateBackgroundPos);
2579
+ vscroll.on('dragmove', updateBackgroundPos);
2580
+
2581
+ areas.add(hscrollArea);
2582
+ areas.add(vscrollArea);
2583
+ scrollbars.add(hscroll);
2584
+ scrollbars.add(vscroll);
2585
+ this.add(areas);
2586
+ this.add(scrollbars);
2587
+
2588
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
2589
+ },
2590
+
2591
+ _reset : function() {
2592
+
2593
+ }
2594
+ };
2595
+
2596
+ Kinetic.Util.extend(Delo.ScrollLayer, Kinetic.Layer);
2597
+
2598
+ Delo.SelectionLayer = function(config) {
2599
+ this._initSelectionLayer(config);
2600
+ };
2601
+
2602
+ Delo.SelectionLayer.prototype = {
2603
+ _initSelectionLayer : function(config) {
2604
+ config.id = 'selection_layer';
2605
+
2606
+ // call super constructor
2607
+ Kinetic.Layer.call(this, config);
2608
+
2609
+ /* set event handlers */
2610
+ var stage = this.getStage();
2611
+ var document = this.getAttr('document');
2612
+
2613
+ document.bind('reset', this._reset, this);
2614
+
2615
+ this._reset();
2616
+
2617
+ // TODO stage나 model이 destroy 될 때 이벤트핸들러들을 모두 해제시켜주어야 한다.
2618
+ },
2619
+
2620
+ _reset : function() {
2621
+ this.removeChildren();
2622
+
2623
+ var background = new Kinetic.Rect({
2624
+ width: this.getAttr('document').width,
2625
+ height: this.getAttr('document').height,
2626
+ fill: 'white',
2627
+ stroke: 'black',
2628
+ strokeWidth: 1,
2629
+ name: 'background',
2630
+ x : 0,
2631
+ y : 0,
2632
+ draggable: true,
2633
+ dragBoundFunc: function(pos) {
2634
+ return {
2635
+ x: this.getX(),
2636
+ y: this.getY()
2637
+ }
2638
+ }
2639
+ });
2640
+
2641
+ this.add(background);
2642
+
2643
+ background.on('click', _.bind(function(e) {
2644
+ if(!e.shiftKey) {
2645
+ // 아무것도 선택하지 않도록 한다.
2646
+ this.getAttr('selection_manager').select();
2647
+ }
2648
+ }, this));
2649
+
2650
+
2651
+ function containes(r1, r2) {
2652
+ var r1x1 = Math.min(r1.x, r1.x + r1.width);
2653
+ var r2x1 = Math.min(r2.x, r2.x + r2.width);
2654
+
2655
+ if(r1x1 > r2x1)
2656
+ return false;
2657
+
2658
+ var r1x2 = Math.max(r1.x, r1.x + r1.width);
2659
+ var r2x2 = Math.max(r2.x, r2.x + r2.width);
2660
+
2661
+ if(r1x2 < r2x2)
2662
+ return false;
2663
+
2664
+ var r1y1 = Math.min(r1.y, r1.y + r1.height);
2665
+ var r2y1 = Math.min(r2.y, r2.y + r2.height);
2666
+
2667
+ if(r1y1 > r2y1)
2668
+ return false;
2669
+
2670
+ var r1y2 = Math.max(r1.y, r1.y + r1.height);
2671
+ var r2y2 = Math.max(r2.y, r2.y + r2.height);
2672
+
2673
+ if(r1y2 < r2y2)
2674
+ return false;
2675
+
2676
+ return true;
2677
+ }
2678
+
2679
+ new Delo.DragTracker({
2680
+ ondragstart : function(e) {
2681
+ if(this._selectbox) {
2682
+ this._selectbox.remove();
2683
+ this._selectbox = undefined;
2684
+ }
2685
+
2686
+ this._selectbox = new Kinetic.Rect({
2687
+ x : e.offsetX,
2688
+ y : e.offsetY,
2689
+ stroke : 'black',
2690
+ strokeWidth : 1,
2691
+ dashArray : [3, 3],
2692
+ name : 'selectbox',
2693
+ opacity : 0.5,
2694
+ width : 0,
2695
+ height : 0
2696
+ });
2697
+
2698
+ this.add(this._selectbox);
2699
+ },
2700
+
2701
+ ondragmove : function(e) {
2702
+ var bound = {}
2703
+ bound.x = this._selectbox.getX();
2704
+ bound.y = this._selectbox.getY();
2705
+ bound.width = e.offsetX - this._selectbox.getX();
2706
+ bound.height = e.offsetY - this._selectbox.getY();
2707
+
2708
+ this._selectbox.setAttrs({
2709
+ width : bound.width,
2710
+ height : bound.height
2711
+ });
2712
+
2713
+ var nodes = [];
2714
+ this.getAttr('parts_layer').getChildren().each(function(node) {
2715
+ if(containes(bound, {
2716
+ x : node.getX(),
2717
+ y : node.getY(),
2718
+ width : node.getWidth(),
2719
+ height : node.getHeight()
2720
+ })) {
2721
+ nodes.push(node);
2722
+ }
2723
+ });
2724
+
2725
+ this.getAttr('selection_manager').select(nodes);
2726
+ },
2727
+
2728
+ ondragend : function(e) {
2729
+ this._selectbox.remove();
2730
+ this._selectbox = undefined;
2731
+
2732
+ this.draw();
2733
+ },
2734
+
2735
+ self : this
2736
+ }).on(background);
2737
+
2738
+ this.draw();
2739
+ }
2740
+ };
2741
+
2742
+ Kinetic.Util.extend(Delo.SelectionLayer, Kinetic.Layer);
2743
+
2744
+ var bwip = require('bwip');
2745
+
2746
+ BarcodeView = function(config) {
2747
+ this.build(config);
2748
+ };
2749
+
2750
+ BarcodeView.prototype = {
2751
+ handleset : [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2752
+
2753
+ build : function(config) {
2754
+ var model = config.model;
2755
+ var attributes = {
2756
+ name: 'image',
2757
+ draggable: (config.mode != 'view'),
2758
+ x : model.get('x'),
2759
+ y : model.get('y')
2760
+ };
2761
+
2762
+ // call super constructor
2763
+ Kinetic.Image.call(this, attributes);
2764
+ // this.shapeType = 'BarcodeView';
2765
+
2766
+ this.setAttr('model', model);
2767
+
2768
+ var self = this;
2769
+
2770
+ this.imageObj = new Image();
2771
+
2772
+ this.imageObj.onload = function() {
2773
+ self.setImage(self.imageObj);
2774
+ model.set({
2775
+ width : self.imageObj.width,
2776
+ height : self.imageObj.height
2777
+ });
2778
+ self.getLayer().draw();
2779
+ };
2780
+
2781
+ this.imageObj.src = this.buildImageUrl();
2782
+
2783
+ /* set event handlers */
2784
+ model.bind('remove', this._remove, this);
2785
+ model.bind('change', this._change, this);
2786
+ },
2787
+
2788
+ buildImageUrl : function() {
2789
+ var model = this.getAttr('model');
2790
+
2791
+ return global.bwip.base64({
2792
+ symbol : model.get('symbol'),
2793
+ text : model.get('text'),
2794
+ alttext : model.get('alttext'),
2795
+ scale_h : model.get('scale_h'),
2796
+ scale_w : model.get('scale_w'),
2797
+ rotation : model.get('rotation')
2798
+ });
2799
+ },
2800
+
2801
+ _change : function(e) {
2802
+ var changed = e.changed;
2803
+
2804
+ // TODO 이미지 변경 조건이 불분명함.
2805
+ if(!changed.x && !changed.y) {
2806
+ this.imageObj.src = this.buildImageUrl();
2807
+ }
2808
+
2809
+ Delo.PartView.prototype._change.call(this, e);
2810
+ }
2811
+ };
2812
+
2813
+ Kinetic.Util.extend(BarcodeView, Delo.PartView);
2814
+ Kinetic.Util.extend(BarcodeView, Kinetic.Image);
2815
+
2816
+ Delo.BoxView = function(config) {
2817
+ this.build(config);
2818
+ };
2819
+
2820
+ Delo.BoxView.prototype = {
2821
+ build : function(config) {
2822
+ var model = config.model;
2823
+
2824
+ // call super constructor
2825
+ Kinetic.Rect.call(this, config.model.attributes);
2826
+
2827
+ this.setDraggable(config.mode != 'view');
2828
+ this.setAttr('model', model);
2829
+
2830
+ // this.shapeType = 'BoxView';
2831
+ // this._setDrawFuncs();
2832
+
2833
+ /* set event handlers */
2834
+ model.bind('remove', this._remove, this);
2835
+ model.bind('change', this._change, this);
2836
+ // },
2837
+ //
2838
+ // onChangePost : function(e) {
2839
+ // // 모델이 변경되었을 때, 특별히 해당 뷰모델에서 추가로 할 작업을 정의한다.
2840
+ // return;
2841
+ // },
2842
+ //
2843
+ // _remove : function(e) {
2844
+ // this.remove();
2845
+ // },
2846
+ //
2847
+ // _change : function(e) {
2848
+ // this.setAttrs(e.changed);
2849
+ //
2850
+ // this.onChangePost(e);
2851
+ //
2852
+ // this.getLayer().draw();
2853
+ }
2854
+ };
2855
+
2856
+ Kinetic.Util.extend(Delo.BoxView, Delo.PartView);
2857
+ Kinetic.Util.extend(Delo.BoxView, Kinetic.Rect);
2858
+
2859
+
2860
+ Delo.EllipseView = function(config) {
2861
+ this.build(config);
2862
+ };
2863
+
2864
+ Delo.EllipseView.prototype = {
2865
+ build : function(config) {
2866
+ var model = config.model;
2867
+ var attributes = {
2868
+ width: model.get('width'),
2869
+ height: model.get('height'),
2870
+ fill: model.get('fill'),
2871
+ stroke: model.get('stroke'),
2872
+ strokeWidth: model.get('strokeWidth'),
2873
+ rotationDeg : model.get('rotationDeg'),
2874
+ // dashArray: [6, 6],
2875
+ // name: 'ellipse',
2876
+ draggable: (config.mode != 'view'),
2877
+ x : model.get('x'),
2878
+ y : model.get('y'),
2879
+ radius : [model.get('width') / 2, model.get('height') / 2],
2880
+ offset : {
2881
+ x : -model.get('width') / 2,
2882
+ y : -model.get('height') / 2
2883
+ }
2884
+ };
2885
+
2886
+ // call super constructor
2887
+ Kinetic.Ellipse.call(this, attributes);
2888
+
2889
+ this.setAttr('model', model);
2890
+
2891
+ // this.shapeType = 'BoxView';
2892
+ // this._setDrawFuncs();
2893
+
2894
+ /* set event handlers */
2895
+ model.bind('remove', this._remove, this);
2896
+ model.bind('change', this._change, this);
2897
+ },
2898
+
2899
+ adjust : function(attrs) {
2900
+ if(attrs.x !== undefined || attrs.y !== undefined || attrs.width !== undefined || attrs.height !== undefined) {
2901
+ var width = attrs.width === undefined ? this.getAttr('width') : attrs.width;
2902
+ var height = attrs.height === undefined ? this.getAttr('height') : attrs.height;
2903
+
2904
+ attrs.radius = [Math.abs(width / 2), Math.abs(height / 2)];
2905
+ attrs.offset = [-width / 2, -height / 2];
2906
+ }
2907
+ return attrs;
2908
+ }
2909
+ };
2910
+
2911
+ Kinetic.Util.extend(Delo.EllipseView, Delo.PartView);
2912
+ Kinetic.Util.extend(Delo.EllipseView, Kinetic.Ellipse);
2913
+
2914
+ Delo.ImageView = function(config) {
2915
+ this.build(config);
2916
+ };
2917
+
2918
+ Delo.ImageView.prototype = {
2919
+ build : function(config) {
2920
+ var model = config.model;
2921
+ var attributes = {
2922
+ x : model.get('x'),
2923
+ y : model.get('y'),
2924
+ width: model.get('width'),
2925
+ height: model.get('height'),
2926
+ rotationDeg : model.get('rotationDeg'),
2927
+ // name : 'image',
2928
+ draggable: (config.mode != 'view')
2929
+ };
2930
+
2931
+ // call super constructor
2932
+ Kinetic.Image.call(this, attributes);
2933
+
2934
+ this.setAttr('model', model);
2935
+
2936
+ var self = this;
2937
+
2938
+ var imageObj = new Image();
2939
+
2940
+ imageObj.onload = function() {
2941
+ self.setImage(imageObj);
2942
+ self.getLayer().draw();
2943
+ };
2944
+
2945
+ imageObj.src = model.get('url');
2946
+ // this.shapeType = 'BoxView';
2947
+ // this._setDrawFuncs();
2948
+
2949
+ /* set event handlers */
2950
+ model.bind('remove', this._remove, this);
2951
+ model.bind('change', this._change, this);
2952
+ }
2953
+ };
2954
+
2955
+ Kinetic.Util.extend(Delo.ImageView, Delo.PartView);
2956
+ Kinetic.Util.extend(Delo.ImageView, Kinetic.Image);
2957
+
2958
+ Delo.LineView = function(config) {
2959
+ this.build(config);
2960
+ };
2961
+
2962
+ Delo.LineView.prototype = {
2963
+ handleset : [0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
2964
+
2965
+ build : function(config) {
2966
+ var model = config.model;
2967
+ var attributes = {
2968
+ points : [[0, 0], [model.get('width'), model.get('height')]],
2969
+ fill: model.get('fill'),
2970
+ stroke: model.get('stroke'),
2971
+ strokeWidth: model.get('strokeWidth'),
2972
+ x : model.get('x'),
2973
+ y : model.get('y'),
2974
+ width : model.get('width'),
2975
+ height : model.get('height'),
2976
+ // dashArray: [6, 6],
2977
+ // name: 'line',
2978
+ draggable: (config.mode != 'view')
2979
+ };
2980
+
2981
+ // call super constructor
2982
+ Kinetic.Line.call(this, attributes);
2983
+
2984
+ this.setAttr('model', model);
2985
+
2986
+ // this.shapeType = 'BoxView';
2987
+ // this._setDrawFuncs();
2988
+
2989
+ /* set event handlers */
2990
+ model.bind('remove', this._remove, this);
2991
+ model.bind('change', this._change, this);
2992
+ },
2993
+
2994
+ adjust : function(attrs) {
2995
+ if(attrs.x !== undefined || attrs.y !== undefined || attrs.width !== undefined || attrs.height !== undefined) {
2996
+ attrs.width = attrs.width === undefined ? this.getAttr('width') : attrs.width;
2997
+ attrs.height = attrs.height === undefined ? this.getAttr('height') : attrs.height;
2998
+
2999
+ attrs.points = [[0, 0], [attrs.width, attrs.height]];
3000
+ }
3001
+ return attrs;
3002
+ }
3003
+ };
3004
+
3005
+ Kinetic.Util.extend(Delo.LineView, Delo.PartView);
3006
+ Kinetic.Util.extend(Delo.LineView, Kinetic.Line);
3007
+
3008
+ Delo.TextView = function(config) {
3009
+ this.build(config);
3010
+ };
3011
+
3012
+ Delo.TextView.prototype = {
3013
+ build : function(config) {
3014
+ var model = config.model;
3015
+
3016
+ // call super constructor
3017
+ Kinetic.Text.call(this, config.model.attributes);
3018
+
3019
+ this.setDraggable(config.mode != 'view');
3020
+ this.setAttr('model', model);
3021
+
3022
+ // this.shapeType = 'BoxView';
3023
+ // this._setDrawFuncs();
3024
+
3025
+ /* set event handlers */
3026
+ model.bind('remove', this._remove, this);
3027
+ model.bind('change', this._change, this);
3028
+ },
3029
+
3030
+ onChangePost : function(e) {
3031
+
3032
+ return;
3033
+ }
3034
+ };
3035
+
3036
+ Kinetic.Util.extend(Delo.TextView, Delo.PartView);
3037
+ Kinetic.Util.extend(Delo.TextView, Kinetic.Text);