diff --git a/packages/core/src/services/interaction/PickingService.ts b/packages/core/src/services/interaction/PickingService.ts index e23a19ff1a..2660ee67b7 100644 --- a/packages/core/src/services/interaction/PickingService.ts +++ b/packages/core/src/services/interaction/PickingService.ts @@ -140,7 +140,14 @@ export default class PickingService implements IPickingService { return features; } private async pickingAllLayer(target: IInteractionTarget) { - if (this.alreadyInPicking || this.layerService.alreadyInRendering) { + if ( + // TODO: this.alreadyInPicking 避免多次重复拾取 + this.alreadyInPicking || + // TODO: this.layerService.alreadyInRendering 一个渲染序列中只进行一次拾取操作 + this.layerService.alreadyInRendering || + // TODO: this.layerService.isMapDragging() 如果地图正在拖拽 则不进行拾取操作 + this.layerService.isMapDragging() + ) { return; } this.alreadyInPicking = true; diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 96d1f052fc..fb39a7180f 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -384,5 +384,6 @@ export interface ILayerService { updateRenderOrder(): void; renderLayers(type?: string): void; getOESTextureFloat(): boolean; + isMapDragging(): boolean; destroy(): void; } diff --git a/packages/core/src/services/layer/LayerService.ts b/packages/core/src/services/layer/LayerService.ts index 9335a261c1..c36ab2876f 100644 --- a/packages/core/src/services/layer/LayerService.ts +++ b/packages/core/src/services/layer/LayerService.ts @@ -162,6 +162,16 @@ export default class LayerService implements ILayerService { return this.renderService.extensionObject.OES_texture_float; } + // TODO: 判断地图是否正在被拖动 + public isMapDragging() { + return this.mapService.dragging; + } + + private runRender() { + this.renderLayers(); + this.layerRenderID = requestAnimationFrame(this.runRender.bind(this)); + } + // 渲染检测 private renderTest(renderType: string | undefined): boolean { const now = new Date().getTime(); @@ -174,8 +184,9 @@ export default class LayerService implements ILayerService { if (renderType) { switch (renderType) { case 'picking': + // return false; // TODO: picking 类型的渲染事件 - // 若是上次触发为地图或动画触发的渲染,则认为是地图事件与拾取事件在同时触发,放弃此次渲染 + // 若是上次触发为地图触发的渲染,则认为是地图事件与拾取事件在同时触发,放弃此次渲染 if ( this.lastRenderType === 'mapRender' || this.lastRenderType === 'animate' @@ -192,6 +203,7 @@ export default class LayerService implements ILayerService { return true; } case 'animate': + // return false; if (this.lastRenderType === 'mapRender') { this.lastRenderType = 'animate'; return false; @@ -225,11 +237,6 @@ export default class LayerService implements ILayerService { }); } - private runRender() { - this.renderLayers('animate'); - this.layerRenderID = requestAnimationFrame(this.runRender.bind(this)); - } - private stopRender() { cancelAnimationFrame(this.layerRenderID); } diff --git a/packages/core/src/services/map/IMapService.ts b/packages/core/src/services/map/IMapService.ts index 32cab61ae3..592e90baa3 100644 --- a/packages/core/src/services/map/IMapService.ts +++ b/packages/core/src/services/map/IMapService.ts @@ -32,6 +32,7 @@ export interface IMapWrapper { export interface IMapService { version?: string; map: RawMap; + dragging: boolean; bgColor: string; setBgColor(color: string): void; init(): void; diff --git a/packages/layers/src/line/index.ts b/packages/layers/src/line/index.ts index 5517840db0..b22f94c406 100644 --- a/packages/layers/src/line/index.ts +++ b/packages/layers/src/line/index.ts @@ -31,6 +31,7 @@ export default class LineLayer extends BaseLayer { line: {}, arc3d: { blend: 'additive' }, arc: { blend: 'additive' }, + arcmini: { blend: 'additive' }, greatcircle: { blend: 'additive' }, }; return defaultConfig[type]; diff --git a/packages/layers/src/line/models/arcmini.ts b/packages/layers/src/line/models/arcmini.ts new file mode 100644 index 0000000000..a369e1761a --- /dev/null +++ b/packages/layers/src/line/models/arcmini.ts @@ -0,0 +1,134 @@ +import { + AttributeType, + gl, + IAnimateOption, + IEncodeFeature, + ILayerConfig, + IModel, + IModelUniform, +} from '@antv/l7-core'; + +import { rgb2arr } from '@antv/l7-utils'; +import { isNumber } from 'lodash'; +import BaseModel from '../../core/BaseModel'; +import { ILineLayerStyleOptions } from '../../core/interface'; +import { LineArcTriangulation } from '../../core/triangulation'; +import line_arcmini_frag from '../shaders/line_arcmini_frag.glsl'; +import line_arcmini_vert from '../shaders/line_arcmini_vert.glsl'; + +export default class ArcMiniModel extends BaseModel { + public getUninforms(): IModelUniform { + const { + opacity, + sourceColor, + targetColor, + forward = true, + segmentNumber = 30, + thetaOffset = 0.314, + } = this.layer.getLayerConfig() as ILineLayerStyleOptions; + + // 转化渐变色 + let useLinearColor = 0; // 默认不生效 + let sourceColorArr = [0, 0, 0, 0]; + let targetColorArr = [0, 0, 0, 0]; + if (sourceColor && targetColor) { + sourceColorArr = rgb2arr(sourceColor); + targetColorArr = rgb2arr(targetColor); + useLinearColor = 1; + } + + return { + u_thetaOffset: thetaOffset, + + u_opacity: isNumber(opacity) ? opacity : 1.0, + + segmentNumber, + u_blur: 0.9, + u_lineDir: forward ? 1 : -1, + + // 渐变色支持参数 + u_linearColor: useLinearColor, + u_sourceColor: sourceColorArr, + u_targetColor: targetColorArr, + }; + } + + public getAnimateUniforms(): IModelUniform { + const { animateOption } = this.layer.getLayerConfig() as ILayerConfig; + return { + u_aimate: this.animateOption2Array(animateOption as IAnimateOption), + u_time: this.layer.getLayerAnimateTime(), + }; + } + + public initModels(): IModel[] { + return this.buildModels(); + } + + public buildModels(): IModel[] { + const { + segmentNumber = 30, + } = this.layer.getLayerConfig() as ILineLayerStyleOptions; + + return [ + this.layer.buildLayerModel({ + moduleName: 'arc2dminiline', + vertexShader: line_arcmini_vert, + fragmentShader: line_arcmini_frag, + triangulation: LineArcTriangulation, + depth: { enable: false }, + blend: this.getBlend(), + segmentNumber, + }), + ]; + } + + protected registerBuiltinAttributes() { + // point layer size; + this.styleAttributeService.registerStyleAttribute({ + name: 'size', + type: AttributeType.Attribute, + descriptor: { + name: 'a_Size', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.DYNAMIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 1, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + const { size = 1 } = feature; + return Array.isArray(size) ? [size[0]] : [size as number]; + }, + }, + }); + + this.styleAttributeService.registerStyleAttribute({ + name: 'instance', // 弧线起始点信息 + type: AttributeType.Attribute, + descriptor: { + name: 'a_Instance', + buffer: { + usage: gl.STATIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 4, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + return [vertex[3], vertex[4], vertex[5], vertex[6]]; + }, + }, + }); + } +} diff --git a/packages/layers/src/line/models/index.ts b/packages/layers/src/line/models/index.ts index 54a3a124e8..d5ab6eb73a 100644 --- a/packages/layers/src/line/models/index.ts +++ b/packages/layers/src/line/models/index.ts @@ -1,12 +1,19 @@ import ArcModel from './arc'; import Arc3DModel from './arc_3d'; +import ArcMiniModel from './arcmini'; import GreatCircleModel from './great_circle'; import LineModel from './line'; -export type LineModelType = 'arc' | 'arc3d' | 'greatcircle' | 'line'; +export type LineModelType = + | 'arc' + | 'arcmini' + | 'arc3d' + | 'greatcircle' + | 'line'; const LineModels: { [key in LineModelType]: any } = { arc: ArcModel, + arcmini: ArcMiniModel, arc3d: Arc3DModel, greatcircle: GreatCircleModel, line: LineModel, diff --git a/packages/layers/src/line/shaders/line_arcmini_frag.glsl b/packages/layers/src/line/shaders/line_arcmini_frag.glsl new file mode 100644 index 0000000000..e8058285c0 --- /dev/null +++ b/packages/layers/src/line/shaders/line_arcmini_frag.glsl @@ -0,0 +1,42 @@ +#define LineTypeSolid 0.0 +#define Animate 0.0 + +uniform float u_opacity; +uniform float u_blur : 0.9; +// varying vec2 v_normal; +varying vec4 v_color; + +uniform float u_time; +uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ]; + +uniform float segmentNumber; +varying float v_distance_ratio; + +uniform float u_linearColor: 0; +uniform vec4 u_sourceColor; +uniform vec4 u_targetColor; + +#pragma include "picking" + +void main() { + + // 设置弧线的底色 + if(u_linearColor == 1.0) { // 使用渐变颜色 + gl_FragColor = mix(u_sourceColor, u_targetColor, v_distance_ratio); + } else { // 使用 color 方法传入的颜色 + gl_FragColor = v_color; + } + + + gl_FragColor.a *= u_opacity; + + if(u_aimate.x == Animate) { + float animateSpeed = u_time / u_aimate.y; // 运动速度 + float alpha =1.0 - fract( mod(1.0- v_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + u_time / u_aimate.y); + alpha = (alpha + u_aimate.w -1.0) / u_aimate.w; + // alpha = smoothstep(0., 1., alpha); + alpha = clamp(alpha, 0.0, 1.0); + gl_FragColor.a *= alpha; + } + gl_FragColor = filterColor(gl_FragColor); +} \ No newline at end of file diff --git a/packages/layers/src/line/shaders/line_arcmini_vert.glsl b/packages/layers/src/line/shaders/line_arcmini_vert.glsl new file mode 100644 index 0000000000..af4356601f --- /dev/null +++ b/packages/layers/src/line/shaders/line_arcmini_vert.glsl @@ -0,0 +1,105 @@ +#define LineTypeSolid 0.0 +#define LineTypeDash 1.0 +#define Animate 0.0 + +attribute vec4 a_Color; +attribute vec3 a_Position; +attribute vec4 a_Instance; +attribute float a_Size; +uniform mat4 u_ModelMatrix; +uniform mat4 u_Mvp; +uniform float segmentNumber; +uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ]; +varying vec4 v_color; +// varying vec2 v_normal; + +uniform float u_lineDir: 1.0; + +// 偏移量 +uniform float u_thetaOffset: 0.314; + +uniform float u_opacity: 1.0; +varying float v_distance_ratio; + +#pragma include "projection" +#pragma include "project" +#pragma include "picking" + +float bezier3(vec3 arr, float t) { + float ut = 1. - t; + return (arr.x * ut + arr.y * t) * ut + (arr.y * ut + arr.z * t) * t; +} +vec2 midPoint(vec2 source, vec2 target) { + vec2 center = target - source; + float r = length(center); + float theta = atan(center.y, center.x); + float thetaOffset = u_thetaOffset; + float r2 = r / 2.0 / cos(thetaOffset); + float theta2 = theta + thetaOffset; + vec2 mid = vec2(r2*cos(theta2) + source.x, r2*sin(theta2) + source.y); + if(u_lineDir == 1.0) { // 正向 + return mid; + } else { // 逆向 + // (mid + vmin)/2 = (s + t)/2 + vec2 vmid = source + target - mid; + return vmid; + } + // return mid; +} +float getSegmentRatio(float index) { + return smoothstep(0.0, 1.0, index / (segmentNumber - 1.)); +} +vec2 interpolate (vec2 source, vec2 target, float t) { + // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation + vec2 mid = midPoint(source, target); + vec3 x = vec3(source.x, mid.x, target.x); + vec3 y = vec3(source.y, mid.y, target.y); + return vec2(bezier3(x ,t), bezier3(y,t)); +} +vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) { + // normalized direction of the line + vec2 dir_screenspace = normalize(line_clipspace); + // rotate by 90 degrees + dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); + vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size) / 2.0; + return offset; +} +vec2 getNormal(vec2 line_clipspace, float offset_direction) { + // normalized direction of the line + vec2 dir_screenspace = normalize(line_clipspace); + // rotate by 90 degrees + dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x); + return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(offset_direction); +} + +void main() { + v_color = a_Color; + + vec2 source = a_Instance.rg; // 起始点 + vec2 target = a_Instance.ba; // 终点 + float segmentIndex = a_Position.x; + 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; + + if(u_aimate.x == Animate && u_lineDir != 1.0) { + v_distance_ratio = 1.0 - v_distance_ratio; + } + + vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0)); + vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0)); + // v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y); + //unProjCustomCoord + + vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y)); + + if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x + gl_Position = u_Mvp * (vec4(curr.xy + offset, 0, 1.0)); + } else { + gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0)); + } + setPickingColor(a_PickingColor); +} diff --git a/packages/maps/src/amap/map.ts b/packages/maps/src/amap/map.ts index a4617729d0..1260b0fec5 100644 --- a/packages/maps/src/amap/map.ts +++ b/packages/maps/src/amap/map.ts @@ -61,6 +61,9 @@ export default class AMapService */ public map: AMap.Map & IAMapInstance; + // TODO: 判断地图是否正在拖拽 + public dragging: boolean = false; + // 背景色 public bgColor: string = 'rgba(0, 0, 0, 0)'; @@ -403,6 +406,16 @@ export default class AMapService } }); + // TODO: 判断地图是否正在被拖拽 + this.map.on('dragstart', () => { + this.dragging = true; + return ''; + }); + this.map.on('dragend', () => { + this.dragging = false; + return ''; + }); + this.viewport = new Viewport(); } diff --git a/packages/maps/src/amap2/map.ts b/packages/maps/src/amap2/map.ts index 1ff15c130b..ed3e137e11 100644 --- a/packages/maps/src/amap2/map.ts +++ b/packages/maps/src/amap2/map.ts @@ -64,6 +64,9 @@ export default class AMapService */ public map: AMap.Map & IAMapInstance; + // TODO: 判断地图是否正在拖拽 + public dragging: boolean = false; + /** * 用于 customCooords 数据的计算 */ @@ -494,6 +497,16 @@ export default class AMapService } } }); + + // TODO: 判断地图是否正在被拖拽 + this.map.on('dragstart', () => { + this.dragging = true; + return ''; + }); + this.map.on('dragend', () => { + this.dragging = false; + return ''; + }); } public exportMap(type: 'jpg' | 'png'): string { diff --git a/packages/maps/src/earth/map.ts b/packages/maps/src/earth/map.ts index 7c25a28352..4dff58130d 100644 --- a/packages/maps/src/earth/map.ts +++ b/packages/maps/src/earth/map.ts @@ -42,6 +42,9 @@ export default class L7EarthService implements IEarthService { public version: string = Version.GLOBEL; public map: Map; + // TODO: 判断地图是否正在拖拽 + public dragging: boolean = false; + // 背景色 public bgColor: string = '#000'; diff --git a/packages/maps/src/map/map.ts b/packages/maps/src/map/map.ts index 2c11cfbafd..4fe4b4c824 100644 --- a/packages/maps/src/map/map.ts +++ b/packages/maps/src/map/map.ts @@ -43,6 +43,9 @@ export default class L7MapService implements IMapService { public version: string = Version.L7MAP; public map: Map; + // TODO: 判断地图是否正在拖拽 + public dragging: boolean = false; + // 背景色 public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)'; @@ -280,6 +283,16 @@ export default class L7MapService implements IMapService { this.map.on('load', this.handleCameraChanged); this.map.on('move', this.handleCameraChanged); + // TODO: 判断地图是否正在被拖拽 + this.map.on('dragstart', () => { + this.dragging = true; + return ''; + }); + this.map.on('dragend', () => { + this.dragging = false; + return ''; + }); + // 不同于高德地图,需要手动触发首次渲染 this.handleCameraChanged(); } diff --git a/packages/maps/src/mapbox/map.ts b/packages/maps/src/mapbox/map.ts index 166b618485..1651be7036 100644 --- a/packages/maps/src/mapbox/map.ts +++ b/packages/maps/src/mapbox/map.ts @@ -50,6 +50,9 @@ export default class MapboxService public version: string = Version.MAPBOX; public map: Map & IMapboxInstance; + // TODO: 判断地图是否正在拖拽 + public dragging: boolean = false; + // 背景色 public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)'; @@ -363,6 +366,16 @@ export default class MapboxService this.map.on('load', this.handleCameraChanged); this.map.on('move', this.handleCameraChanged); + // TODO: 判断地图是否正在被拖拽 + this.map.on('dragstart', () => { + this.dragging = true; + return ''; + }); + this.map.on('dragend', () => { + this.dragging = false; + return ''; + }); + // 不同于高德地图,需要手动触发首次渲染 this.handleCameraChanged(); } diff --git a/stories/MapPerformance/components/BigLine.tsx b/stories/MapPerformance/components/BigLine.tsx new file mode 100644 index 0000000000..ff9bade068 --- /dev/null +++ b/stories/MapPerformance/components/BigLine.tsx @@ -0,0 +1,75 @@ +// @ts-nocheck +// @ts-ignore +import { Scene } from '@antv/l7'; +import { PointLayer, LineLayer } from '@antv/l7-layers'; +import { GaodeMap, Mapbox } from '@antv/l7-maps'; +import * as React from 'react'; + +export default class PointTest extends React.Component { + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + center: [110.19382669582967, 30.258134], + pitch: 0, + zoom: 4, + }), + }); + + let address = + 'https://gw.alipayobjects.com/os/bmw-prod/3f2f9284-3fb1-4838-8baa-6ffd06738fcd.csv'; + fetch(address) + .then((res) => res.text()) + .then((data) => { + const lineLayer = new LineLayer({ + autoFit: true, + blend: 'normal', + }) + .source(data, { + parser: { + type: 'csv', + x: 'f_lon', + y: 'f_lat', + x1: 't_lon', + y1: 't_lat', + }, + }) + .shape('arcmini') + .size(2) + .color('rgb(13,64,140)') + .style({ + segmentNumber: 30, + }) + .select({ + color: '#ff0', + }) + .active({ + color: '#ff0', + }); + // .animate(true) + + scene.addLayer(lineLayer); + }); + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/MapPerformance/components/Map.tsx b/stories/MapPerformance/components/Map.tsx index ad7ea9f9fd..f1e0c14703 100644 --- a/stories/MapPerformance/components/Map.tsx +++ b/stories/MapPerformance/components/Map.tsx @@ -1,3 +1,4 @@ +// @ts-nocheck // @ts-ignore import { Scene } from '@antv/l7'; import { PointLayer } from '@antv/l7-layers'; @@ -169,32 +170,6 @@ export default class PointTest extends React.Component { scene.on('loaded', () => { scene.addLayer(layer); - // @ts-ignore - // layer.layerService.startAnimate2(stats) - - // ILayerService - // --- - // startAnimate2(state: any): void; - // --- - // LayerService - // --- - // private stats: any; - // --- - // @ts-ignore - // public startAnimate2(stats) { - // // @ts-ignore - // this.stats = stats - // if (this.animateInstanceCount++ === 0) { - // this.clock.start(); - // this.runRender(); - // } - // } - // public runRender() { - // // @ts-ignore - // this.stats.update() - // this.renderLayers(); - // this.layerRenderID = requestAnimationFrame(this.runRender.bind(this)); - // } }); }); } diff --git a/stories/MapPerformance/map.stories.tsx b/stories/MapPerformance/map.stories.tsx index 8e879b3e2d..7f62d0746a 100644 --- a/stories/MapPerformance/map.stories.tsx +++ b/stories/MapPerformance/map.stories.tsx @@ -2,6 +2,8 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; import PointTest from './components/Map'; +import BigLine from './components/BigLine' // @ts-ignore storiesOf('地图性能检测', module) .add('点', () => ) +.add('BigLine', () => )