source: Dev/trunk/src/client/dojox/gfx/silverlight.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 28.7 KB
Line 
1define(["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/Color",
2                "dojo/on", "dojo/_base/array", "dojo/dom-geometry", "dojo/dom", "dojo/_base/sniff",
3                "./_base", "./shape", "./path", "./registry"],
4  function(kernel,lang,declare,color,on,arr,domGeom,dom,has,g,gs,pathLib){
5        var sl = g.silverlight = {
6                // summary:
7                //              This the graphics rendering bridge for the Microsoft Silverlight plugin.
8                //              Silverlight is a faster implementation on IE6-8 than the default 2d graphics, VML
9        };
10        kernel.experimental("dojox.gfx.silverlight");
11
12        var dasharray = {
13                        solid:                          "none",
14                        shortdash:                      [4, 1],
15                        shortdot:                       [1, 1],
16                        shortdashdot:           [4, 1, 1, 1],
17                        shortdashdotdot:        [4, 1, 1, 1, 1, 1],
18                        dot:                            [1, 3],
19                        dash:                           [4, 3],
20                        longdash:                       [8, 3],
21                        dashdot:                        [4, 3, 1, 3],
22                        longdashdot:            [8, 3, 1, 3],
23                        longdashdotdot:         [8, 3, 1, 3, 1, 3]
24                },
25                fontweight = {
26                        normal: 400,
27                        bold:   700
28                },
29                caps  = {butt: "Flat", round: "Round", square: "Square"},
30                joins = {bevel: "Bevel", round: "Round"},
31                fonts = {
32                        serif: "Times New Roman",
33                        times: "Times New Roman",
34                        "sans-serif": "Arial",
35                        helvetica: "Arial",
36                        monotone: "Courier New",
37                        courier: "Courier New"
38                };
39
40        function hexColor(/*String|Array|dojo/Color*/ color){
41                // summary:
42                //              converts a color object to a Silverlight hex color string (#aarrggbb)
43                var c = g.normalizeColor(color),
44                        t = c.toHex(), a = Math.round(c.a * 255);
45                a = (a < 0 ? 0 : a > 255 ? 255 : a).toString(16);
46                return "#" + (a.length < 2 ? "0" + a : a) + t.slice(1); // String
47        }
48
49        sl.Shape = declare("dojox.gfx.silverlight.Shape", gs.Shape, {
50                // summary:
51                //              Silverlight-specific implementation of dojox/gfx/shape.Shape methods
52
53                destroy: function(){
54                        // summary:
55                        //              Releases all internal resources owned by this shape. Once this method has been called,
56                        //              the instance is considered destroyed and should not be used anymore.
57                        if(has("gfxRegistry")){
58                                gs.dispose(this);
59                        }
60                        this.rawNode = null;
61                },
62
63                setFill: function(fill){
64                        // summary:
65                        //              sets a fill object (Silverlight)
66                        // fill: Object
67                        //              a fill object
68                        //              (see dojox/gfx.defaultLinearGradient,
69                        //              dojox/gfx.defaultRadialGradient,
70                        //              dojox/gfx.defaultPattern,
71                        //              or dojo/_base/Color)
72
73                        var p = this.rawNode.getHost().content, r = this.rawNode, f;
74                        if(!fill){
75                                // don't fill
76                                this.fillStyle = null;
77                                this._setFillAttr(null);
78                                return this;    // self
79                        }
80                        if(typeof(fill) == "object" && "type" in fill){
81                                // gradient
82                                switch(fill.type){
83                                        case "linear":
84                                                this.fillStyle = f = g.makeParameters(g.defaultLinearGradient, fill);
85                                                var lgb = p.createFromXaml("<LinearGradientBrush/>");
86                                                lgb.mappingMode = "Absolute";
87                                                lgb.startPoint = f.x1 + "," + f.y1;
88                                                lgb.endPoint = f.x2 + "," + f.y2;
89                                                arr.forEach(f.colors, function(c){
90                                                        var t = p.createFromXaml("<GradientStop/>");
91                                                        t.offset = c.offset;
92                                                        t.color = hexColor(c.color);
93                                                        lgb.gradientStops.add(t);
94                                                });
95                                                this._setFillAttr(lgb);
96                                                break;
97                                        case "radial":
98                                                this.fillStyle = f = g.makeParameters(g.defaultRadialGradient, fill);
99                                                var rgb = p.createFromXaml("<RadialGradientBrush/>"),
100                                                        c = g.matrix.multiplyPoint(g.matrix.invert(this._getAdjustedMatrix()), f.cx, f.cy),
101                                                        pt = c.x + "," + c.y;
102                                                rgb.mappingMode = "Absolute";
103                                                rgb.gradientOrigin = pt;
104                                                rgb.center = pt;
105                                                rgb.radiusX = rgb.radiusY = f.r;
106                                                arr.forEach(f.colors, function(c){
107                                                        var t = p.createFromXaml("<GradientStop/>");
108                                                        t.offset = c.offset;
109                                                        t.color = hexColor(c.color);
110                                                        rgb.gradientStops.add(t);
111                                                });
112                                                this._setFillAttr(rgb);
113                                                break;
114                                        case "pattern":
115                                                // don't fill: Silverlight doesn't define TileBrush for some reason
116                                                this.fillStyle = null;
117                                                this._setFillAttr(null);
118                                                break;
119                                }
120                                return this;    // self
121                        }
122                        // color object
123                        this.fillStyle = f = g.normalizeColor(fill);
124                        var scb = p.createFromXaml("<SolidColorBrush/>");
125                        scb.color = f.toHex();
126                        scb.opacity = f.a;
127                        this._setFillAttr(scb);
128                        return this;    // self
129                },
130                _setFillAttr: function(f){
131                        this.rawNode.fill = f;
132                },
133
134                setStroke: function(stroke){
135                        // summary:
136                        //              sets a stroke object (Silverlight)
137                        // stroke: Object
138                        //              a stroke object
139                        //              (see dojox/gfx.defaultStroke)
140
141                        var p = this.rawNode.getHost().content, r = this.rawNode;
142                        if(!stroke){
143                                // don't stroke
144                                this.strokeStyle = null;
145                                r.stroke = null;
146                                return this;
147                        }
148                        // normalize the stroke
149                        if(typeof stroke == "string" || lang.isArray(stroke) || stroke instanceof color){
150                                stroke = {color: stroke};
151                        }
152                        var s = this.strokeStyle = g.makeParameters(g.defaultStroke, stroke);
153                        s.color = g.normalizeColor(s.color);
154                        // generate attributes
155                        if(s){
156                                var scb = p.createFromXaml("<SolidColorBrush/>");
157                                scb.color = s.color.toHex();
158                                scb.opacity = s.color.a;
159                                r.stroke = scb;
160                                r.strokeThickness = s.width;
161                                r.strokeStartLineCap = r.strokeEndLineCap = r.strokeDashCap =
162                                        caps[s.cap];
163                                if(typeof s.join == "number"){
164                                        r.strokeLineJoin = "Miter";
165                                        r.strokeMiterLimit = s.join;
166                                }else{
167                                        r.strokeLineJoin = joins[s.join];
168                                }
169                                var da = s.style.toLowerCase();
170                                if(da in dasharray){ da = dasharray[da]; }
171                                if(da instanceof Array){
172                                        da = lang.clone(da);
173                                        var i;
174                                        /*
175                                        for(var i = 0; i < da.length; ++i){
176                                                da[i] *= s.width;
177                                        }
178                                        */
179                                        if(s.cap != "butt"){
180                                                for(i = 0; i < da.length; i += 2){
181                                                        //da[i] -= s.width;
182                                                        --da[i]
183                                                        if(da[i] < 1){ da[i] = 1; }
184                                                }
185                                                for(i = 1; i < da.length; i += 2){
186                                                        //da[i] += s.width;
187                                                        ++da[i];
188                                                }
189                                        }
190                                        r.strokeDashArray = da.join(",");
191                                }else{
192                                        r.strokeDashArray = null;
193                                }
194                        }
195                        return this;    // self
196                },
197
198                _getParentSurface: function(){
199                        var surface = this.parent;
200                        for(; surface && !(surface instanceof g.Surface); surface = surface.parent);
201                        return surface;
202                },
203
204                _applyTransform: function() {
205                        var tm = this._getAdjustedMatrix(), r = this.rawNode;
206                        if(tm){
207                                var p = this.rawNode.getHost().content,
208                                        mt = p.createFromXaml("<MatrixTransform/>"),
209                                        mm = p.createFromXaml("<Matrix/>");
210                                mm.m11 = tm.xx;
211                                mm.m21 = tm.xy;
212                                mm.m12 = tm.yx;
213                                mm.m22 = tm.yy;
214                                mm.offsetX = tm.dx;
215                                mm.offsetY = tm.dy;
216                                mt.matrix = mm;
217                                r.renderTransform = mt;
218                        }else{
219                                r.renderTransform = null;
220                        }
221                        return this;
222                },
223
224                setRawNode: function(rawNode){
225                        // summary:
226                        //              assigns and clears the underlying node that will represent this
227                        //              shape. Once set, transforms, gradients, etc, can be applied.
228                        //              (no fill & stroke by default)
229                        rawNode.fill = null;
230                        rawNode.stroke = null;
231                        this.rawNode = rawNode;
232                        this.rawNode.tag = this.getUID();
233                },
234
235                // move family
236
237                _moveToFront: function(){
238                        // summary:
239                        //              moves a shape to front of its parent's list of shapes (Silverlight)
240                        var c = this.parent.rawNode.children, r = this.rawNode;
241                        c.remove(r);
242                        c.add(r);
243                        return this;    // self
244                },
245                _moveToBack: function(){
246                        // summary:
247                        //              moves a shape to back of its parent's list of shapes (Silverlight)
248                        var c = this.parent.rawNode.children, r = this.rawNode;
249                        c.remove(r);
250                        c.insert(0, r);
251                        return this;    // self
252                },
253
254                _getAdjustedMatrix: function(){
255                        // summary:
256                        //              returns the adjusted ("real") transformation matrix
257                        return this.matrix;     // dojox/gfx/matrix.Matrix2D
258                },
259               
260                setClip: function(clip){
261                        // summary:
262                        //              sets the clipping area of this shape.
263                        // description:
264                        //              This method overrides the dojox/gfx/shape.Shape.setClip() method.
265                        // clip: Object
266                        //              an object that defines the clipping geometry, or null to remove clip.
267                        this.inherited(arguments);
268                        var r = this.rawNode;
269                        if(clip){
270                                var clipType = clip ? "width" in clip ? "rect" :
271                                                                "cx" in clip ? "ellipse" :
272                                                                "points" in clip ? "polyline" : "d" in clip ? "path" : null : null;
273                                if(clip && !clipType){
274                                        return this;
275                                }
276                                var bbox = this.getBoundingBox() || {x:0, y:0, width:0, height:0};
277                                var clipT = "1,0,0,1,"+(-bbox.x)+","+(-bbox.y);
278                                switch(clipType){
279                                        case "rect":
280                                                r.clip = r.getHost().content.createFromXaml("<RectangleGeometry/>");
281                                                r.clip.rect = clip.x+","+clip.y+","+clip.width+","+clip.height;
282                                                r.clip.transform = clipT;
283                                                break;
284                                        case "ellipse":
285                                                r.clip = r.getHost().content.createFromXaml("<EllipseGeometry/>");
286                                                r.clip.center = clip.cx+","+clip.cy;
287                                                r.clip.radiusX = clip.rx;
288                                                r.clip.radiusY = clip.ry;
289                                                r.clip.transform = "1,0,0,1,"+(-bbox.x)+","+(-bbox.y);
290                                                break;
291                                        case "polyline":
292                                                if(clip.points.length>2){
293                                                        var line, plinegroup = r.getHost().content.createFromXaml("<PathGeometry/>"),
294                                                                pfigure = r.getHost().content.createFromXaml("<PathFigure/>");
295                                                        pfigure.StartPoint = clip.points[0]+","+clip.points[1];
296                                                        for (var i=2; i<=clip.points.length-2;i=i+2){
297                                                                line = r.getHost().content.createFromXaml("<LineSegment/>");
298                                                                line.Point = clip.points[i]+","+clip.points[i+1];
299                                                                pfigure.segments.add(line);
300                                                        }
301                                                        plinegroup.figures.add(pfigure);
302                                                        plinegroup.transform = "1,0,0,1,"+(-bbox.x)+","+(-bbox.y);
303                                                        r.clip = plinegroup;
304                                                }
305                                                break;
306                                        case "path":
307                                                // missing JS api
308                                                break;
309                                }
310                        }else{
311                                r.clip = null;
312                        }
313                        return this;
314                }
315        });
316
317        sl.Group = declare("dojox.gfx.silverlight.Group", sl.Shape, {
318                // summary:
319                //              a group shape (Silverlight), which can be used
320                //              to logically group shapes (e.g, to propagate matricies)
321                constructor: function(){
322                        gs.Container._init.call(this);
323                },
324                setRawNode: function(rawNode){
325                        // summary:
326                        //              sets a raw Silverlight node to be used by this shape
327                        // rawNode: Node
328                        //              a Sliverlight node
329                        this.rawNode = rawNode;
330                        this.rawNode.tag = this.getUID();
331                       
332                },
333                destroy: function(){
334                        // summary:
335                        //              Releases all internal resources owned by this shape. Once this method has been called,
336                        //              the instance is considered disposed and should not be used anymore.
337                        this.clear(true);
338                        // avoid this.inherited
339                        sl.Shape.prototype.destroy.apply(this, arguments);
340                }
341        });
342        sl.Group.nodeType = "Canvas";
343
344        sl.Rect = declare("dojox.gfx.silverlight.Rect", [sl.Shape, gs.Rect], {
345                // summary:
346                //              a rectangle shape (Silverlight)
347                setShape: function(newShape){
348                        // summary:
349                        //              sets a rectangle shape object (Silverlight)
350                        // newShape: Object
351                        //              a rectangle shape object
352                        this.shape = g.makeParameters(this.shape, newShape);
353                        this.bbox = null;
354                        var r = this.rawNode, n = this.shape;
355                        r.width   = n.width;
356                        r.height  = n.height;
357                        r.radiusX = r.radiusY = n.r;
358                        return this._applyTransform();  // self
359                },
360                _getAdjustedMatrix: function(){
361                        // summary:
362                        //              returns the adjusted ("real") transformation matrix
363                        var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
364                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox/gfx/matrix.Matrix2D
365                }
366        });
367        sl.Rect.nodeType = "Rectangle";
368
369        sl.Ellipse = declare("dojox.gfx.silverlight.Ellipse", [sl.Shape, gs.Ellipse], {
370                // summary:
371                //              an ellipse shape (Silverlight)
372                setShape: function(newShape){
373                        // summary:
374                        //              sets an ellipse shape object (Silverlight)
375                        // newShape: Object
376                        //              an ellipse shape object
377                        this.shape = g.makeParameters(this.shape, newShape);
378                        this.bbox = null;
379                        var r = this.rawNode, n = this.shape;
380                        r.width  = 2 * n.rx;
381                        r.height = 2 * n.ry;
382                        return this._applyTransform();  // self
383                },
384                _getAdjustedMatrix: function(){
385                        // summary:
386                        //              returns the adjusted ("real") transformation matrix
387                        var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.rx, dy: s.cy - s.ry};
388                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox/gfx/matrix.Matrix2D
389                }
390        });
391        sl.Ellipse.nodeType = "Ellipse";
392
393        sl.Circle = declare("dojox.gfx.silverlight.Circle", [sl.Shape, gs.Circle], {
394                // summary:
395                //              a circle shape (Silverlight)
396                setShape: function(newShape){
397                        // summary:
398                        //              sets a circle shape object (Silverlight)
399                        // newShape: Object
400                        //              a circle shape object
401                        this.shape = g.makeParameters(this.shape, newShape);
402                        this.bbox = null;
403                        var r = this.rawNode, n = this.shape;
404                        r.width = r.height = 2 * n.r;
405                        return this._applyTransform();  // self
406                },
407                _getAdjustedMatrix: function(){
408                        // summary:
409                        //              returns the adjusted ("real") transformation matrix
410                        var matrix = this.matrix, s = this.shape, delta = {dx: s.cx - s.r, dy: s.cy - s.r};
411                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox/gfx/matrix.Matrix2D
412                }
413        });
414        sl.Circle.nodeType = "Ellipse";
415
416        sl.Line = declare("dojox.gfx.silverlight.Line", [sl.Shape, gs.Line], {
417                // summary:
418                //              a line shape (Silverlight)
419                setShape: function(newShape){
420                        // summary:
421                        //              sets a line shape object (Silverlight)
422                        // newShape: Object
423                        //              a line shape object
424                        this.shape = g.makeParameters(this.shape, newShape);
425                        this.bbox = null;
426                        var r = this.rawNode, n = this.shape;
427                        r.x1 = n.x1; r.y1 = n.y1; r.x2 = n.x2; r.y2 = n.y2;
428                        return this;    // self
429                }
430        });
431        sl.Line.nodeType = "Line";
432
433        sl.Polyline = declare("dojox.gfx.silverlight.Polyline", [sl.Shape, gs.Polyline], {
434                // summary:
435                //              a polyline/polygon shape (Silverlight)
436                setShape: function(points, closed){
437                        // summary:
438                        //              sets a polyline/polygon shape object (Silverlight)
439                        // points: Object|Array
440                        //              a polyline/polygon shape object, or an array of points
441                        if(points && points instanceof Array){
442                                this.shape = g.makeParameters(this.shape, {points: points});
443                                if(closed && this.shape.points.length){
444                                        this.shape.points.push(this.shape.points[0]);
445                                }
446                        }else{
447                                this.shape = g.makeParameters(this.shape, points);
448                        }
449                        this.bbox = null;
450                        this._normalizePoints();
451                        var p = this.shape.points, rp = [];
452                        for(var i = 0; i < p.length; ++i){
453                                rp.push(p[i].x, p[i].y);
454                        }
455                        this.rawNode.points = rp.join(",");
456                        return this;    // self
457                }
458        });
459        sl.Polyline.nodeType = "Polyline";
460
461        sl.Image = declare("dojox.gfx.silverlight.Image", [sl.Shape, gs.Image], {
462                // summary:
463                //              an image (Silverlight)
464                setShape: function(newShape){
465                        // summary:
466                        //              sets an image shape object (Silverlight)
467                        // newShape: Object
468                        //              an image shape object
469                        this.shape = g.makeParameters(this.shape, newShape);
470                        this.bbox = null;
471                        var r = this.rawNode, n = this.shape;
472                        r.width  = n.width;
473                        r.height = n.height;
474                        r.source = n.src;
475                        return this._applyTransform();  // self
476                },
477                _getAdjustedMatrix: function(){
478                        // summary:
479                        //              returns the adjusted ("real") transformation matrix
480                        var matrix = this.matrix, s = this.shape, delta = {dx: s.x, dy: s.y};
481                        return new g.Matrix2D(matrix ? [matrix, delta] : delta);        // dojox/gfx/matrix.Matrix2D
482                },
483                setRawNode: function(rawNode){
484                        // summary:
485                        //              assigns and clears the underlying node that will represent this
486                        //              shape. Once set, transforms, gradients, etc, can be applied.
487                        //              (no fill & stroke by default)
488                        this.rawNode = rawNode;
489                        this.rawNode.tag = this.getUID();
490                }
491        });
492        sl.Image.nodeType = "Image";
493
494        sl.Text = declare("dojox.gfx.silverlight.Text", [sl.Shape, gs.Text], {
495                // summary:
496                //              an anchored text (Silverlight)
497                setShape: function(newShape){
498                        // summary:
499                        //              sets a text shape object (Silverlight)
500                        // newShape: Object
501                        //              a text shape object
502                        this.shape = g.makeParameters(this.shape, newShape);
503                        this.bbox = null;
504                        var r = this.rawNode, s = this.shape;
505                        r.text = "" + s.text; // #14522
506                        r.textDecorations = s.decoration === "underline" ? "Underline" : "None";
507                        r["Canvas.Left"] = -10000;
508                        r["Canvas.Top"]  = -10000;
509                        if(!this._delay){
510                                this._delay = window.setTimeout(lang.hitch(this, "_delayAlignment"), 10);
511                        }
512                        return this;    // self
513                },
514                _delayAlignment: function(){
515                        // handle alignment
516                        var r = this.rawNode, s = this.shape, w, h;
517                        try{
518                                w = r.actualWidth;
519                                h = r.actualHeight;
520                        }catch(e){
521                                // bail out if the node is hidden
522                                return;
523                        }
524                        var x = s.x, y = s.y - h * 0.75;
525                        switch(s.align){
526                                case "middle":
527                                        x -= w / 2;
528                                        break;
529                                case "end":
530                                        x -= w;
531                                        break;
532                        }
533                        this._delta = {dx: x, dy: y};
534                        r["Canvas.Left"] = 0;
535                        r["Canvas.Top"]  = 0;
536                        this._applyTransform();
537                        delete this._delay;
538                },
539                _getAdjustedMatrix: function(){
540                        // summary:
541                        //              returns the adjusted ("real") transformation matrix
542                        var matrix = this.matrix, delta = this._delta, x;
543                        if(matrix){
544                                x = delta ? [matrix, delta] : matrix;
545                        }else{
546                                x = delta ? delta : {};
547                        }
548                        return new g.Matrix2D(x);
549                },
550                setStroke: function(){
551                        // summary:
552                        //              ignore setting a stroke style
553                        return this;    // self
554                },
555                _setFillAttr: function(f){
556                        this.rawNode.foreground = f;
557                },
558                setRawNode: function(rawNode){
559                        // summary:
560                        //              assigns and clears the underlying node that will represent this
561                        //              shape. Once set, transforms, gradients, etc, can be applied.
562                        //              (no fill & stroke by default)
563                        this.rawNode = rawNode;
564                        this.rawNode.tag = this.getUID();
565                },
566                getTextWidth: function(){
567                        // summary:
568                        //              get the text width in pixels
569                        return this.rawNode.actualWidth;
570                },
571                getBoundingBox: function(){
572                        var bbox = null, text = this.getShape().text, r = this.rawNode, w = 0, h = 0;
573                        if(!g._base._isRendered(this)){
574                                return {x:0, y:0, width:0, height:0};
575                        }
576                        if(text){
577                                try{
578                                        w = r.actualWidth;
579                                        h = r.actualHeight;
580                                }catch(e){
581                                        // bail out if the node is hidden
582                                        return null;
583                                }
584                                var loc = g._base._computeTextLocation(this.getShape(), w, h, true);
585                                bbox = {
586                                        x: loc.x,
587                                        y: loc.y,
588                                        width : w,
589                                        height: h
590                                };
591                        }
592                        return bbox;
593                }
594        });
595        sl.Text.nodeType = "TextBlock";
596
597        sl.Path = declare("dojox.gfx.silverlight.Path", [sl.Shape, pathLib.Path], {
598                // summary:
599                //              a path shape (Silverlight)
600                _updateWithSegment: function(segment){
601                        // summary:
602                        //              updates the bounding box of path with new segment
603                        // segment: Object
604                        //              a segment
605                        this.inherited(arguments);
606                        var p = this.shape.path;
607                        if(typeof(p) == "string"){
608                                this.rawNode.data = p ? p : null;
609                        }
610                },
611                setShape: function(newShape){
612                        // summary:
613                        //              forms a path using a shape (Silverlight)
614                        // newShape: Object
615                        //              an SVG path string or a path object (see dojox/gfx.defaultPath)
616                        this.inherited(arguments);
617                        var p = this.shape.path;
618                        this.rawNode.data = p ? p : null;
619                        return this;    // self
620                }
621        });
622        sl.Path.nodeType = "Path";
623
624        sl.TextPath = declare("dojox.gfx.silverlight.TextPath", [sl.Shape, pathLib.TextPath], {
625                // summary:
626                //              a textpath shape (Silverlight)
627                _updateWithSegment: function(segment){
628                        // summary:
629                        //              updates the bounding box of path with new segment
630                        // segment: Object
631                        //              a segment
632                },
633                setShape: function(newShape){
634                        // summary:
635                        //              forms a path using a shape (Silverlight)
636                        // newShape: Object
637                        //              an SVG path string or a path object (see dojox/gfx.defaultPath)
638                },
639                _setText: function(){
640                }
641        });
642        sl.TextPath.nodeType = "text";
643
644        var surfaces = {}, nullFunc = new Function;
645
646        sl.Surface = declare("dojox.gfx.silverlight.Surface", gs.Surface, {
647                // summary:
648                //              a surface object to be used for drawings (Silverlight)
649                constructor: function(){
650                        gs.Container._init.call(this);
651                },
652                destroy: function(){
653                        this.clear(true);
654                        window[this._onLoadName] = nullFunc;
655                        delete surfaces[this._nodeName];
656                        this.inherited(arguments);
657                },
658                setDimensions: function(width, height){
659                        // summary:
660                        //              sets the width and height of the rawNode
661                        // width: String
662                        //              width of surface, e.g., "100px"
663                        // height: String
664                        //              height of surface, e.g., "100px"
665                        this.width  = g.normalizedLength(width);        // in pixels
666                        this.height = g.normalizedLength(height);       // in pixels
667                        var p = this.rawNode && this.rawNode.getHost();
668                        if(p){
669                                p.width = width;
670                                p.height = height;
671                        }
672                        return this;    // self
673                },
674                getDimensions: function(){
675                        // summary:
676                        //              returns an object with properties "width" and "height"
677                        var p = this.rawNode && this.rawNode.getHost();
678                        var t = p ? {width: p.content.actualWidth, height: p.content.actualHeight} : null;
679                        if(t.width  <= 0){ t.width  = this.width; }
680                        if(t.height <= 0){ t.height = this.height; }
681                        return t;       // Object
682                }
683        });
684
685        sl.createSurface = function(parentNode, width, height){
686                // summary:
687                //              creates a surface (Silverlight)
688                // parentNode: Node
689                //              a parent node
690                // width: String
691                //              width of surface, e.g., "100px"
692                // height: String
693                //              height of surface, e.g., "100px"
694
695                if(!width && !height){
696                        var pos = domGeom.position(parentNode);
697                        width  = width  || pos.w;
698                        height = height || pos.h;
699                }
700                if(typeof width == "number"){
701                        width = width + "px";
702                }
703                if(typeof height == "number"){
704                        height = height + "px";
705                }
706
707                var s = new sl.Surface();
708                parentNode = dom.byId(parentNode);
709                s._parent = parentNode;
710                s._nodeName = g._base._getUniqueId();
711
712                // create an empty canvas
713                var t = parentNode.ownerDocument.createElement("script");
714                t.type = "text/xaml";
715                t.id = g._base._getUniqueId();
716                t.text = "<?xml version='1.0'?><Canvas xmlns='http://schemas.microsoft.com/client/2007' Name='" +
717                        s._nodeName + "'/>";
718                parentNode.parentNode.insertBefore(t, parentNode);
719                s._nodes.push(t);
720
721                // build the object
722                var obj, pluginName = g._base._getUniqueId(),
723                        onLoadName = "__" + g._base._getUniqueId() + "_onLoad";
724                s._onLoadName = onLoadName;
725                window[onLoadName] = function(sender){
726                        if(!s.rawNode){
727                                s.rawNode = dom.byId(pluginName, parentNode.ownerDocument).content.root;
728                                // register the plugin with its parent node
729                                surfaces[s._nodeName] = parentNode;
730                                s.onLoad(s);
731                        }
732                };
733                if(has("safari")){
734                        obj = "<embed type='application/x-silverlight' id='" +
735                        pluginName + "' width='" + width + "' height='" + height +
736                        " background='transparent'" +
737                        " source='#" + t.id + "'" +
738                        " windowless='true'" +
739                        " maxFramerate='60'" +
740                        " onLoad='" + onLoadName + "'" +
741                        " onError='__dojoSilverlightError'" +
742                        " /><iframe style='visibility:hidden;height:0;width:0'/>";
743                }else{
744                        obj = "<object type='application/x-silverlight' data='data:application/x-silverlight,' id='" +
745                        pluginName + "' width='" + width + "' height='" + height + "'>" +
746                        "<param name='background' value='transparent' />" +
747                        "<param name='source' value='#" + t.id + "' />" +
748                        "<param name='windowless' value='true' />" +
749                        "<param name='maxFramerate' value='60' />" +
750                        "<param name='onLoad' value='" + onLoadName + "' />" +
751                        "<param name='onError' value='__dojoSilverlightError' />" +
752                        "</object>";
753                }
754                parentNode.innerHTML = obj;
755
756                var pluginNode = dom.byId(pluginName, parentNode.ownerDocument);
757                if(pluginNode.content && pluginNode.content.root){
758                        // the plugin was created synchronously
759                        s.rawNode = pluginNode.content.root;
760                        // register the plugin with its parent node
761                        surfaces[s._nodeName] = parentNode;
762                }else{
763                        // the plugin is being created asynchronously
764                        s.rawNode = null;
765                        s.isLoaded = false;
766                }
767                s._nodes.push(pluginNode);
768
769                s.width  = g.normalizedLength(width);   // in pixels
770                s.height = g.normalizedLength(height);  // in pixels
771
772                return s;       // dojox/gfx.Surface
773        };
774
775        // the function below is meant to be global, it is called from
776        // the Silverlight's error handler
777        __dojoSilverlightError = function(sender, err){
778                var t = "Silverlight Error:\n" +
779                        "Code: " + err.ErrorCode + "\n" +
780                        "Type: " + err.ErrorType + "\n" +
781                        "Message: " + err.ErrorMessage + "\n";
782                switch(err.ErrorType){
783                        case "ParserError":
784                                t += "XamlFile: " + err.xamlFile + "\n" +
785                                        "Line: " + err.lineNumber + "\n" +
786                                        "Position: " + err.charPosition + "\n";
787                                break;
788                        case "RuntimeError":
789                                t += "MethodName: " + err.methodName + "\n";
790                                if(err.lineNumber != 0){
791                                        t +=
792                                                "Line: " + err.lineNumber + "\n" +
793                                                "Position: " + err.charPosition + "\n";
794                                }
795                                break;
796                }
797        };
798
799        // Extenders
800
801        var Font = {
802                _setFont: function(){
803                        // summary:
804                        //              sets a font object (Silverlight)
805                        var f = this.fontStyle, r = this.rawNode, t = f.family.toLowerCase();
806                        r.fontStyle = f.style == "italic" ? "Italic" : "Normal";
807                        r.fontWeight = f.weight in fontweight ? fontweight[f.weight] : f.weight;
808                        r.fontSize = g.normalizedLength(f.size);
809                        r.fontFamily = t in fonts ? fonts[t] : f.family;
810
811                        // update the transform
812                        if(!this._delay){
813                                this._delay = window.setTimeout(lang.hitch(this, "_delayAlignment"), 10);
814                        }
815                }
816        };
817
818        var C = gs.Container, Container = {
819                add: function(shape){
820                        // summary:
821                        //              adds a shape to a group/surface
822                        // shape: dojox/gfx/shape.Shape
823                        //              a Silverlight shape object
824                        if(this != shape.getParent()){
825                                C.add.apply(this, arguments);
826                                this.rawNode.children.add(shape.rawNode);
827                        }
828                        return this;    // self
829                },
830                remove: function(shape, silently){
831                        // summary:
832                        //              remove a shape from a group/surface
833                        // shape: dojox/gfx/shape.Shape
834                        //              a Silverlight shape object
835                        // silently: Boolean?
836                        //              if true, regenerate a picture
837                        if(this == shape.getParent()){
838                                var parent = shape.rawNode.getParent();
839                                if(parent){
840                                        parent.children.remove(shape.rawNode);
841                                }
842                                C.remove.apply(this, arguments);
843                        }
844                        return this;    // self
845                },
846                clear: function(){
847                        // summary:
848                        //              removes all shapes from a group/surface
849                        this.rawNode.children.clear();
850                        return C.clear.apply(this, arguments);
851                },
852                getBoundingBox: C.getBoundingBox,
853                _moveChildToFront: C._moveChildToFront,
854                _moveChildToBack:  C._moveChildToBack
855        };
856
857        var Creator = {
858                createObject: function(shapeType, rawShape){
859                        // summary:
860                        //              creates an instance of the passed shapeType class
861                        // shapeType: Function
862                        //              a class constructor to create an instance of
863                        // rawShape: Object
864                        //              properties to be passed in to the classes "setShape" method
865                        if(!this.rawNode){ return null; }
866                        var shape = new shapeType();
867                        var node = this.rawNode.getHost().content.createFromXaml("<" + shapeType.nodeType + "/>");
868                        shape.setRawNode(node);
869                        shape.setShape(rawShape);
870                        this.add(shape);
871                        return shape;   // dojox/gfx/shape.Shape
872                }
873        };
874
875        lang.extend(sl.Text, Font);
876        //dojo.extend(sl.TextPath, Font);
877
878        lang.extend(sl.Group, Container);
879        lang.extend(sl.Group, gs.Creator);
880        lang.extend(sl.Group, Creator);
881
882        lang.extend(sl.Surface, Container);
883        lang.extend(sl.Surface, gs.Creator);
884        lang.extend(sl.Surface, Creator);
885
886        function mouseFix(s, a){
887                var ev = {target: s, currentTarget: s, preventDefault: function(){}, stopPropagation: function(){}};
888                try{
889                        if(a.source){
890                                // support silverlight 2.0
891                                ev.target = a.source;
892                                var gfxId = ev.target.tag;                             
893                                ev.gfxTarget = gs.byId(gfxId);
894                        }
895                }catch(e){
896                        // a.source does not exist in 1.0
897                }
898       
899                if(a){
900                        try{
901                                ev.ctrlKey = a.ctrl;
902                                ev.shiftKey = a.shift;
903                                var p = a.getPosition(null);
904                                ev.x = ev.offsetX = ev.layerX = p.x;
905                                ev.y = ev.offsetY = ev.layerY = p.y;
906                                // calculate clientX and clientY
907                                var parent = surfaces[s.getHost().content.root.name];
908                                var t = domGeom.position(parent);
909                                ev.clientX = t.x + p.x;
910                                ev.clientY = t.y + p.y;
911                        }catch(e){
912                                // squelch bugs in MouseLeave's implementation
913                        }
914                }
915                return ev;
916        }
917       
918        function keyFix(s, a){
919                var ev = {
920                        keyCode:  a.platformKeyCode,
921                        ctrlKey:  a.ctrl,
922                        shiftKey: a.shift
923                };
924                try{
925                        if(a.source){
926                                // source is defined from Silverlight 2+
927                                ev.target = a.source;
928                                ev.gfxTarget = gs.byId(ev.target.tag);
929                        }
930                }catch(e){
931                        // a.source does not exist in 1.0
932                }
933                return ev;
934        }
935       
936        var eventNames = {
937                onclick:                {name: "MouseLeftButtonUp", fix: mouseFix},
938                onmouseenter:   {name: "MouseEnter", fix: mouseFix},
939                onmouseleave:   {name: "MouseLeave", fix: mouseFix},
940                onmouseover:    {name: "MouseEnter", fix: mouseFix},
941                onmouseout:             {name: "MouseLeave", fix: mouseFix},
942                onmousedown:    {name: "MouseLeftButtonDown", fix: mouseFix},
943                onmouseup:              {name: "MouseLeftButtonUp", fix: mouseFix},
944                onmousemove:    {name: "MouseMove", fix: mouseFix},
945                onkeydown:              {name: "KeyDown", fix: keyFix},
946                onkeyup:                {name: "KeyUp", fix: keyFix}
947        };
948       
949        var eventsProcessing = {
950                connect: function(name, object, method){
951                        return this.on(name, method ? lang.hitch(object, method) : object);
952                },
953
954                on: function(name, listener){
955                        if(typeof name === "string"){
956                                if(name.indexOf("mouse") === 0){
957                                        name = "on" + name;
958                                }
959                                var token, n = name in eventNames ? eventNames[name] :
960                                        {name: name, fix: function(){ return {}; }};
961                                token = this.getEventSource().addEventListener(n.name, function(s, a){ listener(n.fix(s, a)); });
962                                return {
963                                        name: n.name,
964                                        token: token,
965                                        remove: lang.hitch(this, function(){
966                                                this.getEventSource().removeEventListener(n.name, token);
967                                        })
968                                };
969                        }else{
970                                // pass this so that it gets back in this.on with the event name
971                                return on(this, name, listener);
972                        }
973                },
974
975                disconnect: function(token){
976                        return token.remove();
977                }
978        };
979       
980        lang.extend(sl.Shape, eventsProcessing);
981        lang.extend(sl.Surface, eventsProcessing);
982       
983        // patch dojox/gfx
984        g.equalSources = function(a, b){
985                // summary:
986                //              compares event sources, returns true if they are equal
987                return a && b && a.equals(b);
988        };
989       
990        return sl;
991});
992
Note: See TracBrowser for help on using the repository browser.