leaflet多边形填充图片

效果图:

 leaflet 有imageOverlay图层根据两个点坐标生成图像,但体验感不太好,设计上传一张图片后,常常不能对齐,就尝试自己封装个图层。如上图所示,图片有两种方式,一种方式是使用canvas  createPattern方法平铺纹理,另一种是通过canvas clip剪切方法,

这个方法对图片尺寸有些要求,图片尺寸必须和裁剪的矩形宽高成比例且不能有空白区域,不然不能对齐。

代码如下:

复制代码
<!DOCTYPE html>
<html>

<head>
    <title>Leaflet debug page</title>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
        integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
        crossorigin="" />
    <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
        integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
        crossorigin=""></script>
    <script src="../dist/leaflet.polygonImage.js"></script>
    <script src="./data/index.js"></script>
</head>

<body>
    <div id="map" style="width: 1920px; height: 1080px; border: 1px solid #ccc"></div>


    <script>
        var map = L.map('map').setView([37, 102], 4.2);
        L.tileLayer('http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}', {
            attribution: ''
        }).addTo(map);
        let coordinates = L.geoJSON(boundaries).getLayers()[0]._latlngs;

        var polygonimg = L.polygonimg(coordinates, {
            img: "./img/map.png", // 裁剪图片
            //  img: "./img/img1.png", // 平铺纹理图片
            type: "clip", //clip  repeat

        }).addTo(map);
    </script>

</body>

