zoukankan      html  css  js  c++  java
  • leaflet拓展wms以及wmts地图范围裁剪(附源码下载)

    前言

    leaflet 入门开发系列环境知识点了解:

    内容概览

    leaflet拓展wms以及wmts地图范围裁剪功能
    源代码demo下载

    效果图如下:

    具体实现参考leaflet裁剪插件:https://github.com/aparshin/leaflet-boundary-canvas

    • 自定义wms以及wmts类的部分核心代码,裁剪部分参照leaflet-boundary-canvas插件核心裁剪部分源码,完整的见源码demo下载
    var isRingBbox = function (ring, bbox) {
    if (ring.length !== 4) {
    return false;
    }
     
    var p, sumX = 0, sumY = 0;
     
    for (p = 0; p < 4; p++) {
    if ((ring[p].x !== bbox.min.x && ring[p].x !== bbox.max.x) ||
    (ring[p].y !== bbox.min.y && ring[p].y !== bbox.max.y)) {
    return false;
    }
     
    sumX += ring[p].x;
    sumY += ring[p].y;
     
    //bins[Number(ring[p].x === bbox.min.x) + 2 * Number(ring[p].y === bbox.min.y)] = 1;
    }
     
    //check that we have all 4 vertex of bbox in our geometry
    return sumX === 2*(bbox.min.x + bbox.max.x) && sumY === 2*(bbox.min.y + bbox.max.y);
    };
    var ExtendMethods = {
    _toMercGeometry: function(b, isGeoJSON) {
    var res = [];
    var c, r, p,
    mercComponent,
    mercRing,
    coords;
     
    if (!isGeoJSON) {
    if (!(b[0] instanceof Array)) {
    b = [[b]];
    } else if (!(b[0][0] instanceof Array)) {
    b = [b];
    }
    }
     
    for (c = 0; c < b.length; c++) {
    mercComponent = [];
    for (r = 0; r < b[c].length; r++) {
    mercRing = [];
    for (p = 0; p < b[c][r].length; p++) {
    coords = isGeoJSON ? L.latLng(b[c][r][p][1], b[c][r][p][0]) : b[c][r][p];
    mercRing.push(this._map.project(coords, 0));
    }
    mercComponent.push(mercRing);
    }
    res.push(mercComponent);
    }
     
    return res;
    },
     
    //lazy calculation of layer's boundary in map's projection. Bounding box is also calculated
    _getOriginalMercBoundary: function () {
    if (this._mercBoundary) {
    return this._mercBoundary;
    }
     
    var compomentBbox, c;
     
    if (L.Util.isArray(this.options.boundary)) { //Depricated: just array of coordinates
    this._mercBoundary = this._toMercGeometry(this.options.boundary);
    } else { //GeoJSON
    this._mercBoundary = [];
    var processGeoJSONObject = function(obj) {
    if (obj.type === 'GeometryCollection') {
    obj.geometries.forEach(processGeoJSONObject);
    } else if (obj.type === 'Feature') {
    processGeoJSONObject(obj.geometry);
    } else if (obj.type === 'FeatureCollection') {
    obj.features.forEach(processGeoJSONObject);
    } else if (obj.type === 'Polygon') {
    this._mercBoundary = this._mercBoundary.concat(this._toMercGeometry([obj.coordinates], true));
    } else if (obj.type === 'MultiPolygon') {
    this._mercBoundary = this._mercBoundary.concat(this._toMercGeometry(obj.coordinates, true));
    }
    }.bind(this);
    processGeoJSONObject(this.options.boundary);
    }
     
    this._mercBbox = new L.Bounds();
    for (c = 0; c < this._mercBoundary.length; c++) {
    compomentBbox = new L.Bounds(this._mercBoundary[c][0]);
    this._mercBbox.extend(compomentBbox.min);
    this._mercBbox.extend(compomentBbox.max);
    }
     
    return this._mercBoundary;
    },
     
    _getClippedGeometry: function(geom, bounds) {
    var clippedGeom = [],
    clippedComponent,
    clippedExternalRing,
    clippedHoleRing,
    iC, iR;
     
    for (iC = 0; iC < geom.length; iC++) {
    clippedComponent = [];
    clippedExternalRing = L.PolyUtil.clipPolygon(geom[iC][0], bounds);
    if (clippedExternalRing.length === 0) {
    continue;
    }
     
    clippedComponent.push(clippedExternalRing);
     
    for (iR = 1; iR < geom[iC].length; iR++) {
    clippedHoleRing = L.PolyUtil.clipPolygon(geom[iC][iR], bounds);
    if (clippedHoleRing.length > 0) {
    clippedComponent.push(clippedHoleRing);
    }
    }
    clippedGeom.push(clippedComponent);
    }
     
    if (clippedGeom.length === 0) { //we are outside of all multipolygon components
    return {isOut: true};
    }
     
    for (iC = 0; iC < clippedGeom.length; iC++) {
    if (isRingBbox(clippedGeom[iC][0], bounds)) {
    //inside exterior rings and no holes
    if (clippedGeom[iC].length === 1) {
    return {isIn: true};
    }
    } else { //intersects exterior ring
    return {geometry: clippedGeom};
    }
     
    for (iR = 1; iR < clippedGeom[iC].length; iR++) {
    //inside exterior ring, but have intersection with a hole
    if (!isRingBbox(clippedGeom[iC][iR], bounds)) {
    return {geometry: clippedGeom};
    }
    }
    }
     
    //we are inside all holes in geometry
    return {isOut: true};
    },
     
    // Calculates intersection of original boundary geometry and tile boundary.
    // Uses quadtree as cache to speed-up intersection.
    // Return
    // {isOut: true} if no intersection,
    // {isIn: true} if tile is fully inside layer's boundary
    // {geometry: <LatLng[][][]>} otherwise
    _getTileGeometry: function (x, y, z, skipIntersectionCheck) {
    if ( !this.options.boundary) {
    return {isIn: true};
    }
     
    var cacheID = x + ":" + y + ":" + z,
    zCoeff = Math.pow(2, z),
    parentState,
    cache = this._boundaryCache;
     
    if (cache[cacheID]) {
    return cache[cacheID];
    }
     
    var mercBoundary = this._getOriginalMercBoundary(),
    ts = this.options.tileSize,
    tileBbox = new L.Bounds(new L.Point(x * ts / zCoeff, y * ts / zCoeff), new L.Point((x + 1) * ts / zCoeff, (y + 1) * ts / zCoeff));
     
    //fast check intersection
    if (!skipIntersectionCheck && !tileBbox.intersects(this._mercBbox)) {
    return {isOut: true};
    }
     
    if (z === 0) {
    cache[cacheID] = {geometry: mercBoundary};
    return cache[cacheID];
    }
     
    parentState = this._getTileGeometry(Math.floor(x / 2), Math.floor(y / 2), z - 1, true);
     
    if (parentState.isOut || parentState.isIn) {
    return parentState;
    }
     
    cache[cacheID] = this._getClippedGeometry(parentState.geometry, tileBbox);
    return cache[cacheID];
    },
     
    _drawTileInternal: function (canvas, tilePoint, url, callback) {
    var zoom = this._getZoomForUrl(),
    state = this._getTileGeometry(tilePoint.x, tilePoint.y, zoom);
     
    if (state.isOut) {
    callback();
    return;
    }
     
    var ts = this.options.tileSize,
    tileX = ts * tilePoint.x,
    tileY = ts * tilePoint.y,
    zCoeff = Math.pow(2, zoom),
    ctx = canvas.getContext('2d'),
    imageObj = new Image(),
    _this = this;
     
    var setPattern = function () {
    var c, r, p,
    pattern,
    geom;
     
    if (!state.isIn) {
    geom = state.geometry;
    //console.log('geom',geom);
    ctx.beginPath();
     
    for (c = 0; c < geom.length; c++) {
    for (r = 0; r < geom[c].length; r++) {
    if (geom[c][r].length === 0) {
    continue;
    }
     
    ctx.moveTo(geom[c][r][0].x * zCoeff - tileX, geom[c][r][0].y * zCoeff - tileY);
    for (p = 1; p < geom[c][r].length; p++) {
    ctx.lineTo(geom[c][r][p].x * zCoeff - tileX, geom[c][r][p].y * zCoeff - tileY);
    }
    }
    }
    ctx.clip();
    }
     
    pattern = ctx.createPattern(imageObj, "repeat");
    ctx.beginPath();
    ctx.rect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = pattern;
    ctx.fill();
    callback();
    };
     
    if (this.options.crossOrigin) {
    imageObj.crossOrigin = '';
    }
     
    imageObj.onload = function () {
    //TODO: implement correct image loading cancelation
    canvas.complete = true; //HACK: emulate HTMLImageElement property to make happy L.TileLayer
    setTimeout(setPattern, 0); //IE9 bug - black tiles appear randomly if call setPattern() without timeout
    }
     
    imageObj.src = url;
    //console.log('imageObj.src',imageObj.src);
    },
    };
     
    L.TileLayer.GISHOMEWMS = L.TileLayer.WMS.extend({
    defaultWmsParams: {
    service: 'WMS',
    request: 'GetMap',
    layers: '',
    styles: '',
    format: 'image/jpeg',
    transparent: false,
    version: '1.1.1',
    boundary: null
    },
    options: {
    crs: null,
    uppercase: false
    },
    includes: ExtendMethods,
    initialize: function(url, options) {
     
    this._url = url;
    var wmsParams = L.extend({}, this.defaultWmsParams);
    // all keys that are not TileLayer options go to WMS params
    for (var i in options) {
    if (!(i in this.options)) {
    wmsParams[i] = options[i];
    }
    }
    // options = setOptions(this, options);
    var realRetina = options.detectRetina && L.Browser.retina ? 2 : 1;
    var tileSize = this.getTileSize();
    wmsParams.width = tileSize.x * realRetina;
    wmsParams.height = tileSize.y * realRetina;
    this.wmsParams = wmsParams;
    //编辑
    L.TileLayer.prototype.initialize.call(this, url, options);
    this._boundaryCache = {}; //cache index "x:y:z"
    this._mercBoundary = null;
    this._mercBbox = null;
     
    options = L.setOptions(this, options);
    },
    onAdd: function (map) {
     
    this._crs = this.options.crs || map.options.crs;
    this._wmsVersion = parseFloat(this.wmsParams.version);
     
    var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
    this.wmsParams[projectionKey] = this._crs.code;
     
    //L.TileLayer.prototype.onAdd.call(this, map);
    (L.TileLayer.Canvas || L.TileLayer).prototype.onAdd.call(this, map);
    },
    //编辑
    createTile: function(coords, done){
    var tile = document.createElement('canvas'),
    url = this.getTileUrl(coords);
    tile.width = tile.height = this.options.tileSize;
    this._drawTileInternal(tile, coords, url, L.bind(done, null, null, tile));
     
    return tile;
    }
    });
    L.tileLayer.gishomewms = function(url, options) {
    return new L.TileLayer.GISHOMEWMS(url, options);
    };
    L.TileLayer.WMTS = L.TileLayer.extend({
    defaultWmtsParams: {
    service: 'WMTS',
    request: 'GetTile',
    version: '1.0.0',
    layers: '',
    styles: '',
    tilematrixSet: '',
    // format: 'image/jpeg',
    format: 'image/png',
    boundary: null
    },
    includes: ExtendMethods,
    initialize: function(url, options) {
     
    this._url = url;
    var wmtsParams = L.extend({}, this.defaultWmtsParams);
    var tileSize = options.tileSize || this.options.tileSize;
    if (options.detectRetina && L.Browser.retina) {
    wmtsParams.width = wmtsParams.height = tileSize * 2;
    } else {
    wmtsParams.width = wmtsParams.height = tileSize;
    }
    for (var i in options) {
    if (!this.options.hasOwnProperty(i) && i !== "matrixIds") {
    wmtsParams[i] = options[i];
    }
    }
    this.wmtsParams = wmtsParams;
    this.matrixIds = options.matrixIds || this.getDefaultMatrix();
     
    //编辑
    L.TileLayer.prototype.initialize.call(this, url, options);
    this._boundaryCache = {}; //cache index "x:y:z"
    this._mercBoundary = null;
    this._mercBbox = null;
    // if (this.options.trackAttribution) {
    // this._attributionRemoved = true;
    // this.getAttribution = null;
    // }
     
    L.setOptions(this, options);
    },
    /*onAdd: function(map) {
    this._crs = this.options.crs || map.options.crs;
    L.TileLayer.prototype.onAdd.call(this, map);
    },*/
    getTileUrl: function(coords) {
    var tileSize = this.options.tileSize;
    var nwPoint = coords.multiplyBy(tileSize);
    nwPoint.x += 1;
    nwPoint.y -= 1;
    var sePoint = nwPoint.add(new L.Point(tileSize, tileSize));
    var zoom = this._tileZoom;
    var nw = this._crs.project(this._map.unproject(nwPoint, zoom));
    var se = this._crs.project(this._map.unproject(sePoint, zoom));
    var tilewidth = se.x - nw.x;
    var ident = this.matrixIds[zoom].identifier;
    var tilematrix = ident; //this.wmtsParams.tilematrixSet + ":" + ident //bug在加载天地图时会出错,在加载geoserver发布的wmts时又有用
    var X0 = this.matrixIds[zoom].topLeftCorner.lng;
    var Y0 = this.matrixIds[zoom].topLeftCorner.lat;
    var tilecol = Math.floor((nw.x - X0) / tilewidth);
    var tilerow = -Math.floor((nw.y - Y0) / tilewidth);
    var url = L.Util.template(this._url, {
    s: this._getSubdomain(coords)
    });
    return url + L.Util.getParamString(this.wmtsParams, url) + "&tilematrix=" + tilematrix + "&tilerow=" + tilerow + "&tilecol=" + tilecol;
    },
    setParams: function(params, noRedraw) {
    L.extend(this.wmtsParams, params);
    if (!noRedraw) {
    this.redraw();
    }
    return this;
    },
    getDefaultMatrix: function() {
    var matrixIds3857 = new Array(22);
    for (var i = 0; i < 22; i++) {
    matrixIds3857[i] = {
    identifier: "" + i,
    topLeftCorner: new L.LatLng(90, -180)
    };
    }
    return matrixIds3857;
    },
    //编辑
    createTile: function(coords, done){
    var tile = document.createElement('canvas'),
    url = this.getTileUrl(coords);
    tile.width = tile.height = this.options.tileSize;
    this._drawTileInternal(tile, coords, url, L.bind(done, null, null, tile));
     
    return tile;
    }
    });
    L.tileLayer.wmts = function(url, options) {
    return new L.TileLayer.WMTS(url, options);
    };
    • 自定义wms以及wmts类调用
    //wmts图层
    var wmtsLayer = new L.TileLayer.WMTS('http://t{s}.tianditu.gov.cn/img_c/wmts?tk=7786923a385369346d56b966bb6ad62f', {
    tileSize: 256,
    layer: "img",
    tilematrixSet: "c",
    format: "tile",
    matrixIds: matrixIds,
    subdomains: ["0", "1", "2", "3", "4", "5", "6", "7"],
    boundary: geojson,
    });
    map.addLayer(wmtsLayer);
    //wms图层
    var wmsLayer = L.tileLayer.gishomewms("http://localhost:8080/geoserver/ZKYGIS/wms?", {
    layers: "ZKYGIS:district_code", //需要加载的图层
    format: "image/png", //返回的数据格式
    transparent: true,
    maxZoom: 21,
    boundary: geojson
    });
    map.addLayer(wmsLayer);

    完整demo源码见小专栏文章尾部小专栏

    文章尾部提供源代码下载,对本专栏感兴趣的话,可以关注一波

    GIS之家作品店铺:GIS之家作品店铺
    GIS之家源码咨询:GIS之家webgis入门开发系列demo源代码咨询
  • 相关阅读:
    django文件上传
    django验证码
    auth模块---笔记
    css笔记
    django模板系统---2
    django模板系统
    Django中间件
    前端笔记---1
    我的django笔记---1
    DNS服务器的搭建
  • 原文地址:https://www.cnblogs.com/giserhome/p/14367347.html
Copyright © 2011-2022 走看看