shape.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. define("dojox/gfx/shape", ["./_base", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/window", "dojo/_base/sniff",
  2. "dojo/_base/connect", "dojo/_base/array", "dojo/dom-construct", "dojo/_base/Color", "./matrix"],
  3. function(g, lang, declare, win, has, events, arr, domConstruct, Color, matrixLib){
  4. /*=====
  5. dojox.gfx.shape = {
  6. // summary:
  7. // This module contains the core graphics Shape API.
  8. // Different graphics renderer implementation modules (svg, canvas, vml, silverlight, etc.) extend this
  9. // basic api to provide renderer-specific implementations for each shape.
  10. };
  11. =====*/
  12. var shape = g.shape = {};
  13. // a set of ids (keys=type)
  14. var _ids = {};
  15. // a simple set impl to map shape<->id
  16. var registry = {};
  17. var disposeCount = 0, fixIELeak = has("ie") < 9;
  18. function repack(oldRegistry){
  19. var newRegistry = {};
  20. for(var key in oldRegistry){
  21. if(oldRegistry.hasOwnProperty(key)){
  22. newRegistry[key] = oldRegistry[key]
  23. }
  24. }
  25. return newRegistry;
  26. }
  27. shape.register = function(/*dojox.gfx.shape.Shape*/shape){
  28. // summary:
  29. // Register the specified shape into the graphics registry.
  30. // shape: dojox.gfx.shape.Shape
  31. // The shape to register.
  32. // returns:
  33. // The unique id associated with this shape.
  34. // the id pattern : type+number (ex: Rect0,Rect1,etc)
  35. var t = shape.declaredClass.split('.').pop();
  36. var i = t in _ids ? ++_ids[t] : ((_ids[t] = 0));
  37. var uid = t+i;
  38. registry[uid] = shape;
  39. return uid;
  40. };
  41. shape.byId = function(/*String*/id){
  42. // summary:
  43. // Returns the shape that matches the specified id.
  44. // id: String
  45. // The unique identifier for this Shape.
  46. return registry[id]; //dojox.gfx.shape.Shape
  47. };
  48. shape.dispose = function(/*dojox.gfx.shape.Shape*/shape){
  49. // summary:
  50. // Removes the specified shape from the registry.
  51. // shape: dojox.gfx.shape.Shape
  52. // The shape to unregister.
  53. delete registry[shape.getUID()];
  54. ++disposeCount;
  55. if(fixIELeak && disposeCount>10000){
  56. registry = repack(registry);
  57. disposeCount = 0;
  58. }
  59. };
  60. declare("dojox.gfx.shape.Shape", null, {
  61. // summary: a Shape object, which knows how to apply
  62. // graphical attributes and transformations
  63. constructor: function(){
  64. // rawNode: Node
  65. // underlying graphics-renderer-specific implementation object (if applicable)
  66. this.rawNode = null;
  67. // shape: Object: an abstract shape object
  68. // (see dojox.gfx.defaultPath,
  69. // dojox.gfx.defaultPolyline,
  70. // dojox.gfx.defaultRect,
  71. // dojox.gfx.defaultEllipse,
  72. // dojox.gfx.defaultCircle,
  73. // dojox.gfx.defaultLine,
  74. // or dojox.gfx.defaultImage)
  75. this.shape = null;
  76. // matrix: dojox.gfx.Matrix2D
  77. // a transformation matrix
  78. this.matrix = null;
  79. // fillStyle: Object
  80. // a fill object
  81. // (see dojox.gfx.defaultLinearGradient,
  82. // dojox.gfx.defaultRadialGradient,
  83. // dojox.gfx.defaultPattern,
  84. // or dojo.Color)
  85. this.fillStyle = null;
  86. // strokeStyle: Object
  87. // a stroke object
  88. // (see dojox.gfx.defaultStroke)
  89. this.strokeStyle = null;
  90. // bbox: dojox.gfx.Rectangle
  91. // a bounding box of this shape
  92. // (see dojox.gfx.defaultRect)
  93. this.bbox = null;
  94. // virtual group structure
  95. // parent: Object
  96. // a parent or null
  97. // (see dojox.gfx.Surface,
  98. // dojox.gfx.shape.VirtualGroup,
  99. // or dojox.gfx.Group)
  100. this.parent = null;
  101. // parentMatrix: dojox.gfx.Matrix2D
  102. // a transformation matrix inherited from the parent
  103. this.parentMatrix = null;
  104. var uid = shape.register(this);
  105. this.getUID = function(){
  106. return uid;
  107. }
  108. },
  109. // trivial getters
  110. getNode: function(){
  111. // summary: Different graphics rendering subsystems implement shapes in different ways. This
  112. // method provides access to the underlying graphics subsystem object. Clients calling this
  113. // method and using the return value must be careful not to try sharing or using the underlying node
  114. // in a general way across renderer implementation.
  115. // Returns the underlying graphics Node, or null if no underlying graphics node is used by this shape.
  116. return this.rawNode; // Node
  117. },
  118. getShape: function(){
  119. // summary: returns the current Shape object or null
  120. // (see dojox.gfx.defaultPath,
  121. // dojox.gfx.defaultPolyline,
  122. // dojox.gfx.defaultRect,
  123. // dojox.gfx.defaultEllipse,
  124. // dojox.gfx.defaultCircle,
  125. // dojox.gfx.defaultLine,
  126. // or dojox.gfx.defaultImage)
  127. return this.shape; // Object
  128. },
  129. getTransform: function(){
  130. // summary: Returns the current transformation matrix applied to this Shape or null
  131. return this.matrix; // dojox.gfx.Matrix2D
  132. },
  133. getFill: function(){
  134. // summary: Returns the current fill object or null
  135. // (see dojox.gfx.defaultLinearGradient,
  136. // dojox.gfx.defaultRadialGradient,
  137. // dojox.gfx.defaultPattern,
  138. // or dojo.Color)
  139. return this.fillStyle; // Object
  140. },
  141. getStroke: function(){
  142. // summary: Returns the current stroke object or null
  143. // (see dojox.gfx.defaultStroke)
  144. return this.strokeStyle; // Object
  145. },
  146. getParent: function(){
  147. // summary: Returns the parent Shape, Group or VirtualGroup or null if this Shape is unparented.
  148. // (see dojox.gfx.Surface,
  149. // dojox.gfx.shape.VirtualGroup,
  150. // or dojox.gfx.Group)
  151. return this.parent; // Object
  152. },
  153. getBoundingBox: function(){
  154. // summary: Returns the bounding box Rectanagle for this shape or null if a BoundingBox cannot be
  155. // calculated for the shape on the current renderer or for shapes with no geometric area (points).
  156. // A bounding box is a rectangular geometric region
  157. // defining the X and Y extent of the shape.
  158. // (see dojox.gfx.defaultRect)
  159. return this.bbox; // dojox.gfx.Rectangle
  160. },
  161. getTransformedBoundingBox: function(){
  162. // summary: returns an array of four points or null
  163. // four points represent four corners of the untransformed bounding box
  164. var b = this.getBoundingBox();
  165. if(!b){
  166. return null; // null
  167. }
  168. var m = this._getRealMatrix(),
  169. gm = matrixLib;
  170. return [ // Array
  171. gm.multiplyPoint(m, b.x, b.y),
  172. gm.multiplyPoint(m, b.x + b.width, b.y),
  173. gm.multiplyPoint(m, b.x + b.width, b.y + b.height),
  174. gm.multiplyPoint(m, b.x, b.y + b.height)
  175. ];
  176. },
  177. getEventSource: function(){
  178. // summary: returns a Node, which is used as
  179. // a source of events for this shape
  180. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  181. return this.rawNode; // Node
  182. },
  183. // empty settings
  184. setShape: function(shape){
  185. // summary: sets a shape object
  186. // (the default implementation simply ignores it)
  187. // shape: Object
  188. // a shape object
  189. // (see dojox.gfx.defaultPath,
  190. // dojox.gfx.defaultPolyline,
  191. // dojox.gfx.defaultRect,
  192. // dojox.gfx.defaultEllipse,
  193. // dojox.gfx.defaultCircle,
  194. // dojox.gfx.defaultLine,
  195. // or dojox.gfx.defaultImage)
  196. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  197. this.shape = g.makeParameters(this.shape, shape);
  198. this.bbox = null;
  199. return this; // self
  200. },
  201. setFill: function(fill){
  202. // summary: sets a fill object
  203. // (the default implementation simply ignores it)
  204. // fill: Object
  205. // a fill object
  206. // (see dojox.gfx.defaultLinearGradient,
  207. // dojox.gfx.defaultRadialGradient,
  208. // dojox.gfx.defaultPattern,
  209. // or dojo.Color)
  210. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  211. if(!fill){
  212. // don't fill
  213. this.fillStyle = null;
  214. return this; // self
  215. }
  216. var f = null;
  217. if(typeof(fill) == "object" && "type" in fill){
  218. // gradient or pattern
  219. switch(fill.type){
  220. case "linear":
  221. f = g.makeParameters(g.defaultLinearGradient, fill);
  222. break;
  223. case "radial":
  224. f = g.makeParameters(g.defaultRadialGradient, fill);
  225. break;
  226. case "pattern":
  227. f = g.makeParameters(g.defaultPattern, fill);
  228. break;
  229. }
  230. }else{
  231. // color object
  232. f = g.normalizeColor(fill);
  233. }
  234. this.fillStyle = f;
  235. return this; // self
  236. },
  237. setStroke: function(stroke){
  238. // summary: sets a stroke object
  239. // (the default implementation simply ignores it)
  240. // stroke: Object
  241. // a stroke object
  242. // (see dojox.gfx.defaultStroke)
  243. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  244. if(!stroke){
  245. // don't stroke
  246. this.strokeStyle = null;
  247. return this; // self
  248. }
  249. // normalize the stroke
  250. if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof Color){
  251. stroke = {color: stroke};
  252. }
  253. var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
  254. s.color = g.normalizeColor(s.color);
  255. return this; // self
  256. },
  257. setTransform: function(matrix){
  258. // summary: sets a transformation matrix
  259. // matrix: dojox.gfx.Matrix2D
  260. // a matrix or a matrix-like object
  261. // (see an argument of dojox.gfx.Matrix2D
  262. // constructor for a list of acceptable arguments)
  263. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  264. this.matrix = matrixLib.clone(matrix ? matrixLib.normalize(matrix) : matrixLib.identity);
  265. return this._applyTransform(); // self
  266. },
  267. _applyTransform: function(){
  268. // summary: physically sets a matrix
  269. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  270. return this; // self
  271. },
  272. // z-index
  273. moveToFront: function(){
  274. // summary: moves a shape to front of its parent's list of shapes
  275. var p = this.getParent();
  276. if(p){
  277. p._moveChildToFront(this);
  278. this._moveToFront(); // execute renderer-specific action
  279. }
  280. return this; // self
  281. },
  282. moveToBack: function(){
  283. // summary: moves a shape to back of its parent's list of shapes
  284. var p = this.getParent();
  285. if(p){
  286. p._moveChildToBack(this);
  287. this._moveToBack(); // execute renderer-specific action
  288. }
  289. return this;
  290. },
  291. _moveToFront: function(){
  292. // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront()
  293. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  294. },
  295. _moveToBack: function(){
  296. // summary: renderer-specific hook, see dojox.gfx.shape.Shape.moveToFront()
  297. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  298. },
  299. // apply left & right transformation
  300. applyRightTransform: function(matrix){
  301. // summary: multiplies the existing matrix with an argument on right side
  302. // (this.matrix * matrix)
  303. // matrix: dojox.gfx.Matrix2D
  304. // a matrix or a matrix-like object
  305. // (see an argument of dojox.gfx.Matrix2D
  306. // constructor for a list of acceptable arguments)
  307. return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
  308. },
  309. applyLeftTransform: function(matrix){
  310. // summary: multiplies the existing matrix with an argument on left side
  311. // (matrix * this.matrix)
  312. // matrix: dojox.gfx.Matrix2D
  313. // a matrix or a matrix-like object
  314. // (see an argument of dojox.gfx.Matrix2D
  315. // constructor for a list of acceptable arguments)
  316. return matrix ? this.setTransform([matrix, this.matrix]) : this; // self
  317. },
  318. applyTransform: function(matrix){
  319. // summary: a shortcut for dojox.gfx.Shape.applyRightTransform
  320. // matrix: dojox.gfx.Matrix2D
  321. // a matrix or a matrix-like object
  322. // (see an argument of dojox.gfx.Matrix2D
  323. // constructor for a list of acceptable arguments)
  324. return matrix ? this.setTransform([this.matrix, matrix]) : this; // self
  325. },
  326. // virtual group methods
  327. removeShape: function(silently){
  328. // summary: removes the shape from its parent's list of shapes
  329. // silently: Boolean
  330. // if true, do not redraw a picture yet
  331. if(this.parent){
  332. this.parent.remove(this, silently);
  333. }
  334. return this; // self
  335. },
  336. _setParent: function(parent, matrix){
  337. // summary: sets a parent
  338. // parent: Object
  339. // a parent or null
  340. // (see dojox.gfx.Surface,
  341. // dojox.gfx.shape.VirtualGroup,
  342. // or dojox.gfx.Group)
  343. // matrix: dojox.gfx.Matrix2D
  344. // a 2D matrix or a matrix-like object
  345. this.parent = parent;
  346. return this._updateParentMatrix(matrix); // self
  347. },
  348. _updateParentMatrix: function(matrix){
  349. // summary: updates the parent matrix with new matrix
  350. // matrix: dojox.gfx.Matrix2D
  351. // a 2D matrix or a matrix-like object
  352. this.parentMatrix = matrix ? matrixLib.clone(matrix) : null;
  353. return this._applyTransform(); // self
  354. },
  355. _getRealMatrix: function(){
  356. // summary: returns the cumulative ('real') transformation matrix
  357. // by combining the shape's matrix with its parent's matrix
  358. var m = this.matrix;
  359. var p = this.parent;
  360. while(p){
  361. if(p.matrix){
  362. m = matrixLib.multiply(p.matrix, m);
  363. }
  364. p = p.parent;
  365. }
  366. return m; // dojox.gfx.Matrix2D
  367. }
  368. });
  369. shape._eventsProcessing = {
  370. connect: function(name, object, method){
  371. // summary: connects a handler to an event on this shape
  372. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  373. // redirect to fixCallback to normalize events and add the gfxTarget to the event. The latter
  374. // is done by dojox.gfx.fixTarget which is defined by each renderer
  375. return events.connect(this.getEventSource(), name, shape.fixCallback(this, g.fixTarget, object, method));
  376. },
  377. disconnect: function(token){
  378. // summary: connects a handler by token from an event on this shape
  379. // COULD BE RE-IMPLEMENTED BY THE RENDERER!
  380. events.disconnect(token);
  381. }
  382. };
  383. shape.fixCallback = function(gfxElement, fixFunction, scope, method){
  384. // summary:
  385. // Wraps the callback to allow for tests and event normalization
  386. // before it gets invoked. This is where 'fixTarget' is invoked.
  387. // gfxElement: Object
  388. // The GFX object that triggers the action (ex.:
  389. // dojox.gfx.Surface and dojox.gfx.Shape). A new event property
  390. // 'gfxTarget' is added to the event to reference this object.
  391. // for easy manipulation of GFX objects by the event handlers.
  392. // fixFunction: Function
  393. // The function that implements the logic to set the 'gfxTarget'
  394. // property to the event. It should be 'dojox.gfx.fixTarget' for
  395. // most of the cases
  396. // scope: Object
  397. // Optional. The scope to be used when invoking 'method'. If
  398. // omitted, a global scope is used.
  399. // method: Function|String
  400. // The original callback to be invoked.
  401. if(!method){
  402. method = scope;
  403. scope = null;
  404. }
  405. if(lang.isString(method)){
  406. scope = scope || win.global;
  407. if(!scope[method]){ throw(['dojox.gfx.shape.fixCallback: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
  408. return function(e){
  409. return fixFunction(e,gfxElement) ? scope[method].apply(scope, arguments || []) : undefined; }; // Function
  410. }
  411. return !scope
  412. ? function(e){
  413. return fixFunction(e,gfxElement) ? method.apply(scope, arguments) : undefined; }
  414. : function(e){
  415. return fixFunction(e,gfxElement) ? method.apply(scope, arguments || []) : undefined; }; // Function
  416. };
  417. lang.extend(shape.Shape, shape._eventsProcessing);
  418. shape.Container = {
  419. // summary: a container of shapes, which can be used
  420. // as a foundation for renderer-specific groups, or as a way
  421. // to logically group shapes (e.g, to propagate matricies)
  422. _init: function() {
  423. // children: Array: a list of children
  424. this.children = [];
  425. },
  426. // group management
  427. openBatch: function() {
  428. // summary: starts a new batch, subsequent new child shapes will be held in
  429. // the batch instead of appending to the container directly
  430. },
  431. closeBatch: function() {
  432. // summary: submits the current batch, append all pending child shapes to DOM
  433. },
  434. add: function(shape){
  435. // summary: adds a shape to the list
  436. // shape: dojox.gfx.Shape
  437. // the shape to add to the list
  438. var oldParent = shape.getParent();
  439. if(oldParent){
  440. oldParent.remove(shape, true);
  441. }
  442. this.children.push(shape);
  443. return shape._setParent(this, this._getRealMatrix()); // self
  444. },
  445. remove: function(shape, silently){
  446. // summary: removes a shape from the list
  447. // shape: dojox.gfx.shape.Shape
  448. // the shape to remove
  449. // silently: Boolean
  450. // if true, do not redraw a picture yet
  451. for(var i = 0; i < this.children.length; ++i){
  452. if(this.children[i] == shape){
  453. if(silently){
  454. // skip for now
  455. }else{
  456. shape.parent = null;
  457. shape.parentMatrix = null;
  458. }
  459. this.children.splice(i, 1);
  460. break;
  461. }
  462. }
  463. return this; // self
  464. },
  465. clear: function(){
  466. // summary: removes all shapes from a group/surface
  467. var shape;
  468. for(var i = 0; i < this.children.length;++i){
  469. shape = this.children[i];
  470. shape.parent = null;
  471. shape.parentMatrix = null;
  472. }
  473. this.children = [];
  474. return this; // self
  475. },
  476. // moving child nodes
  477. _moveChildToFront: function(shape){
  478. // summary: moves a shape to front of the list of shapes
  479. // shape: dojox.gfx.shape.Shape
  480. // one of the child shapes to move to the front
  481. for(var i = 0; i < this.children.length; ++i){
  482. if(this.children[i] == shape){
  483. this.children.splice(i, 1);
  484. this.children.push(shape);
  485. break;
  486. }
  487. }
  488. return this; // self
  489. },
  490. _moveChildToBack: function(shape){
  491. // summary: moves a shape to back of the list of shapes
  492. // shape: dojox.gfx.shape.Shape
  493. // one of the child shapes to move to the front
  494. for(var i = 0; i < this.children.length; ++i){
  495. if(this.children[i] == shape){
  496. this.children.splice(i, 1);
  497. this.children.unshift(shape);
  498. break;
  499. }
  500. }
  501. return this; // self
  502. }
  503. };
  504. declare("dojox.gfx.shape.Surface", null, {
  505. // summary: a surface object to be used for drawings
  506. constructor: function(){
  507. // underlying node
  508. this.rawNode = null;
  509. // the parent node
  510. this._parent = null;
  511. // the list of DOM nodes to be deleted in the case of destruction
  512. this._nodes = [];
  513. // the list of events to be detached in the case of destruction
  514. this._events = [];
  515. },
  516. destroy: function(){
  517. // summary: destroy all relevant external resources and release all
  518. // external references to make this object garbage-collectible
  519. // dispose children from registry
  520. var _dispose = function(s){
  521. shape.dispose(s);
  522. s.parent = null;
  523. if(s.children && s.children.length){
  524. arr.forEach(s.children, _dispose);
  525. s.children = null;
  526. }
  527. };
  528. arr.forEach(this.children, _dispose);
  529. this.children = null;
  530. // destroy dom construct
  531. arr.forEach(this._nodes, domConstruct.destroy);
  532. this._nodes = [];
  533. arr.forEach(this._events, events.disconnect);
  534. this._events = [];
  535. this.rawNode = null; // recycle it in _nodes, if it needs to be recycled
  536. if(has("ie")){
  537. while(this._parent.lastChild){
  538. domConstruct.destroy(this._parent.lastChild);
  539. }
  540. }else{
  541. this._parent.innerHTML = "";
  542. }
  543. this._parent = null;
  544. },
  545. getEventSource: function(){
  546. // summary: returns a node, which can be used to attach event listeners
  547. return this.rawNode; // Node
  548. },
  549. _getRealMatrix: function(){
  550. // summary: always returns the identity matrix
  551. return null; // dojox.gfx.Matrix2D
  552. },
  553. isLoaded: true,
  554. onLoad: function(/*dojox.gfx.Surface*/ surface){
  555. // summary: local event, fired once when the surface is created
  556. // asynchronously, used only when isLoaded is false, required
  557. // only for Silverlight.
  558. },
  559. whenLoaded: function(/*Object|Null*/ context, /*Function|String*/ method){
  560. var f = lang.hitch(context, method);
  561. if(this.isLoaded){
  562. f(this);
  563. }else{
  564. var h = events.connect(this, "onLoad", function(surface){
  565. events.disconnect(h);
  566. f(surface);
  567. });
  568. }
  569. }
  570. });
  571. lang.extend(shape.Surface, shape._eventsProcessing);
  572. declare("dojox.gfx.Point", null, {
  573. // summary: a hypothetical 2D point to be used for drawings - {x, y}
  574. // description: This object is defined for documentation purposes.
  575. // You should use the naked object instead: {x: 1, y: 2}.
  576. });
  577. declare("dojox.gfx.Rectangle", null, {
  578. // summary: a hypothetical rectangle - {x, y, width, height}
  579. // description: This object is defined for documentation purposes.
  580. // You should use the naked object instead: {x: 1, y: 2, width: 100, height: 200}.
  581. });
  582. declare("dojox.gfx.shape.Rect", shape.Shape, {
  583. // summary: a generic rectangle
  584. constructor: function(rawNode){
  585. // rawNode: Node
  586. // The underlying graphics system object (typically a DOM Node)
  587. this.shape = g.getDefault("Rect");
  588. this.rawNode = rawNode;
  589. },
  590. getBoundingBox: function(){
  591. // summary: returns the bounding box (its shape in this case)
  592. return this.shape; // dojox.gfx.Rectangle
  593. }
  594. });
  595. declare("dojox.gfx.shape.Ellipse", shape.Shape, {
  596. // summary: a generic ellipse
  597. constructor: function(rawNode){
  598. // rawNode: Node
  599. // a DOM Node
  600. this.shape = g.getDefault("Ellipse");
  601. this.rawNode = rawNode;
  602. },
  603. getBoundingBox: function(){
  604. // summary: returns the bounding box
  605. if(!this.bbox){
  606. var shape = this.shape;
  607. this.bbox = {x: shape.cx - shape.rx, y: shape.cy - shape.ry,
  608. width: 2 * shape.rx, height: 2 * shape.ry};
  609. }
  610. return this.bbox; // dojox.gfx.Rectangle
  611. }
  612. });
  613. declare("dojox.gfx.shape.Circle", shape.Shape, {
  614. // summary: a generic circle
  615. // (this is a helper object, which is defined for convenience)
  616. constructor: function(rawNode){
  617. // rawNode: Node
  618. // a DOM Node
  619. this.shape = g.getDefault("Circle");
  620. this.rawNode = rawNode;
  621. },
  622. getBoundingBox: function(){
  623. // summary: returns the bounding box
  624. if(!this.bbox){
  625. var shape = this.shape;
  626. this.bbox = {x: shape.cx - shape.r, y: shape.cy - shape.r,
  627. width: 2 * shape.r, height: 2 * shape.r};
  628. }
  629. return this.bbox; // dojox.gfx.Rectangle
  630. }
  631. });
  632. declare("dojox.gfx.shape.Line", shape.Shape, {
  633. // summary: a generic line
  634. // (this is a helper object, which is defined for convenience)
  635. constructor: function(rawNode){
  636. // rawNode: Node
  637. // a DOM Node
  638. this.shape = g.getDefault("Line");
  639. this.rawNode = rawNode;
  640. },
  641. getBoundingBox: function(){
  642. // summary: returns the bounding box
  643. if(!this.bbox){
  644. var shape = this.shape;
  645. this.bbox = {
  646. x: Math.min(shape.x1, shape.x2),
  647. y: Math.min(shape.y1, shape.y2),
  648. width: Math.abs(shape.x2 - shape.x1),
  649. height: Math.abs(shape.y2 - shape.y1)
  650. };
  651. }
  652. return this.bbox; // dojox.gfx.Rectangle
  653. }
  654. });
  655. declare("dojox.gfx.shape.Polyline", shape.Shape, {
  656. // summary: a generic polyline/polygon
  657. // (this is a helper object, which is defined for convenience)
  658. constructor: function(rawNode){
  659. // rawNode: Node
  660. // a DOM Node
  661. this.shape = g.getDefault("Polyline");
  662. this.rawNode = rawNode;
  663. },
  664. setShape: function(points, closed){
  665. // summary: sets a polyline/polygon shape object
  666. // points: Object
  667. // a polyline/polygon shape object
  668. // closed: Boolean
  669. // close the polyline to make a polygon
  670. if(points && points instanceof Array){
  671. // points: Array: an array of points
  672. this.inherited(arguments, [{points: points}]);
  673. if(closed && this.shape.points.length){
  674. this.shape.points.push(this.shape.points[0]);
  675. }
  676. }else{
  677. this.inherited(arguments, [points]);
  678. }
  679. return this; // self
  680. },
  681. _normalizePoints: function(){
  682. // summary: normalize points to array of {x:number, y:number}
  683. var p = this.shape.points, l = p && p.length;
  684. if(l && typeof p[0] == "number"){
  685. var points = [];
  686. for(var i = 0; i < l; i += 2){
  687. points.push({x: p[i], y: p[i + 1]});
  688. }
  689. this.shape.points = points;
  690. }
  691. },
  692. getBoundingBox: function(){
  693. // summary: returns the bounding box
  694. if(!this.bbox && this.shape.points.length){
  695. var p = this.shape.points;
  696. var l = p.length;
  697. var t = p[0];
  698. var bbox = {l: t.x, t: t.y, r: t.x, b: t.y};
  699. for(var i = 1; i < l; ++i){
  700. t = p[i];
  701. if(bbox.l > t.x) bbox.l = t.x;
  702. if(bbox.r < t.x) bbox.r = t.x;
  703. if(bbox.t > t.y) bbox.t = t.y;
  704. if(bbox.b < t.y) bbox.b = t.y;
  705. }
  706. this.bbox = {
  707. x: bbox.l,
  708. y: bbox.t,
  709. width: bbox.r - bbox.l,
  710. height: bbox.b - bbox.t
  711. };
  712. }
  713. return this.bbox; // dojox.gfx.Rectangle
  714. }
  715. });
  716. declare("dojox.gfx.shape.Image", shape.Shape, {
  717. // summary: a generic image
  718. // (this is a helper object, which is defined for convenience)
  719. constructor: function(rawNode){
  720. // rawNode: Node
  721. // a DOM Node
  722. this.shape = g.getDefault("Image");
  723. this.rawNode = rawNode;
  724. },
  725. getBoundingBox: function(){
  726. // summary: returns the bounding box (its shape in this case)
  727. return this.shape; // dojox.gfx.Rectangle
  728. },
  729. setStroke: function(){
  730. // summary: ignore setting a stroke style
  731. return this; // self
  732. },
  733. setFill: function(){
  734. // summary: ignore setting a fill style
  735. return this; // self
  736. }
  737. });
  738. declare("dojox.gfx.shape.Text", shape.Shape, {
  739. // summary: a generic text
  740. constructor: function(rawNode){
  741. // rawNode: Node
  742. // a DOM Node
  743. this.fontStyle = null;
  744. this.shape = g.getDefault("Text");
  745. this.rawNode = rawNode;
  746. },
  747. getFont: function(){
  748. // summary: returns the current font object or null
  749. return this.fontStyle; // Object
  750. },
  751. setFont: function(newFont){
  752. // summary: sets a font for text
  753. // newFont: Object
  754. // a font object (see dojox.gfx.defaultFont) or a font string
  755. this.fontStyle = typeof newFont == "string" ? g.splitFontString(newFont) :
  756. g.makeParameters(g.defaultFont, newFont);
  757. this._setFont();
  758. return this; // self
  759. }
  760. });
  761. shape.Creator = {
  762. // summary: shape creators
  763. createShape: function(shape){
  764. // summary: creates a shape object based on its type; it is meant to be used
  765. // by group-like objects
  766. // shape: Object
  767. // a shape descriptor object
  768. switch(shape.type){
  769. case g.defaultPath.type: return this.createPath(shape);
  770. case g.defaultRect.type: return this.createRect(shape);
  771. case g.defaultCircle.type: return this.createCircle(shape);
  772. case g.defaultEllipse.type: return this.createEllipse(shape);
  773. case g.defaultLine.type: return this.createLine(shape);
  774. case g.defaultPolyline.type: return this.createPolyline(shape);
  775. case g.defaultImage.type: return this.createImage(shape);
  776. case g.defaultText.type: return this.createText(shape);
  777. case g.defaultTextPath.type: return this.createTextPath(shape);
  778. }
  779. return null;
  780. },
  781. createGroup: function(){
  782. // summary: creates a group shape
  783. return this.createObject(g.Group); // dojox.gfx.Group
  784. },
  785. createRect: function(rect){
  786. // summary: creates a rectangle shape
  787. // rect: Object
  788. // a path object (see dojox.gfx.defaultRect)
  789. return this.createObject(g.Rect, rect); // dojox.gfx.Rect
  790. },
  791. createEllipse: function(ellipse){
  792. // summary: creates an ellipse shape
  793. // ellipse: Object
  794. // an ellipse object (see dojox.gfx.defaultEllipse)
  795. return this.createObject(g.Ellipse, ellipse); // dojox.gfx.Ellipse
  796. },
  797. createCircle: function(circle){
  798. // summary: creates a circle shape
  799. // circle: Object
  800. // a circle object (see dojox.gfx.defaultCircle)
  801. return this.createObject(g.Circle, circle); // dojox.gfx.Circle
  802. },
  803. createLine: function(line){
  804. // summary: creates a line shape
  805. // line: Object
  806. // a line object (see dojox.gfx.defaultLine)
  807. return this.createObject(g.Line, line); // dojox.gfx.Line
  808. },
  809. createPolyline: function(points){
  810. // summary: creates a polyline/polygon shape
  811. // points: Object
  812. // a points object (see dojox.gfx.defaultPolyline)
  813. // or an Array of points
  814. return this.createObject(g.Polyline, points); // dojox.gfx.Polyline
  815. },
  816. createImage: function(image){
  817. // summary: creates a image shape
  818. // image: Object
  819. // an image object (see dojox.gfx.defaultImage)
  820. return this.createObject(g.Image, image); // dojox.gfx.Image
  821. },
  822. createText: function(text){
  823. // summary: creates a text shape
  824. // text: Object
  825. // a text object (see dojox.gfx.defaultText)
  826. return this.createObject(g.Text, text); // dojox.gfx.Text
  827. },
  828. createPath: function(path){
  829. // summary: creates a path shape
  830. // path: Object
  831. // a path object (see dojox.gfx.defaultPath)
  832. return this.createObject(g.Path, path); // dojox.gfx.Path
  833. },
  834. createTextPath: function(text){
  835. // summary: creates a text shape
  836. // text: Object
  837. // a textpath object (see dojox.gfx.defaultTextPath)
  838. return this.createObject(g.TextPath, {}).setText(text); // dojox.gfx.TextPath
  839. },
  840. createObject: function(shapeType, rawShape){
  841. // summary: creates an instance of the passed shapeType class
  842. // SHOULD BE RE-IMPLEMENTED BY THE RENDERER!
  843. // shapeType: Function
  844. // a class constructor to create an instance of
  845. // rawShape: Object
  846. // properties to be passed in to the classes 'setShape' method
  847. return null; // dojox.gfx.Shape
  848. }
  849. };
  850. return shape;
  851. });