OpenLayers结合JSTS实现空间扩展

概况

JSTS是JavaScript 空间分析库,常见API有buffer、union、intersection、symDifference、getBoundary、getCentroid、convexHull,css样式可以根据自己的需求写。
环境:webpack构建的vue项目,另外,JS资源官网是可以找到的。

一、需要在项目中引入用到的文件

image.png

二、写一个工具类文件Utils.js

包含创建地图,添加图层,数据的转换,JSTS API 的使用

let wktReader = new OpenLayers.Format.WKT();
// 初始化地图
let initMap = (name, url) => {
    OpenLayers.Layer.OFFLINEMAP = OpenLayers.Class(
        OpenLayers.Layer.XYZ,
        {
            name: 'MAP',
            url: 'https://yoururl/${z}/${x}/${y}.png',  // 这是你发布的地图
            sphericalMercator: true,    // 是否应将平铺范围设置为球形墨卡托的默认值,地图才可以显示 
            wrapDateLine: true,         // 允许拖动平移地图
            tileOptions: null,
            isBaseLayer: true,
            zoom: 10,
            initialize: function (a, b, c) {
                OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments)
                this.tileOptions = OpenLayers.Util.extend(
                    { crossOriginKeyword: 'anonymous' },
                    this.options && this.options.tileOptions
                )
            },
            clone: function (a) {
                a == null && (a = new OFFLINEMAP(this.name, this.url, this.getOptions()));
                return a = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [a])
            },
            getOption(){
                // console.log(this.getOptions())
            },
            CLASS_NAME: 'OpenLayers.Layer.OFFLINEMAP'
        }
    )
}
// 创建地图
let CreatMap = (_this, name) => {
    _this.map = new OpenLayers.Map({
        div: 'map',
        projection: new OpenLayers.Projection('EPSG:900913'),       // 指定添加到此地图的图层的默认投影
        displayProjection: new OpenLayers.Projection('EPSG:4326'),  // 要求proj4js支持EPSG:4326的其他投影
        center: [12614654.172192, 2647187.2285552],                 // 中心点
        isBaseLayer: true,
        numZoomLevels: [0, 24],                                     // 地图缩放级别
        resolutions: [                                              // 地图分辨率的列表(每像素地图单位)以降序排列
            0.0439453125, 
            0.703125, 
            0.3515625, 
            0.17578125, 
            0.087890625, 
            0.0439453125
        ],
        zoom: 16,                                                   // 设置地图级别 ,貌似没有效果
    });
    var configIP = 'https://yourUrl/${z}/${x}/${y}.png';
    var mapoptions = {
        name: 'map',
        url: configIP,
        sphericalMercator: true,
        wrapDateLine: true,
        tileOptions: null,
        box: true,  // 允许框选
        numZoomLevels: 24,
        isBaseLayer: true,
        controls: [],
        zoom: 16
    };

    // * 集合图层,从layer中继承
    var layer = new OpenLayers.Layer.OFFLINEMAP(mapoptions);
    layer.getOption()
    _this.map.addLayer(layer);
    
    // 设置图层样式
    var polystyle = new OpenLayers.Style(
        {
            pointRadius: 3.5,
            fillOpacity: 0.7,
            fillColor: 'black',
            strokeWidth: 1,
            strokeOpacity: 1,
            graphicZIndex: 1
        },
        {
            rules:[
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: 'COLOR',
                        value: 1
                    }),
                    symbolizer: {
                        fillOpacity: 0.9,
                        fillColor: '#03A9F4',
                        strokeWidth: 0.5,
                        strokeOpacity: 0.9,
                        strokeColor: 'white'
                    }
                }),
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: 'COLOR',
                        value: 2
                    }),
                    symbolizer: {
                        fillOpacity: 0.9,
                        fillColor: '#82d09a',
                        strokeWidth: 0.5,
                        strokeOpacity: 0.9,
                        strokeColor: 'white'
                    }
                }),
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: 'COLOR',
                        value: 3
                    }),
                    symbolizer: {
                        fillOpacity: 0.9,
                        fillColor: '#ffbc00',
                        strokeWidth: 3,
                        strokeOpacity: 0.9,
                        strokeColor: '#ffbc00'
                    }
                }),
                new OpenLayers.Rule({
                    filter: new OpenLayers.Filter.Comparison({
                        type: OpenLayers.Filter.Comparison.EQUAL_TO,
                        property: 'COLOR',
                        value: 4
                    }),
                    symbolizer: {
                        fillOpacity: 0.9,
                        fillColor: '#a7fff7',
                        strokeWidth: 3,
                        strokeOpacity: 0.9,
                        strokeColor: '#a7fff7'
                    }
                })
            ]
        }
    );

    // 创建一个图层,添加需要计算的polygon
    var wfslayer = new OpenLayers.Layer.Vector(name, {
        styleMap: new OpenLayers.StyleMap({
            'default': polystyle
        })
    });
    this.layer = wfslayer;
    _this.map.addLayer(wfslayer)
};