</html>  
复制代码
leaflet.polygonImage.js:
复制代码
  (function (root, plugin) {
            /**
             * UMD wrapper.
             * When used directly in the Browser it expects Leaflet to be globally
             * available as `L`. The plugin then adds itself to Leaflet.
             * When used as a CommonJS module (e.g. with browserify) only the plugin
             * factory gets exported, so one hast to call the factory manually and pass
             * Leaflet as the only parameter.
             * @see {@link https://github.com/umdjs/umd}
             */
            if (typeof define === 'function' && define.amd) {
                define(['leaflet'], plugin);
            } else if (typeof exports === 'object') {
                module.exports = plugin;
            } else {
                plugin(root.L);
            }
        }(this, function (L) {
            // Plugin is already added to Leaflet
            if (L.Polygonimg) {
                return L;
            }

            /**
             * Core renderer.
             * @constructor
             * @param {HTMLElement | string} canvas - &lt;canvas> element or its id
             * to initialize the instance on.
             */
            var Polygonimg = function (canvas) {
                if (!(this instanceof Polygonimg)) {
                    return new Polygonimg(canvas);
                }


                this._canvas = canvas = typeof canvas === 'string' ?
                    document.getElementById(canvas) :
                    canvas;

                this._ctx = canvas.getContext('2d');
                this._width = canvas.width;
                this._height = canvas.height;
                this._data = [];
                this._img = '';
                this._type = "cover"
                //  this.draw();
            };

            Polygonimg.prototype = {
                /**
                 * Sets the width of the canvas. Used when clearing the canvas.
                 * @param {number} width - Width of the canvas.
                 */
                width: function (width) {
                    this._width = width;
                    return this;
                },

                /**
                 * Sets the height of the canvas. Used when clearing the canvas.
                 * @param {number} height - Height of the canvas.
                 */
                height: function (height) {
                    this._height = height;
                    return this;
                },
                img: function (img) {
                    this._img = img;
                    return this;
                },
                type: function (type) {
                    this._type = type;
                    return this
                },
                size: function (size) {
                    this._size = size;
                    return this;
                },
                bounds: function (bounds) {
                    this._bounds = bounds;
                    return this;
                },
                /**
                 * Sets the data that gets drawn on the canvas.
                 * @param {(Path|Path[])} data - A single path or an array of paths.
                 */
                data: function (data) {
                    this._data = data;
                    return this;
                },
                /**
                 * Draws the currently set paths.
                 */
                draw: function () {
                    console.log(this)
                    this._ctx.globalCompositeOperation = 'source-over';
                    this._ctx.lineCap = 'round';

                    var ctx = this._ctx;
                    var data = this._data;
                    let that = this;
                    var bounds = this._bounds;
                    var size = this._size;

                    var canvasImage = new Image();
                    //赋值图片地址
                    canvasImage.src = this._img;

                    //开始一个新的绘制路径
                    //  this._ctx.beginPath();
                    //设置路径起点坐标

                    canvasImage.onload = function () {

                        if (that._type == 'clip') {
                            //保存画布当前状态
                            ctx.save();
                            //开始一个新的绘制路径
                            ctx.beginPath();
                            //设置路径起点坐标
                            for (let i = 0; i < data.length; i++) {
                                for (let j = 0; j < data[i].length; j++) {
                                    if (j == 0) {
                                        ctx.moveTo(data[i][j].x, data[i][j].y);
                                    } else {
                                        ctx.lineTo(data[i][j].x, data[i][j].y);
                                    }
                                }
                            }

                            //先关闭绘制路径。注意,此时将会使用直线连接当前端点和起始端点。
                            ctx.closePath();
                            // 剪切,将在面积内的图片显示
                            ctx.clip();
                            ctx.drawImage(this, bounds.min.x, bounds.min.y, size.x, size.y);
                            ctx.restore();
                        } else if (that._type == 'repeat') {
                            //开始一个新的绘制路径
                            ctx.beginPath();
                            //设置路径起点坐标
                            for (let i = 0; i < data.length; i++) {
                                for (let j = 0; j < data[i].length; j++) {
                                    if (j == 0) {
                                        ctx.moveTo(data[i][j].x, data[i][j].y);
                                    } else {
                                        ctx.lineTo(data[i][j].x, data[i][j].y);
                                    }
                                }
                            }
                            //先关闭绘制路径。注意,此时将会使用直线连接当前端点和起始端点。
                            ctx.closePath();
                            ctx.stroke();
                            //使用createPattern平铺
                            ctx.fillStyle = ctx.createPattern(canvasImage, 'repeat')
                            ctx.fill()
                        }


                    };

                },


            };


            var Renderer = L.Canvas.extend({
                _initContainer: function () {
                    L.Canvas.prototype._initContainer.call(this);
                    this._polygonimg = new Polygonimg(this._container);
                },
                _update: function () {
                    L.Canvas.prototype._update.call(this);
                    this._polygonimg.width(this._container.width);
                    this._polygonimg.height(this._container.height);
                },

                _updatePoly: function (layer) {
                    if (!this._drawing) {
                        return;
                    }

                    var parts = layer._parts;
                    //    console.log(layer, 'parts')

                    var bounds = layer._rawPxBounds
                    var size = bounds.getSize()
                    if (!parts.length) {
                        return;
                    }

                    this._updateOptions(layer);

                    this._polygonimg
                        .data(parts)
                        .bounds(bounds)
                        .size(size)
                        .draw();
                },

                _updateOptions: function (layer) {

                    if (layer.options.img) {
                        this._polygonimg.img(layer.options.img);
                    }
                    if (layer.options.type) {
                        this._polygonimg.type(layer.options.type);
                    }
                }
            });

            var renderer = function (options) {
                return L.Browser.canvas ? new Renderer(options) : null;
            };




            L.Polygonimg = L.Polygon.extend({
                statics: {
                    Renderer: Renderer,
                    renderer: renderer
                },

                options: {
                    renderer: renderer(),

                }
            });

            L.polygonimg = function (latlngs, options) {
                return new L.Polygonimg(latlngs, options);
            };


            return L;
        }));
复制代码

 data为leaflet多边形数据,平铺纹理我想通过修改canvas像素点位置来自定义纹理的宽高,奈何能力有限没搞出来,感兴趣的朋友欢迎交流。

posted @   风紧了  阅读(528)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
/* 点击爆炸效果*/
/* 鼠标点击求赞文字特效 */ /*鼠标跟随效果*/
点击右上角即可分享
微信分享提示