123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218 |
- /*
- Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
- */
- if(!dojo._hasResource["dojox.drawing.stencil._Base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.drawing.stencil._Base"] = true;
- dojo.provide("dojox.drawing.stencil._Base");
- dojo.require("dojo.fx.easing");
- /*=====
- StencilArgs = {
- // container: [readonly] dojo.gfx.group
- // The parent shape that contains all
- // shapes used in a Stencil
- container:null,
- //
- // anchorType: String
- // Optionally blank or 'group'. 'group' tells
- // an anchor point that it must constrain
- // itself to other anchor points.
- anchorType:"",
- //
- // isText: Boolean
- // Whether this is a text object or not
- // (either stencil.text or tools.TextBlock)
- isText:false,
- //
- // shortType: String
- // The type of stencil that corresponds with the types and
- // constructors used in Drawing.registerTool
- shortType:"",
- //
- // annotation: Boolean
- // A Stencil used within a Stencil. An annotation
- // is not selectable or clickable. A Label would
- // be one example.
- annotation:false,
- //
- // subShape: Boolean
- // A Stencil used within a Stencil. A subShape
- // is clickable. An arrow head would be an example.
- subShape:false,
- //
- // style: Object
- // An instance of the styles and defaults used within
- // the Stencil.
- style:null,
- //
- // util: Object
- // Pointer to util.common
- util:null,
- //
- // mouse: Object
- // Pointer to the mouse instance
- mouse:null,
- //
- // keys: Object
- // Pointer to the keys class
- keys:null,
- //
- // points: StencilPoints
- // Points is an array of objects that make up the
- // description of a Stencil. The points to a Rect
- // that is 100x100 and at x:10 and y:10 would look like:
- // [{x:10,y:10}, {x:110, y:10}, {x:110, y:110}, {x:10, y:110}]
- // Points go clockwise from the top left. In the case of Paths,
- // they would go in the order that the Stencil would be drawn.
- // Always when the points Array is set, a data Object is created
- // as well. So never set points directly, always use setPoints().
- // See:
- // setPoints()
- points:[],
- //
- // data: StencilData
- // A data object typically (but not always) resembles the data
- // that is used to create the dojox.gfx Shape. The same Rect
- // example shown in points above would look like:
- // {x:10, y:10, width:100, height:100}
- // And an Ellipse with the same coordinates:
- // {cx:55, cy:55, rx:50, ry:50}
- // The only Stencil that does not support data (at this time)
- // is the Path. While x1,x2,x3... culd be used in a data object
- // it doesn't provide much benefit.
- // Always when a data object is set, a set of points is created
- // as well. So never set data directly, always use setData().
- // See:
- // setData()
- data:null,
- //
- // marginZero [readonly] Number
- // How closely shape can get to y:0 or x:0. Less than zero has
- // bugs in VML. This is set with defaults, and should be equal
- // to half the size of an anchor point (5 px)
- marginZero:0,
- //
- // created [readonly] Boolean
- // Whether the Stencil has been rendered for the first time or
- // not.
- created: false,
- //
- // highlighted [readonly] Boolean
- // Whether the Stencil is highlighted or not.
- highlighted:false,
- //
- // selected [readonly] Boolean
- // Whether the Stencil is selected or not.
- selected:false,
- //
- // draws [readonly] Boolean
- // Whether the Stencil can draw with a mouse drag or can just
- // be created programmtically. If the Stencil comes from the
- // stencil package, it should be draw:false. If it comes from
- // the tools package it should be draw:true.
- draws:false
- }
- StencilPoint = {
- // summary:
- // One point Object in the points Array
- // x: Number
- // x position of point
- // y: Number
- // y position of point
- }
- ToolsSetup = {
- // summary:
- // An object attached to a Tool's constructor
- // used to inform the toolbar of its information
- // and properties.
- // description:
- // This object is inserted into the *function* of
- // a tool (not a stencil). Like: function.ToolsSetup
- // It must be attached after constructr creation, so
- // this object is found at the botton of the file.
- //
- // name:String
- // Fully qualified name of constructor
- // tooltip: Stirng
- // Text to display on toolbar button hover
- // iconClass: String
- // CSS class with icon information to attach
- // to toolbar button.
- }
- =====*/
- dojox.drawing.stencil._Base = dojox.drawing.util.oo.declare(
- // summary:
- // The base class used for all Stencils.
- // description:
- // All stencils extend this base class.
- // Most methods and events can be found here.
- //
- function(options){
- //console.log("______Base", this.type, options)
- // clone style so changes are reflected in future shapes
- dojo.mixin(this, options);
- this.style = options.style || dojox.drawing.defaults.copy();
- if(options.stencil){
- this.stencil = options.stencil;
- this.util = options.stencil.util;
- this.mouse = options.stencil.mouse;
- this.container = options.stencil.container;
- this.style = options.stencil.style;
- }
- // don't use the 'g' on these, it affects
- // the global RegExp
- var lineTypes = /Line|Vector|Axes|Arrow/;
- var textTypes = /Text/;
- this.shortType = this.util.abbr(this.type);
- this.isText = textTypes.test(this.type);
- this.isLine = lineTypes.test(this.type);
- this.renderHit = this.style.renderHitLayer;
- if(!this.renderHit && this.style.renderHitLines && this.isLine){
- this.renderHit = true;
- }
- if(!this.renderHit && this.style.useSelectedStyle){
- this.useSelectedStyle = true;
- this.selCopy = dojo.clone(this.style.selected);
- for(var nm in this.style.norm){
- if(this.style.selected[nm]===undefined){
- this.style.selected[nm] = this.style.norm[nm];
- }
- }
- this.textSelected = dojo.clone(this.style.text);
- this.textSelected.color = this.style.selected.fill;
- }
- this.angleSnap = this.style.angleSnap || 1;
- this.marginZero = options.marginZero || this.style.anchors.marginZero;
- this.id = options.id || this.util.uid(this.type);
- this._cons = [];
- if(!this.annotation && !this.subShape){
- this.util.attr(this.container, "id", this.id);
- }
- this.connect(this, "onBeforeRender", "preventNegativePos");
- this._offX = this.mouse.origin.x;
- this._offY = this.mouse.origin.y;
- if(this.isText){
- this.align = options.align || this.align;
- this.valign = options.valign || this.valign;
- if(options.data && options.data.makeFit){
- var textObj = this.makeFit(options.data.text, options.data.width);
- this.textSize = this.style.text.size = textObj.size;
- this._lineHeight = textObj.box.h;
- }else{
- this.textSize = parseInt(this.style.text.size, 10);
- this._lineHeight = this.textSize * 1.4;
- }
- // TODO: thinner text selection
- //this.style.hitSelected.width *= 0.5;
- //
- // ouch. how verbose. My mixin is weak....
- this.deleteEmptyCreate = options.deleteEmptyCreate!==undefined ? options.deleteEmptyCreate : this.style.text.deleteEmptyCreate;
- this.deleteEmptyModify = options.deleteEmptyModify!==undefined ? options.deleteEmptyModify : this.style.text.deleteEmptyModify;
- }
- //this.drawingType
- this.attr(options.data);
- // make truthy
- // add to renders below
- // this.baseRender && render()
- //if(this.type == "dojox.drawing.tools.TextBlock"){
- if(this.noBaseRender){
- // TextBlock will handle rendering itself
- return;
- }
- //console.log("BASE OPTS:", options)
- if(options.points){
- //console.log("__________Base.constr >>>> ", this.type, "points", options.points)
- if(options.data && options.data.closePath===false){
- this.closePath = false;
- }
- this.setPoints(options.points);
- this.connect(this, "render", this, "onRender", true);
- this.baseRender && this.enabled && this.render();
- options.label && this.setLabel(options.label);
- options.shadow && this.addShadow(options.shadow);
- }else if(options.data){
- //console.log("___________Base.constr", this.type, "options data", options.data)
- options.data.width = options.data.width ? options.data.width : this.style.text.minWidth;
- options.data.height = options.data.height ? options.data.height : this._lineHeight;
- this.setData(options.data);
- this.connect(this, "render", this, "onRender", true);
- this.baseRender && this.enabled && this.render(options.data.text);
- this.baseRender && options.label && this.setLabel(options.label);
- this.baseRender && options.shadow && this.addShadow(options.shadow);
- }else if(this.draws){
- //console.log("_____________Base.constr", this.type, "draws")
- this.points = [];
- this.data = {};
- this.connectMouse();
- this._postRenderCon = dojo.connect(this, "render", this, "_onPostRender");
- }
- if(this.showAngle){
- this.angleLabel = new dojox.drawing.annotations.Angle({stencil:this});
- }
- if(!this.enabled){
- this.disable();
- this.moveToBack();
- // some things render some don't...
- this.render(options.data.text);
- }
- },
- {
- // type: String
- // The type of Stencil this is. Should be overridden
- // by extending classes.
- // FIXME: should this be declaredClass?
- type:"dojox.drawing.stencil",
- //
- // minimumSize: Number
- // The minimum size allowed for a render. If the size
- // is less, the shape is destroyed.
- minimumSize:10,
- //
- // enabled [readonly] Boolean
- // Whether the Stencil is enabled or not.
- enabled:true,
- drawingType:"stencil",
- //points:[],
- setData: function(/*StencilData*/data){
- // summary:
- // Setter for Stencil data; also converts
- // data to points. See individual Stencils
- // for specific data properties.
- this.data = data;
- this.points = this.dataToPoints();
- },
- setPoints: function(/*StencilPoints*/points){
- // summary:
- // Setter for Stencil points; also converts
- // points to data. See individual Stencils
- // for specific points properties.
- this.points = points;
- // Path doesn't do data
- if(this.pointsToData){
- this.data = this.pointsToData();
- }
- },
- onDelete: function(/* Stencil */ stencil){
- // summary:
- // Stub - fires before this is destroyed
- console.info("onDelete", this.id);
- },
- onBeforeRender: function(/*Object*/ stencil){
- // summary:
- // Stub - Fires before render occurs.
- },
- onModify: function(/*Object*/stencil){
- // summary:
- // Stub - fires on change of any property,
- // including style properties
- },
- onChangeData: function(/*Object*/ stencil){
- // summary:
- // Stub - fires on change of dimensional
- // properties or a text change
- },
- onChangeText: function(value){ // value or 'this' ?
- // summary:
- // Stub - fires on change of text in a
- // TextBlock tool only
- },
- onRender: function(/*Object*/ stencil){
- // summary:
- // Stub - Fires on creation.
- // Drawing connects to this (once!) to be
- // notified of drag completion. But only if it
- // was registered as a Tool. Creating Stencil in and of
- // itself does not register it.
- //
- // This should fire
- // at the *end* of creation (not during drag)
- //
- // FIXME:
- // This should probably be onCreate. It should
- // only fire once. But the mechanism for determining
- // this is more complicated than it sounds.
- //
- this._postRenderCon = dojo.connect(this, "render", this, "_onPostRender");
- this.created = true;
- this.disconnectMouse();
- // for Silverlight
- if(this.shape){
- this.shape.superClass = this;
- }else{
- this.container.superClass = this;
- }
- this._setNodeAtts(this);
- //console.warn("ONRENDER", this.id, this)
- },
- onChangeStyle: function(/*Object*/stencil){
- // summary:
- // Fires when styles of shape has changed
- //
- this._isBeingModified = true; // need this to prevent onRender
- if(!this.enabled){
- this.style.current = this.style.disabled;
- this.style.currentText = this.style.textDisabled;
- this.style.currentHit = this.style.hitNorm;
- }else{
- this.style.current = this.style.norm;
- this.style.currentHit = this.style.hitNorm;
- this.style.currentText = this.style.text;
- }
- if(this.selected){
- if(this.useSelectedStyle){
- this.style.current = this.style.selected;
- this.style.currentText = this.textSelected;
- }
- this.style.currentHit = this.style.hitSelected;
- }else if(this.highlighted){
- //this.style.current = this.style.highlighted;
- this.style.currentHit = this.style.hitHighlighted;
- //this.style.currentText = this.style.textHighlighted;
- }
- // NOTE: Can't just change props like setStroke
- // because Silverlight throws error
- this.render();
- },
- animate: function(options, create){
- console.warn("ANIMATE..........................")
- var d = options.d || options.duration || 1000;
- var ms = options.ms || 20;
- var ease = options.ease || dojo.fx.easing.linear;
- var steps = options.steps;
- var ts = new Date().getTime();
- var w = 100;
- var cnt = 0;
- var isArray = true;
- var sp, ep;
- if(dojo.isArray(options.start)){
- sp = options.start;
- ep = options.end;
- }else if(dojo.isObject(options.start)){
- sp = options.start;
- ep = options.end;
- isArray = false;
- }else{
- console.warn("No data provided to animate")
- }
- var v = setInterval(dojo.hitch(this, function(){
- var t = new Date().getTime() - ts;
- var p = ease(1-t/d);
- if(t > d || cnt++ > 100){
- clearInterval(v);
- return;
- }
- if(isArray){
- var pnts = [];
- dojo.forEach(sp, function(pt, i){
- var o = {
- x: (ep[i].x-sp[i].x)*p + sp[i].x,
- y: (ep[i].y-sp[i].y)*p + sp[i].y
- };
- pnts.push(o);
- });
- this.setPoints(pnts);
- this.render();
- }else{
- var o = {};
- for(var nm in sp){
- o[nm] = (ep[nm] - sp[nm]) * p + sp[nm];
- }
- this.attr(o);
- }
- //console.dir(pnts)
- //this.attr("height", w);
- ////console.log("W:", w)
- //w += 5;
- }), ms);
- },
- attr: function(/*String | Object*/key, /* ? String | Number */value){
- // summary
- // Changes properties in the style or disabled styles,
- // depending on whether the object is enabled.
- // Also can be used to change most position and size props.
- // NOTE: JUST A SETTTER!! TODO!
- // WARNING:
- // Not doing any Stencil-type checking here. Setting a height
- // on a line or an angle on a rectangle will just not render.
- // FIXME
- // 'width' attr is used for line width. How to change the width of a stencil?
- var n = this.enabled?this.style.norm:this.style.disabled;
- var t = this.enabled?this.style.text:this.style.textDisabled;
- var ts = this.textSelected || {},
- o,
- nm,
- width,
- styleWas = dojo.toJson(n),
- textWas = dojo.toJson(t);
- var coords = {
- x:true,
- y:true,
- r:true,
- height:true,
- width:true,
- radius:true,
- angle:true
- };
- var propChange = false;
- if(typeof(key)!="object"){
- o = {};
- o[key] = value;
- }else{
- // prevent changing actual data
- o = dojo.clone(key);
- }
- if(o.width){
- // using width for size,
- // borderWidth should be used
- // for line thickness
- width = o.width;
- delete o.width;
- }
- for(nm in o){
- if(nm in n){ n[nm] = o[nm]; }
- if(nm in t){ t[nm] = o[nm]; }
- if(nm in ts){ ts[nm] = o[nm]; }
- if(nm in coords){
- coords[nm] = o[nm];
- propChange = true;
- if(nm == "radius" && o.angle===undefined){
- o.angle = coords.angle = this.getAngle();
- }else if(nm == "angle" && o.radius===undefined){
- o.radius = coords.radius = this.getRadius();
- }
- }
- if(nm == "text"){
- this.setText(o.text);
- }
- if(nm == "label"){
- this.setLabel(o.label);
- }
- }
- if(o.borderWidth!==undefined){
- n.width = o.borderWidth;
- }
-
- if(this.useSelectedStyle){
- // using the orginal selected style copy as
- // a reference map of what props to copy
- for(nm in this.style.norm){
- if(this.selCopy[nm]===undefined){
- this.style.selected[nm] = this.style.norm[nm];
- }
- }
- this.textSelected.color = this.style.selected.color;
- }
- if(!this.created){
- return;
- }
- // basic transform
- if(o.x!==undefined || o.y!==undefined){
- var box = this.getBounds(true);
- var mx = { dx:0, dy:0 };
- for(nm in o){
- if(nm=="x" || nm =="y" || nm =="r"){
- mx["d"+nm] = o[nm] - box[nm];
- }
- }
- this.transformPoints(mx);
- }
- var p = this.points;
- if(o.angle!==undefined){
- this.dataToPoints({
- x:this.data.x1,
- y:this.data.y1,
- angle:o.angle,
- radius:o.radius
- });
- } else if(width!==undefined){
- p[1].x = p[2].x = p[0].x + width;
- this.pointsToData(p);
- }
- if(o.height!==undefined && o.angle===undefined){
- console.log("Doing P2D-2");
- p[2].y = p[3].y = p[0].y + o.height;
- this.pointsToData(p);
- }
- if(o.r!==undefined){
- this.data.r = Math.max(0, o.r);
- }
- //console.dir(this.data);
- if(propChange || textWas!=dojo.toJson(t) || styleWas != dojo.toJson(n)){
- // to trigger the render
- // other events will be called post render
- this.onChangeStyle(this);
- }
- o.width = width;
-
- if(o.cosphi!=undefined){
- !this.data? this.data = {cosphi:o.cosphi} : this.data.cosphi = o.cosphi;
- this.style.zAxis = o.cosphi!=0 ? true : false;
- }
- },
- exporter: function(){
- // summary:
- // Exports Stencil data
- //
- var type = this.type.substring(this.type.lastIndexOf(".")+1).charAt(0).toLowerCase()
- + this.type.substring(this.type.lastIndexOf(".")+2);
- var o = dojo.clone(this.style.norm);
- o.borderWidth = o.width;
- delete o.width;
- if(type=="path"){
- o.points = this.points;
- }else{
- o = dojo.mixin(o, this.data);
- }
- o.type = type;
- if(this.isText){
- o.text = this.getText();
- o = dojo.mixin(o, this.style.text);
- delete o.minWidth;
- delete o.deleteEmptyCreate;
- delete o.deleteEmptyModify;
- }
- var lbl = this.getLabel();
- if(lbl){
- o.label = lbl;
- }
- return o;
- },
- // TODO:
- // Makes these all called by att()
- // Should points and data be?
- //
- disable: function(){
- // summary:
- // Disables Stencil so it is not selectable.
- // Changes the color to the disabled style.
- this.enabled = false;
- this.renderHit = false;
- this.onChangeStyle(this);
- },
- enable: function(){
- // summary:
- // Enables Stencil so it is not selectable (if
- // it was selectable to begin with). Changes the
- // color to the current style.
- this.enabled = true;
- this.renderHit = true;
- this.onChangeStyle(this);
- },
- select: function(){
- // summary:
- // Called when the Stencil is selected.
- // NOTE: Calling this will not select the Stencil
- // calling this just sets the style to the 'selected'
- // theme. 'manager.Stencil' should be used for selecting
- // Stencils.
- //
- this.selected = true;
- this.onChangeStyle(this);
- },
- deselect: function(/*Boolean*/useDelay){
- // summary:
- // Called when the Stencil is deselected.
- // NOTE: Calling this will not deselect the Stencil
- // calling this just sets the style to the current
- // theme. 'manager.Stencil' should be used for selecting
- // and deselecting Stencils.
- //
- // arguments:
- // useDelay: Boolean
- // Adds slight delay before the style is set.
- //
- // should not have to render here because the deselection
- // re-renders after the transform
- // but... oh well.
- if(useDelay){
- setTimeout(dojo.hitch(this, function(){
- this.selected = false;
- this.onChangeStyle(this);
- }),200);
- }else{
- this.selected = false;
- this.onChangeStyle(this);
- }
- },
- _toggleSelected: function(){
- if(!this.selected){ return; }
- this.deselect();
- setTimeout(dojo.hitch(this, "select"), 0);
- },
- highlight: function(){
- // summary:
- // Changes style to the highlight theme.
- this.highlighted = true;
- this.onChangeStyle(this);
- },
- unhighlight: function(){
- // summary:
- // Changes style to the current theme.
- this.highlighted = false;
- this.onChangeStyle(this);
- },
- moveToFront: function(){
- // summary:
- // Moves Stencil to the front of all other items
- // on the canvas.
- this.container && this.container.moveToFront();
- },
- moveToBack: function(){
- // summary:
- // Moves Stencil to the back of all other items
- // on the canvas.
- this.container && this.container.moveToBack();
- },
- onTransformBegin: function(/* ? manager.Anchor */anchor){
- // summary:
- // Fired at the start of a transform. This would be
- // an anchor drag or a selection.
- //
- this._isBeingModified = true;
- },
- onTransformEnd: function(/* manager.Anchor */anchor){
- // summary:
- // Called from anchor point up mouse up
- this._isBeingModified = false;
- this.onModify(this);
- },
- onTransform: function(/* ? manager.Anchor */anchor){
- // summary:
- // Called from anchor point mouse drag
- // also called from plugins.Pan.checkBounds
- if(!this._isBeingModified){
- this.onTransformBegin();
- }
- // this is not needed for anchor moves, but it
- // is for stencil move:
- this.setPoints(this.points);
- this.render();
- },
- transformPoints: function(mx){
- // summary:
- // Moves object to a new X Y location
- // mx is additive. So mx.dx=1 will move the stencil
- // 1 pixel to the right from wherever it was.
- //
- // An attempt is made to prevent < 0 errors, but
- // this won't work on all shapes (like Axes)
- //
- if(!mx.dx && !mx.dy){
- // no change
- return;
- }
- var backup = dojo.clone(this.points), abort = false;
- dojo.forEach(this.points, function(o){
- o.x += mx.dx;
- o.y += mx.dy;
- if(o.x<this.marginZero || o.y<this.marginZero){
- abort = true;
- }
- });
- if(abort){
- this.points = backup;
- console.error("Attempt to set object '"+this.id+"' to less than zero.");
- return;
- }
- this.onTransform();
- this.onTransformEnd();
- },
- applyTransform: function(mx){
- // summary:
- // Applies the transform to the stencil
- // NOTE: PARTIALLY IMPLEMENTED
- // Only applies x y coords
- this.transformPoints(mx);
- },
- setTransform: function(/*Object*/mx){
- // summary:
- // Sets the transform to the stencil
- // NOTE: PARTIALLY IMPLEMENTED
- // Only applies x y coords
- this.attr({
- x:mx.dx,
- y:mx.dy
- });
- },
- getTransform: function(){
- // summary:
- // Returns the current transform (position) of the Stencil's
- // container
- return this.selected ? this.container.getParent().getTransform() : {dx:0, dy:0}; // Object
- },
- addShadow: function(/*Object*/args){
- args = args===true ? {} : args;
- args.stencil = this;
- this.shadow = new dojox.drawing.annotations.BoxShadow(args);
- },
- removeShadow: function(){
- this.shadow.destroy();
- },
- setLabel: function(/*String*/text){
- // summary:
- // Creates and sets a label annotation for the Stencil.
- // If Stencil contains a labelPosition method, that will
- // be used for positioning. Otherwise
- // dojox.drawing.util.positioning.label is used.
- // arguments:
- // text: String
- // The text to set as the label.
- //
- if(!this._label){
- this._label = new dojox.drawing.annotations.Label({
- text:text,
- util:this.util,
- mouse:this.mouse,
- stencil:this,
- annotation:true,
- container:this.container,
- labelPosition:this.labelPosition
- });
- }else if(text!=undefined){
- this._label.setLabel(text);
- }
- },
-
- getLabel: function(){
- // summary:
- // Get the text of the label.
- //
- if(this._label){
- return this._label.getText(); // String
- }
- return null; //null
- },
- getAngle: function(){
- // summary:
- // Gets angle of Stencil
- // NOTE: Only works for Lines, Arrows, Vectors and Axes
- // (works on points, not transforms)
- var d = this.pointsToData();
- var obj = {
- start:{
- x:d.x1,
- y:d.y1
- },
- x:d.x2,
- y:d.y2
- };
- var angle = this.util.angle(obj, this.angleSnap);
- // converting the angle for display: -180 -> 180, -90 -> 270
- angle<0 ? angle = 360 + angle : angle;
- return angle;
- },
- getRadius: function(){
- // summary:
- // Gets radius (length) of Stencil
- // NOTE: Only works for Lines, Arrows and Vectors
- // (not for Ellipse, Axes has its own version)
- //
- var box = this.getBounds(true);
- var line = {start:{x:box.x1, y:box.y1}, x:box.x2, y:box.y2};
- return this.util.length(line);
- },
- getBounds: function(/* ? Boolean*/absolute){
- // summary:
- // Returns the coordinates of the Stencil. This is often
- // different than the data or the points.
- // arguments:
- // absolute: Boolean
- // Keeps lines from flipping (see note).
- //
- // NOTE: Won't work for paths or annotations (labels, Axes, arrow tips)
- // They should overwrite.
- // NOTE: Primarily used for checking for if shape is off
- // canvas. Therefore Lines could get flipped. Use absolute
- // to prevent this.
- //
- var p = this.points, x1, y1, x2, y2;
- if(p.length==2){
- if(absolute){
- x1 = p[0].x;
- y1 = p[0].y;
- x2 = p[1].x;
- y2 = p[1].y
- }else{
- x1 = p[0].x < p[1].x ? p[0].x : p[1].x;
- y1 = p[0].y < p[1].y ? p[0].y : p[1].y;
- x2 = p[0].x < p[1].x ? p[1].x : p[0].x;
- y2 = p[0].y < p[1].y ? p[1].y : p[0].y;
- }
- return {
- x1:x1,
- y1:y1,
- x2:x2,
- y2:y2,
- x:x1,
- y:y1,
- w:x2-x1,
- h:y2-y1
- }; // Object
- }else{
- return {
- x1:p[0].x,
- y1:p[0].y,
- x2:p[2].x,
- y2:p[2].y,
- x:p[0].x,
- y:p[0].y,
- w:p[2].x - p[0].x,
- h:p[2].y - p[0].y
- }; // Object
- }
- },
- preventNegativePos: function(){
- // summary:
- // Internal. Prevent item from being drawn/rendered less
- // than zero on the X or Y.
- //
- // if being modified anchors will prevent less than zero.
- if(this._isBeingModified){ return; }
- // FIXME: why is this sometimes empty?
- if(!this.points || !this.points.length){ return; }
- if(this.type=="dojox.drawing.tools.custom.Axes"){
- // this scenario moves all points if < 0
- var minY = this.marginZero, minX = this.marginZero;
- dojo.forEach(this.points, function(p){ minY = Math.min(p.y, minY); });
- dojo.forEach(this.points, function(p){ minX = Math.min(p.x, minX); });
- if(minY<this.marginZero){
- dojo.forEach(this.points, function(p, i){
- p.y = p.y + (this.marginZero-minY)
- }, this);
- }
- if(minX<this.marginZero){
- dojo.forEach(this.points, function(p){
- p.x += (this.marginZero-minX)
- }, this);
- }
- }else{
- // this scenario moves just the one point that is < 0
- dojo.forEach(this.points, function(p){
- p.x = p.x < 0 ? this.marginZero : p.x;
- p.y = p.y < 0 ? this.marginZero : p.y;
- });
- }
- this.setPoints(this.points);
- },
- _onPostRender: function(/*Object*/data){
- // summary:
- // Drag-create or programmatic create calls onRender
- // and afterwards, _onPostRender is called and
- // manages further events.
- //
- // TODO: can this be onModify? Is that more clear?
- //
- //console.info("...........post render.....");
- if(this._isBeingModified){
- this.onModify(this);
- this._isBeingModified = false;
- }else if(!this.created){
- //this.onCreate(this);
- //this.onRender(this);
- }
- if(!this.editMode && !this.selected && this._prevData && dojo.toJson(this._prevData) != dojo.toJson(this.data)){
- //console.info("_Base data changed ----> : this.editMode:", this.editMode)
- this.onChangeData(this);
- this._prevData = dojo.clone(this.data);
- }else if(!this._prevData && (!this.isText || this.getText())){
- //console.info("_Base no prevData..........................");
- this._prevData = dojo.clone(this.data);
- }
- },
- _setNodeAtts: function(shape){
- // summary:
- // Internal. Sets the rawNode attribute. (Or in Silverlight
- // an "object attribute". "stencil" is
- // used by the application to determine if
- // something is selectable or not. This also
- // sets the mouse custom events like:
- // "onStencilUp". To disable the selectability,
- // make the att "", which causes a standard
- // mouse event.
- // Labels are special and used to select master stencils.
- var att = this.enabled && (!this.annotation || this.drawingType=="label") ? this.drawingType : "";
- this.util.attr(shape, "drawingType", att);
- },
- destroy: function(){
- // summary:
- // Destroys this Stencil
- // Note:
- // Can connect to this, but it's better to
- // connect to onDelete
- //
- // prevent loops:
- if(this.destroyed){ return; }
- if(this.data || this.points && this.points.length){
- this.onDelete(this);
- }
- this.disconnectMouse();
- this.disconnect(this._cons);
- dojo.disconnect(this._postRenderCon);
- this.remove(this.shape, this.hit);
- this.destroyed = true;
- },
- remove: function(/*Shape...*/){
- // summary:
- // Removes shape(s), typically before a re-render
- // No args defaults to this.shape
- // Pass in multiple args to remove multiple shapes
- //
- // FIXME: Use an Array of all shapes
- //
- var a = arguments;
- if(!a.length){
- if(!this.shape){ return; }
- a = [this.shape];
- }
- for(var i=0;i<a.length;i++){
- if(a[i]){
- a[i].removeShape();
- }
- }
- },
- connectMult: function(/*dojo.connect args */){
- // summary:
- // Convenience method for batches of quick connects
- // Handles are not returned and therefore cannot be
- // disconnected until Shape destroy time
- //
- if(arguments.length>1){
- // arguments are the connect params
- this._cons.push(this.connect.apply(this, arguments));
- }else if(dojo.isArray(arguments[0][0])){
- // an array of arrays of params
- dojo.forEach(arguments[0], function(ar){
- this._cons.push(this.connect.apply(this, ar));
- }, this);
- }else{
- //one array of params
- this._cons.push(this.connect.apply(this, arguments[0]));
- }
- },
- // TODO: connect to a Shape event from outside class
- connect: function(o, e, s, m, /* Boolean*/once){
- // summary:
- // Convenience method for quick connects
- // See comments below for possiblities
- // functions can be strings
- // once:
- // If true, the connection happens only
- // once then disconnects. Five args are required
- // for this functionality.
- //
- var c;
- if(typeof(o)!="object"){
- if(s){
- // ** function object function **
- m = s; s = e; e=o; o = this;
- }else{
- // ** function function **
- m = e; e = o; o = s = this;
- }
- }else if(!m){
- // ** object function function **
- m = s; s = this;
- }else if(once){
- // ** object function object function Boolean **
- c = dojo.connect(o, e, function(evt){
- dojo.hitch(s, m)(evt);
- dojo.disconnect(c);
- });
- this._cons.push(c);
- return c;
- }else{
- // ** object function object function **
- }
- c = dojo.connect(o, e, s, m);
- this._cons.push(c);
- return c;
- },
- disconnect: function(/*handle | Array*/handles){
- // summary:
- // Removes connections based on passed
- // handles arguments
- if(!handles){ return }
- if(!dojo.isArray(handles)){ handles=[handles]; }
- dojo.forEach(handles, dojo.disconnect, dojo);
- },
- connectMouse: function(){
- // summary:
- // Internal. Registers this Stencil to receive
- // mouse events.
- this._mouseHandle = this.mouse.register(this);
- },
- disconnectMouse: function(){
- // summary:
- // Internal. Unregisters this Stencil from receiving
- // mouse events.
- this.mouse.unregister(this._mouseHandle);
- },
- // Should be overwritten by sub class:
- render: function(){
- // summary:
- // This Stencil's render description. Often
- // calls 'sub render' methods.
- },
- //renderOutline: function(){},
- dataToPoints: function(/*Object*/data){
- // summary:
- // Converts data to points.
- },
- pointsToData: function(/*Array*/points){
- // summary:
- // Converts points to data
- },
- onDown: function(/*EventObject*/obj){
- // summary:
- // Mouse event, fired on mousedown on canvas
- //
- // by default, object is ready to accept data
- // turn this off for dragging or onRender will
- // keep firing and register the shape
- // NOTE: Not needed for all stencils. Axes needs it.
- this._downOnCanvas = true;
- dojo.disconnect(this._postRenderCon);
- this._postRenderCon = null;
- },
- onMove: function(/*EventObject*/obj){
- // summary:
- // Mouse event, fired on mousemove while mouse
- // is not down.
- // NOTE: Not currently implemented
- },
- onDrag: function(/*EventObject*/obj){
- // summary:
- // Mouse event, fired on mousemove while mouse
- // is down on canvas
- },
- onUp: function(/*EventObject*/obj){
- // summary:
- // Mouse event, fired on mouseup
- }
- }
- );
- }
|