创建地图图例以匹配 OpenLayers.Style

发布于 2024-10-21 08:11:43 字数 361 浏览 9 评论 0原文

我创建了一个 OpenLayers.Style 为我的多边形着色,一个为我的点调整大小的样式以及所有爵士乐,现在我想向用户解释这些样式代表什么。

我在 OpenLayers 中看不到任何允许我使用这些样式绘制自己的图例的内容。一切似乎都指向我假设的地图服务器正在向我发送数据,但我没有。

目前看来我必须绘制一些样本点/区域并抓取它们来制作我自己的图例。有没有更好的方法可以直接基于样式来完成此操作,这样当样式更改时我就不必重新生成图像?

更新 我有一个很好的答案,依赖于 GeoExt (以及 ExtJS),我仍然想听听是否有人有 jQuery 兼容的答案。特别是如果它是纯 Javascript 和 OpenLayers。

I've created an OpenLayers.Style that colours my polygons, a style that sizes my points and all that jazz, now I want to explain to the user what those styles represent.

I can't see anything in OpenLayers that allows me to draw my own legend using those styles. Everything seems to point me towards the assumed map server that is sending me data, which I don't have.

At the moment it looks like I'll have to draw some sample points/areas and screen grab them to make my own legend. Is there a better way to do it based straight off the Style so I don't have to regenerate the images when the Style gets changed?

Update
I've had a good answer that relies on GeoExt (and thus ExtJS), I'd still like to hear if anyone has a jQuery compatible answer. Especially if it is plain Javascript and OpenLayers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

赠意 2024-10-28 08:11:43

我能够使用 ol.Map 类作为符号容器来解决我的图例需求。也许有点破解,但似乎适用于大多数(?)矢量图层(我没有 WMS)。

所以我正在做的是:

  1. 循环遍历地图图层并选择矢量类型

    if(lyr instanceof ol.layer.Vector)

  2. 检查使用什么类型的样式并存储在数组中

    var style = lyr.getStyle();
    var image = style.getImage();
    如果(图像){
        if(ol.style.Icon 的图像实例){
            //来自url的光栅图标
            var icon2 = new ol.style.Icon( ({
                src: image.getSrc()
            }))
            var iconStyle2 = new ol.style.Style({
                图片:图标2
            });
            行={};
            row.style = iconStyle2;
            row.title = lyr.get('标题');               
        }
        else{ //ol.style.RegularShape?
            行={};
            row.style = 样式;
            row.title = lyr.get('标题');               
        }
    }别的{
        行={};
        row.style = 样式;
        row.title = lyr.get('标题');
    }
    
  3. 还存储几何类型

    //几何类型
    var feats = lyr.getSource().getFeatures();
    if (feats && feats.length>0){
        if(feats[0].getGeometry() instanceof ol.geom.Point || feats[0].getGeometry() instanceof ol.geom.MultiPoint){
            row.geomType="点";
        }else if (feats[0].getGeometry()instanceof ol.geom.LineString || feats[0].getGeometry()instanceof ol.geom.MultiLineString){
            row.geomType="线";
        }别的{
            row.geomType="多边形";
        }
    }
    
  4. 循环存储的图例行并构造所需的 HTML 元素,通常是“迷你地图”的 div 和图层名称

    for (i = 0; i < legendRows.length; i++) { 
        row = document.createElement("tr");
        //象征
        cell = document.createElement("td");
        cell.style =“宽度:35px”;
        var div = document.createElement("div");
        div.style="宽度:32px;高度:32px;";
        div.id = "mapLegendRowSymbolDiv" + i; 
        tble.appendChild(行);
        row.appendChild(单元格);
        cell.appendChild(div);
        //图层标题
        cell = document.createElement("td");      
        tble.appendChild(行);
        row.appendChild(单元格);
        cell.innerHTML=legendRows[i].title; 
    }
    
    //追加表
    $( "#legendText" ).empty();
    $( "#legendText" ).append(tble);
    
  5. 一旦 HTML 元素已添加到页面,启动地图并插入假特征以显示符号

    //循环图例行并插入地图
    var 范围 = [0, 0, 32, 32];
    var 投影 = new ol.proj.Projection({
        代码: 'xkcd-image',
        单位:“像素”,
        范围:范围
    });
    for (i = 0; i < legendRows.length; i++) { 
        //目标div
        var targetDiv = document.getElementById("mapLegendRowSymbolDiv" + i);
        //图标层
        var sourceLegend = new ol.source.Vector({wrapX: false});
        var vectorLegend = new ol.layer.Vector({
            来源:来源传奇,
            样式: legendRows[i].style
        });
        //地图
        var mapLegend = new ol.Map({
            控制:[],
            图层:[
                新的 ol.layer.Image({
                    来源: new ol.source.ImageStatic({
                        投影:投影,
                        图像范围:范围
                    })
                }),
                矢量图例
            ],
            目标:targetDiv,
            视图:新的 ol.View({
                投影:投影,
                中心:ol.extent.getCenter(extent),
                变焦:2,
                最大缩放:2
            })
        });
        //图标功能取决于类型
        变种几何;
        if(legendRows[i].geomType=='点'){
            geom = new ol.geom.Point([16,16]);
        }else if(legendRows[i].geomType=='多边形'){
            var polyCoords = [];
            polyCoords.push([15.7, 15.7]);
            polyCoords.push([16.3, 15.7]);
            polyCoords.push([16.3, 16.3]);
            polyCoords.push([15.7, 16.3]);
            polyCoords.push([15.7, 15.7]);
            geom = new ol.geom.Polygon([polyCoords]);
        }别的{
            var lineCoords = [];                
            lineCoords.push([15.6, 15.6]);
            lineCoords.push([16, 16]);
            lineCoords.push([16, 15.8]);
            lineCoords.push([16.4, 16.2]);
            geom = new ol.geom.LineString(lineCoords);
        }
        var feature = new ol.Feature({
            几何:几何
        });
        vectorLegend.getSource().addFeature(feature);
    }   
    

