Bienvenue sur PostGIS.fr

Bienvenue sur PostGIS.fr , le site de la communauté des utilisateurs francophones de PostGIS.

PostGIS ajoute le support d'objets géographique à la base de données PostgreSQL. En effet, PostGIS "spatialise" le serverur PostgreSQL, ce qui permet de l'utiliser comme une base de données SIG.

Maintenu à jour, en fonction de nos disponibilités et des diverses sorties des outils que nous testons, nous vous proposons l'ensemble de nos travaux publiés en langue française.

source: trunk/workshop-routing-foss4g/web/OpenLayers/lib/OpenLayers/Renderer/VML.js @ 76

Revision 76, 32.6 KB checked in by djay, 12 years ago (diff)

Ajout du répertoire web

  • Property svn:executable set to *
Line 
1/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
2 * full list of contributors). Published under the Clear BSD license. 
3 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
4 * full text of the license. */
5
6/**
7 * @requires OpenLayers/Renderer/Elements.js
8 */
9
10/**
11 * Class: OpenLayers.Renderer.VML
12 * Render vector features in browsers with VML capability.  Construct a new
13 * VML renderer with the <OpenLayers.Renderer.VML> constructor.
14 *
15 * Note that for all calculations in this class, we use (num | 0) to truncate a
16 * float value to an integer. This is done because it seems that VML doesn't
17 * support float values.
18 *
19 * Inherits from:
20 *  - <OpenLayers.Renderer.Elements>
21 */
22OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
23
24    /**
25     * Property: xmlns
26     * {String} XML Namespace URN
27     */
28    xmlns: "urn:schemas-microsoft-com:vml",
29   
30    /**
31     * Property: symbolCache
32     * {DOMElement} node holding symbols. This hash is keyed by symbol name,
33     *     and each value is a hash with a "path" and an "extent" property.
34     */
35    symbolCache: {},
36
37    /**
38     * Property: offset
39     * {Object} Hash with "x" and "y" properties
40     */
41    offset: null,
42   
43    /**
44     * Constructor: OpenLayers.Renderer.VML
45     * Create a new VML renderer.
46     *
47     * Parameters:
48     * containerID - {String} The id for the element that contains the renderer
49     */
50    initialize: function(containerID) {
51        if (!this.supported()) { 
52            return; 
53        }
54        if (!document.namespaces.olv) {
55            document.namespaces.add("olv", this.xmlns);
56            var style = document.createStyleSheet();
57            var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox']; 
58            for (var i = 0, len = shapes.length; i < len; i++) {
59
60                style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " +
61                              "position: absolute; display: inline-block;");
62            }                 
63        }
64       
65        OpenLayers.Renderer.Elements.prototype.initialize.apply(this, 
66                                                                arguments);
67    },
68
69    /**
70     * APIMethod: destroy
71     * Deconstruct the renderer.
72     */
73    destroy: function() {
74        OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
75    },
76
77    /**
78     * APIMethod: supported
79     * Determine whether a browser supports this renderer.
80     *
81     * Returns:
82     * {Boolean} The browser supports the VML renderer
83     */
84    supported: function() {
85        return !!(document.namespaces);
86    },   
87
88    /**
89     * Method: setExtent
90     * Set the renderer's extent
91     *
92     * Parameters:
93     * extent - {<OpenLayers.Bounds>}
94     * resolutionChanged - {Boolean}
95     *
96     * Returns:
97     * {Boolean} true to notify the layer that the new extent does not exceed
98     *     the coordinate range, and the features will not need to be redrawn.
99     */
100    setExtent: function(extent, resolutionChanged) {
101        OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, 
102                                                               arguments);
103        var resolution = this.getResolution();
104   
105        var left = (extent.left/resolution) | 0;
106        var top = (extent.top/resolution - this.size.h) | 0;
107        if (resolutionChanged || !this.offset) {
108            this.offset = {x: left, y: top};
109            left = 0;
110            top = 0;
111        } else {
112            left = left - this.offset.x;
113            top = top - this.offset.y;
114        }
115
116       
117        var org = left + " " + top;
118        this.root.coordorigin = org;
119        var roots = [this.root, this.vectorRoot, this.textRoot];
120        var root;
121        for(var i=0, len=roots.length; i<len; ++i) {
122            root = roots[i];
123
124            var size = this.size.w + " " + this.size.h;
125            root.coordsize = size;
126           
127        }
128        // flip the VML display Y axis upside down so it
129        // matches the display Y axis of the map
130        this.root.style.flip = "y";
131       
132        return true;
133    },
134
135
136    /**
137     * Method: setSize
138     * Set the size of the drawing surface
139     *
140     * Parameters:
141     * size - {<OpenLayers.Size>} the size of the drawing surface
142     */
143    setSize: function(size) {
144        OpenLayers.Renderer.prototype.setSize.apply(this, arguments);
145       
146        // setting width and height on all roots to avoid flicker which we
147        // would get with 100% width and height on child roots
148        var roots = [
149            this.rendererRoot,
150            this.root,
151            this.vectorRoot,
152            this.textRoot
153        ];
154        var w = this.size.w + "px";
155        var h = this.size.h + "px";
156        var root;
157        for(var i=0, len=roots.length; i<len; ++i) {
158            root = roots[i];
159            root.style.width = w;
160            root.style.height = h;
161        }
162    },
163
164    /**
165     * Method: getNodeType
166     * Get the node type for a geometry and style
167     *
168     * Parameters:
169     * geometry - {<OpenLayers.Geometry>}
170     * style - {Object}
171     *
172     * Returns:
173     * {String} The corresponding node type for the specified geometry
174     */
175    getNodeType: function(geometry, style) {
176        var nodeType = null;
177        switch (geometry.CLASS_NAME) {
178            case "OpenLayers.Geometry.Point":
179                if (style.externalGraphic) {
180                    nodeType = "olv:rect";
181                } else if (this.isComplexSymbol(style.graphicName)) {
182                    nodeType = "olv:shape";
183                } else {
184                    nodeType = "olv:oval";
185                }
186                break;
187            case "OpenLayers.Geometry.Rectangle":
188                nodeType = "olv:rect";
189                break;
190            case "OpenLayers.Geometry.LineString":
191            case "OpenLayers.Geometry.LinearRing":
192            case "OpenLayers.Geometry.Polygon":
193            case "OpenLayers.Geometry.Curve":
194            case "OpenLayers.Geometry.Surface":
195                nodeType = "olv:shape";
196                break;
197            default:
198                break;
199        }
200        return nodeType;
201    },
202
203    /**
204     * Method: setStyle
205     * Use to set all the style attributes to a VML node.
206     *
207     * Parameters:
208     * node - {DOMElement} An VML element to decorate
209     * style - {Object}
210     * options - {Object} Currently supported options include
211     *                              'isFilled' {Boolean} and
212     *                              'isStroked' {Boolean}
213     * geometry - {<OpenLayers.Geometry>}
214     */
215    setStyle: function(node, style, options, geometry) {
216        style = style  || node._style;
217        options = options || node._options;
218        var fillColor = style.fillColor;
219
220        if (node._geometryClass === "OpenLayers.Geometry.Point") {
221            if (style.externalGraphic) {
222                if (style.graphicTitle) {
223                    node.title=style.graphicTitle;
224                } 
225                var width = style.graphicWidth || style.graphicHeight;
226                var height = style.graphicHeight || style.graphicWidth;
227                width = width ? width : style.pointRadius*2;
228                height = height ? height : style.pointRadius*2;
229
230                var resolution = this.getResolution();
231                var xOffset = (style.graphicXOffset != undefined) ?
232                    style.graphicXOffset : -(0.5 * width);
233                var yOffset = (style.graphicYOffset != undefined) ?
234                    style.graphicYOffset : -(0.5 * height);
235               
236                node.style.left = (((geometry.x/resolution - this.offset.x)+xOffset) | 0) + "px";
237                node.style.top = (((geometry.y/resolution - this.offset.y)-(yOffset+height)) | 0) + "px";
238                node.style.width = width + "px";
239                node.style.height = height + "px";
240                node.style.flip = "y";
241               
242                // modify fillColor and options for stroke styling below
243                fillColor = "none";
244                options.isStroked = false;
245            } else if (this.isComplexSymbol(style.graphicName)) {
246                var cache = this.importSymbol(style.graphicName);
247                node.path = cache.path;
248                node.coordorigin = cache.left + "," + cache.bottom;
249                var size = cache.size;
250                node.coordsize = size + "," + size;       
251                this.drawCircle(node, geometry, style.pointRadius);
252                node.style.flip = "y";
253            } else {
254                this.drawCircle(node, geometry, style.pointRadius);
255            }
256        }
257
258        // fill
259        if (options.isFilled) { 
260            node.fillcolor = fillColor; 
261        } else { 
262            node.filled = "false"; 
263        }
264        var fills = node.getElementsByTagName("fill");
265        var fill = (fills.length == 0) ? null : fills[0];
266        if (!options.isFilled) {
267            if (fill) {
268                node.removeChild(fill);
269            }
270        } else {
271            if (!fill) {
272                fill = this.createNode('olv:fill', node.id + "_fill");
273            }
274            fill.opacity = style.fillOpacity;
275
276            if (node._geometryClass === "OpenLayers.Geometry.Point" &&
277                    style.externalGraphic) {
278
279                // override fillOpacity
280                if (style.graphicOpacity) {
281                    fill.opacity = style.graphicOpacity;
282                }
283               
284                fill.src = style.externalGraphic;
285                fill.type = "frame";
286               
287                if (!(style.graphicWidth && style.graphicHeight)) {
288                  fill.aspect = "atmost";
289                }               
290            }
291            if (fill.parentNode != node) {
292                node.appendChild(fill);
293            }
294        }
295
296        // additional rendering for rotated graphics or symbols
297        var rotation = style.rotation;
298        if ((rotation !== undefined || node._rotation !== undefined)) {
299            node._rotation = rotation;
300            if (style.externalGraphic) {
301                this.graphicRotate(node, xOffset, yOffset, style);
302                // make the fill fully transparent, because we now have
303                // the graphic as imagedata element. We cannot just remove
304                // the fill, because this is part of the hack described
305                // in graphicRotate
306                fill.opacity = 0;
307            } else if(node._geometryClass === "OpenLayers.Geometry.Point") {
308                node.style.rotation = rotation || 0;
309            }
310        }
311
312        // stroke
313        var strokes = node.getElementsByTagName("stroke");
314        var stroke = (strokes.length == 0) ? null : strokes[0];
315        if (!options.isStroked) {
316            node.stroked = false;
317            if (stroke) {
318                stroke.on = false;
319            }
320        } else {
321            if (!stroke) {
322                stroke = this.createNode('olv:stroke', node.id + "_stroke");
323                node.appendChild(stroke);
324            }
325            stroke.on = true;
326            stroke.color = style.strokeColor; 
327            stroke.weight = style.strokeWidth + "px"; 
328            stroke.opacity = style.strokeOpacity;
329            stroke.endcap = style.strokeLinecap == 'butt' ? 'flat' :
330                (style.strokeLinecap || 'round');
331            if (style.strokeDashstyle) {
332                stroke.dashstyle = this.dashStyle(style);
333            }
334        }
335       
336        if (style.cursor != "inherit" && style.cursor != null) {
337            node.style.cursor = style.cursor;
338        }
339        return node;
340    },
341
342    /**
343     * Method: graphicRotate
344     * If a point is to be styled with externalGraphic and rotation, VML fills
345     * cannot be used to display the graphic, because rotation of graphic
346     * fills is not supported by the VML implementation of Internet Explorer.
347     * This method creates a olv:imagedata element inside the VML node,
348     * DXImageTransform.Matrix and BasicImage filters for rotation and
349     * opacity, and a 3-step hack to remove rendering artefacts from the
350     * graphic and preserve the ability of graphics to trigger events.
351     * Finally, OpenLayers methods are used to determine the correct
352     * insertion point of the rotated image, because DXImageTransform.Matrix
353     * does the rotation without the ability to specify a rotation center
354     * point.
355     *
356     * Parameters:
357     * node    - {DOMElement}
358     * xOffset - {Number} rotation center relative to image, x coordinate
359     * yOffset - {Number} rotation center relative to image, y coordinate
360     * style   - {Object}
361     */
362    graphicRotate: function(node, xOffset, yOffset, style) {
363        var style = style || node._style;
364        var rotation = style.rotation || 0;
365       
366        var aspectRatio, size;
367        if (!(style.graphicWidth && style.graphicHeight)) {
368            // load the image to determine its size
369            var img = new Image();
370            img.onreadystatechange = OpenLayers.Function.bind(function() {
371                if(img.readyState == "complete" ||
372                        img.readyState == "interactive") {
373                    aspectRatio = img.width / img.height;
374                    size = Math.max(style.pointRadius * 2, 
375                        style.graphicWidth || 0,
376                        style.graphicHeight || 0);
377                    xOffset = xOffset * aspectRatio;
378                    style.graphicWidth = size * aspectRatio;
379                    style.graphicHeight = size;
380                    this.graphicRotate(node, xOffset, yOffset, style);
381                }
382            }, this);
383            img.src = style.externalGraphic;
384           
385            // will be called again by the onreadystate handler
386            return;
387        } else {
388            size = Math.max(style.graphicWidth, style.graphicHeight);
389            aspectRatio = style.graphicWidth / style.graphicHeight;
390        }
391       
392        var width = Math.round(style.graphicWidth || size * aspectRatio);
393        var height = Math.round(style.graphicHeight || size);
394        node.style.width = width + "px";
395        node.style.height = height + "px";
396       
397        // Three steps are required to remove artefacts for images with
398        // transparent backgrounds (resulting from using DXImageTransform
399        // filters on svg objects), while preserving awareness for browser
400        // events on images:
401        // - Use the fill as usual (like for unrotated images) to handle
402        //   events
403        // - specify an imagedata element with the same src as the fill
404        // - style the imagedata element with an AlphaImageLoader filter
405        //   with empty src
406        var image = document.getElementById(node.id + "_image");
407        if (!image) {
408            image = this.createNode("olv:imagedata", node.id + "_image");
409            node.appendChild(image);
410        }
411        image.style.width = width + "px";
412        image.style.height = height + "px";
413        image.src = style.externalGraphic;
414        image.style.filter =
415            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + 
416            "src='', sizingMethod='scale')";
417
418        var rot = rotation * Math.PI / 180;
419        var sintheta = Math.sin(rot);
420        var costheta = Math.cos(rot);
421
422        // do the rotation on the image
423        var filter =
424            "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
425            ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
426            ",SizingMethod='auto expand')\n";
427
428        // set the opacity (needed for the imagedata)
429        var opacity = style.graphicOpacity || style.fillOpacity;
430        if (opacity && opacity != 1) {
431            filter += 
432                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + 
433                opacity+")\n";
434        }
435        node.style.filter = filter;
436
437        // do the rotation again on a box, so we know the insertion point
438        var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
439        var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
440        imgBox.rotate(style.rotation, centerPoint);
441        var imgBounds = imgBox.getBounds();
442
443        node.style.left = Math.round(
444            parseInt(node.style.left) + imgBounds.left) + "px";
445        node.style.top = Math.round(
446            parseInt(node.style.top) - imgBounds.bottom) + "px";
447    },
448
449    /**
450     * Method: postDraw
451     * Does some node postprocessing to work around browser issues:
452     * - Some versions of Internet Explorer seem to be unable to set fillcolor
453     *   and strokecolor to "none" correctly before the fill node is appended
454     *   to a visible vml node. This method takes care of that and sets
455     *   fillcolor and strokecolor again if needed.
456     * - In some cases, a node won't become visible after being drawn. Setting
457     *   style.visibility to "visible" works around that.
458     *
459     * Parameters:
460     * node - {DOMElement}
461     */
462    postDraw: function(node) {
463        node.style.visibility = "visible";
464        var fillColor = node._style.fillColor;
465        var strokeColor = node._style.strokeColor;
466        if (fillColor == "none" &&
467                node.fillcolor != fillColor) {
468            node.fillcolor = fillColor;
469        }
470        if (strokeColor == "none" &&
471                node.strokecolor != strokeColor) {
472            node.strokecolor = strokeColor;
473        }
474    },
475
476
477    /**
478     * Method: setNodeDimension
479     * Get the geometry's bounds, convert it to our vml coordinate system,
480     * then set the node's position, size, and local coordinate system.
481     *   
482     * Parameters:
483     * node - {DOMElement}
484     * geometry - {<OpenLayers.Geometry>}
485     */
486    setNodeDimension: function(node, geometry) {
487
488        var bbox = geometry.getBounds();
489        if(bbox) {
490            var resolution = this.getResolution();
491       
492            var scaledBox = 
493                new OpenLayers.Bounds((bbox.left/resolution - this.offset.x) | 0,
494                                      (bbox.bottom/resolution - this.offset.y) | 0,
495                                      (bbox.right/resolution - this.offset.x) | 0,
496                                      (bbox.top/resolution - this.offset.y) | 0);
497           
498            // Set the internal coordinate system to draw the path
499            node.style.left = scaledBox.left + "px";
500            node.style.top = scaledBox.top + "px";
501            node.style.width = scaledBox.getWidth() + "px";
502            node.style.height = scaledBox.getHeight() + "px";
503   
504            node.coordorigin = scaledBox.left + " " + scaledBox.top;
505            node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
506        }
507    },
508   
509    /**
510     * Method: dashStyle
511     *
512     * Parameters:
513     * style - {Object}
514     *
515     * Returns:
516     * {String} A VML compliant 'stroke-dasharray' value
517     */
518    dashStyle: function(style) {
519        var dash = style.strokeDashstyle;
520        switch (dash) {
521            case 'solid':
522            case 'dot':
523            case 'dash':
524            case 'dashdot':
525            case 'longdash':
526            case 'longdashdot':
527                return dash;
528            default:
529                // very basic guessing of dash style patterns
530                var parts = dash.split(/[ ,]/);
531                if (parts.length == 2) {
532                    if (1*parts[0] >= 2*parts[1]) {
533                        return "longdash";
534                    }
535                    return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
536                } else if (parts.length == 4) {
537                    return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
538                        "dashdot";
539                }
540                return "solid";
541        }
542    },
543
544    /**
545     * Method: createNode
546     * Create a new node
547     *
548     * Parameters:
549     * type - {String} Kind of node to draw
550     * id - {String} Id for node
551     *
552     * Returns:
553     * {DOMElement} A new node of the given type and id
554     */
555    createNode: function(type, id) {
556        var node = document.createElement(type);
557        if (id) {
558            node.id = id;
559        }
560       
561        // IE hack to make elements unselectable, to prevent 'blue flash'
562        // while dragging vectors; #1410
563        node.unselectable = 'on';
564        node.onselectstart = OpenLayers.Function.False;
565       
566        return node;   
567    },
568   
569    /**
570     * Method: nodeTypeCompare
571     * Determine whether a node is of a given type
572     *
573     * Parameters:
574     * node - {DOMElement} An VML element
575     * type - {String} Kind of node
576     *
577     * Returns:
578     * {Boolean} Whether or not the specified node is of the specified type
579     */
580    nodeTypeCompare: function(node, type) {
581
582        //split type
583        var subType = type;
584        var splitIndex = subType.indexOf(":");
585        if (splitIndex != -1) {
586            subType = subType.substr(splitIndex+1);
587        }
588
589        //split nodeName
590        var nodeName = node.nodeName;
591        splitIndex = nodeName.indexOf(":");
592        if (splitIndex != -1) {
593            nodeName = nodeName.substr(splitIndex+1);
594        }
595
596        return (subType == nodeName);
597    },
598
599    /**
600     * Method: createRenderRoot
601     * Create the renderer root
602     *
603     * Returns:
604     * {DOMElement} The specific render engine's root element
605     */
606    createRenderRoot: function() {
607        return this.nodeFactory(this.container.id + "_vmlRoot", "div");
608    },
609
610    /**
611     * Method: createRoot
612     * Create the main root element
613     *
614     * Parameters:
615     * suffix - {String} suffix to append to the id
616     *
617     * Returns:
618     * {DOMElement}
619     */
620    createRoot: function(suffix) {
621        return this.nodeFactory(this.container.id + suffix, "olv:group");
622    },
623   
624    /**************************************
625     *                                    *
626     *     GEOMETRY DRAWING FUNCTIONS     *
627     *                                    *
628     **************************************/
629   
630    /**
631     * Method: drawPoint
632     * Render a point
633     *
634     * Parameters:
635     * node - {DOMElement}
636     * geometry - {<OpenLayers.Geometry>}
637     *
638     * Returns:
639     * {DOMElement} or false if the point could not be drawn
640     */
641    drawPoint: function(node, geometry) {
642        return this.drawCircle(node, geometry, 1);
643    },
644
645    /**
646     * Method: drawCircle
647     * Render a circle.
648     * Size and Center a circle given geometry (x,y center) and radius
649     *
650     * Parameters:
651     * node - {DOMElement}
652     * geometry - {<OpenLayers.Geometry>}
653     * radius - {float}
654     *
655     * Returns:
656     * {DOMElement} or false if the circle could not ne drawn
657     */
658    drawCircle: function(node, geometry, radius) {
659        if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
660            var resolution = this.getResolution();
661
662            node.style.left = (((geometry.x /resolution - this.offset.x) | 0) - radius) + "px";
663            node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
664   
665            var diameter = radius * 2;
666           
667            node.style.width = diameter + "px";
668            node.style.height = diameter + "px";
669            return node;
670        }
671        return false;
672    },
673
674
675    /**
676     * Method: drawLineString
677     * Render a linestring.
678     *
679     * Parameters:
680     * node - {DOMElement}
681     * geometry - {<OpenLayers.Geometry>}
682     *
683     * Returns:
684     * {DOMElement}
685     */
686    drawLineString: function(node, geometry) {
687        return this.drawLine(node, geometry, false);
688    },
689
690    /**
691     * Method: drawLinearRing
692     * Render a linearring
693     *
694     * Parameters:
695     * node - {DOMElement}
696     * geometry - {<OpenLayers.Geometry>}
697     *
698     * Returns:
699     * {DOMElement}
700     */
701    drawLinearRing: function(node, geometry) {
702        return this.drawLine(node, geometry, true);
703    },
704
705    /**
706     * Method: DrawLine
707     * Render a line.
708     *
709     * Parameters:
710     * node - {DOMElement}
711     * geometry - {<OpenLayers.Geometry>}
712     * closeLine - {Boolean} Close the line? (make it a ring?)
713     *
714     * Returns:
715     * {DOMElement}
716     */
717    drawLine: function(node, geometry, closeLine) {
718
719        this.setNodeDimension(node, geometry);
720
721        var resolution = this.getResolution();
722        var numComponents = geometry.components.length;
723        var parts = new Array(numComponents);
724
725        var comp, x, y;
726        for (var i = 0; i < numComponents; i++) {
727            comp = geometry.components[i];
728            x = (comp.x/resolution - this.offset.x) | 0;
729            y = (comp.y/resolution - this.offset.y) | 0;
730            parts[i] = " " + x + "," + y + " l ";
731        }
732        var end = (closeLine) ? " x e" : " e";
733        node.path = "m" + parts.join("") + end;
734        return node;
735    },
736
737    /**
738     * Method: drawPolygon
739     * Render a polygon
740     *
741     * Parameters:
742     * node - {DOMElement}
743     * geometry - {<OpenLayers.Geometry>}
744     *
745     * Returns:
746     * {DOMElement}
747     */
748    drawPolygon: function(node, geometry) {
749        this.setNodeDimension(node, geometry);
750
751        var resolution = this.getResolution();
752   
753        var path = [];
754        var linearRing, i, j, len, ilen, comp, x, y;
755        for (j = 0, len=geometry.components.length; j<len; j++) {
756            linearRing = geometry.components[j];
757
758            path.push("m");
759            for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
760                comp = linearRing.components[i];
761                x = (comp.x / resolution - this.offset.x) | 0;
762                y = (comp.y / resolution - this.offset.y) | 0;
763                path.push(" " + x + "," + y);
764                if (i==0) {
765                    path.push(" l");
766                }
767            }
768            path.push(" x ");
769        }
770        path.push("e");
771        node.path = path.join("");
772        return node;
773    },
774
775    /**
776     * Method: drawRectangle
777     * Render a rectangle
778     *
779     * Parameters:
780     * node - {DOMElement}
781     * geometry - {<OpenLayers.Geometry>}
782     *
783     * Returns:
784     * {DOMElement}
785     */
786    drawRectangle: function(node, geometry) {
787        var resolution = this.getResolution();
788   
789        node.style.left = ((geometry.x/resolution - this.offset.x) | 0) + "px";
790        node.style.top = ((geometry.y/resolution - this.offset.y) | 0) + "px";
791        node.style.width = ((geometry.width/resolution) | 0) + "px";
792        node.style.height = ((geometry.height/resolution) | 0) + "px";
793       
794        return node;
795    },
796   
797    /**
798     * Method: drawText
799     * This method is only called by the renderer itself.
800     *
801     * Parameters:
802     * featureId - {String}
803     * style -
804     * location - {<OpenLayers.Geometry.Point>}
805     */
806    drawText: function(featureId, style, location) {
807        var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "olv:rect");
808        var textbox = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_textbox", "olv:textbox");
809       
810        var resolution = this.getResolution();
811        label.style.left = ((location.x/resolution - this.offset.x) | 0) + "px";
812        label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
813        label.style.flip = "y";
814
815        textbox.innerText = style.label;
816
817        if (style.fontColor) {
818            textbox.style.color = style.fontColor;
819        }
820        if (style.fontOpacity) {
821            textbox.style.filter = 'alpha(opacity=' + (style.fontOpacity * 100) + ')';
822        }
823        if (style.fontFamily) {
824            textbox.style.fontFamily = style.fontFamily;
825        }
826        if (style.fontSize) {
827            textbox.style.fontSize = style.fontSize;
828        }
829        if (style.fontWeight) {
830            textbox.style.fontWeight = style.fontWeight;
831        }
832        if(style.labelSelect === true) {
833            label._featureId = featureId;
834            textbox._featureId = featureId;
835            textbox._geometry = location;
836            textbox._geometryClass = location.CLASS_NAME;
837        }
838        textbox.style.whiteSpace = "nowrap";
839        // fun with IE: IE7 in standards compliant mode does not display any
840        // text with a left inset of 0. So we set this to 1px and subtract one
841        // pixel later when we set label.style.left
842        textbox.inset = "1px,0px,0px,0px";
843
844        if(!label.parentNode) {
845            label.appendChild(textbox);
846            this.textRoot.appendChild(label);
847        }
848
849        var align = style.labelAlign || "cm";
850        if (align.length == 1) {
851            align += "m";
852        }
853        var xshift = textbox.clientWidth *
854            (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(0,1)]);
855        var yshift = textbox.clientHeight *
856            (OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
857        label.style.left = parseInt(label.style.left)-xshift-1+"px";
858        label.style.top = parseInt(label.style.top)+yshift+"px";
859       
860    },
861
862    /**
863     * Method: drawSurface
864     *
865     * Parameters:
866     * node - {DOMElement}
867     * geometry - {<OpenLayers.Geometry>}
868     *
869     * Returns:
870     * {DOMElement}
871     */
872    drawSurface: function(node, geometry) {
873
874        this.setNodeDimension(node, geometry);
875
876        var resolution = this.getResolution();
877   
878        var path = [];
879        var comp, x, y;
880        for (var i=0, len=geometry.components.length; i<len; i++) {
881            comp = geometry.components[i];
882            x = (comp.x / resolution - this.offset.x) | 0;
883            y = (comp.y / resolution - this.offset.y) | 0;
884            if ((i%3)==0 && (i/3)==0) {
885                path.push("m");
886            } else if ((i%3)==1) {
887                path.push(" c");
888            }
889            path.push(" " + x + "," + y);
890        }
891        path.push(" x e");
892
893        node.path = path.join("");
894        return node;
895    },
896   
897    /**
898     * Method: moveRoot
899     * moves this renderer's root to a different renderer.
900     *
901     * Parameters:
902     * renderer - {<OpenLayers.Renderer>} target renderer for the moved root
903     * root - {DOMElement} optional root node. To be used when this renderer
904     *     holds roots from multiple layers to tell this method which one to
905     *     detach
906     *
907     * Returns:
908     * {Boolean} true if successful, false otherwise
909     */
910    moveRoot: function(renderer) {
911        var layer = this.map.getLayer(renderer.container.id);
912        if(layer instanceof OpenLayers.Layer.Vector.RootContainer) {
913            layer = this.map.getLayer(this.container.id);
914        }
915        layer && layer.renderer.clear();
916        OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this, arguments);
917        layer && layer.redraw();
918    },
919   
920    /**
921     * Method: importSymbol
922     * add a new symbol definition from the rendererer's symbol hash
923     *
924     * Parameters:
925     * graphicName - {String} name of the symbol to import
926     *
927     * Returns:
928     * {Object} - hash of {DOMElement} "symbol" and {Number} "size"
929     */     
930    importSymbol: function (graphicName)  {
931        var id = this.container.id + "-" + graphicName;
932       
933        // check if symbol already exists in the cache
934        var cache = this.symbolCache[id];
935        if (cache) {
936            return cache;
937        }
938       
939        var symbol = OpenLayers.Renderer.symbol[graphicName];
940        if (!symbol) {
941            throw new Error(graphicName + ' is not a valid symbol name');
942        }
943
944        var symbolExtent = new OpenLayers.Bounds(
945                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
946       
947        var pathitems = ["m"];
948        for (var i=0; i<symbol.length; i=i+2) {
949            var x = symbol[i];
950            var y = symbol[i+1];
951            symbolExtent.left = Math.min(symbolExtent.left, x);
952            symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
953            symbolExtent.right = Math.max(symbolExtent.right, x);
954            symbolExtent.top = Math.max(symbolExtent.top, y);
955
956            pathitems.push(x);
957            pathitems.push(y);
958            if (i == 0) {
959                pathitems.push("l");
960            }
961        }
962        pathitems.push("x e");
963        var path = pathitems.join(" ");
964
965        var diff = (symbolExtent.getWidth() - symbolExtent.getHeight()) / 2;
966        if(diff > 0) {
967            symbolExtent.bottom = symbolExtent.bottom - diff;
968            symbolExtent.top = symbolExtent.top + diff;
969        } else {
970            symbolExtent.left = symbolExtent.left + diff;
971            symbolExtent.right = symbolExtent.right - diff;
972        }
973       
974        cache = {
975            path: path,
976            size: symbolExtent.getWidth(), // equals getHeight() now
977            left: symbolExtent.left,
978            bottom: symbolExtent.bottom
979        };
980        this.symbolCache[id] = cache;
981       
982        return cache;
983    },
984   
985    CLASS_NAME: "OpenLayers.Renderer.VML"
986});
987
988/**
989 * Constant: OpenLayers.Renderer.VML.LABEL_SHIFT
990 * {Object}
991 */
992OpenLayers.Renderer.VML.LABEL_SHIFT = {
993    "l": 0,
994    "c": .5,
995    "r": 1,
996    "t": 0,
997    "m": .5,
998    "b": 1
999};
Note: See TracBrowser for help on using the repository browser.