Openlayers中专题图的设计与实现

  开博第一篇。今天搞定自动专题图的问题,必须纪念一下!

  借鉴行走_博文,总结如下:

  一、相关模块功能类比较多,这里先介绍下各个关键类在这个样式渲染环节中的作用和功能:

      Symbolizer  样式,记录样式信息的Object。特点:样式只针对具体的点、线、面等对象(点对象所需的样式和面对像所需的样式可能不同,查看其API,集合用户对象可以知道需要设置怎样的样式属性来控制对象显示)。一般不需要用户构建,而是由Style创建出来,内部在使用的时候通过css或者canvas的画笔控制来显示不同效果。

      Style   样式类,定义某种状态的完全样式,点线面等全部包括在内。内含defaultStyle属性记录所设置的样式(属性-值)集合对象Object。提供了createSymbolizer方法来为具体的点、线等对象提供Symbolizer样式。

      关于 style中对rule属性的使用控制…产看下面的设计代码分析内容

       StyleMap: 图层样式,定义多种状态下的图层样式,其属性styles中存储由key(‘state’), value(‘Style’) 组成的状态-样式键值对构成。  StyleMap信息被赋予到使用样式显示的Vector图层,默认支持四种样式,下面是OP中StyleMap样式的初始状态

Stylemap.styles = {
 
            "default": new OpenLayers.Style(
 
                OpenLayers.Feature.Vector.style["default"]),
 
            "select": new OpenLayers.Style(
 
                OpenLayers.Feature.Vector.style["select"]),
 
            "temporary": new OpenLayers.Style(
 
                OpenLayers.Feature.Vector.style["temporary"]),
 
            "delete": new OpenLayers.Style(
 
                OpenLayers.Feature.Vector.style["delete"])
 
}

         使用的过程中,vector根据不同状态获取不同样式,然后将使用对应的样式显示feature对象。

        OpenLayer.Layer.Vector  矢量图层,是最终的显示承载对象,根据和map,控件的交互,可以获取,设置当前feature的状态,然后从stylemap中读取样式,应用到具体的feature显示上。

       OpenLayer.Feature.Vector  矢量对象,要显示的基本对象,记录几何信息geometry等,默认使用的时候会应用图层样式,如果对feature单独设置样式,则不管什么都以设置的样式作为显示依据,而不去管图层样式怎么设置。

       Renderer  使用样式和几何对象属性等来展示Feature要素的最终工具,根据不同浏览器和支持情况选用不同的渲染工具,支持的VML,SVG,Canvas。

       Rule规则定义,通过定义规则来指定不同情况下的样式属性值,来决定最终样式采用的显示属性(定义规则..)

       Filter: Rule规则定义的具体规则都是由Filter来实现和完成的的,规则的具体定义和执行者……

       Context:我们知道Style上的${XXX}取值方法,通过XXX命名的属性可以动态设置属性的值作为样式的备选值(参加下面的示例1)

       Context提供了另外一种更为直接的方法,XXX不指定属性名,而直接指定对应的方法,在方法内部完成由属性值–>样式属性的转换。使用方式类似,相比之下Context更为直接,直接使用方法,接受feature作为参数,内部通过复杂的逻辑处理来获取最终结果,因此提供了更为灵活和多边的样式设置方式。Context可以提供比直接取值更大的操作变化。下面给出两个示例(都是从OpenLayers的examples中直接借过来的说..完成示例可以查看OpenLayers/examples/styles_context.html     OpenLayers/examples/styles_map.html)

     示例一:使用${XXX},xxx代表属性名

//feature添加type属性
             var features = new Array(50);
             for (var i=0; i<features.length; i++) {
                features[i] = new OpenLayers.Feature.Vector(
                    new OpenLayers.Geometry.Point(
                        (360 * Math.random()) - 180, (180 * Math.random()) - 90
                    ), {
                        type: 5 + parseInt(5 * Math.random())
                    }
                );
            }
           //设置${}取值,使用type的值来设置点对象半径
 
          var myStyles = new OpenLayers.StyleMap({
                "default": new OpenLayers.Style({
                    pointRadius: "${type}", // 通过属性名取值,作为样式的值
                    fillColor: "#ffcc66",
                    strokeColor: "#ff9933",
                    strokeWidth: 2,
                    graphicZIndex: 1
                }),
                "select": new OpenLayers.Style({
                    fillColor: "#66ccff",
                    strokeColor: "#3399ff",
                    graphicZIndex: 2
                })
            });

