1 if(!dojo._hasResource["dojox.gfx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.gfx._base"] = true;
3 dojo.provide("dojox.gfx._base");
6 var g = dojox.gfx, b = g._base;
8 // candidates for dojox.style (work on VML and SVG nodes)
9 g._hasClass = function(/*DomNode*/node, /*String*/classStr){
11 // Returns whether or not the specified classes are a portion of the
12 // class list currently applied to the node.
13 // return (new RegExp('(^|\\s+)'+classStr+'(\\s+|$)')).test(node.className) // Boolean
14 return ((" "+node.getAttribute("className")+" ").indexOf(" "+classStr+" ") >= 0); // Boolean
16 g._addClass = function(/*DomNode*/node, /*String*/classStr){
18 // Adds the specified classes to the end of the class list on the
20 var cls = node.getAttribute("className");
21 if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
22 node.setAttribute("className", cls + (cls ? ' ' : '') + classStr);
25 g._removeClass = function(/*DomNode*/node, /*String*/classStr){
26 // summary: Removes classes from node.
27 node.setAttribute("className", node.getAttribute("className").replace(new RegExp('(^|\\s+)'+classStr+'(\\s+|$)'), "$1$2"));
31 // candidate for dojox.html.metrics (dynamic font resize handler is not implemented here)
33 // derived from Morris John's emResized measurer
34 b._getFontMeasurements = function(){
36 // Returns an object that has pixel equivilents of standard font size values.
38 '1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
39 'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
43 // we do a font-size fix if and only if one isn't applied already.
44 // NOTE: If someone set the fontSize on the HTML Element, this will kill it.
45 dojo.doc.documentElement.style.fontSize="100%";
48 // set up the measuring node.
49 var div=dojo.doc.createElement("div");
50 div.style.position="absolute";
51 div.style.left="-100px";
53 div.style.width="30px";
54 div.style.height="1000em";
57 div.style.padding="0";
58 div.style.outline="0";
59 div.style.lineHeight="1";
60 div.style.overflow="hidden";
61 dojo.body().appendChild(div);
63 // do the measurements.
64 for(var p in heights){
65 div.style.fontSize = p;
66 heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
69 dojo.body().removeChild(div);
71 return heights; // object
74 var fontMeasurements = null;
76 b._getCachedFontMeasurements = function(recalculate){
77 if(recalculate || !fontMeasurements){
78 fontMeasurements = b._getFontMeasurements();
80 return fontMeasurements;
83 // candidate for dojox.html.metrics
85 var measuringNode = null, empty = {};
86 b._getTextBox = function(/* String */ text, /* Object */ style, /* String? */ className){
89 m = measuringNode = dojo.doc.createElement("div");
90 m.style.position = "absolute";
91 m.style.left = "-10000px";
93 dojo.body().appendChild(m);
100 m.style.margin = "0";
101 m.style.padding = "0";
102 m.style.outline = "0";
104 if(arguments.length > 1 && style){
106 if(i in empty){ continue; }
107 m.style[i] = style[i];
111 if(arguments.length > 2 && className){
112 m.className = className;
116 return dojo.marginBox(m);
119 // candidate for dojo.dom
122 b._getUniqueId = function(){
123 // summary: returns a unique string for use with any DOM element
126 id = dojo._scopeName + "Unique" + (++uniqueId);
127 }while(dojo.byId(id));
132 dojo.mixin(dojox.gfx, {
133 // summary: defines constants, prototypes, and utility functions
135 // default shapes, which are used to fill in missing parameters
136 defaultPath: {type: "path", path: ""},
137 defaultPolyline: {type: "polyline", points: []},
138 defaultRect: {type: "rect", x: 0, y: 0, width: 100, height: 100, r: 0},
139 defaultEllipse: {type: "ellipse", cx: 0, cy: 0, rx: 200, ry: 100},
140 defaultCircle: {type: "circle", cx: 0, cy: 0, r: 100},
141 defaultLine: {type: "line", x1: 0, y1: 0, x2: 100, y2: 100},
142 defaultImage: {type: "image", x: 0, y: 0, width: 0, height: 0, src: ""},
143 defaultText: {type: "text", x: 0, y: 0, text: "",
144 align: "start", decoration: "none", rotated: false, kerning: true },
145 defaultTextPath: {type: "textpath", text: "",
146 align: "start", decoration: "none", rotated: false, kerning: true },
148 // default geometric attributes
149 defaultStroke: {type: "stroke", color: "black", style: "solid", width: 1, cap: "butt", join: 4},
150 defaultLinearGradient: {type: "linear", x1: 0, y1: 0, x2: 100, y2: 100,
151 colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
152 defaultRadialGradient: {type: "radial", cx: 0, cy: 0, r: 100,
153 colors: [{offset: 0, color: "black"}, {offset: 1, color: "white"}]},
154 defaultPattern: {type: "pattern", x: 0, y: 0, width: 0, height: 0, src: ""},
155 defaultFont: {type: "font", style: "normal", variant: "normal", weight: "normal",
156 size: "10pt", family: "serif"},
158 normalizeColor: function(/*Color*/ color){
159 // summary: converts any legal color representation to normalized dojo.Color object
160 return (color instanceof dojo.Color) ? color : new dojo.Color(color); // dojo.Color
162 normalizeParameters: function(existed, update){
163 // summary: updates an existing object with properties from an "update" object
164 // existed: Object: the "target" object to be updated
165 // update: Object: the "update" object, whose properties will be used to update the existed object
168 for(var x in existed){
169 if(x in update && !(x in empty)){
170 existed[x] = update[x];
174 return existed; // Object
176 makeParameters: function(defaults, update){
177 // summary: copies the original object, and all copied properties from the "update" object
178 // defaults: Object: the object to be cloned before updating
179 // update: Object: the object, which properties are to be cloned during updating
180 if(!update) return dojo.clone(defaults);
182 for(var i in defaults){
184 result[i] = dojo.clone((i in update) ? update[i] : defaults[i]);
187 return result; // Object
189 formatNumber: function(x, addSpace){
190 // summary: converts a number to a string using a fixed notation
191 // x: Number: number to be converted
192 // addSpace: Boolean?: if it is true, add a space before a positive number
193 var val = x.toString();
194 if(val.indexOf("e") >= 0){
197 var point = val.indexOf(".");
198 if(point >= 0 && val.length - point > 5){
203 return val; // String
205 return addSpace ? " " + val : val; // String
208 makeFontString: function(font){
209 // summary: converts a font object to a CSS font string
210 // font: Object: font object (see dojox.gfx.defaultFont)
211 return font.style + " " + font.variant + " " + font.weight + " " + font.size + " " + font.family; // Object
213 splitFontString: function(str){
214 // summary: converts a CSS font string to a font object
215 // str: String: a CSS font string
216 var font = dojo.clone(dojox.gfx.defaultFont);
217 var t = str.split(/\s+/);
219 if(t.length < 5){ break; }
223 var i = t[3].indexOf("/");
224 font.size = i < 0 ? t[3] : t[3].substring(0, i);
231 if(t[4].substr(0, 1) == "/"){
236 if(j + 3 > t.length){ break; }
238 font.family = t[j + 1];
240 return font; // Object
243 cm_in_pt: 72 / 2.54, // Number: centimeters per inch
244 mm_in_pt: 7.2 / 2.54, // Number: millimeters per inch
245 px_in_pt: function(){
246 // summary: returns a number of pixels per point
247 return dojox.gfx._base._getCachedFontMeasurements()["12pt"] / 12; // Number
249 pt2px: function(len){
250 // summary: converts points to pixels
251 // len: Number: a value in points
252 return len * dojox.gfx.px_in_pt(); // Number
254 px2pt: function(len){
255 // summary: converts pixels to points
256 // len: Number: a value in pixels
257 return len / dojox.gfx.px_in_pt(); // Number
259 normalizedLength: function(len) {
260 // summary: converts any length value to pixels
261 // len: String: a length, e.g., "12pc"
262 if(len.length == 0) return 0;
264 var px_in_pt = dojox.gfx.px_in_pt();
265 var val = parseFloat(len);
266 switch(len.slice(-2)){
267 case "px": return val;
268 case "pt": return val * px_in_pt;
269 case "in": return val * 72 * px_in_pt;
270 case "pc": return val * 12 * px_in_pt;
271 case "mm": return val / dojox.gfx.mm_in_pt * px_in_pt;
272 case "cm": return val / dojox.gfx.cm_in_pt * px_in_pt;
275 return parseFloat(len); // Number
278 // a constant used to split a SVG/VML path into primitive components
279 pathVmlRegExp: /([A-Za-z]+)|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
280 pathSvgRegExp: /([A-Za-z])|(\d+(\.\d+)?)|(\.\d+)|(-\d+(\.\d+)?)|(-\.\d+)/g,
282 equalSources: function(a, b){
283 // summary: compares event sources, returns true if they are equal
284 return a && b && a == b;