UNPKG

@mapgis/webclient-leaflet-plugin

Version:

484 lines (425 loc) 17.3 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> util/extend/layer/tile/L.TileLayer.Clip.js</title> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/app.min.css"> <link type="text/css" rel="stylesheet" href="styles/iframe.css"> <link type="text/css" rel="stylesheet" href=""> </head> <body class="layout small-header"> <div id="stickyNavbarOverlay"></div> <div class="top-nav"> <div class="inner"> <a id="hamburger" role="button" class="navbar-burger" aria-label="menu" aria-expanded="false"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> <div class="logo"> <h1> MapGIS Client for JavaScript API</h1> </div> <div class="menu"> <div class="navigation"> <a class="link user-link " href="/docs/cesium/index.html" > Cesium </a> <a class="link user-link " href="/docs/mapboxgl/index.html" > MapboxGL </a> <a class="link user-link " href="/docs/leaflet/index.html" > Leaflet </a> <a class="link user-link " href="/docs/openlayers/index.html" > OpenLayers </a> </div> </div> </div> </div> <div id="main"> <div class="sidebar " id="sidebarNav" > <div> <span class="mapgis-api-document-span"><a href="index.html">API文档</a></span> </div> <div class="search-wrapper"> <input id="search" type="text" placeholder="搜索文档..." class="input"> </div> <nav> <div class="category"><div style="font-weight: bold;vertical-align: middle;padding: 0.4rem 0;" class="mapgis-menu-span"><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/m.png" alt="">视图模块</div><ul class="mapgis-sidebar-menus"><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="DrawControl.html">DrawControl</a><span style="display: none;"><p>绘制工具</p></span></li><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="MapView.html">MapView</a><span style="display: none;"><p>二维场景视图(leaflet引擎),对地图引擎进行管理,如果要对地图图层进行管理请参考[Map]{@link Map},<br/> 参考示例: <a href='#MapView'>[初始化二维场景视图]</a> <br>[ES5引入方式]:<br/> Zondy.MapView() <br/> [ES6引入方式]:<br/> import { MapView } from '@mapgis/webclient-leaflet-plugin' <br/></p></span></li><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="Popup.html">Popup</a><span style="display: none;"><p>二维场景信息弹窗(leaflet引擎) 参考示例: <a href='#MapView'>[初始化二维场景视图]</a> [ES6引入方式]:<br/> import { Popup } from '@mapgis/webclient-leaflet-plugin' <br/> 自定义样式说明:<br/> zondy-popup__content 弹窗容器样式<br/> zondy-popup__tip 弹窗对话框箭头样式<br/> zondy-popup__header 弹窗头部样式<br/> zondy-popup__content 弹窗主体样式<br/> zondy-popup__footer 弹窗底部样式<br/></p></span></li><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="Screenshot.html">Screenshot</a><span style="display: none;"><p>屏幕打印工具</p></span></li></ul><div style="font-weight: bold;vertical-align: middle;padding: 0.4rem 0;" class="mapgis-menu-span"><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/m.png" alt="">草图编辑模块</div><ul class="mapgis-sidebar-menus"><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="SketchEditorLeaflet.html">SketchEditorLeaflet</a><span style="display: none;"><p>二维场景草图编辑类<br/> <br>[ES5引入方式]:<br/> const { SketchEditorLeaflet } = Zondy <br/> [ES6引入方式]:<br/> import { SketchEditorLeaflet } from &quot;@mapgis/webclient-leaflet-plugin&quot; <br/></p></span></li></ul><div style="font-weight: bold;vertical-align: middle;padding: 0.4rem 0;" class="mapgis-menu-span"><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/m.png" alt="">渲染器模块</div><ul class="mapgis-sidebar-menus"><li><img style="width: 20px;margin-right: 6px;vertical-align: middle;" src="./styles/c.png" alt=""><a href="Zondy.ThemeLayer.GraphThemeLayer.html">GraphThemeLayer</a><span style="display: none;"><p>统计专题图通过为每个要素绘制统计图表来反映其对应的专题值的大小。它可同时表示多个字段属性信息,在区域本身与各区域之间形成横向和纵向的对比。<br>统计专题图多用于具有相关数量特征的地图上,比如表示不同地区多年的粮食产量、GDP、人口等,不同时段客运量、地铁流量等。目前提供的统计图类型有:柱状图(Bar),折线图(Line),饼图(Pie),三维柱状图(Bar3D),点状图(Point),环状图(Ring)。</p></span></li></ul></div> </nav> </div> <div class="core" id="main-content-wrapper"> <div class="content"> <header id="page-title" class="page-title"> <span class="page-title-main">类名</span> <span class="page-title-sub">util/extend/layer/tile/L.TileLayer.Clip.js</span> </header> <section> <article> <pre class="prettyprint source linenums"><code>import * as L from '@mapgis/leaflet' // eslint-disable-next-line import/no-extraneous-dependencies import * as T from '@turf/turf' import { defaultValue, FetchMethod } from '@mapgis/webclient-common' L.TileLayer.Clip = L.TileLayer.extend({ options: { clippingArea: null }, initialize(url, options) { L.TileLayer.prototype.initialize.call(this, url, options) // 缓存clippingArea像素边界 this._clippingAreaPx = null // 缓存瓦片裁剪区 this._TileClippingGeometryCache = {} // 设置请求方式 this.httpMethod = defaultValue(options.httpMethod, FetchMethod.get) }, createTile(coords, done) { const src = this.getTileUrl(coords) return this._drawClippingTile(src, coords, done) }, /** * @description: 设置裁剪区域 * @param {*} data * @return {*} */ setClippingArea(data) { this.options.clippingArea = data this._clearClippingCache() this.redraw() return this }, /** * @description: 获取裁剪区域 * @return {*} */ getClippingArea() { return this.options.clippingArea }, /** * @description: 根据瓦片行列号获取空间裁剪区 * @param {*} x * @param {*} y * @param {*} z * @return {*} */ _getTileGeometryAndState(x, y, z) { // 不设置裁剪区默认不裁剪 if (!this.options.clippingArea) { return { in: true, geometry: null } } // 缓存瓦片id const cacheId = `${x},${y},${z}` // 返回缓存的几何 if (this._TileClippingGeometryCache[cacheId]) { return { intersect: true, geometry: this._TileClippingGeometryCache[cacheId] } } const clippingAreaPx = this._getClippingAreaPx() const tileSize = this.options.tileSize const zLevel = Math.pow(2, z - this.options.zoomOffset) // 计算0级范围 const x1 = (x * tileSize) / zLevel const y1 = (y * tileSize) / zLevel const x2 = ((x + 1) * tileSize) / zLevel const y2 = ((y + 1) * tileSize) / zLevel const tileBbox = T.polygon([ [ [x1, y1], [x2, y1], [x2, y2], [x1, y2], [x1, y1] ] ]) // 判断裁剪区>瓦片范围 if (T.booleanContains(clippingAreaPx, tileBbox)) { return { in: true, geometry: null } } // 判断裁剪区&lt;瓦片范围 if (T.booleanContains(tileBbox, clippingAreaPx)) { this._TileClippingGeometryCache[cacheId] = clippingAreaPx return { intersect: true, geometry: clippingAreaPx } } // 判断是否相交 if (!T.booleanOverlap(clippingAreaPx, tileBbox)) { return { out: true, geometry: null } } const intersectResult = T.intersect(clippingAreaPx, tileBbox) if (!intersectResult) { return { out: true, geometry: null } } this._TileClippingGeometryCache[cacheId] = intersectResult return { intersect: true, geometry: intersectResult } }, /** * 获取合并后的点集 * @param {Number[][][]} polygon 面 * @return {Number[][][]} 计算像素坐标系点 */ _toMercGeometry(polygons) { // 缓存0级地图下几何的相对位置 const rings = [] for (let j = 0; j &lt; polygons.length; j++) { const ring = [] for (let k = 0; k &lt; polygons[j].length; k++) { const p = this._map.project( L.latLng(polygons[j][k][1], polygons[j][k][0]), 0 ) ring.push([p.x, p.y]) } rings.push(ring) } return rings }, /** * 计算裁剪区像素坐标几何以及更新其四至 * @return {Object|null} 合并后的点集 */ _getClippingAreaPx() { if (this._clippingAreaPx) { return this._clippingAreaPx } if (this.options.clippingArea) { this._clippingAreaPx = T.polygon( this._toMercGeometry(this.options.clippingArea) ) this._clippingAreaPxBounds = T.bbox(this._clippingAreaPx) } else { this._clippingAreaPx = null this._clippingAreaPxBounds = null } return this._clippingAreaPx }, /** * @description: 清空缓存 * @return {*} */ _clearClippingCache() { this._clippingAreaPx = null this._clippingAreaPxBounds = null this._TileClippingGeometryCache = {} }, /** * @description: 重绘图片 * @param {*} url * @param {*} coords * @param {*} done * @return {*} */ _drawClippingTile(url, coords, done) { const { x, y, z } = coords const state = this._getTileGeometryAndState(x, y, z) // 创建tile const tile = document.createElement('img') // 处理状态 if (state.in) { return this._getTileImage(tile, url, done) } if (state.out) { const canvas = document.createElement('canvas') canvas.width = this.options.width canvas.height = this.options.height return this._getTileImage(tile, null, done) } if (state.intersect &amp;&amp; state.geometry) { this._getTileImage(tile, url, done) // 创建绘制的canvas const canvas = document.createElement('canvas') canvas.width = this.options.tileSize canvas.height = this.options.tileSize const ctx = canvas.getContext('2d') const tileSize = this.options.tileSize const tileX = tileSize * x const tileY = tileSize * y const zLevel = Math.pow(2, z - this.options.zoomOffset) const geometryCoords = T.coordAll(state.geometry) // 图像加载完毕绘制canvas tile.onload = function () { canvas.complete = true // 定时器 setTimeout(() => { const pattern = ctx.createPattern(tile, 'repeat') let drawX let drawY // 开始绘制 ctx.beginPath() // 移动到开始点 drawX = geometryCoords[0][0] * zLevel - tileX drawY = geometryCoords[0][1] * zLevel - tileY ctx.moveTo(drawX, drawY) for (let j = 1; j &lt; geometryCoords.length; j++) { drawX = geometryCoords[j][0] * zLevel - tileX drawY = geometryCoords[j][1] * zLevel - tileY // 开始绘制 ctx.lineTo(drawX, drawY) } // 设置裁剪 ctx.clip() ctx.beginPath() ctx.rect(0, 0, canvas.width, canvas.height) ctx.fillStyle = pattern ctx.fill() done() }, 0) } if (this.options.crossOrigin) { tile.crossOrigin = '' } return canvas } }, _getTileImage(tile, url, done) { if (!url) return tile L.DomEvent.on(tile, 'load', L.Util.bind(this._tileOnLoad, this, done, tile)) L.DomEvent.on( tile, 'error', L.Util.bind(this._tileOnError, this, done, tile) ) if (this.options.crossOrigin || this.options.crossOrigin === '') { tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin } // for this new option we follow the documented behavior // more closely by only setting the property when string if (typeof this.options.referrerPolicy === 'string') { tile.referrerPolicy = this.options.referrerPolicy } // The alt attribute is set to the empty string, // allowing screen readers to ignore the decorative image tiles. // https://www.w3.org/WAI/tutorials/images/decorative/ // https://www.w3.org/TR/html-aria/#el-img-empty-alt tile.alt = '' // 验证是否为base64字符串 let imageUrl = url if (!/data:image\/jpg;base64/.test(url)) { imageUrl = this._getInterceptorsUrl(url) const config = this._map.options.config tile.onload = function () { L.InterceptorsUtils.serviceConfigResponseInterceptors( config, imageUrl, tile ) } } if (this.httpMethod === FetchMethod.post) { this._postImage(tile, url) } else { tile.src = imageUrl } return tile }, // 由子类实现 _postImage(tile, options) {}, _getInterceptorsUrl(url) { // 处理拦截器代码 const config = this._map.options.config const tokenStr = `&amp;${L.InterceptorsUtils.serviceConfigToken(config)}` let imageUrl = L.InterceptorsUtils.serviceConfigRequestInterceptors( config, url ) if (tokenStr !== '&amp;') { imageUrl += tokenStr } return imageUrl } }) L.TileLayer.clip = function (url, options) { return new L.TileLayer.Clip(url, options) } </code></pre> </article> </section> </div> <footer class="footer"> <div class="content has-text-centered"> <p>文档生成<a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a></p> <p class="sidebar-created-by"> <a href="http://www.smaryun.com" target="_blank">司马云</a> <span>© 2023 云生态圈</span> <a href="http://192.168.82.89:8086/#/index" target="_blank">MapGIS Client for JavaScript</a> </p> </div> </footer> </div> <div id="side-nav" class="side-nav"> <div style="margin-bottom: 10px;"> <img style="vertical-align: middle;margin-right: 10px;width: 30px;" src="./styles/anchor.png"/><a href="#page-title">构造函数</a> </div> <div style="margin-bottom: 10px;"> <img style="vertical-align: middle;margin-right: 10px;width: 30px;" src="./styles/anchor.png"/><a href="#member">成员变量</a> </div> <div style="margin-bottom: 10px;"> <img style="vertical-align: middle;margin-right: 10px;width: 30px;" src="./styles/anchor.png"/><a href="#function">方法</a> </div> <div> <img style="vertical-align: middle;margin-right: 10px;width: 30px;" src="./styles/anchor.png"/><a href="#event">事件</a> </div> </div> </div> <script src="scripts/linenumber.js"> </script> <script src="scripts/search.js"> </script> </body> </html>