// 把 wkt 转成 geometry
let toGeometryFromWkt = (wkt) => {
    var geometry = wktReader.read(wkt);
    var attributes = {
        name:'name',
        wkt: wkt
    }
    geometry.attributes = attributes;
    return geometry
};

// 添加一个 feature 到图层
let addFeature = (wkt, layer, i) => {
    var geometry = toGeometryFromWkt(wkt);
    // 扩展属性
    $.extend(geometry.attributes, {
        NAME: 'name',
        WKT: wkt,
        COLOR: i
    });
    if (wkt != null) {
        this.layer.addFeatures(geometry)
    }
}

// 清除
let removeFeature = (_this, name, clearName) => {
    if (clearName.length) {
        for (let i = 0; i < clearName.length; i++) {
            _this[clearName[i]] = ''
        }
    }
    var layer = _this.map.getLayersByName(name);
    if (layer.length > 0) {
        layer[0].removeAllFeatures()
    }
    _this.map.setCenter([12614654.172192, 2647187.2285552], 24);
}

// jsts API
let JstsUtils = (param) => {
    var firstGeom = null;
    var secondGeom = null;
    var jstsFirstGeom = null;
    var jstsSecondGeom = null;
    var jstsResultGeom = null;
    var jstsReader = new jsts.io.WKTReader();
    var jstsParser = new jsts.io.OpenLayersParser();
    if (param.firstwkt) {
        firstGeom = toGeometryFromWkt(param.firstwkt);
        jstsFirstGeom = jstsParser.read(firstGeom.geometry)
    }
    if (param.secondwkt) {
        secondGeom = toGeometryFromWkt(param.secondwkt);
        jstsSecondGeom = jstsParser.read(secondGeom.geometry)
    }
    // 空间分析功能
    switch (param.name) {
        case 'buffer':
            jstsResultGeom = jstsFirstGeom.buffer(parseFloat(param.radiu == null ? 0.0 : param.radiu))
            break;
        case 'union':
            jstsResultGeom = jstsFirstGeom.union(jstsSecondGeom);
            break;
        case 'intersection':
            jstsResultGeom = jstsFirstGeom.intersection(jstsSecondGeom);
            break;
        case 'symDifference':
            jstsResultGeom = jstsFirstGeom.symDifference(jstsSecondGeom);
            break;
        case 'getBoundary':
            jstsResultGeom = jstsFirstGeom.getBoundary();
            break;
        case 'getCentroid':
            jstsResultGeom = jstsFirstGeom.getCentroid();
            break;
        case 'convexHull':
            jstsResultGeom = jstsFirstGeom.convexHull();
            break;
        default:
            throw 'data format error!';
    }
    // 转成openlayer geometry 对象
    return jstsParser.write(jstsResultGeom)
};

export {
    initMap,
    CreatMap,
    toGeometryFromWkt,
    addFeature,
    JstsUtils,
    removeFeature
}

三、写一个公共的组件public-single-space.vue

<template>
    <div class="col-md-12">
        <div class="layout">
            <div class="nav">
                <div class="feature">
                    <div class="coll_btn_box">
                        <button @click="drawGeometry">绘制</button>
                        <button @click="drawRun">运行</button>
                        <button @click="revertMap">清除</button>
                    </div>
                    <div class="legend_btn_box">
                        <div :class="item.cla" v-for="(item,index) in btnData" :key="index">
                            <span class="rect"></span>
                            <span class="txt">{{item.text}}</span>
                        </div>
                    </div>
                </div>
                <textarea v-model="value" class="text_area"></textarea>
            </div>
            <div class="map">
                <div id="map" class="map_box"></div>
            </div>
        </div>
    </div>
</template>
<script>
    export default {
        name: "public-single-space",
        props:{
            btnData:{
                type: [Array,Object]
            },
            value:{
                type: String,
                default: ''
            }
        },
        methods:{
            drawGeometry(){
                this.$emit('draw_geometry');
            },
            drawRun(){
                this.$emit('draw_run');
            },
            revertMap(){
                this.$emit('revert_map');
            }
        },
    };
</script>
<style scoped>
    @import "../assets/css/common.css";
</style>

四、使用,单个图形(以convexHull为案例)

  • convexHull(外接矩形)
  • buffer(缓冲区)
  • getCentroid(中心点)
  • getBoundary(边框)
<template>
    <publicSingleSpace
        :btnData="btnData"
        :value="polygon"
        @draw_geometry="drawGeometry"
        @draw_run="drawRun"
        @revert_map="revertMap">
    </publicSingleSpace>