通过此,我能够创建和更新单独的图例对话框 (jQuery UI):

在此处输入图像描述

我还没有进行很多测试,这种方法可能存在一些问题......

I was able to solve my legend needs using the ol.Map-class as a container for the symbols. Maybe a bit of a hack, but seems to work for most (?) vector layers (I have no WMS's).

So what I'm doing is:

  1. loop through the map layers and pick out the vector type with

    if(lyr instanceof ol.layer.Vector)

  2. check what type of style is used and store in an array

    var style = lyr.getStyle();
    var image = style.getImage();
    if(image){
        if(image instanceof ol.style.Icon){
            //raster icon from url
            var icon2 = new ol.style.Icon( ({
                src: image.getSrc()
            }))
            var iconStyle2 = new ol.style.Style({
                image: icon2
            });
            row = {};
            row.style = iconStyle2;
            row.title = lyr.get('title');               
        }
        else{ //ol.style.RegularShape?
            row = {};
            row.style = style;
            row.title = lyr.get('title');               
        }
    }else{
        row = {};
        row.style = style;
        row.title = lyr.get('title');
    }
    
  3. also store the geometry type

    //geometry type
    var feats = lyr.getSource().getFeatures();
    if (feats && feats.length>0){
        if(feats[0].getGeometry() instanceof ol.geom.Point || feats[0].getGeometry() instanceof ol.geom.MultiPoint){
            row.geomType="point";
        }else if (feats[0].getGeometry() instanceof ol.geom.LineString || feats[0].getGeometry() instanceof ol.geom.MultiLineString){
            row.geomType="line";
        }else{
            row.geomType="polygon";
        }
    }
    
  4. loop through the stored to-be legend rows and construct the HTML elements needed, typically a div for the "mini-map" and the layer name

    for (i = 0; i < legendRows.length; i++) { 
        row = document.createElement("tr");
        //symbol
        cell = document.createElement("td");
        cell.style="width:35px";
        var div = document.createElement("div");
        div.style="width:32px; height:32px;";
        div.id = "mapLegendRowSymbolDiv" + i; 
        tble.appendChild(row);
        row.appendChild(cell);
        cell.appendChild(div);
        //layer title
        cell = document.createElement("td");      
        tble.appendChild(row);
        row.appendChild(cell);
        cell.innerHTML=legendRows[i].title; 
    }
    
    //append table
    $( "#legendText" ).empty();
    $( "#legendText" ).append(tble);
    
  5. once HTML elements have been added to the page, initiate the maps and insert the fake features to display the symbols

    //loop legend rows and and insert the maps
    var extent = [0, 0, 32, 32];
    var projection = new ol.proj.Projection({
        code: 'xkcd-image',
        units: 'pixels',
        extent: extent
    });
    for (i = 0; i < legendRows.length; i++) { 
        //target div
        var targetDiv = document.getElementById("mapLegendRowSymbolDiv" + i);
        //layer for icon
        var sourceLegend = new ol.source.Vector({wrapX: false});
        var vectorLegend = new ol.layer.Vector({
            source: sourceLegend,
            style: legendRows[i].style
        });
        //map
        var mapLegend = new ol.Map({
            controls: [],
            layers: [
                new ol.layer.Image({
                    source: new ol.source.ImageStatic({
                        projection: projection,
                        imageExtent: extent
                    })
                }),
                vectorLegend
            ],
            target: targetDiv,
            view: new ol.View({
                projection: projection,
                center: ol.extent.getCenter(extent),
                zoom: 2,
                maxZoom: 2
            })
        });
        //icon feature depending on type
        var geom;
        if(legendRows[i].geomType=='point'){
            geom = new ol.geom.Point([16,16]);
        }else if(legendRows[i].geomType=='polygon'){
            var polyCoords = [];
            polyCoords.push([15.7, 15.7]);
            polyCoords.push([16.3, 15.7]);
            polyCoords.push([16.3, 16.3]);
            polyCoords.push([15.7, 16.3]);
            polyCoords.push([15.7, 15.7]);
            geom = new ol.geom.Polygon([polyCoords]);
        }else{
            var lineCoords = [];                
            lineCoords.push([15.6, 15.6]);
            lineCoords.push([16, 16]);
            lineCoords.push([16, 15.8]);
            lineCoords.push([16.4, 16.2]);
            geom = new ol.geom.LineString(lineCoords);
        }
        var feature = new ol.Feature({
            geometry: geom
        });
        vectorLegend.getSource().addFeature(feature);
    }   
    

With this, I was able create and update a separate Legend dialog (jQuery UI):

enter image description here

I haven't tested a lot yet, there may be some problems with this approach...

匿名的好友 2024-10-28 08:11:43

实际上,OpenLayers 不支持你想要的(或者至少我不知道该怎么做)。正如 Chau 告诉您的,GeoExt 的 LegendPanel 是您唯一的希望。

有趣的链接:

http://geoext.org/lib/GeoExt/widgets/LegendPanel.html< /a>

http://www.mail-archive. com/[电子邮件受保护]/msg01318.html

Actually, OpenLayers doesn't support what you want (or at least I don't know how to do it). As Chau told you, LegendPanel from GeoExt is your only hope.

