diff --git a/demos/01_point_circle.html b/demos/01_point_circle.html index 37b3ff6d54..8014217389 100644 --- a/demos/01_point_circle.html +++ b/demos/01_point_circle.html @@ -54,7 +54,7 @@ window.scene = scene; scene.on('loaded', () => { $.get('https://gw.alipayobjects.com/os/rmsportal/epnZEheZeDgsiSjSPcCv.json', data => { console.log(data); - const circleLayer = scene.PointLayer({ + const circleLayer = = scene.PointLayer({ zIndex: 0, }) .source(data,{ @@ -76,7 +76,6 @@ scene.on('loaded', () => { }) .source(circleLayer.layerSource) .shape('point_count', 'text') - .active(true) .size('point_count', [ 10, 20, 24 ]) .color('#FFF') .style({ diff --git a/demos/datafilter.html b/demos/datafilter.html new file mode 100644 index 0000000000..6453fa643b --- /dev/null +++ b/demos/datafilter.html @@ -0,0 +1,68 @@ + + + + + + + + + + + hexagon demo + + + + +
+ + + + + + + + + diff --git a/demos/point.html b/demos/point.html new file mode 100644 index 0000000000..c6e4e37bfb --- /dev/null +++ b/demos/point.html @@ -0,0 +1,81 @@ + + + + + + 气泡图 + + + +
+ + + + + + \ No newline at end of file diff --git a/demos/vector2.html b/demos/vector2.html index 45db086525..69e0647023 100644 --- a/demos/vector2.html +++ b/demos/vector2.html @@ -38,18 +38,18 @@ const scene = new L7.Scene({ // 高德数据服务 https://mvt.amap.com/district/CHN2/{z}/{x}/{y}/4096?key=608d75903d29ad471362f8c58c550daf scene.on('loaded', () => { - const attributeCtr = new L7.Control.Attribution(); - attributeCtr.addTo(scene); scene.addTileSource('test',{ url:' https://mvt.amap.com/district/CHN2/{z}/{x}/{y}/4096?key=608d75903d29ad471362f8c58c550daf', type:'vector', minZoom: 0, maxZoom:9 + }) const layer = scene.PolygonLayer({ zIndex:0, + attribution:'高德地图' }) .source('test',{ parser:{ @@ -66,13 +66,20 @@ scene.on('loaded', () => { opacity:1.0 }) .render(); + let id =0; + layer.on('click',(e) => { const { lnglat, feature } = e; - const popup = new L7.Popup() + console.log(lnglat); + const popup = new L7.Popup({ + id:id++ + }) .setLnglat([lnglat.lng, lnglat.lat]) - .setHTML(feature.properties.NAME_CHN.toString()).addTo(scene); + .setText(feature.properties.NAME_CHN.toString()).addTo(scene); }) - +scene.on('click',(e)=>{ + console.log(e); +}) const layer2 = scene.LineLayer({ zIndex:10, }) diff --git a/package.json b/package.json index e73c1b723b..af289a9994 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@antv/l7", - "version": "1.3.0-beta.1", + "version": "1.3.0-beta.4", "description": "Large-scale WebGL-powered Geospatial Data Visualization", "main": "build/L7.js", "browser": "build/L7-min.js", diff --git a/src/component/css/l7.css b/src/component/css/l7.css index 93356e0a90..117e1f6bd5 100644 --- a/src/component/css/l7.css +++ b/src/component/css/l7.css @@ -345,12 +345,12 @@ border-radius: 5px; } .l7-control-layers-toggle { - background-image: url(../images/layers.png); + background-image: url(../images/layers.svg); width: 36px; height: 36px; } .l7-retina .l7-control-layers-toggle { - background-image: url(../images/layers-2x.png); + background-image: url(../images/layers.svg); background-size: 26px 26px; } .l7-touch .l7-control-layers-toggle { diff --git a/src/component/images/layers-2x.png b/src/component/images/layers-2x.png deleted file mode 100644 index 200c333dca..0000000000 Binary files a/src/component/images/layers-2x.png and /dev/null differ diff --git a/src/component/images/layers.png b/src/component/images/layers.png deleted file mode 100644 index 1a72e5784b..0000000000 Binary files a/src/component/images/layers.png and /dev/null differ diff --git a/src/component/images/layers.svg b/src/component/images/layers.svg new file mode 100644 index 0000000000..615f4172d7 --- /dev/null +++ b/src/component/images/layers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/component/popup.js b/src/component/popup.js index d88c1457e4..1de80ff6f4 100644 --- a/src/component/popup.js +++ b/src/component/popup.js @@ -11,15 +11,18 @@ export default class Popup extends Base { anchor: 'bottom', ...cfg }); + bindAll([ '_update', '_onClickClose', 'remove' ], this); } addTo(scene) { this._scene = scene; - if (this.get('closeOnClick')) { - this._scene.on('click', this._onClickClose); - } this._scene.on('camerachange', this._update); this._update(); + if (this.get('closeOnClick')) { + setTimeout(() => { // TODO 事件冲突 + this._scene.on('click', this._onClickClose); + }, 30); + } } setLnglat(lngLat) { this.lngLat = lngLat; diff --git a/src/core/controller/mapping.js b/src/core/controller/mapping.js index 7b0d4e6495..799bed9e8d 100644 --- a/src/core/controller/mapping.js +++ b/src/core/controller/mapping.js @@ -18,15 +18,20 @@ export default class Mapping { _init() { this._initControllers(); - this._initTileAttrs(); + this._initAttrs(); this._mapping(); } update() { this.mesh.set('scales', {}); - this._initTileAttrs(); + this._initAttrs(); this._updateMaping(); } + reMapping() { + this.mesh.set('scales', {}); + this._initAttrs(); + this._mapping(); + } _initControllers() { const scalesOption = this.layer.get('scaleOptions'); @@ -144,7 +149,7 @@ export default class Mapping { } - _initTileAttrs() { + _initAttrs() { const attrOptions = this.layer.get('attrOptions'); for (const type in attrOptions) { if (attrOptions.hasOwnProperty(type)) { diff --git a/src/core/engine/picking/picking.js b/src/core/engine/picking/picking.js index c01736fcc7..8b6d0dbba8 100755 --- a/src/core/engine/picking/picking.js +++ b/src/core/engine/picking/picking.js @@ -20,7 +20,7 @@ class Picking { depthBuffer: true }; - this._pickingTexture = new THREE.WebGLRenderTarget(this._width, this._height, parameters); + this._pickingTexture = new THREE.WebGLRenderTarget(this._width / 10, this._height / 10, parameters); this._nextId = 1; diff --git a/src/core/layer.js b/src/core/layer.js index 676c70288c..6a1250b82e 100644 --- a/src/core/layer.js +++ b/src/core/layer.js @@ -81,16 +81,15 @@ export default class Layer extends Base { /** * 将图层添加加到 Object * @param {*} object three 物体 - * @param {*} type mesh类型是区别是填充还是边线 */ - add(object, type = 'fill') { + add(object) { // composer合图层绘制 if (object.type === 'composer') { this._object3D = object; this.scene._engine.composerLayers.push(object); return; } - type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object; + this.layerMesh = object; this._visibleWithZoom(); object.onBeforeRender = () => { // 每次渲染前改变状态 const zoom = this.scene.getZoom(); @@ -105,9 +104,8 @@ export default class Layer extends Base { this.afterRender(); }; this._object3D.add(object); - if (type === 'fill') { - this.get('pickingController').addPickMesh(object); - } + this.get('pickingController').addPickMesh(object); + } remove(object) { if (object.type === 'composer') { @@ -279,6 +277,7 @@ export default class Layer extends Base { setData(data, cfg) { this.layerSource.setData(data, cfg); this.repaint(); + this.scene._engine.update(); } _createScale(field) { // TODO scale更新 @@ -331,7 +330,7 @@ export default class Layer extends Base { this.scene.style.update(this._attrs); return this; } - this.init(); + this._updateDraw(); this.scene._engine.update(); return this; } @@ -345,7 +344,6 @@ export default class Layer extends Base { init() { this._initControllers(); this._mapping(); - this._updateDraw(); } _initInteraction() { if (this.get('allowActive')) { @@ -379,6 +377,7 @@ export default class Layer extends Base { setActive(id, color) { this._activeIds = id; + if (!color) color = Global.activeColor; if (!Array.isArray(color)) { color = ColorUtil.color2RGBA(color); } @@ -407,31 +406,35 @@ export default class Layer extends Base { const preStyle = this.get('preStyleOption'); const nextStyle = this.get('styleOptions'); if (preAttrs === undefined && preStyle === undefined) { // 首次渲染 - // this._mapping(); - // this._scaleByZoom(); this._setPreOption(); + this.init(); this._initInteraction(); this._initMapEvent(); + if (this.layerData.length === 0) { + return; + } this.draw(); return; } - if (!Util.isEqual(preAttrs.color, nextAttrs.color)) { - this._updateAttributes(this.layerMesh); - } // 更新数据过滤 filter if (!Util.isEqual(preAttrs.filter, nextAttrs.filter)) { - // 更新color; + this.repaint(); + this._setPreOption(); + return; + } + + if (!Util.isEqual(preAttrs.color, nextAttrs.color)) { this._updateAttributes(this.layerMesh); } // 更新Size if (!Util.isEqual(preAttrs.size, nextAttrs.size)) { // 更新color; - this._updateSize(); + this.repaint(); } // 更新形状 if (!Util.isEqual(preAttrs.shape, nextAttrs.shape)) { // 更新color; - this._updateShape(); + this.repaint(); } if (!Util.isEqual(preStyle, nextStyle)) { // 判断新增,修改,删除 @@ -442,7 +445,6 @@ export default class Layer extends Base { }); this._updateStyle(newStyle); } - this._setPreOption(); } _updateSize(zoom) { @@ -525,6 +527,9 @@ export default class Layer extends Base { style }; } + _updateFilter() { + this.get('mappingController').reMapping(); + } /** * 用于过滤数据 * @param {*} object 更新颜色和数据过滤 diff --git a/src/core/scene.js b/src/core/scene.js index 4cec1837db..0b04128292 100644 --- a/src/core/scene.js +++ b/src/core/scene.js @@ -3,7 +3,6 @@ import { LAYER_MAP } from '../layer'; import Base from './base'; import LoadImage from './image'; import FontAtlasManager from './atlas/font-manager'; -// import { MapProvider } from '../map/AMap'; import { getMap } from '../map/index'; import Global from '../global'; import { getInteraction } from '../interaction/index'; @@ -42,6 +41,9 @@ export default class Scene extends Base { if (this.get('scaleControl')) { new Control.Scale().addTo(this); } + if (this.get('attributionControl')) { + new Control.Attribution().addTo(this); + } } // 为pickup场景添加 object 对象 addPickMesh(object) { @@ -145,9 +147,7 @@ export default class Scene extends Base { // 要素拾取 if (e.target.nodeName !== 'CANVAS') return; e.pixel || (e.pixel = e.point); - requestAnimationFrame(() => { - this._engine._picking.pickdata(e); - }); + this._engine._picking.pickdata(e); }, true); }); } diff --git a/src/core/source.js b/src/core/source.js index af4291252a..a7b3baa10d 100644 --- a/src/core/source.js +++ b/src/core/source.js @@ -40,6 +40,7 @@ export default class Source extends Base { this._transforms = transform || []; this.set('data', data); this._init(); + this.emit('SourceUpdate'); } // 数据更新 updateTransfrom(cfg) { diff --git a/src/geom/material/textMaterial.js b/src/geom/material/textMaterial.js index 267ee808bd..2387d4099d 100644 --- a/src/geom/material/textMaterial.js +++ b/src/geom/material/textMaterial.js @@ -6,7 +6,8 @@ export default function TextMaterial(_uniforms) { const { vs, fs, uniforms } = getModule('text'); const material = new Material({ defines: { - DEVICE_PIXEL_RATIO: window.devicePixelRatio + SDF_PX: '8.0', + EDGE_GAMMA: 0.105 / window.devicePixelRatio }, uniforms: wrapUniforms(merge(uniforms, _uniforms)), vertexShader: vs, diff --git a/src/geom/shader/arcline_vert.glsl b/src/geom/shader/arcline_vert.glsl index 953519383f..9ad64a2301 100644 --- a/src/geom/shader/arcline_vert.glsl +++ b/src/geom/shader/arcline_vert.glsl @@ -56,7 +56,6 @@ void main() { float segmentRatio = getSegmentRatio(segmentIndex); float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0)); float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir); - v_distance_ratio = segmentIndex / segmentNumber; vec3 curr = getPos(source, target, segmentRatio); vec3 next = getPos(source, target, nextSegmentRatio); vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, position.y); diff --git a/src/geom/shader/meshline_frag.glsl b/src/geom/shader/meshline_frag.glsl index e83e1e7594..c5fd5565ca 100644 --- a/src/geom/shader/meshline_frag.glsl +++ b/src/geom/shader/meshline_frag.glsl @@ -42,14 +42,15 @@ void main() { #endif #ifdef DASHLINE - float time = u_time; + float time = 0.; #ifdef ANIMATE - time =0; + time = u_time / 1000. ; #endif - gl_FragColor.a *= u_opacity * ceil(mod(v_distance_ratio + u_dash_offset + time / 10., v_dash_array) - (v_dash_array * u_dash_ratio)); + gl_FragColor.a *= u_opacity * ceil(mod(v_distance_ratio + u_dash_offset + time, v_dash_array) - (v_dash_array * u_dash_ratio)); #else gl_FragColor.a *= u_opacity; #endif + #ifdef ANIMATE float alpha =1.0 - fract( mod(1.0- v_distance_ratio,u_interval)* (1.0/u_interval) + u_time / u_duration); alpha = (alpha + u_trailLength -1.0) / u_trailLength; diff --git a/src/geom/shader/text_frag.glsl b/src/geom/shader/text_frag.glsl index a09523f5cd..e6376d0e80 100644 --- a/src/geom/shader/text_frag.glsl +++ b/src/geom/shader/text_frag.glsl @@ -1,6 +1,3 @@ -#define SDF_PX 8.0 -#define EDGE_GAMMA 0.105 / float(DEVICE_PIXEL_RATIO) - uniform sampler2D u_sdf_map; uniform float u_gamma_scale : 0.5; uniform float u_font_size : 24; @@ -26,6 +23,6 @@ void main() { highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); - gl_FragColor = mix(v_color * u_font_opacity, u_halo_color, smoothstep(0., .5, 1. - dist)) * alpha; + gl_FragColor = mix(v_color * u_font_opacity, u_halo_color, smoothstep(0., 0.5, 1. - dist)) * alpha; #pragma include "pick" } \ No newline at end of file diff --git a/src/global.js b/src/global.js index 7161b52d5b..90bc9b840a 100644 --- a/src/global.js +++ b/src/global.js @@ -16,7 +16,8 @@ const Global = { pitch: 0, hash: false, zoomControl: true, - scaleControl: true + scaleControl: true, + attributionControl: true }, animate: true, height: 0, diff --git a/src/layer/render/index.js b/src/layer/render/index.js index 6918a84151..37c936177f 100644 --- a/src/layer/render/index.js +++ b/src/layer/render/index.js @@ -4,6 +4,7 @@ import DrawFill from './polygon/drawFill'; import DrawLine from './polygon/drawLine'; import DrawAnimate from './polygon/drawAnimate'; import Draw3DShape from './point/draw_3d_shape'; +import DrawText from './text/drawText'; registerRender('polygon', 'fill', DrawFill); registerRender('polygon', 'extrude', DrawFill); @@ -23,7 +24,6 @@ registerRender('line', 'greatCircle', DrawArcLine); import DrawPointImage from './point/drawImage'; import DrawPointNormal from './point/drawNormal'; import DrawPointStroke from './point/drawStroke'; -import DrawPointText from './point/drawText'; import DrawPointCircle from './point/drawCircle'; import DrawHexagon from './heatmap/hexagon'; @@ -31,11 +31,12 @@ import DrawHexagon from './heatmap/hexagon'; registerRender('point', 'image', DrawPointImage); registerRender('point', 'normal', DrawPointNormal); registerRender('point', 'stroke', DrawPointStroke); -registerRender('point', 'text', DrawPointText); +registerRender('point', 'text', DrawText); registerRender('point', 'fill', DrawPointCircle); registerRender('point', 'shape', Draw3DShape); registerRender('point', 'extrude', Draw3DShape); + // heatmap import DrawGrid from './heatmap/gird'; @@ -55,8 +56,6 @@ registerRender('image', 'image', DrawImage); // image -import DrawText from './text/drawText'; - registerRender('text', 'text', DrawText); export { getRender }; diff --git a/src/layer/render/point/drawText.js b/src/layer/render/point/drawText.js index 95d1f8949d..527758b526 100644 --- a/src/layer/render/point/drawText.js +++ b/src/layer/render/point/drawText.js @@ -54,3 +54,4 @@ export default function DrawText(layerData, layer) { const mesh = new THREE.Mesh(geometry, material); return mesh; } + diff --git a/src/layer/render/text/drawText.js b/src/layer/render/text/drawText.js index eacdb39859..0f3b40cdcb 100644 --- a/src/layer/render/text/drawText.js +++ b/src/layer/render/text/drawText.js @@ -2,14 +2,52 @@ import * as THREE from '../../../core/three'; import TextMaterial from '../../../geom/material/textMaterial'; import TextBuffer from '../../../geom/buffer/point/text'; import ColorUtil from '../../../attr/color-util'; - -export default function DrawText(layerData, layer, updateGeometry = false) { +import CollisionIndex from '../../../util/collision-index'; +export default function DrawText(layerData, layer) { const style = layer.get('styleOptions'); const activeOption = layer.get('activedOptions'); - const { strokeWidth, strokeColor, opacity, - fontFamily, fontWeight, spacing, textAnchor, textOffset, padding } = style; + const { strokeWidth, strokeColor, opacity } = style; const { width, height } = layer.scene.getSize(); + const { geometry, texture, fontAtlas } = _updateGeometry(layerData, layer); + layer.scene.on('camerachange', () => { + const { geometry } = _updateGeometry(layerData, layer); + layer.layerMesh.geometry = geometry; + layer.layerMesh.geometry.needsUpdate = true; + }); + + + const material = new TextMaterial({ + name: layer.layerId, + u_sdf_map: texture, + u_halo_color: ColorUtil.toRGB(strokeColor).map(e => e / 255), + u_halo_width: strokeWidth, + u_halo_blur: 0.5, + u_font_opacity: opacity, + u_sdf_map_size: [ fontAtlas.width, fontAtlas.height ], + u_viewport_size: [ width, height ], + u_activeColor: activeOption.fill + }); + const mesh = new THREE.Mesh(geometry, material); + + // 更新 viewport + window.addEventListener('resize', () => { + const { width, height } = layer.scene.getSize(); + material.uniforms.u_viewport_size.value = [ width, height ]; + material.uniforms.needsUpdate = true; + }, false); + + // 关闭视锥裁剪 + mesh.frustumCulled = false; + return mesh; +} + +function _updateGeometry(layerData, layer) { + const style = layer.get('styleOptions'); + const { + fontFamily, fontWeight, spacing, textAnchor, textOffset, padding } = style; + const { width, height } = layer.scene.getSize(); + const collisionIndex = new CollisionIndex(width, height); const { _camera: { projectionMatrix, matrixWorldInverse } } = layer.scene._engine; // 计算 MVP 矩阵 @@ -39,7 +77,7 @@ export default function DrawText(layerData, layer, updateGeometry = false) { padding }, layer.scene.fontAtlasManager, - layer.collisionIndex, + collisionIndex, mvpMatrix ); @@ -69,34 +107,5 @@ export default function DrawText(layerData, layer, updateGeometry = false) { 'a_size', new THREE.Float32BufferAttribute(textSizes, 1) ); - - // 只需要更新顶点数据 - if (updateGeometry) { - return geometry; - } - - const material = new TextMaterial({ - name: layer.layerId, - u_sdf_map: texture, - u_halo_color: ColorUtil.toRGB(strokeColor).map(e => e / 255), - u_halo_width: strokeWidth, - u_halo_blur: 0.5, - u_font_opacity: opacity, - u_sdf_map_size: [ fontAtlas.width, fontAtlas.height ], - u_viewport_size: [ width, height ], - u_activeColor: activeOption.fill - }); - const mesh = new THREE.Mesh(geometry, material); - - // 更新 viewport - window.addEventListener('resize', () => { - const { width, height } = layer.scene.getSize(); - material.uniforms.u_viewport_size.value = [ width, height ]; - material.uniforms.needsUpdate = true; - }, false); - - // 关闭视锥裁剪 - mesh.frustumCulled = false; - return mesh; + return { geometry, texture, fontAtlas }; } - diff --git a/src/layer/text_layer.js b/src/layer/text_layer.js index b14343ce38..ca45e6e750 100644 --- a/src/layer/text_layer.js +++ b/src/layer/text_layer.js @@ -1,23 +1,9 @@ import Layer from '../core/layer'; import { getRender } from './render'; -import CollisionIndex from '../util/collision-index'; export default class TextLayer extends Layer { shape(field, values) { super.shape(field, values); this.shape = 'text'; - - // 创建碰撞检测索引 - const { width, height } = this.scene.getSize(); - this.collisionIndex = new CollisionIndex(width, height); - - // 相机变化,需要重新构建索引,由于文本可见性的改变,也需要重新组装顶点数据 - this.scene.on('camerachange', () => { - this.collisionIndex = new CollisionIndex(width, height); - - this.layerMesh.geometry = getRender(this.type, this.shape)(this.layerData, this, true); - this.layerMesh.geometry.needsUpdate = true; - }); - return this; } draw() {