From 181d7bc42f6a0be656669113486cb54d8c388d94 Mon Sep 17 00:00:00 2001 From: thinkinggis Date: Tue, 2 Apr 2019 11:59:43 +0800 Subject: [PATCH] feat(layer): add tile --- demos/01_point_circle.html | 17 ++-- demos/line.html | 70 ++++++++++----- package.json | 2 +- src/core/layer.js | 4 +- src/geom/base.js | 53 +++++++---- src/geom/material/lineMaterial.js | 3 +- src/geom/shader/line_vert.glsl | 3 +- src/geom/shader/meshline_vert.glsl | 5 +- src/geom/shape/line.js | 2 +- src/layer/pointLayer.js | 4 +- src/layer/tile/imageTile.js | 137 +++++++++++++++++++++++++++++ src/layer/tile/tile-cache.js | 22 +++++ src/layer/tile/tile.js | 59 +++++++++++++ src/source/parser/geojson.js | 3 +- src/source/transform/cluster.js | 2 +- src/util/lru-cache.js | 71 +++++++++++++++ 16 files changed, 399 insertions(+), 58 deletions(-) create mode 100644 src/layer/tile/imageTile.js create mode 100644 src/layer/tile/tile-cache.js create mode 100644 src/layer/tile/tile.js create mode 100644 src/util/lru-cache.js diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html index ce3ac03fb3..a03bf2326e 100644 --- a/demos/01_point_circle.html +++ b/demos/01_point_circle.html @@ -24,7 +24,7 @@ +
时间: 6时
+
+ +
+ - diff --git a/package.json b/package.json index 7dc407177f..a978237bf9 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/l7", - "version": "1.1.7", + "version": "1.1.8", "description": "Large-scale WebGL-powered Geospatial Data Visualization", "main": "build/l7.js", "browser": "build/l7.js", diff --git a/src/core/layer.js b/src/core/layer.js index 6b974bddbc..290e64a6fc 100644 --- a/src/core/layer.js +++ b/src/core/layer.js @@ -557,7 +557,6 @@ export default class Layer extends Base { let { featureId, point2d, type } = e; if (featureId < 0 && this._activeIds !== null) { type = 'mouseleave'; - // featureId = this._activeIds; } this._activeIds = featureId; const feature = this.layerSource.getSelectFeature(featureId); @@ -579,7 +578,7 @@ export default class Layer extends Base { } /** * 用于过滤数据 - * @param {*} object 需要过滤的mesh + * @param {*} object 更新颜色和数据过滤 */ _updateFilter(object) { this._updateMaping(); @@ -629,6 +628,7 @@ export default class Layer extends Base { this._object3D.visible = true; } } + // 重新构建mesh redraw() { this._object3D.children.forEach(child => { diff --git a/src/geom/base.js b/src/geom/base.js index 9e1488b9df..dc04754965 100644 --- a/src/geom/base.js +++ b/src/geom/base.js @@ -1,21 +1,38 @@ -import Base from '../core/base'; -export class GeomBase extends Base { + +export const GeomBase = { + color: 'updateDraw', + size: 'repaint', + filter: 'updateDraw', + layer: '', + pickable: true, + setLayer(layer) { + this.layer = layer; + this.style = layer.get('styleOption'); + }, + getShape(type) { + return type; + }, + draw() { + const shape = this.getShape(); + this.Mesh = shape.Mesh(); + }, + // 更新geometry buffer; + updateDraw() { + + }, + repaint() { + + } +}; +export const shapeBae = { geometryBuffer() { + }, + + geometry() {}, + + material() {}, + + mesh() { } - geometry() { - } - - material() { - - } - - drawMesh() { - - } - - -} - - -export default GeomBase; +}; diff --git a/src/geom/material/lineMaterial.js b/src/geom/material/lineMaterial.js index 2adf7377c4..91a1c4d204 100644 --- a/src/geom/material/lineMaterial.js +++ b/src/geom/material/lineMaterial.js @@ -55,7 +55,8 @@ export function MeshLineMaterial(options) { }, vertexShader: vs, fragmentShader: fs, - transparent: true + transparent: true, + blending: THREE.AdditiveBlending }); return material; } diff --git a/src/geom/shader/line_vert.glsl b/src/geom/shader/line_vert.glsl index e214d46a61..c54c2ac07f 100644 --- a/src/geom/shader/line_vert.glsl +++ b/src/geom/shader/line_vert.glsl @@ -16,7 +16,8 @@ void main() { } #ifdef ANIMATE vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.; + // vTime = 1.0- (28800. + mod(u_time* 10.,28800.)- position.z / 1000.) / 100.; #endif - gl_Position = matModelViewProjection * vec4(position.xy,0., 1.0); + gl_Position = matModelViewProjection * vec4(position.xy, 0., 1.0); worldId = id_toPickColor(pickingId); } \ No newline at end of file diff --git a/src/geom/shader/meshline_vert.glsl b/src/geom/shader/meshline_vert.glsl index dcb775d27f..76c5d8b73a 100644 --- a/src/geom/shader/meshline_vert.glsl +++ b/src/geom/shader/meshline_vert.glsl @@ -20,7 +20,7 @@ uniform float u_trailLength; void main() { mat4 matModelViewProjection = projectionMatrix * modelViewMatrix; - vec3 pointPos = position.xyz + vec3(normal * a_size * pow(2.0,20.0-u_zoom) / 2.0 * a_miter); + vec3 pointPos = vec3(position.xy,0.) + vec3(normal * a_size * pow(2.0,20.0-u_zoom) / 2.0 * a_miter); v_color = a_color; if(pickingId == u_activeId) { v_color = u_activeColor; @@ -30,8 +30,9 @@ void main() { float alpa =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration); alpa = (alpa + u_trailLength -1.0) / u_trailLength; vTime = clamp(alpa,0.,1.); + // vTime = (28800. + mod(u_time* 1000.,28800.)- position.z) / 100.; #endif worldId = id_toPickColor(pickingId); -gl_Position = matModelViewProjection * vec4(pointPos, 1.0); + gl_Position = matModelViewProjection * vec4(pointPos.xy, 0., 1.0); } \ No newline at end of file diff --git a/src/geom/shape/line.js b/src/geom/shape/line.js index ec68f55770..f171c1f86c 100644 --- a/src/geom/shape/line.js +++ b/src/geom/shape/line.js @@ -94,7 +94,7 @@ export function Line(path, props, positionsIndex) { indexArray[c++] = i + 2; indexArray[c++] = i + 3; } - point[2] = size[1]; + // point[2] = size[1]; positions.push(...point); positions.push(...point); diff --git a/src/layer/pointLayer.js b/src/layer/pointLayer.js index 922830f94b..8168a67c56 100644 --- a/src/layer/pointLayer.js +++ b/src/layer/pointLayer.js @@ -135,9 +135,9 @@ export default class PointLayer extends Layer { const preBox = cfg.bbox; const preZoom = cfg.zoom; if (!(preBox && preBox[0] < bbox[0] && preBox[1] < bbox[1] && preBox[2] > bbox[2] && preBox[3] < bbox[3] && // 当前范围在范围内 - (Math.abs(zoom - preZoom)) < 1)) { + (Math.abs(zoom - preZoom)) < 0.5)) { const newbbox = [ SW.lng - step, SW.lat - step, NE.lng + step, NE.lat + step ]; - this.layerSource.updateCusterData(Math.floor(zoom), newbbox); + this.layerSource.updateCusterData(Math.floor(zoom - 1), newbbox); this.repaint(); } } diff --git a/src/layer/tile/imageTile.js b/src/layer/tile/imageTile.js new file mode 100644 index 0000000000..c14a052e01 --- /dev/null +++ b/src/layer/tile/imageTile.js @@ -0,0 +1,137 @@ +// import * as THREE from '../../core/three'; +// import Tile from './tile'; +// export default class ImageTile extends Tile { +// constructor(layer, z, x, y) { + +// } +// requestTileAsync() { +// // Making this asynchronous really speeds up the LOD framerate +// setTimeout(() => { +// if (!this._mesh) { +// this._mesh = this._createMesh(); +// this._requestTile(); +// } +// }, 0); +// } +// _requestTile() { +// const urlParams = { +// x: this._tile[0], +// y: this._tile[1], +// z: this._tile[2] +// }; + +// const url = this._getTileURL(urlParams); + +// const image = document.createElement('img'); + +// image.addEventListener('load', event => { +// const texture = new THREE.Texture(); + +// texture.image = image; +// texture.needsUpdate = true; + +// // Silky smooth images when tilted +// texture.magFilter = THREE.LinearFilter; +// texture.minFilter = THREE.LinearMipMapLinearFilter; + +// // TODO: Set this to renderer.getMaxAnisotropy() / 4 +// texture.anisotropy = 4; + +// texture.needsUpdate = true; + +// // Something went wrong and the tile or its material is missing +// // +// // Possibly removed by the cache before the image loaded +// if (!this._mesh || !this._mesh.children[0] || !this._mesh.children[0].material) { +// return; +// } + +// this._mesh.children[0].material.map = texture; +// this._mesh.children[0].material.needsUpdate = true; + +// this._texture = texture; +// this._ready = true; +// }, false); + +// // image.addEventListener('progress', event => {}, false); +// // image.addEventListener('error', event => {}, false); + +// image.crossOrigin = ''; + +// // Load image +// image.src = url; + +// this._image = image; +// } + +// _createMesh() { +// // Something went wrong and the tile +// // +// // Possibly removed by the cache before loaded +// if (!this._center) { +// return; +// } + +// const mesh = new THREE.Object3D(); +// const geom = new THREE.PlaneBufferGeometry(this._side, this._side, 1); + +// let material; +// if (!this._world._environment._skybox) { +// material = new THREE.MeshBasicMaterial({ +// depthWrite: false +// }); + +// // const material = new THREE.MeshPhongMaterial({ +// // depthWrite: false +// // }); +// } else { +// // Other MeshStandardMaterial settings +// // +// // material.envMapIntensity will change the amount of colour reflected(?) +// // from the environment map–can be greater than 1 for more intensity + +// material = new THREE.MeshStandardMaterial({ +// depthWrite: false +// }); +// material.roughness = 1; +// material.metalness = 0.1; +// material.envMap = this._world._environment._skybox.getRenderTarget(); +// } + +// const localMesh = new THREE.Mesh(geom, material); +// localMesh.rotation.x = -90 * Math.PI / 180; + +// localMesh.receiveShadow = true; + +// mesh.add(localMesh); +// mesh.renderOrder = 0.1; + +// mesh.position.x = this._center[0]; +// mesh.position.z = this._center[1]; + +// // const box = new BoxHelper(localMesh); +// // mesh.add(box); +// // +// // mesh.add(this._createDebugMesh()); + +// return mesh; +// } +// _abortRequest() { +// if (!this._image) { +// return; +// } + +// this._image.src = ''; +// } + +// destroy() { +// // Cancel any pending requests +// this._abortRequest(); + +// // Clear image reference +// this._image = null; + +// super.destroy(); +// } + +// } diff --git a/src/layer/tile/tile-cache.js b/src/layer/tile/tile-cache.js new file mode 100644 index 0000000000..cd42e03cd1 --- /dev/null +++ b/src/layer/tile/tile-cache.js @@ -0,0 +1,22 @@ +import LRUCache from '../../util/lru-cache'; +export default class TileCache { + constructor(limit = 50) { + this._cache = new LRUCache(limit); + } + + getTile(z, x, y) { + const key = this._generateKey(z, x, y); + return this._cache.get(key); + } + + setTile(tile, z, x, y) { + const key = this._generateKey(z, x, y); + this._cache.set(key, tile); + } + _generateKey(z, x, y) { + return [ z, x, y ].join('_'); + } + destory() { + this._cache.clear(); + } +} diff --git a/src/layer/tile/tile.js b/src/layer/tile/tile.js new file mode 100644 index 0000000000..8ca5d10b48 --- /dev/null +++ b/src/layer/tile/tile.js @@ -0,0 +1,59 @@ +// const r2d = 180 / Math.PI; +// const tileURLRegex = /\{([zxy])\}/g; +// export class Tile { +// constructor(layer, z, x, y) { +// this.layer = layer; +// this._tile = [ z, x, y ]; + +// } +// _createMesh() {} +// _createDebugMesh() {} + +// _getTileURL(urlParams) { +// if (!urlParams.s) { +// // Default to a random choice of a, b or c +// urlParams.s = String.fromCharCode(97 + Math.floor(Math.random() * 3)); +// } + +// tileURLRegex.lastIndex = 0; +// return this._path.replace(tileURLRegex, function(value, key) { +// // Replace with paramter, otherwise keep existing value +// return urlParams[key]; +// }); +// } + +// _tileBoundsFromWGS84(boundsWGS84) { +// const sw = this._layer._world.latLonToPoint(LatLon(boundsWGS84[1], boundsWGS84[0])); +// const ne = this._layer._world.latLonToPoint(LatLon(boundsWGS84[3], boundsWGS84[2])); + +// return [sw.x, sw.y, ne.x, ne.y]; +// } + +// // Get tile bounds in WGS84 coordinates +// _tileBoundsWGS84(tile) { +// const e = this._tile2lon(tile[0] + 1, tile[2]); +// const w = this._tile2lon(tile[0], tile[2]); +// const s = this._tile2lat(tile[1] + 1, tile[2]); +// const n = this._tile2lat(tile[1], tile[2]); +// return [ w, s, e, n ]; +// } + +// _tile2lon(x, z) { +// return x / Math.pow(2, z) * 360 - 180; +// } + +// _tile2lat(y, z) { +// const n = Math.PI - 2 * Math.PI * y / Math.pow(2, z); +// return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))); +// } + +// _boundsToCenter(bounds) { +// const x = bounds[0] + (bounds[2] - bounds[0]) / 2; +// const y = bounds[1] + (bounds[3] - bounds[1]) / 2; + +// return [ x, y ]; +// } +// destory() { + +// } +// } diff --git a/src/source/parser/geojson.js b/src/source/parser/geojson.js index 6385fa0d42..d157b4ffec 100644 --- a/src/source/parser/geojson.js +++ b/src/source/parser/geojson.js @@ -1,11 +1,10 @@ import * as turfMeta from '@turf/meta'; -import { default as cleanCoords } from '@turf/clean-coords'; import { getCoords } from '@turf/invariant'; export default function geoJSON(data) { const resultData = []; turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个 - const coord = getCoords(cleanCoords(currentFeature)); + const coord = getCoords(currentFeature); const dataItem = { ...currentFeature.properties, coordinates: coord, diff --git a/src/source/transform/cluster.js b/src/source/transform/cluster.js index 4d87f3f360..5a88bedd53 100644 --- a/src/source/transform/cluster.js +++ b/src/source/transform/cluster.js @@ -1,6 +1,6 @@ import Supercluster from 'supercluster'; export function cluster(data, option) { - const { radius = 40, maxZoom = 16, minZoom = 0, field, zoom = 2 } = option; + const { radius = 80, maxZoom = 18, minZoom = 0, field, zoom = 2 } = option; if (data.pointIndex) { const clusterPoint = data.pointIndex.getClusters(data.extent, zoom); data.dataArray = formatData(clusterPoint); diff --git a/src/util/lru-cache.js b/src/util/lru-cache.js new file mode 100644 index 0000000000..8b417e53e2 --- /dev/null +++ b/src/util/lru-cache.js @@ -0,0 +1,71 @@ +/** + * LRU Cache class with limit + * + * Update order for each get/set operation + * Delete oldest when reach given limit + */ + +export default class LRUCache { + constructor(limit = 5) { + this.limit = limit; + + this.clear(); + } + + clear() { + this._cache = {}; + // access/update order, first item is oldest, last item is newest + this._order = []; + } + + get(key) { + const value = this._cache[key]; + if (value) { + // update order + this._deleteOrder(key); + this._appendOrder(key); + } + return value; + } + + set(key, value) { + if (!this._cache[key]) { + // if reach limit, delete the oldest + if (Object.keys(this._cache).length === this.limit) { + this.delete(this._order[0]); + } + + this._cache[key] = value; + this._appendOrder(key); + } else { + // if found in cache, delete the old one, insert new one to the first of list + this.delete(key); + + this._cache[key] = value; + this._appendOrder(key); + } + } + + delete(key) { + const value = this._cache[key]; + if (value) { + this._deleteCache(key); + this._deleteOrder(key); + } + } + + _deleteCache(key) { + delete this._cache[key]; + } + + _deleteOrder(key) { + const index = this._order.findIndex(o => o === key); + if (index >= 0) { + this._order.splice(index, 1); + } + } + + _appendOrder(key) { + this._order.push(key); + } +}