Interesting links:

http://geoext.org/lib/GeoExt/widgets/LegendPanel.html

http://www.mail-archive.com/[email protected]/msg01318.html

旧街凉风 2024-10-28 08:11:43

作为一种选择,您可以创建具有与 OL3 样式相同属性的 SVG 元素。下面是圆形样式的示例(您还需要类似的方法以及其他类型):

getIconLegend = function(style) {
    style = style.getImage();
    var radius = style.getRadius();
    var strokeWidth = style.getStroke().getWidth();
    var dx = radius + strokeWidth;

    var svgElem = $('<svg />')
        .attr({
            width: dx * 2,
            height: dx * 2
        });

    $('<circle />')
        .attr({
            cx: dx,
            cy: dx,
            r: radius,
            stroke: style.getStroke().getColor(),
            'stroke-width': strokeWidth,
            fill: style.getFill().getColor()
        })
        .appendTo(svgElem);

    // Convert DOM object to string to overcome from some SVG manipulation related oddities
    return $('<div>').append(svgElem).html();
}

由于使用 jQuery 进行的 SVG 操作与 HTML 元素有些不同,因此我将对象转换为字符串作为回报。详细信息可以从 jquery's append not work with svg element?

稍后 找到,您可以将图例图标粘贴到 HTML 中

$('#legendText').prepend($(getIconLegend(yourFeature.getStyle())));

As one option, you could create SVG elements with same attributes like in OL3 style. Here's example for circle style (you would need similar methods also other types):

getIconLegend = function(style) {
    style = style.getImage();
    var radius = style.getRadius();
    var strokeWidth = style.getStroke().getWidth();
    var dx = radius + strokeWidth;

    var svgElem = $('<svg />')
        .attr({
            width: dx * 2,
            height: dx * 2
        });

    $('<circle />')
        .attr({
            cx: dx,
            cy: dx,
            r: radius,
            stroke: style.getStroke().getColor(),
            'stroke-width': strokeWidth,
            fill: style.getFill().getColor()
        })
        .appendTo(svgElem);

    // Convert DOM object to string to overcome from some SVG manipulation related oddities
    return $('<div>').append(svgElem).html();
}

Since SVG manipulation with jQuery is bit different from HTML elements, I'm converting object to string in return. Details can be found from jquery's append not working with svg element?

Later, you can stick legend icon to HTML with

$('#legendText').prepend($(getIconLegend(yourFeature.getStyle())));
≈。彩虹 2024-10-28 08:11:43

使用普通 OpenLayers 最接近您想要的效果是使用 WMS 服务而不是 WFS 或任何用于获取功能的方法。 WMS 具有请求类型 GetLegendGraphic,顾名思义,它允许您动态获取显示应用于图层的样式的图像。

The closest you can get to what you want with plain OpenLayers is if you use WMS service instead of WFS or whatever method you use to fetch features. WMS has request type GetLegendGraphic that, as name suggests, lets you dynamically fetch image that shows what style is applied to layer.

旧瑾黎汐 2024-10-28 08:11:43

可以制作半手图例:

对于WMS功能
使用 Geoserver,GetLegendGraphic 可以生成每个 WMS 图层的图像图例

对于 WFS 功能
对于每个图层,可以根据其样式 属性:

  • Fill 的颜色(例如:style.getFill().getColor()
  • Stroke 的属性(例如:style.getStroke().getColor()
  • Image 的图像,这是一个 HTMLElement,具体取决于样式(例如: style.getImage().getImage())

A half-handed legend can be made:

For WMS features
With a Geoserver, GetLegendGraphic can generate an image legend for each WMS layer

For WFS features
For each layer, a legend can be built based on its style attributes:

  • Fill's color (ex: style.getFill().getColor())
  • Stroke's attributes (ex: style.getStroke().getColor())
  • Image's image, which is an HTMLElement, depending on the style (ex: style.getImage().getImage())
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文