123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293 |
- if (!dojo._hasResource["dojox.gfx.vml"]) { // _hasResource checks added by
- // build. Do not use _hasResource
- // directly in your code.
- dojo._hasResource["dojox.gfx.vml"] = true;
- dojo.provide("dojox.gfx.vml");
- dojo.require("dojox.gfx._base");
- dojo.require("dojox.gfx.shape");
- dojo.require("dojox.gfx.path");
- dojo.require("dojox.gfx.arc");
- // dojox.gfx.vml.xmlns: String: a VML's namespace
- dojox.gfx.vml.xmlns = "urn:schemas-microsoft-com:vml";
- // dojox.gfx.vml.text_alignment: Object: mapping from SVG alignment to VML
- // alignment
- dojox.gfx.vml.text_alignment = {
- start : "left",
- middle : "center",
- end : "right"
- };
- dojox.gfx.vml._parseFloat = function(str) {
- // summary: a helper function to parse VML-specific floating-point
- // values
- // str: String: a representation of a floating-point number
- return str.match(/^\d+f$/i) ? parseInt(str) / 65536 : parseFloat(str); // Number
- };
- dojox.gfx.vml._bool = {
- "t" : 1,
- "true" : 1
- };
- dojo.extend(dojox.gfx.Shape, {
- // summary: VML-specific implementation of dojox.gfx.Shape methods
- setFill : function(fill) {
- // summary: sets a fill object (VML)
- // fill: Object: a fill object
- // (see dojox.gfx.defaultLinearGradient,
- // dojox.gfx.defaultRadialGradient,
- // dojox.gfx.defaultPattern,
- // or dojo.Color)
- if (!fill) {
- // don't fill
- this.fillStyle = null;
- this.rawNode.filled = "f";
- return this;
- }
- if (typeof fill == "object" && "type" in fill) {
- // gradient
- switch (fill.type) {
- case "linear" :
- var f = dojox.gfx.makeParameters(
- dojox.gfx.defaultLinearGradient, fill), s = [], a = f.colors, matrix = this
- ._getRealMatrix(), m = dojox.gfx.matrix;
- this.fillStyle = f;
- dojo.forEach(a, function(v, i, a) {
- a[i].color = dojox.gfx
- .normalizeColor(v.color);
- });
- if (a[0].offset > 0) {
- s.push("0 " + a[0].color.toHex());
- }
- for (var i = 0; i < a.length; ++i) {
- s.push(a[i].offset.toFixed(8) + " "
- + a[i].color.toHex());
- }
- var i = a.length - 1;
- if (a[i].offset < 1) {
- s.push("1 " + a[i].color.toHex());
- }
- var fo = this.rawNode.fill;
- fo.colors.value = s.join(";");
- fo.method = "sigma";
- fo.type = "gradient";
- var fc1 = matrix
- ? m.multiplyPoint(matrix, f.x1, f.y1)
- : {
- x : f.x1,
- y : f.y1
- }, fc2 = matrix ? m.multiplyPoint(matrix, f.x2,
- f.y2) : {
- x : f.x2,
- y : f.y2
- };
- fo.angle = (m._radToDeg(Math.atan2(fc2.x - fc1.x, fc2.y
- - fc1.y)) + 180)
- % 360;
- fo.on = true;
- break;
- case "radial" :
- var f = dojox.gfx.makeParameters(
- dojox.gfx.defaultRadialGradient, fill);
- this.fillStyle = f;
- var l = parseFloat(this.rawNode.style.left), t = parseFloat(this.rawNode.style.top), w = parseFloat(this.rawNode.style.width), h = parseFloat(this.rawNode.style.height), c = isNaN(w)
- ? 1
- : 2 * f.r / w, a = new Array(f.colors.length);
- // massage colors
- dojo.forEach(f.colors, function(v, i) {
- a[i] = {
- offset : 1 - v.offset * c,
- color : dojox.gfx
- .normalizeColor(v.color)
- };
- });
- var i = a.length - 1;
- while (i >= 0 && a[i].offset < 0) {
- --i;
- }
- if (i < a.length - 1) {
- // correct excessive colors
- var q = a[i], p = a[i + 1];
- p.color = dojo.blendColors(q.color, p.color,
- q.offset / (q.offset - p.offset));
- p.offset = 0;
- while (a.length - i > 2)
- a.pop();
- }
- // set colors
- var i = a.length - 1, s = [];
- if (a[i].offset > 0) {
- s.push("0 " + a[i].color.toHex());
- }
- for (; i >= 0; --i) {
- s.push(a[i].offset.toFixed(8) + " "
- + a[i].color.toHex());
- }
- if (a[0].offset < 1) {
- s.push("1 " + a[0].color.toHex());
- }
- var fo = this.rawNode.fill;
- fo.colors.value = s.join(";");
- fo.method = "sigma";
- fo.type = "gradientradial";
- if (isNaN(w) || isNaN(h) || isNaN(l) || isNaN(t)) {
- fo.focusposition = "0.5 0.5";
- } else {
- fo.focusposition = ((f.cx - l) / w).toFixed(8)
- + " " + ((f.cy - t) / h).toFixed(8);
- }
- fo.focussize = "0 0";
- fo.on = true;
- break;
- case "pattern" :
- var f = dojox.gfx.makeParameters(
- dojox.gfx.defaultPattern, fill);
- this.fillStyle = f;
- var fo = this.rawNode.fill;
- fo.type = "tile";
- fo.src = f.src;
- if (f.width && f.height) {
- // in points
- fo.size.x = dojox.gfx.px2pt(f.width);
- fo.size.y = dojox.gfx.px2pt(f.height);
- }
- fo.alignShape = "f";
- fo.position.x = 0;
- fo.position.y = 0;
- fo.origin.x = f.width ? f.x / f.width : 0;
- fo.origin.y = f.height ? f.y / f.height : 0;
- fo.on = true;
- break;
- }
- this.rawNode.fill.opacity = 1;
- return this;
- }
- // color object
- this.fillStyle = dojox.gfx.normalizeColor(fill);
- this.rawNode.fillcolor = this.fillStyle.toHex();
- this.rawNode.fill.opacity = this.fillStyle.a;
- this.rawNode.filled = true;
- return this; // self
- },
- setStroke : function(stroke) {
- // summary: sets a stroke object (VML)
- // stroke: Object: a stroke object
- // (see dojox.gfx.defaultStroke)
- if (!stroke) {
- // don't stroke
- this.strokeStyle = null;
- this.rawNode.stroked = "f";
- return this;
- }
- // normalize the stroke
- if (typeof stroke == "string") {
- stroke = {
- color : stroke
- };
- }
- var s = this.strokeStyle = dojox.gfx.makeParameters(
- dojox.gfx.defaultStroke, stroke);
- s.color = dojox.gfx.normalizeColor(s.color);
- // generate attributes
- var rn = this.rawNode;
- rn.stroked = true;
- rn.strokecolor = s.color.toCss();
- rn.strokeweight = s.width + "px"; // TODO: should we assume that
- // the width is always in
- // pixels?
- if (rn.stroke) {
- rn.stroke.opacity = s.color.a;
- rn.stroke.endcap = this._translate(this._capMap, s.cap);
- if (typeof s.join == "number") {
- rn.stroke.joinstyle = "miter";
- rn.stroke.miterlimit = s.join;
- } else {
- rn.stroke.joinstyle = s.join;
- // rn.stroke.miterlimit = s.width;
- }
- rn.stroke.dashstyle = s.style == "none" ? "Solid" : s.style;
- }
- return this; // self
- },
- _capMap : {
- butt : 'flat'
- },
- _capMapReversed : {
- flat : 'butt'
- },
- _translate : function(dict, value) {
- return (value in dict) ? dict[value] : value;
- },
- _applyTransform : function() {
- if (this.fillStyle && this.fillStyle.type == "linear") {
- this.setFill(this.fillStyle);
- }
- var matrix = this._getRealMatrix();
- if (!matrix)
- return this;
- var skew = this.rawNode.skew;
- if (typeof skew == "undefined") {
- for (var i = 0; i < this.rawNode.childNodes.length; ++i) {
- if (this.rawNode.childNodes[i].tagName == "skew") {
- skew = this.rawNode.childNodes[i];
- break;
- }
- }
- }
- if (skew) {
- skew.on = "f";
- var mt = matrix.xx.toFixed(8) + " " + matrix.xy.toFixed(8)
- + " " + matrix.yx.toFixed(8) + " "
- + matrix.yy.toFixed(8) + " 0 0", offset = Math
- .floor(matrix.dx).toFixed()
- + "px " + Math.floor(matrix.dy).toFixed() + "px", s = this.rawNode.style, l = parseFloat(s.left), t = parseFloat(s.top), w = parseFloat(s.width), h = parseFloat(s.height);
- if (isNaN(l))
- l = 0;
- if (isNaN(t))
- t = 0;
- if (isNaN(w))
- w = 1;
- if (isNaN(h))
- h = 1;
- var origin = (-l / w - 0.5).toFixed(8) + " "
- + (-t / h - 0.5).toFixed(8);
- skew.matrix = mt;
- skew.origin = origin;
- skew.offset = offset;
- skew.on = true;
- }
- return this;
- },
- setRawNode : function(rawNode) {
- // summary:
- // assigns and clears the underlying node that will represent this
- // shape. Once set, transforms, gradients, etc, can be applied.
- // (no fill & stroke by default)
- rawNode.stroked = "f";
- rawNode.filled = "f";
- this.rawNode = rawNode;
- },
- // move family
- _moveToFront : function() {
- // summary: moves a shape to front of its parent's list of shapes
- // (VML)
- this.rawNode.parentNode.appendChild(this.rawNode);
- return this;
- },
- _moveToBack : function() {
- // summary: moves a shape to back of its parent's list of shapes
- // (VML)
- var r = this.rawNode, p = r.parentNode, n = p.firstChild;
- p.insertBefore(r, n);
- if (n.tagName == "rect") {
- // surface has a background rectangle, which position should be
- // preserved
- n.swapNode(r);
- }
- return this;
- },
- _getRealMatrix : function() {
- // summary: returns the cumulative ("real") transformation matrix
- // by combining the shape's matrix with its parent's matrix
- return this.parentMatrix ? new dojox.gfx.Matrix2D([
- this.parentMatrix, this.matrix]) : this.matrix; // dojox.gfx.Matrix2D
- }
- });
- dojo.declare("dojox.gfx.Group", dojox.gfx.Shape, {
- // summary: a group shape (VML), which can be used
- // to logically group shapes (e.g, to propagate matricies)
- constructor : function() {
- dojox.gfx.vml.Container._init.call(this);
- },
- // apply transformation
- _applyTransform : function() {
- // summary: applies a transformation matrix to a group
- var matrix = this._getRealMatrix();
- for (var i = 0; i < this.children.length; ++i) {
- this.children[i]._updateParentMatrix(matrix);
- }
- return this; // self
- }
- });
- dojox.gfx.Group.nodeType = "group";
- dojo.declare("dojox.gfx.Rect", dojox.gfx.shape.Rect, {
- // summary: a rectangle shape (VML)
- setShape : function(newShape) {
- // summary: sets a rectangle shape object (VML)
- // newShape: Object: a rectangle shape object
- var shape = this.shape = dojox.gfx.makeParameters(this.shape,
- newShape);
- this.bbox = null;
- var style = this.rawNode.style;
- style.left = shape.x.toFixed();
- style.top = shape.y.toFixed();
- style.width = (typeof shape.width == "string" && shape.width
- .indexOf("%") >= 0) ? shape.width : shape.width.toFixed();
- style.height = (typeof shape.width == "string" && shape.height
- .indexOf("%") >= 0) ? shape.height : shape.height.toFixed();
- var r = Math.min(
- 1,
- (shape.r / Math.min(parseFloat(shape.width),
- parseFloat(shape.height)))).toFixed(8);
- // a workaround for the VML's arcsize bug: cannot read arcsize of an
- // instantiated node
- var parent = this.rawNode.parentNode, before = null;
- if (parent) {
- if (parent.lastChild != this.rawNode) {
- for (var i = 0; i < parent.childNodes.length; ++i) {
- if (parent.childNodes[i] == this.rawNode) {
- before = parent.childNodes[i + 1];
- break;
- }
- }
- }
- parent.removeChild(this.rawNode);
- }
- this.rawNode.arcsize = r;
- if (parent) {
- if (before) {
- parent.insertBefore(this.rawNode, before);
- } else {
- parent.appendChild(this.rawNode);
- }
- }
- // set all necessary styles, which are lost by VML (yes, it's a
- // VML's bug)
- return this.setTransform(this.matrix).setFill(this.fillStyle)
- .setStroke(this.strokeStyle); // self
- }
- });
- dojox.gfx.Rect.nodeType = "roundrect"; // use a roundrect so the stroke
- // join type is respected
- dojo.declare("dojox.gfx.Ellipse", dojox.gfx.shape.Ellipse, {
- // summary: an ellipse shape (VML)
- setShape : function(newShape) {
- // summary: sets an ellipse shape object (VML)
- // newShape: Object: an ellipse shape object
- var shape = this.shape = dojox.gfx.makeParameters(
- this.shape, newShape);
- this.bbox = null;
- var style = this.rawNode.style;
- style.left = (shape.cx - shape.rx).toFixed();
- style.top = (shape.cy - shape.ry).toFixed();
- style.width = (shape.rx * 2).toFixed();
- style.height = (shape.ry * 2).toFixed();
- return this.setTransform(this.matrix); // self
- }
- });
- dojox.gfx.Ellipse.nodeType = "oval";
- dojo.declare("dojox.gfx.Circle", dojox.gfx.shape.Circle, {
- // summary: a circle shape (VML)
- setShape : function(newShape) {
- // summary: sets a circle shape object (VML)
- // newShape: Object: a circle shape object
- var shape = this.shape = dojox.gfx.makeParameters(
- this.shape, newShape);
- this.bbox = null;
- var style = this.rawNode.style;
- style.left = (shape.cx - shape.r).toFixed();
- style.top = (shape.cy - shape.r).toFixed();
- style.width = (shape.r * 2).toFixed();
- style.height = (shape.r * 2).toFixed();
- return this; // self
- }
- });
- dojox.gfx.Circle.nodeType = "oval";
- dojo.declare("dojox.gfx.Line", dojox.gfx.shape.Line, {
- // summary: a line shape (VML)
- constructor : function(rawNode) {
- if (rawNode)
- rawNode.setAttribute("dojoGfxType", "line");
- },
- setShape : function(newShape) {
- // summary: sets a line shape object (VML)
- // newShape: Object: a line shape object
- var shape = this.shape = dojox.gfx.makeParameters(
- this.shape, newShape);
- this.bbox = null;
- this.rawNode.path.v = "m" + shape.x1.toFixed() + " "
- + shape.y1.toFixed() + "l" + shape.x2.toFixed()
- + " " + shape.y2.toFixed() + "e";
- return this.setTransform(this.matrix); // self
- }
- });
- dojox.gfx.Line.nodeType = "shape";
- dojo.declare("dojox.gfx.Polyline", dojox.gfx.shape.Polyline, {
- // summary: a polyline/polygon shape (VML)
- constructor : function(rawNode) {
- if (rawNode)
- rawNode.setAttribute("dojoGfxType", "polyline");
- },
- setShape : function(points, closed) {
- // summary: sets a polyline/polygon shape object (VML)
- // points: Object: a polyline/polygon shape object
- // closed: Boolean?: if true, close the polyline explicitely
- if (points && points instanceof Array) {
- // branch
- // points: Array: an array of points
- this.shape = dojox.gfx.makeParameters(this.shape, {
- points : points
- });
- if (closed && this.shape.points.length)
- this.shape.points.push(this.shape.points[0]);
- } else {
- this.shape = dojox.gfx.makeParameters(this.shape,
- points);
- }
- this.bbox = null;
- var attr = [], p = this.shape.points;
- if (p.length > 0) {
- attr.push("m");
- var k = 1;
- if (typeof p[0] == "number") {
- attr.push(p[0].toFixed());
- attr.push(p[1].toFixed());
- k = 2;
- } else {
- attr.push(p[0].x.toFixed());
- attr.push(p[0].y.toFixed());
- }
- if (p.length > k) {
- attr.push("l");
- for (var i = k; i < p.length; ++i) {
- if (typeof p[i] == "number") {
- attr.push(p[i].toFixed());
- } else {
- attr.push(p[i].x.toFixed());
- attr.push(p[i].y.toFixed());
- }
- }
- }
- }
- attr.push("e");
- this.rawNode.path.v = attr.join(" ");
- return this.setTransform(this.matrix); // self
- }
- });
- dojox.gfx.Polyline.nodeType = "shape";
- dojo.declare("dojox.gfx.Image", dojox.gfx.shape.Image, {
- // summary: an image (VML)
- constructor : function(rawNode) {
- if (rawNode)
- rawNode.setAttribute("dojoGfxType", "image");
- },
- getEventSource : function() {
- // summary: returns a Node, which is used as
- // a source of events for this shape
- return this.rawNode ? this.rawNode.firstChild : null; // Node
- },
- setShape : function(newShape) {
- // summary: sets an image shape object (VML)
- // newShape: Object: an image shape object
- var shape = this.shape = dojox.gfx.makeParameters(
- this.shape, newShape);
- this.bbox = null;
- var firstChild = this.rawNode.firstChild;
- firstChild.src = shape.src;
- if (shape.width || shape.height) {
- firstChild.style.width = shape.width;
- firstChild.style.height = shape.height;
- }
- return this.setTransform(this.matrix); // self
- },
- _applyTransform : function() {
- var matrix = this._getRealMatrix();
- if (!matrix)
- return this;
- matrix = dojox.gfx.matrix.multiply(matrix, {
- dx : this.shape.x,
- dy : this.shape.y
- });
- var f = this.rawNode.filters["DXImageTransform.Microsoft.Matrix"];
- f.M11 = matrix.xx;
- f.M12 = matrix.xy;
- f.M21 = matrix.yx;
- f.M22 = matrix.yy;
- f.Dx = matrix.dx;
- f.Dy = matrix.dy;
- return this;
- }
- });
- dojox.gfx.Image.nodeType = "div";
- dojo.declare("dojox.gfx.Text", dojox.gfx.shape.Text, {
- // summary: an anchored text (VML)
- constructor : function(rawNode) {
- if (rawNode) {
- rawNode.setAttribute("dojoGfxType", "text");
- }
- this.fontStyle = null;
- },
- _alignment : {
- start : "left",
- middle : "center",
- end : "right"
- },
- setShape : function(newShape) {
- // summary: sets a text shape object (VML)
- // newShape: Object: a text shape object
- this.shape = dojox.gfx.makeParameters(this.shape, newShape);
- this.bbox = null;
- var r = this.rawNode, s = this.shape, x = s.x, y = s.y
- .toFixed();
- switch (s.align) {
- case "middle" :
- x -= 5;
- break;
- case "end" :
- x -= 10;
- break;
- }
- this.rawNode.path.v = "m" + x.toFixed() + "," + y + "l"
- + (x + 10).toFixed() + "," + y + "e";
- // find path and text path
- var p = null, t = null, c = r.childNodes;
- for (var i = 0; i < c.length; ++i) {
- var tag = c[i].tagName;
- if (tag == "path") {
- p = c[i];
- if (t)
- break;
- } else if (tag == "textpath") {
- t = c[i];
- if (p)
- break;
- }
- }
- if (!p) {
- p = this.rawNode.ownerDocument.createElement("v:path");
- r.appendChild(p);
- }
- if (!t) {
- t = this.rawNode.ownerDocument
- .createElement("v:textpath");
- r.appendChild(t);
- }
- p.textPathOk = true;
- t.on = true;
- var a = dojox.gfx.vml.text_alignment[s.align];
- t.style["v-text-align"] = a ? a : "left";
- t.style["text-decoration"] = s.decoration;
- t.style["v-rotate-letters"] = s.rotated;
- t.style["v-text-kern"] = s.kerning;
- t.string = s.text;
- return this.setTransform(this.matrix); // self
- },
- _setFont : function() {
- // summary: sets a font object (VML)
- var f = this.fontStyle, c = this.rawNode.childNodes;
- for (var i = 0; i < c.length; ++i) {
- if (c[i].tagName == "textpath") {
- c[i].style.font = dojox.gfx.makeFontString(f);
- break;
- }
- }
- this.setTransform(this.matrix);
- },
- _getRealMatrix : function() {
- // summary: returns the cumulative ("real") transformation
- // matrix
- // by combining the shape's matrix with its parent's matrix;
- // it makes a correction for a font size
- var matrix = dojox.gfx.Shape.prototype._getRealMatrix
- .call(this);
- // It appears that text is always aligned vertically at a
- // middle of x-height (???).
- // It is impossible to obtain these metrics from VML => I
- // try to approximate it with
- // more-or-less util value of 0.7 * FontSize, which is
- // typical for European fonts.
- if (matrix) {
- matrix = dojox.gfx.matrix.multiply(matrix, {
- dy : -dojox.gfx
- .normalizedLength(this.fontStyle
- ? this.fontStyle.size
- : "10pt")
- * 0.35
- });
- }
- return matrix; // dojox.gfx.Matrix2D
- },
- getTextWidth : function() {
- // summary: get the text width, in px
- var rawNode = this.rawNode, _display = rawNode.style.display;
- rawNode.style.display = "inline";
- var _width = dojox.gfx
- .pt2px(parseFloat(rawNode.currentStyle.width));
- rawNode.style.display = _display;
- return _width;
- }
- });
- dojox.gfx.Text.nodeType = "shape";
- dojox.gfx.path._calcArc = function(alpha) {
- // return a start point, 1st and 2nd control points, and an end point
- var cosa = Math.cos(alpha), sina = Math.sin(alpha), p2 = {
- x : cosa + (4 / 3) * (1 - cosa),
- y : sina - (4 / 3) * cosa * (1 - cosa) / sina
- };
- return {
- s : {
- x : cosa,
- y : -sina
- },
- c1 : {
- x : p2.x,
- y : -p2.y
- },
- c2 : p2,
- e : {
- x : cosa,
- y : sina
- }
- };
- };
- dojo.declare("dojox.gfx.Path", dojox.gfx.path.Path, {
- // summary: a path shape (VML)
- constructor : function(rawNode) {
- if (rawNode && !rawNode.getAttribute("dojoGfxType")) {
- rawNode.setAttribute("dojoGfxType", "path");
- }
- this.vmlPath = "";
- this.lastControl = {};
- },
- _updateWithSegment : function(segment) {
- // summary: updates the bounding box of path with new segment
- // segment: Object: a segment
- var last = dojo.clone(this.last);
- dojox.gfx.Path.superclass._updateWithSegment.apply(this, arguments);
- // add a VML path segment
- var path = this[this.renderers[segment.action]](segment, last);
- if (typeof this.vmlPath == "string") {
- this.vmlPath += path.join("");
- this.rawNode.path.v = this.vmlPath + " r0,0 e";
- } else {
- this.vmlPath = this.vmlPath.concat(path);
- }
- },
- setShape : function(newShape) {
- // summary: forms a path using a shape (VML)
- // newShape: Object: an VML path string or a path object (see
- // dojox.gfx.defaultPath)
- this.vmlPath = [];
- this.lastControl = {};
- dojox.gfx.Path.superclass.setShape.apply(this, arguments);
- this.vmlPath = this.vmlPath.join("");
- this.rawNode.path.v = this.vmlPath + " r0,0 e";
- return this;
- },
- _pathVmlToSvgMap : {
- m : "M",
- l : "L",
- t : "m",
- r : "l",
- c : "C",
- v : "c",
- qb : "Q",
- x : "z",
- e : ""
- },
- // VML-specific segment renderers
- renderers : {
- M : "_moveToA",
- m : "_moveToR",
- L : "_lineToA",
- l : "_lineToR",
- H : "_hLineToA",
- h : "_hLineToR",
- V : "_vLineToA",
- v : "_vLineToR",
- C : "_curveToA",
- c : "_curveToR",
- S : "_smoothCurveToA",
- s : "_smoothCurveToR",
- Q : "_qCurveToA",
- q : "_qCurveToR",
- T : "_qSmoothCurveToA",
- t : "_qSmoothCurveToR",
- A : "_arcTo",
- a : "_arcTo",
- Z : "_closePath",
- z : "_closePath"
- },
- _addArgs : function(path, args, from, upto) {
- if (typeof upto == "undefined") {
- upto = args.length;
- }
- if (typeof from == "undefined") {
- from = 0;
- }
- for (var i = from; i < upto; ++i) {
- path.push(" ");
- path.push(args[i].toFixed());
- }
- },
- _addArgsAdjusted : function(path, last, args, from, upto) {
- if (typeof upto == "undefined") {
- upto = args.length;
- }
- if (typeof from == "undefined") {
- from = 0;
- }
- for (var i = from; i < upto; i += 2) {
- path.push(" ");
- path.push((last.x + args[i]).toFixed());
- path.push(" ");
- path.push((last.y + args[i + 1]).toFixed());
- }
- },
- _moveToA : function(segment) {
- var p = [" m"], n = segment.args, l = n.length;
- if (l == 2) {
- this._addArgs(p, n);
- } else {
- this._addArgs(p, n, 0, 2);
- p.push(" l");
- this._addArgs(p, n, 2);
- }
- this.lastControl = {};
- return p;
- },
- _moveToR : function(segment, last) {
- var p = ["x" in last ? " t" : " m"], n = segment.args, l = n.length;
- if (l == 2) {
- this._addArgs(p, n);
- } else {
- this._addArgs(p, n, 0, 2);
- p.push(" r");
- this._addArgs(p, n, 2);
- }
- this.lastControl = {};
- return p;
- },
- _lineToA : function(segment) {
- var p = [" l"];
- this._addArgs(p, segment.args);
- this.lastControl = {};
- return p;
- },
- _lineToR : function(segment) {
- var p = [" r"];
- this._addArgs(p, segment.args);
- this.lastControl = {};
- return p;
- },
- _hLineToA : function(segment, last) {
- var p = [" l"], n = segment.args, l = n.length, y = " "
- + last.y.toFixed();
- for (var i = 0; i < l; ++i) {
- p.push(" ");
- p.push(n[i].toFixed());
- p.push(y);
- }
- this.lastControl = {};
- return p;
- },
- _hLineToR : function(segment) {
- var p = [" r"], n = segment.args, l = n.length;
- for (var i = 0; i < l; ++i) {
- p.push(" ");
- p.push(n[i].toFixed());
- p.push(" 0");
- }
- this.lastControl = {};
- return p;
- },
- _vLineToA : function(segment, last) {
- var p = [" l"], n = segment.args, l = n.length, x = " "
- + last.x.toFixed();
- for (var i = 0; i < l; ++i) {
- p.push(x);
- p.push(" ");
- p.push(n[i].toFixed());
- }
- this.lastControl = {};
- return p;
- },
- _vLineToR : function(segment) {
- var p = [" r"], n = segment.args, l = n.length;
- for (var i = 0; i < l; ++i) {
- p.push(" 0 ");
- p.push(n[i].toFixed());
- }
- this.lastControl = {};
- return p;
- },
- _curveToA : function(segment) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 6) {
- p.push(" c");
- this._addArgs(p, n, i, i + 6);
- }
- this.lastControl = {
- x : n[l - 4],
- y : n[l - 3],
- type : "C"
- };
- return p;
- },
- _curveToR : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 6) {
- p.push(" v");
- this._addArgs(p, n, i, i + 6);
- this.lastControl = {
- x : last.x + n[i + 2],
- y : last.y + n[i + 3]
- };
- last.x += n[i + 4];
- last.y += n[i + 5];
- }
- this.lastControl.type = "C";
- return p;
- },
- _smoothCurveToA : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 4) {
- p.push(" c");
- if (this.lastControl.type == "C") {
- this._addArgs(p, [2 * last.x - this.lastControl.x,
- 2 * last.y - this.lastControl.y]);
- } else {
- this._addArgs(p, [last.x, last.y]);
- }
- this._addArgs(p, n, i, i + 4);
- }
- this.lastControl = {
- x : n[l - 4],
- y : n[l - 3],
- type : "C"
- };
- return p;
- },
- _smoothCurveToR : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 4) {
- p.push(" v");
- if (this.lastControl.type == "C") {
- this._addArgs(p, [last.x - this.lastControl.x,
- last.y - this.lastControl.y]);
- } else {
- this._addArgs(p, [0, 0]);
- }
- this._addArgs(p, n, i, i + 4);
- this.lastControl = {
- x : last.x + n[i],
- y : last.y + n[i + 1]
- };
- last.x += n[i + 2];
- last.y += n[i + 3];
- }
- this.lastControl.type = "C";
- return p;
- },
- _qCurveToA : function(segment) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 4) {
- p.push(" qb");
- this._addArgs(p, n, i, i + 4);
- }
- this.lastControl = {
- x : n[l - 4],
- y : n[l - 3],
- type : "Q"
- };
- return p;
- },
- _qCurveToR : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 4) {
- p.push(" qb");
- this._addArgsAdjusted(p, last, n, i, i + 4);
- this.lastControl = {
- x : last.x + n[i],
- y : last.y + n[i + 1]
- };
- last.x += n[i + 2];
- last.y += n[i + 3];
- }
- this.lastControl.type = "Q";
- return p;
- },
- _qSmoothCurveToA : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 2) {
- p.push(" qb");
- if (this.lastControl.type == "Q") {
- this._addArgs(p, [
- this.lastControl.x = 2 * last.x
- - this.lastControl.x,
- this.lastControl.y = 2 * last.y
- - this.lastControl.y]);
- } else {
- this._addArgs(p, [this.lastControl.x = last.x,
- this.lastControl.y = last.y]);
- }
- this._addArgs(p, n, i, i + 2);
- }
- this.lastControl.type = "Q";
- return p;
- },
- _qSmoothCurveToR : function(segment, last) {
- var p = [], n = segment.args, l = n.length;
- for (var i = 0; i < l; i += 2) {
- p.push(" qb");
- if (this.lastControl.type == "Q") {
- this._addArgs(p, [
- this.lastControl.x = 2 * last.x
- - this.lastControl.x,
- this.lastControl.y = 2 * last.y
- - this.lastControl.y]);
- } else {
- this._addArgs(p, [this.lastControl.x = last.x,
- this.lastControl.y = last.y]);
- }
- this._addArgsAdjusted(p, last, n, i, i + 2);
- }
- this.lastControl.type = "Q";
- return p;
- },
- _arcTo : function(segment, last) {
- var p = [], n = segment.args, l = n.length, relative = segment.action == "a";
- for (var i = 0; i < l; i += 7) {
- var x1 = n[i + 5], y1 = n[i + 6];
- if (relative) {
- x1 += last.x;
- y1 += last.y;
- }
- var result = dojox.gfx.arc.arcAsBezier(last, n[i], n[i + 1],
- n[i + 2], n[i + 3] ? 1 : 0, n[i + 4] ? 1 : 0, x1, y1);
- for (var j = 0; j < result.length; ++j) {
- p.push(" c");
- this._addArgs(p, result[j]);
- }
- last = {
- x : x1,
- y : y1
- };
- }
- this.lastControl = {};
- return p;
- },
- _closePath : function() {
- this.lastControl = {};
- return ["x"];
- }
- });
- dojox.gfx.Path.nodeType = "shape";
- dojo.declare("dojox.gfx.TextPath", dojox.gfx.Path, {
- // summary: a textpath shape (VML)
- constructor : function(rawNode) {
- if (rawNode) {
- rawNode.setAttribute("dojoGfxType", "textpath");
- }
- this.fontStyle = null;
- if (!("text" in this)) {
- this.text = dojo.clone(dojox.gfx.defaultTextPath);
- }
- if (!("fontStyle" in this)) {
- this.fontStyle = dojo.clone(dojox.gfx.defaultFont);
- }
- },
- setText : function(newText) {
- // summary: sets a text to be drawn along the path
- this.text = dojox.gfx.makeParameters(this.text,
- typeof newText == "string" ? {
- text : newText
- } : newText);
- this._setText();
- return this; // self
- },
- setFont : function(newFont) {
- // summary: sets a font for text
- this.fontStyle = typeof newFont == "string" ? dojox.gfx
- .splitFontString(newFont) : dojox.gfx
- .makeParameters(dojox.gfx.defaultFont, newFont);
- this._setFont();
- return this; // self
- },
- _setText : function() {
- // summary: sets a text shape object (VML)
- this.bbox = null;
- var r = this.rawNode, s = this.text,
- // find path and text path
- p = null, t = null, c = r.childNodes;
- for (var i = 0; i < c.length; ++i) {
- var tag = c[i].tagName;
- if (tag == "path") {
- p = c[i];
- if (t)
- break;
- } else if (tag == "textpath") {
- t = c[i];
- if (p)
- break;
- }
- }
- if (!p) {
- p = this.rawNode.ownerDocument.createElement("v:path");
- r.appendChild(p);
- }
- if (!t) {
- t = this.rawNode.ownerDocument
- .createElement("v:textpath");
- r.appendChild(t);
- }
- p.textPathOk = true;
- t.on = true;
- var a = dojox.gfx.vml.text_alignment[s.align];
- t.style["v-text-align"] = a ? a : "left";
- t.style["text-decoration"] = s.decoration;
- t.style["v-rotate-letters"] = s.rotated;
- t.style["v-text-kern"] = s.kerning;
- t.string = s.text;
- },
- _setFont : function() {
- // summary: sets a font object (VML)
- var f = this.fontStyle, c = this.rawNode.childNodes;
- for (var i = 0; i < c.length; ++i) {
- if (c[i].tagName == "textpath") {
- c[i].style.font = dojox.gfx.makeFontString(f);
- break;
- }
- }
- }
- });
- dojox.gfx.TextPath.nodeType = "shape";
- dojo.declare("dojox.gfx.Surface", dojox.gfx.shape.Surface, {
- // summary: a surface object to be used for drawings (VML)
- constructor : function() {
- dojox.gfx.vml.Container._init.call(this);
- },
- setDimensions : function(width, height) {
- // summary: sets the width and height of the rawNode
- // width: String: width of surface, e.g., "100px"
- // height: String: height of surface, e.g., "100px"
- this.width = dojox.gfx.normalizedLength(width); // in pixels
- this.height = dojox.gfx.normalizedLength(height); // in pixels
- if (!this.rawNode)
- return this;
- var cs = this.clipNode.style, r = this.rawNode, rs = r.style, bs = this.bgNode.style;
- cs.width = width;
- cs.height = height;
- cs.clip = "rect(0 " + width + " " + height + " 0)";
- rs.width = width;
- rs.height = height;
- r.coordsize = width + " " + height;
- bs.width = width;
- bs.height = height;
- return this; // self
- },
- getDimensions : function() {
- // summary: returns an object with properties "width" and "height"
- var t = this.rawNode ? {
- width : dojox.gfx.normalizedLength(this.rawNode.style.width),
- height : dojox.gfx.normalizedLength(this.rawNode.style.height)
- } : null;
- if (t.width <= 0) {
- t.width = this.width;
- }
- if (t.height <= 0) {
- t.height = this.height;
- }
- return t; // Object
- }
- });
- dojox.gfx.createSurface = function(parentNode, width, height) {
- // summary: creates a surface (VML)
- // parentNode: Node: a parent node
- // width: String: width of surface, e.g., "100px"
- // height: String: height of surface, e.g., "100px"
- if (!width) {
- width = "100%";
- }
- if (!height) {
- height = "100%";
- }
- var s = new dojox.gfx.Surface(), p = dojo.byId(parentNode), c = s.clipNode = p.ownerDocument
- .createElement("div"), r = s.rawNode = p.ownerDocument
- .createElement("v:group"), cs = c.style, rs = r.style;
- p.style.width = width;
- p.style.height = height;
- cs.width = width;
- cs.height = height;
- cs.clip = "rect(0 " + width + " " + height + " 0)";
- cs.position = "absolute";
- rs.width = width;
- rs.height = height;
- r.coordsize = (width == "100%" ? width : parseFloat(width)) + " "
- + (height == "100%" ? height : parseFloat(height));
- r.coordorigin = "0 0";
- // create a background rectangle, which is required to show all other
- // shapes
- var b = s.bgNode = r.ownerDocument.createElement("v:rect"), bs = b.style;
- bs.left = bs.top = 0;
- bs.width = rs.width;
- bs.height = rs.height;
- b.filled = b.stroked = "f";
- r.appendChild(b);
- c.appendChild(r);
- p.appendChild(c);
- s.width = dojox.gfx.normalizedLength(width); // in pixels
- s.height = dojox.gfx.normalizedLength(height); // in pixels
- return s; // dojox.gfx.Surface
- };
- // Extenders
- dojox.gfx.vml.Container = {
- _init : function() {
- dojox.gfx.shape.Container._init.call(this);
- },
- add : function(shape) {
- // summary: adds a shape to a group/surface
- // shape: dojox.gfx.Shape: an VML shape object
- if (this != shape.getParent()) {
- this.rawNode.appendChild(shape.rawNode);
- // dojox.gfx.Group.superclass.add.apply(this, arguments);
- // this.inherited(arguments);
- dojox.gfx.shape.Container.add.apply(this, arguments);
- }
- return this; // self
- },
- remove : function(shape, silently) {
- // summary: remove a shape from a group/surface
- // shape: dojox.gfx.Shape: an VML shape object
- // silently: Boolean?: if true, regenerate a picture
- if (this == shape.getParent()) {
- if (this.rawNode == shape.rawNode.parentNode) {
- this.rawNode.removeChild(shape.rawNode);
- }
- // dojox.gfx.Group.superclass.remove.apply(this, arguments);
- // this.inherited(arguments);
- dojox.gfx.shape.Container.remove.apply(this, arguments);
- }
- return this; // self
- },
- clear : function() {
- // summary: removes all shapes from a group/surface
- var r = this.rawNode;
- while (r.firstChild != r.lastChild) {
- if (r.firstChild != this.bgNode) {
- r.removeChild(r.firstChild);
- }
- if (r.lastChild != this.bgNode) {
- r.removeChild(r.lastChild);
- }
- }
- // return this.inherited(arguments); // self
- return dojox.gfx.shape.Container.clear.apply(this, arguments);
- },
- _moveChildToFront : dojox.gfx.shape.Container._moveChildToFront,
- _moveChildToBack : dojox.gfx.shape.Container._moveChildToBack
- };
- dojo.mixin(dojox.gfx.shape.Creator, {
- // summary: VML shape creators
- createGroup : function() {
- // summary: creates a VML group shape
- var g = this.createObject(dojox.gfx.Group, null); // dojox.gfx.Group
- // create a background rectangle, which is required to show all
- // other shapes
- var r = g.rawNode.ownerDocument.createElement("v:rect");
- r.style.left = r.style.top = 0;
- r.style.width = g.rawNode.style.width;
- r.style.height = g.rawNode.style.height;
- r.filled = r.stroked = "f";
- g.rawNode.appendChild(r);
- g.bgNode = r;
- return g; // dojox.gfx.Group
- },
- createImage : function(image) {
- // summary: creates a VML image shape
- // image: Object: an image object (see dojox.gfx.defaultImage)
- if (!this.rawNode)
- return null;
- var shape = new dojox.gfx.Image(), node = this.rawNode.ownerDocument
- .createElement('div');
- node.style.position = "absolute";
- node.style.width = this.rawNode.style.width;
- node.style.height = this.rawNode.style.height;
- node.style.filter = "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, Dx=0, Dy=0)";
- var img = this.rawNode.ownerDocument.createElement('img');
- node.appendChild(img);
- shape.setRawNode(node);
- this.rawNode.appendChild(node);
- shape.setShape(image);
- this.add(shape);
- return shape; // dojox.gfx.Image
- },
- createObject : function(shapeType, rawShape) {
- // summary: creates an instance of the passed shapeType class
- // shapeType: Function: a class constructor to create an instance of
- // rawShape: Object: properties to be passed in to the classes
- // "setShape" method
- // overrideSize: Boolean: set the size explicitly, if true
- if (!this.rawNode)
- return null;
- var shape = new shapeType(), node = this.rawNode.ownerDocument
- .createElement('v:' + shapeType.nodeType);
- shape.setRawNode(node);
- this.rawNode.appendChild(node);
- switch (shapeType) {
- case dojox.gfx.Group :
- case dojox.gfx.Line :
- case dojox.gfx.Polyline :
- case dojox.gfx.Text :
- case dojox.gfx.Path :
- case dojox.gfx.TextPath :
- this._overrideSize(node);
- }
- shape.setShape(rawShape);
- this.add(shape);
- return shape; // dojox.gfx.Shape
- },
- _overrideSize : function(node) {
- var p = this;
- for (; p && !(p instanceof dojox.gfx.Surface); p = p.parent);
- node.style.width = p.width;
- node.style.height = p.height;
- node.coordsize = p.width + " " + p.height;
- }
- });
- dojo.extend(dojox.gfx.Group, dojox.gfx.vml.Container);
- dojo.extend(dojox.gfx.Group, dojox.gfx.shape.Creator);
- dojo.extend(dojox.gfx.Surface, dojox.gfx.vml.Container);
- dojo.extend(dojox.gfx.Surface, dojox.gfx.shape.Creator);
- }
|