_base.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. define("dojox/gfx/_base", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/Color", "dojo/_base/sniff", "dojo/_base/window",
  2. "dojo/_base/array","dojo/dom", "dojo/dom-construct","dojo/dom-geometry"],
  3. function(lang, html, Color, has, win, arr, dom, domConstruct, domGeom){
  4. // module:
  5. // dojox/gfx
  6. // summary:
  7. // This module contains common core Graphics API used by different graphics renderers.
  8. var g = lang.getObject("dojox.gfx", true),
  9. b = g._base = {};
  10. /*===== g = dojox.gfx; b = dojox.gfx._base; =====*/
  11. // candidates for dojox.style (work on VML and SVG nodes)
  12. g._hasClass = function(/*DomNode*/node, /*String*/classStr){
  13. // summary:
  14. // Returns whether or not the specified classes are a portion of the
  15. // class list currently applied to the node.
  16. // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
  17. var cls = node.getAttribute("className");
  18. return cls && (" " + cls + " ").indexOf(" " + classStr + " ") >= 0; // Boolean
  19. };
  20. g._addClass = function(/*DomNode*/node, /*String*/classStr){
  21. // summary:
  22. // Adds the specified classes to the end of the class list on the
  23. // passed node.
  24. var cls = node.getAttribute("className") || "";
  25. if(!cls || (" " + cls + " ").indexOf(" " + classStr + " ") < 0){
  26. node.setAttribute("className", cls + (cls ? " " : "") + classStr);
  27. }
  28. };
  29. g._removeClass = function(/*DomNode*/node, /*String*/classStr){
  30. // summary: Removes classes from node.
  31. var cls = node.getAttribute("className");
  32. if(cls){
  33. node.setAttribute(
  34. "className",
  35. cls.replace(new RegExp('(^|\\s+)' + classStr + '(\\s+|$)'), "$1$2")
  36. );
  37. }
  38. };
  39. // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
  40. // derived from Morris John's emResized measurer
  41. b._getFontMeasurements = function(){
  42. // summary:
  43. // Returns an object that has pixel equivilents of standard font
  44. // size values.
  45. var heights = {
  46. '1em': 0, '1ex': 0, '100%': 0, '12pt': 0, '16px': 0, 'xx-small': 0,
  47. 'x-small': 0, 'small': 0, 'medium': 0, 'large': 0, 'x-large': 0,
  48. 'xx-large': 0
  49. };
  50. var p;
  51. if(has("ie")){
  52. // we do a font-size fix if and only if one isn't applied already.
  53. // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
  54. win.doc.documentElement.style.fontSize="100%";
  55. }
  56. // set up the measuring node.
  57. var div = domConstruct.create("div", {style: {
  58. position: "absolute",
  59. left: "0",
  60. top: "-100px",
  61. width: "30px",
  62. height: "1000em",
  63. borderWidth: "0",
  64. margin: "0",
  65. padding: "0",
  66. outline: "none",
  67. lineHeight: "1",
  68. overflow: "hidden"
  69. }}, win.body());
  70. // do the measurements.
  71. for(p in heights){
  72. div.style.fontSize = p;
  73. heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
  74. }
  75. win.body().removeChild(div);
  76. return heights; //object
  77. };
  78. var fontMeasurements = null;
  79. b._getCachedFontMeasurements = function(recalculate){
  80. if(recalculate || !fontMeasurements){
  81. fontMeasurements = b._getFontMeasurements();
  82. }
  83. return fontMeasurements;
  84. };
  85. // candidate for dojox.html.metrics
  86. var measuringNode = null, empty = {};
  87. b._getTextBox = function( /*String*/ text,
  88. /*Object*/ style,
  89. /*String?*/ className){
  90. var m, s, al = arguments.length;
  91. var i;
  92. if(!measuringNode){
  93. measuringNode = domConstruct.create("div", {style: {
  94. position: "absolute",
  95. top: "-10000px",
  96. left: "0"
  97. }}, win.body());
  98. }
  99. m = measuringNode;
  100. // reset styles
  101. m.className = "";
  102. s = m.style;
  103. s.borderWidth = "0";
  104. s.margin = "0";
  105. s.padding = "0";
  106. s.outline = "0";
  107. // set new style
  108. if(al > 1 && style){
  109. for(i in style){
  110. if(i in empty){ continue; }
  111. s[i] = style[i];
  112. }
  113. }
  114. // set classes
  115. if(al > 2 && className){
  116. m.className = className;
  117. }
  118. // take a measure
  119. m.innerHTML = text;
  120. if(m["getBoundingClientRect"]){
  121. var bcr = m.getBoundingClientRect();
  122. return {l: bcr.left, t: bcr.top, w: bcr.width || (bcr.right - bcr.left), h: bcr.height || (bcr.bottom - bcr.top)};
  123. }else{
  124. return domGeom.getMarginBox(m);
  125. }
  126. };
  127. // candidate for dojo.dom
  128. var uniqueId = 0;
  129. b._getUniqueId = function(){
  130. // summary: returns a unique string for use with any DOM element
  131. var id;
  132. do{
  133. id = dojo._scopeName + "xUnique" + (++uniqueId);
  134. }while(dom.byId(id));
  135. return id;
  136. };
  137. lang.mixin(g, {
  138. // summary:
  139. // defines constants, prototypes, and utility functions for the core Graphics API
  140. // default shapes, which are used to fill in missing parameters
  141. defaultPath: {
  142. // summary:
  143. // Defines the default Path prototype object.
  144. type: "path",
  145. // type: String
  146. // Specifies this object is a Path, default value 'path'.
  147. path: ""
  148. // path: String
  149. // The path commands. See W32C SVG 1.0 specification.
  150. // Defaults to empty string value.
  151. },
  152. defaultPolyline: {
  153. // summary:
  154. // Defines the default PolyLine prototype.
  155. type: "polyline",
  156. // type: String
  157. // Specifies this object is a PolyLine, default value 'polyline'.
  158. points: []
  159. // points: Array
  160. // An array of point objects [{x:0,y:0},...] defining the default polyline's line segments. Value is an empty array [].
  161. },
  162. defaultRect: {
  163. // summary:
  164. // Defines the default Rect prototype.
  165. type: "rect",
  166. // type: String
  167. // Specifies this default object is a type of Rect. Value is 'rect'
  168. x: 0,
  169. // x: Number
  170. // The X coordinate of the default rectangles position, value 0.
  171. y: 0,
  172. // y: Number
  173. // The Y coordinate of the default rectangle's position, value 0.
  174. width: 100,
  175. // width: Number
  176. // The width of the default rectangle, value 100.
  177. height: 100,
  178. // height: Number
  179. // The height of the default rectangle, value 100.
  180. r: 0
  181. // r: Number
  182. // The corner radius for the default rectangle, value 0.
  183. },
  184. defaultEllipse: {
  185. // summary:
  186. // Defines the default Ellipse prototype.
  187. type: "ellipse",
  188. // type: String
  189. // Specifies that this object is a type of Ellipse, value is 'ellipse'
  190. cx: 0,
  191. // cx: Number
  192. // The X coordinate of the center of the ellipse, default value 0.
  193. cy: 0,
  194. // cy: Number
  195. // The Y coordinate of the center of the ellipse, default value 0.
  196. rx: 200,
  197. // rx: Number
  198. // The radius of the ellipse in the X direction, default value 200.
  199. ry: 100
  200. // ry: Number
  201. // The radius of the ellipse in the Y direction, default value 200.
  202. },
  203. defaultCircle: {
  204. // summary:
  205. // An object defining the default Circle prototype.
  206. type: "circle",
  207. // type: String
  208. // Specifies this object is a circle, value 'circle'
  209. cx: 0,
  210. // cx: Number
  211. // The X coordinate of the center of the circle, default value 0.
  212. cy: 0,
  213. // cy: Number
  214. // The Y coordinate of the center of the circle, default value 0.
  215. r: 100
  216. // r: Number
  217. // The radius, default value 100.
  218. },
  219. defaultLine: {
  220. // summary:
  221. // An pbject defining the default Line prototype.
  222. type: "line",
  223. // type: String
  224. // Specifies this is a Line, value 'line'
  225. x1: 0,
  226. // x1: Number
  227. // The X coordinate of the start of the line, default value 0.
  228. y1: 0,
  229. // y1: Number
  230. // The Y coordinate of the start of the line, default value 0.
  231. x2: 100,
  232. // x2: Number
  233. // The X coordinate of the end of the line, default value 100.
  234. y2: 100
  235. // y2: Number
  236. // The Y coordinate of the end of the line, default value 100.
  237. },
  238. defaultImage: {
  239. // summary:
  240. // Defines the default Image prototype.
  241. type: "image",
  242. // type: String
  243. // Specifies this object is an image, value 'image'.
  244. x: 0,
  245. // x: Number
  246. // The X coordinate of the image's position, default value 0.
  247. y: 0,
  248. // y: Number
  249. // The Y coordinate of the image's position, default value 0.
  250. width: 0,
  251. // width: Number
  252. // The width of the image, default value 0.
  253. height: 0,
  254. // height:Number
  255. // The height of the image, default value 0.
  256. src: ""
  257. // src: String
  258. // The src url of the image, defaults to empty string.
  259. },
  260. defaultText: {
  261. // summary:
  262. // Defines the default Text prototype.
  263. type: "text",
  264. // type: String
  265. // Specifies this is a Text shape, value 'text'.
  266. x: 0,
  267. // x: Number
  268. // The X coordinate of the text position, default value 0.
  269. y: 0,
  270. // y: Number
  271. // The Y coordinate of the text position, default value 0.
  272. text: "",
  273. // text: String
  274. // The text to be displayed, default value empty string.
  275. align: "start",
  276. // align: String
  277. // The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
  278. decoration: "none",
  279. // decoration: String
  280. // The text decoration , one of 'none', ... . Default value 'none'.
  281. rotated: false,
  282. // rotated: Boolean
  283. // Whether the text is rotated, boolean default value false.
  284. kerning: true
  285. // kerning: Boolean
  286. // Whether kerning is used on the text, boolean default value true.
  287. },
  288. defaultTextPath: {
  289. // summary:
  290. // Defines the default TextPath prototype.
  291. type: "textpath",
  292. // type: String
  293. // Specifies this is a TextPath, value 'textpath'.
  294. text: "",
  295. // text: String
  296. // The text to be displayed, default value empty string.
  297. align: "start",
  298. // align: String
  299. // The horizontal text alignment, one of 'start', 'end', 'center'. Default value 'start'.
  300. decoration: "none",
  301. // decoration: String
  302. // The text decoration , one of 'none', ... . Default value 'none'.
  303. rotated: false,
  304. // rotated: Boolean
  305. // Whether the text is rotated, boolean default value false.
  306. kerning: true
  307. // kerning: Boolean
  308. // Whether kerning is used on the text, boolean default value true.
  309. },
  310. // default stylistic attributes
  311. defaultStroke: {
  312. // summary:
  313. // A stroke defines stylistic properties that are used when drawing a path.
  314. // This object defines the default Stroke prototype.
  315. type: "stroke",
  316. // type: String
  317. // Specifies this object is a type of Stroke, value 'stroke'.
  318. color: "black",
  319. // color: String
  320. // The color of the stroke, default value 'black'.
  321. style: "solid",
  322. // style: String
  323. // The style of the stroke, one of 'solid', ... . Default value 'solid'.
  324. width: 1,
  325. // width: Number
  326. // The width of a stroke, default value 1.
  327. cap: "butt",
  328. // cap: String
  329. // The endcap style of the path. One of 'butt', 'round', ... . Default value 'butt'.
  330. join: 4
  331. // join: Number
  332. // The join style to use when combining path segments. Default value 4.
  333. },
  334. defaultLinearGradient: {
  335. // summary:
  336. // An object defining the default stylistic properties used for Linear Gradient fills.
  337. // Linear gradients are drawn along a virtual line, which results in appearance of a rotated pattern in a given direction/orientation.
  338. type: "linear",
  339. // type: String
  340. // Specifies this object is a Linear Gradient, value 'linear'
  341. x1: 0,
  342. // x1: Number
  343. // The X coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
  344. y1: 0,
  345. // y1: Number
  346. // The Y coordinate of the start of the virtual line along which the gradient is drawn, default value 0.
  347. x2: 100,
  348. // x2: Number
  349. // The X coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
  350. y2: 100,
  351. // y2: Number
  352. // The Y coordinate of the end of the virtual line along which the gradient is drawn, default value 100.
  353. colors: [
  354. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  355. ]
  356. // colors: Array
  357. // An array of colors at given offsets (from the start of the line). The start of the line is
  358. // defined at offest 0 with the end of the line at offset 1.
  359. // Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
  360. },
  361. defaultRadialGradient: {
  362. // summary:
  363. // An object specifying the default properties for RadialGradients using in fills patterns.
  364. type: "radial",
  365. // type: String
  366. // Specifies this is a RadialGradient, value 'radial'
  367. cx: 0,
  368. // cx: Number
  369. // The X coordinate of the center of the radial gradient, default value 0.
  370. cy: 0,
  371. // cy: Number
  372. // The Y coordinate of the center of the radial gradient, default value 0.
  373. r: 100,
  374. // r: Number
  375. // The radius to the end of the radial gradient, default value 100.
  376. colors: [
  377. { offset: 0, color: "black" }, { offset: 1, color: "white" }
  378. ]
  379. // colors: Array
  380. // An array of colors at given offsets (from the center of the radial gradient).
  381. // The center is defined at offest 0 with the outer edge of the gradient at offset 1.
  382. // Default value, [{ offset: 0, color: 'black'},{offset: 1, color: 'white'}], is a gradient from black to white.
  383. },
  384. defaultPattern: {
  385. // summary:
  386. // An object specifying the default properties for a Pattern using in fill operations.
  387. type: "pattern",
  388. // type: String
  389. // Specifies this object is a Pattern, value 'pattern'.
  390. x: 0,
  391. // x: Number
  392. // The X coordinate of the position of the pattern, default value is 0.
  393. y: 0,
  394. // y: Number
  395. // The Y coordinate of the position of the pattern, default value is 0.
  396. width: 0,
  397. // width: Number
  398. // The width of the pattern image, default value is 0.
  399. height: 0,
  400. // height: Number
  401. // The height of the pattern image, default value is 0.
  402. src: ""
  403. // src: String
  404. // A url specifing the image to use for the pattern.
  405. },
  406. defaultFont: {
  407. // summary:
  408. // An object specifying the default properties for a Font used in text operations.
  409. type: "font",
  410. // type: String
  411. // Specifies this object is a Font, value 'font'.
  412. style: "normal",
  413. // style: String
  414. // The font style, one of 'normal', 'bold', default value 'normal'.
  415. variant: "normal",
  416. // variant: String
  417. // The font variant, one of 'normal', ... , default value 'normal'.
  418. weight: "normal",
  419. // weight: String
  420. // The font weight, one of 'normal', ..., default value 'normal'.
  421. size: "10pt",
  422. // size: String
  423. // The font size (including units), default value '10pt'.
  424. family: "serif"
  425. // family: String
  426. // The font family, one of 'serif', 'sanserif', ..., default value 'serif'.
  427. },
  428. getDefault: (function(){
  429. // summary:
  430. // Returns a function used to access default memoized prototype objects (see them defined above).
  431. var typeCtorCache = {};
  432. // a memoized delegate()
  433. return function(/*String*/ type){
  434. var t = typeCtorCache[type];
  435. if(t){
  436. return new t();
  437. }
  438. t = typeCtorCache[type] = new Function();
  439. t.prototype = g[ "default" + type ];
  440. return new t();
  441. }
  442. })(),
  443. normalizeColor: function(/*dojo.Color|Array|string|Object*/ color){
  444. // summary:
  445. // converts any legal color representation to normalized
  446. // dojo.Color object
  447. return (color instanceof Color) ? color : new Color(color); // dojo.Color
  448. },
  449. normalizeParameters: function(existed, update){
  450. // summary:
  451. // updates an existing object with properties from an 'update'
  452. // object
  453. // existed: Object
  454. // the target object to be updated
  455. // update: Object
  456. // the 'update' object, whose properties will be used to update
  457. // the existed object
  458. var x;
  459. if(update){
  460. var empty = {};
  461. for(x in existed){
  462. if(x in update && !(x in empty)){
  463. existed[x] = update[x];
  464. }
  465. }
  466. }
  467. return existed; // Object
  468. },
  469. makeParameters: function(defaults, update){
  470. // summary:
  471. // copies the original object, and all copied properties from the
  472. // 'update' object
  473. // defaults: Object
  474. // the object to be cloned before updating
  475. // update: Object
  476. // the object, which properties are to be cloned during updating
  477. var i = null;
  478. if(!update){
  479. // return dojo.clone(defaults);
  480. return lang.delegate(defaults);
  481. }
  482. var result = {};
  483. for(i in defaults){
  484. if(!(i in result)){
  485. result[i] = lang.clone((i in update) ? update[i] : defaults[i]);
  486. }
  487. }
  488. return result; // Object
  489. },
  490. formatNumber: function(x, addSpace){
  491. // summary: converts a number to a string using a fixed notation
  492. // x: Number
  493. // number to be converted
  494. // addSpace: Boolean
  495. // whether to add a space before a positive number
  496. var val = x.toString();
  497. if(val.indexOf("e") >= 0){
  498. val = x.toFixed(4);
  499. }else{
  500. var point = val.indexOf(".");
  501. if(point >= 0 && val.length - point > 5){
  502. val = x.toFixed(4);
  503. }
  504. }
  505. if(x < 0){
  506. return val; // String
  507. }
  508. return addSpace ? " " + val : val; // String
  509. },
  510. // font operations
  511. makeFontString: function(font){
  512. // summary: converts a font object to a CSS font string
  513. // font: Object: font object (see dojox.gfx.defaultFont)
  514. return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
  515. },
  516. splitFontString: function(str){
  517. // summary:
  518. // converts a CSS font string to a font object
  519. // description:
  520. // Converts a CSS font string to a gfx font object. The CSS font
  521. // string components should follow the W3C specified order
  522. // (see http://www.w3.org/TR/CSS2/fonts.html#font-shorthand):
  523. // style, variant, weight, size, optional line height (will be
  524. // ignored), and family.
  525. // str: String
  526. // a CSS font string
  527. var font = g.getDefault("Font");
  528. var t = str.split(/\s+/);
  529. do{
  530. if(t.length < 5){ break; }
  531. font.style = t[0];
  532. font.variant = t[1];
  533. font.weight = t[2];
  534. var i = t[3].indexOf("/");
  535. font.size = i < 0 ? t[3] : t[3].substring(0, i);
  536. var j = 4;
  537. if(i < 0){
  538. if(t[4] == "/"){
  539. j = 6;
  540. }else if(t[4].charAt(0) == "/"){
  541. j = 5;
  542. }
  543. }
  544. if(j < t.length){
  545. font.family = t.slice(j).join(" ");
  546. }
  547. }while(false);
  548. return font; // Object
  549. },
  550. // length operations
  551. cm_in_pt: 72 / 2.54,
  552. // cm_in_pt: Number
  553. // points per centimeter (constant)
  554. mm_in_pt: 7.2 / 2.54,
  555. // mm_in_pt: Number
  556. // points per millimeter (constant)
  557. px_in_pt: function(){
  558. // summary: returns the current number of pixels per point.
  559. return g._base._getCachedFontMeasurements()["12pt"] / 12; // Number
  560. },
  561. pt2px: function(len){
  562. // summary: converts points to pixels
  563. // len: Number
  564. // a value in points
  565. return len * g.px_in_pt(); // Number
  566. },
  567. px2pt: function(len){
  568. // summary: converts pixels to points
  569. // len: Number
  570. // a value in pixels
  571. return len / g.px_in_pt(); // Number
  572. },
  573. normalizedLength: function(len) {
  574. // summary: converts any length value to pixels
  575. // len: String
  576. // a length, e.g., '12pc'
  577. if(len.length === 0){ return 0; }
  578. if(len.length > 2){
  579. var px_in_pt = g.px_in_pt();
  580. var val = parseFloat(len);
  581. switch(len.slice(-2)){
  582. case "px": return val;
  583. case "pt": return val * px_in_pt;
  584. case "in": return val * 72 * px_in_pt;
  585. case "pc": return val * 12 * px_in_pt;
  586. case "mm": return val * g.mm_in_pt * px_in_pt;
  587. case "cm": return val * g.cm_in_pt * px_in_pt;
  588. }
  589. }
  590. return parseFloat(len); // Number
  591. },
  592. pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  593. // pathVmlRegExp: RegExp
  594. // a constant regular expression used to split a SVG/VML path into primitive components
  595. pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
  596. // pathVmlRegExp: RegExp
  597. // a constant regular expression used to split a SVG/VML path into primitive components
  598. equalSources: function(a /*Object*/, b /*Object*/){
  599. // summary: compares event sources, returns true if they are equal
  600. // a: first event source
  601. // b: event source to compare against a
  602. return a && b && a === b;
  603. },
  604. switchTo: function(renderer/*String|Object*/){
  605. // summary: switch the graphics implementation to the specified renderer.
  606. // renderer:
  607. // Either the string name of a renderer (eg. 'canvas', 'svg, ...) or the renderer
  608. // object to switch to.
  609. var ns = typeof renderer == "string" ? g[renderer] : renderer;
  610. if(ns){
  611. arr.forEach(["Group", "Rect", "Ellipse", "Circle", "Line",
  612. "Polyline", "Image", "Text", "Path", "TextPath",
  613. "Surface", "createSurface", "fixTarget"], function(name){
  614. g[name] = ns[name];
  615. });
  616. }
  617. }
  618. });
  619. return g; // defaults object api
  620. });