</template>
<script>
    import publicSingleSpace from './public-single-space'
    import {
        initMap,
        CreatMap,
        addFeature,
        toGeometryFromWkt,
        JstsUtils,
        removeFeature
    } from './Utils.js'

    export default {
        nam: 'ConvexHull',
        components: {
            publicSingleSpace
        },
        data() {
            return {
                map: null,
                polygon: "POLYGON((113.31886002411747 23.12592000980574,113.31973442425445 23.125826276039394,113.31975051750989 23.1248050670806,113.31944474568361 23.125628941581002,113.3187741934338 23.12513067078125,113.31862398972841 23.125638808311095,113.31886002411747 23.12592000980574))",
                layerName: 'convexHull_layer',
                wkt: '',
                btnData:[
                    { cla: 'legend_blue', text: '多边形'},
                    { cla: 'legend_red', text: '边界'},
                ],
            }
        },
        mounted() {
            initMap();
            CreatMap(this, this.layerName);
        },
        methods: {
            drawGeometry() {
                var geometry = toGeometryFromWkt(this.polygon);
                var feature = geometry.geometry.transform(
                    new OpenLayers.Projection("EPSG:4326"),
                    new OpenLayers.Projection("EPSG:900913")
                );
                this.wkt = feature.toString();
                addFeature(this.wkt, this.map.layers, 1);
            },
            drawRun() {
                if(this.wkt != ''){
                    var convexHullFeature = new OpenLayers.Feature.Vector("convexHullVector");
                    convexHullFeature.geometry = JstsUtils({
                        name: "convexHull",
                        firstwkt: this.wkt
                    });
                    var feature = convexHullFeature.geometry.toString();
                    addFeature(feature, this.map.layers, 3);
                }
            },
            revertMap() {
                removeFeature(this, this.layerName,['wkt'])
            }
        }
    };
</script>
<style scoped>
    @import "../assets/css/common.css";
</style>
五、单个图形效果
image.png

image.png

image.png

image.png

六、使用,两个图形(以intersection为例)

  • intersection(相交区)
  • symDifference(不同区)
  • union(合并区)
<template>
    <div class="col-md-12">
        <div class="layout">
            <div class="nav twoNav">
                <div class="left">
                    <div class="feature">
                        <div class="coll_btn_box">
                            <button @click="drawGeometry(1)">绘制</button>
                        </div>
                        <div class="legend_btn_box">
                            <div class="legend_blue">
                                <span class="rect"></span>
                                <span class="txt">几何体1</span>
                            </div>
                            <div class="legend_green">
                                <span class="rect"></span>
                                <span class="txt">几何体2</span>
                            </div>
                            <div class="legend_red">
                                <span class="rect"></span>
                                <span class="txt">相交区</span>
                            </div>
                        </div>
                    </div>
                    <textarea v-model="value1" class="text_area"> </textarea>
                </div>
                <div class="right">
                    <div class="feature">
                        <div class="coll_btn_box">
                            <button @click="drawGeometry(2)">绘制</button>
                            <button @click="drawRun">运行</button>
                            <button @click="revertMap">清除</button>
                        </div>
                    </div>
                    <textarea v-model="value2" class="text_area"> </textarea>
                </div>
            </div>

            <div class="map">
                <div id="map" class="map_box"></div>
            </div>
        </div>
    </div>
</template>
<script>
    import {
        initMap,
        CreatMap,
        addFeature,
        toGeometryFromWkt,
        JstsUtils,
        removeFeature
    } from './Utils.js'

    export default {
        nam: "Intersection",
        data() {
            return {
                map: null,
                value1: "POLYGON((113.31886002411747 23.12592000980574,113.31973442425445 23.125826276039394,113.31975051750989 23.1248050670806,113.31944474568361 23.125628941581002,113.3187741934338 23.12513067078125,113.31862398972841 23.125638808311095,113.31886002411747 23.12592000980574))",
                value2: "POLYGON((113.31875810016938 23.125846009469857,113.31926235546736 23.125323072596977,113.31904241432473 23.124652131736205,113.31856498112215 23.124775466705003,113.31880637993568 23.12506160339534,113.31875810016938 23.125846009469857))",
                layerName: 'intersection_layer',
                wkt: '',
                wktS: '',
            };
        },
        mounted() {
            initMap();
            CreatMap(this, this.layerName);
        },
        methods: {
            drawGeometry(index) {
                var val = index == 1 ?  this.value1 : this.value2;
                var geometry = toGeometryFromWkt(val);
                var featrue = geometry.geometry.transform(
                    new OpenLayers.Projection("EPSG:4326"),
                    new OpenLayers.Projection("EPSG:900913")
                );
                var string = featrue.toString();
                if(index == 1){
                    this.wkt = string;
                }else{
                    this.wktS = string;
                }
                addFeature(string, this.map.layers, index);
            },
            drawRun() {
                var convexHullFeature = new OpenLayers.Feature.Vector("convexHullVector");
                convexHullFeature.geometry = JstsUtils({
                    name: "intersection", // symDifference/合并区
                    firstwkt: this.wkt,
                    secondwkt: this.wktS
                });
                var feature = convexHullFeature.geometry.toString();
                addFeature(feature, this.map.layers, 3);
            },
            revertMap(){
                removeFeature(this, this.layerName, ['wkt','wktS'])
            }
        }
    };
</script>
<style scoped>
    @import "../assets/css/common.css";
</style>

七、两个图形效果图

image.png

image.png

image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。