示例二:使用${XXX},XXX代表调用方法

var features = new Array(50);
            for (var i=0; i<features.length; i++) {
                features[i] = new OpenLayers.Feature.Vector(
                    new OpenLayers.Geometry.Point(
                        (360 * Math.random()) - 180, -90 * Math.random()
                    ), {
                        type: 5 + parseInt(5 * Math.random())
                    }
                );
            }
            // 定义context,主要是定义根据属性获取样式值的方法create the layer styleMap by giving the default style a context
            var colors = ["red", "green", "blue"];
            var context = {
                getColor: function(feature) {
                    var region = parseInt((feature.geometry.x + 180) / 120);
                    return colors[region];
                },
                getSize: function(feature) {
                    return feature.attributes["type"] / map.getResolution() * .703125;
                }
            };
           //使用方法,设置样式..
           var template = {
                pointRadius: "${getSize}", // using context.getSize(feature)
                fillColor: "${getColor}" // using context.getColor(feature)
            };
            //生成样式并最终使用样式
            var style = new OpenLayers.Style(template, {context: context});
            var layer2 = new OpenLayers.Layer.Vector('Points', {
                styleMap: new OpenLayers.StyleMap(style),
                renderers: renderer
            });

二、样式的使用。我们所使用的样式中一般有两个样式的最终源头(即用户可以设置修改样式的方法)

         1、  设置layer.vector的style(Object对象)或者styleMap(key: Style对象)样式。style直接使用,styleMap用来根据featur的几何对象和状态来设置对应的样式,这个环节中使用了对规则rule和context的相关使用,后面专门介绍。

         2、  直接设置feature的样式Style。Object类型

        使用优先级比较  feature.style  >  layer.style   > layer.StyleMap

        前两个都是简单的Object对象,意味着用户知道具体的feature类型是点还是线面,知道需要设置哪些样式才有效,然后设置固定样式,所以针对性好,但是不具备状态属性和,也不存在对rule和context使用时候的灵活性。。。。关于这块的区别在下面的分析中会看的更清楚些。

 

  三、最后来说明下最标准完备的StyleMap,Style,Rule,Context,Symbolizer,Vector,Renderer的关系。。(相互之间调用和生成的顺序关系),我们假设设置StyleMap:

      1. 关于StyleMap的初始化,这里贴出StyleMap的构造函数源码说明:

        initialize: function (style, options) {
                this.styles = {
                    "default": new OpenLayers.Style(
                        OpenLayers.Feature.Vector.style["default"]),
                    "select": new OpenLayers.Style(
                        OpenLayers.Feature.Vector.style["select"]),
                    "temporary": new OpenLayers.Style(
                        OpenLayers.Feature.Vector.style["temporary"]),
                    "delete": new OpenLayers.Style(
                        OpenLayers.Feature.Vector.style["delete"])
                };
                 
                // take whatever the user passed as style parameter and convert it
                // into parts of stylemap.
                if(style instanceof OpenLayers.Style) {
                    // user passed a style object
                    this.styles["default"] = style;
                    this.styles["select"] = style;
                    this.styles["temporary"] = style;
                    this.styles["delete"] = style;
                } else if(typeof style == "object") {
                    for(var key in style) {
                        if(style[key] instanceof OpenLayers.Style) {
                            // user passed a hash of style objects
                            this.styles[key] = style[key];
                        } else if(typeof style[key] == "object") {
                            // user passsed a hash of style hashes
                            this.styles[key] = new OpenLayers.Style(style[key]);
                        } else {
                            // user passed a style hash (i.e. symbolizer)
                            this.styles["default"] = new OpenLayers.Style(style);
                            this.styles["select"] = new OpenLayers.Style(style);
                            this.styles["temporary"] = new OpenLayers.Style(style);
                            this.styles["delete"] = new OpenLayers.Style(style);
                            break;
                        }
                    }
                }
                OpenLayers.Util.extend(this, options);
            },

        代码分析,其设计基本如下:第一步默认读取vector中定义的样式来完成初始化。。第二步通过样式参数来设置具体的用户样式,

        分多种情况对象:

        1)         独立的样式对象Style,将四种状态样式都设置为此,即相当于没有状态区别

        2)         样式组成的键值对key:Style(或者Object),读取提供的样式,覆盖默认值,如果后面的值不是Style对象,内部做封装后设置

        3)         只是一个Object对象,直接封装成Style样式,然后同1)

      2. 关于StyleMap—>style—>Symbolizer的转换过程,中间使用到的Rule,filter,context,等:

        1)       矢量图层使用StyleMap的createSymbolizer: function(feature, intent)方法来获取一个Symbolizer对象。

                  参数: feature  具体的矢量元素,包含几何信息,attribute等

                  Intent: 记录feature的当前状态,”default”或者”select”….

        2)       查看StyleMap的源码会发现在其CreateSymbolizer中最终是通过调用Style的CreateSymbolizer方法来获取的样式结果的。源码如下:

                  this.styles[intent].createSymbolizer(feature)

        3)       Style的CreateSymbolizer方法分解:

                 A、关于context的使用:

                   通过方法调用createLiterals ---> createLiteral,最终由OpenLayers.String.format 来完成对属性值标记${property} 到样式值的转换

        OpenLayers.Style.createLiteral = function(value, context, feature, property) {
            if (typeof value == "string" && value.indexOf("${") != -1) {
                value = OpenLayers.String.format(value, context, [feature, property]);
                value = (isNaN(value) || !value) ? value : parseFloat(value);
            }
            return value;
        };
            return value;
        } ;

            B、关于Rule的使用

                      同样在createSymbolizer方法中

                      a)         通过调用rule的evaluate方法来判断是否对当前Feature应用规则,其中rule的evaluate方法调用的是具体Filter中的同名方法实现

                      b)         如果使用规则,则调用applySymbolizer(rule, style, feature)来实现对规则中定义的样式添加到返回样式结果中。

                      c)         多个规则多次应用。

        举例说明:如果针对feature的属性foo来设置,当foo的值小于25的时候我们使用蓝色图片,但其位于25和50之间,使用绿色图片,位于50和75之间使用使用金色图片,其他else的情况下使用默认图片。那么我们则需要根据不同条件定义不同的规则,需要4个rule对象,rules数组的定义如下:(代码来自OpenLayers/examples/style_rule.js),可运行对应的案例查看结果(完成示例参考OpenLayers/examples/style-rules.html)

        rules: [
                        new OpenLayers.Rule({
                            // a rule contains an optional filter
                            filter: new OpenLayers.Filter.Comparison({
                                type: OpenLayers.Filter.Comparison.LESS_THAN,
                                property: "foo", // the "foo" feature attribute
                                value: 25
                            }),
                            // if a feature matches the above filter, use this symbolizer
                            symbolizer: {
                                externalGraphic: "../img/marker-blue.png"
                            }
                        }),
                        new OpenLayers.Rule({
                            filter: new OpenLayers.Filter.Comparison({
                                type: OpenLayers.Filter.Comparison.BETWEEN,
                                property: "foo",
                                lowerBoundary: 25,
                                upperBoundary: 50
                            }),
                            symbolizer: {
                                externalGraphic: "../img/marker-green.png"
                            }
                        }),
                        new OpenLayers.Rule({
                            filter: new OpenLayers.Filter.Comparison({
                                type: OpenLayers.Filter.Comparison.BETWEEN,
                                property: "foo",
                                lowerBoundary: 50,
                                upperBoundary: 75
                            }),
                            symbolizer: {
                                externalGraphic: "../img/marker-gold.png"
                            }
                        }),
                        new OpenLayers.Rule({
                            // apply this rule if no others apply
                            elseFilter: true,
                            symbolizer: {
                                externalGraphic: "../img/marker.png"
                            }
                        })
                    ]
      3.    关于addUniqueValueRules方法,该方法可以视为是通过Rule和Context的特殊情况,等值判断Filter来实现的一个特例.(其内部具体实现过程和使用方式有所不同,参考openlayers/examples/styles-unique.html示例。,但是总觉没那么多必要专门弄个这么接口,想了解的话可以查看Openlayer/examples/styles-unique.html)

  PS:遗留问题,在读取wfs服务时涉及跨域问题,借鉴网上多种方法都未能解决,如有亲测可用的方法,期待分享!

posted @ 2013-01-21 10:16  LegendTian  阅读(1400)  评论(0)    收藏  举报