This commit is contained in:
2912401452 2021-10-26 17:59:59 +08:00
commit e0757ed868
17 changed files with 446 additions and 34 deletions

View File

@ -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;

View File

@ -384,5 +384,6 @@ export interface ILayerService {
updateRenderOrder(): void;
renderLayers(type?: string): void;
getOESTextureFloat(): boolean;
isMapDragging(): boolean;
destroy(): void;
}

View File

@ -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);
}

View File

@ -32,6 +32,7 @@ export interface IMapWrapper {
export interface IMapService<RawMap = {}> {
version?: string;
map: RawMap;
dragging: boolean;
bgColor: string;
setBgColor(color: string): void;
init(): void;

View File

@ -31,6 +31,7 @@ export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
line: {},
arc3d: { blend: 'additive' },
arc: { blend: 'additive' },
arcmini: { blend: 'additive' },
greatcircle: { blend: 'additive' },
};
return defaultConfig[type];

View File

@ -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]];
},
},
});
}
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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 {

View File

@ -42,6 +42,9 @@ export default class L7EarthService implements IEarthService<Map> {
public version: string = Version.GLOBEL;
public map: Map;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
// 背景色
public bgColor: string = '#000';

View File

@ -43,6 +43,9 @@ export default class L7MapService implements IMapService<Map> {
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<Map> {
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();
}

View File

@ -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();
}

View File

@ -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 (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -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));
// }
});
});
}

View File

@ -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('点', () => <PointTest />)
.add('BigLine', () => <BigLine />)