mirror of https://gitee.com/antv-l7/antv-l7
feat(layer): add arc2d layer
This commit is contained in:
parent
dd97c55ac4
commit
d5155afcac
|
@ -136,7 +136,11 @@ export function RasterImageTriangulation(feature: IEncodeFeature) {
|
|||
size: 5,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3D弧线顶点
|
||||
* @param feature 映射数据
|
||||
* @param segNum 弧线线段数
|
||||
*/
|
||||
export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) {
|
||||
const coordinates = feature.coordinates as IPosition[];
|
||||
const positions = [];
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { container, ILayerPlugin, TYPES } from '@l7/core';
|
||||
import BaseLayer from './core/BaseLayer';
|
||||
import HeatMapGridLayer from './heatmap/grid';
|
||||
import LineLayer from './line/index';
|
||||
import ArcLineLayer from './line/arc';
|
||||
import Arc2DLineLayer from './line/arc2d';
|
||||
import LineLayer from './line/index';
|
||||
import Point3dLayer from './point/extrude';
|
||||
import PointImageLayer from './point/image';
|
||||
import PointLayer from './point/index';
|
||||
|
@ -74,6 +75,7 @@ export {
|
|||
ImageLayer,
|
||||
HeatMapGridLayer,
|
||||
ArcLineLayer,
|
||||
Arc2DLineLayer,
|
||||
// Line,
|
||||
// ImageLayer,
|
||||
// HeatMapLayer,
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { LineArcTriangulation } from '../core/triangulation';
|
||||
import line_arc2d_vert from './shaders/line_arc2d_vert.glsl';
|
||||
import line_arc_frag from './shaders/line_arc_frag.glsl';
|
||||
interface IArcLayerStyleOptions {
|
||||
opacity: number;
|
||||
segmentNumber: number;
|
||||
}
|
||||
export default class Arc2DLineLayer extends BaseLayer<IArcLayerStyleOptions> {
|
||||
public name: string = 'LineLayer';
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
const { opacity } = this.getStyleOptions();
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
uniforms: {
|
||||
u_Opacity: opacity || 1,
|
||||
segmentNumber: 30,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected buildModels() {
|
||||
this.registerBuiltinAttributes(this);
|
||||
this.models = [
|
||||
this.buildLayerModel({
|
||||
moduleName: 'arc2dline',
|
||||
vertexShader: line_arc2d_vert,
|
||||
fragmentShader: line_arc_frag,
|
||||
triangulation: LineArcTriangulation,
|
||||
depth: { enable: false },
|
||||
blend: {
|
||||
enable: true,
|
||||
func: {
|
||||
srcRGB: gl.ONE,
|
||||
srcAlpha: 1,
|
||||
dstRGB: gl.ONE,
|
||||
dstAlpha: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private registerBuiltinAttributes(layer: ILayer) {
|
||||
// point layer size;
|
||||
layer.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 } = feature;
|
||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
layer.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]];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
precision mediump float;
|
||||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float segmentNumber;
|
||||
varying vec4 v_color;
|
||||
|
||||
#pragma include "projection"
|
||||
|
||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
||||
}
|
||||
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.));
|
||||
}
|
||||
|
||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
||||
vec2 x = mix(source, target, ratio);
|
||||
vec2 center = mix(source, target, 0.5);
|
||||
float dSourceCenter = distance(source, center);
|
||||
float dXCenter = distance(x, center);
|
||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
|
||||
}
|
||||
|
||||
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
|
||||
float vertex_height = paraboloid(source, target, segmentRatio);
|
||||
|
||||
return vec3(
|
||||
mix(source, target, segmentRatio),
|
||||
sqrt(max(0.0, vertex_height))
|
||||
);
|
||||
}
|
||||
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 * a_Size / 2.0;
|
||||
return offset;
|
||||
}
|
||||
float getAngularDist (vec2 source, vec2 target) {
|
||||
vec2 delta = source - target;
|
||||
vec2 sin_half_delta = sin(delta / 2.0);
|
||||
float a =
|
||||
sin_half_delta.y * sin_half_delta.y +
|
||||
cos(source.y) * cos(target.y) *
|
||||
sin_half_delta.x * sin_half_delta.x;
|
||||
return 2.0 * atan(sqrt(a), sqrt(1.0 - a));
|
||||
}
|
||||
vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) {
|
||||
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
|
||||
if(abs(angularDist - PI) < 0.001) {
|
||||
return (1.0 - t) * source + t * target;
|
||||
}
|
||||
float a = sin((1.0 - t) * angularDist) / sin(angularDist);
|
||||
float b = sin(t * angularDist) / sin(angularDist);
|
||||
vec2 sin_source = sin(source);
|
||||
vec2 cos_source = cos(source);
|
||||
vec2 sin_target = sin(target);
|
||||
vec2 cos_target = cos(target);
|
||||
float x = a * cos_source.y * cos_source.x + b * cos_target.y * cos_target.x;
|
||||
float y = a * cos_source.y * sin_source.x + b * cos_target.y * sin_target.x;
|
||||
float z = a * sin_source.y + b * sin_target.y;
|
||||
return vec2(atan(y, x), atan(z, sqrt(x * x + y * y)));
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec2 source = radians(a_Instance.rg);
|
||||
vec2 target = radians(a_Instance.ba);
|
||||
float angularDist = getAngularDist(source, target);
|
||||
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);
|
||||
|
||||
vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0));
|
||||
vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0));
|
||||
|
||||
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
|
||||
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ uniform mat4 u_ModelMatrix;
|
|||
varying vec4 v_color;
|
||||
varying float v_dash_array;
|
||||
varying vec3 v_normal;
|
||||
|
||||
#pragma include "projection"
|
||||
void main() {
|
||||
v_normal = a_Normal;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import Arc2DLineDemo from './components/Arc2DLine';
|
||||
import ArcLineDemo from './components/Arcline';
|
||||
import GridHeatMap from './components/heatMapgrid';
|
||||
import LineLayer from './components/Line';
|
||||
|
@ -16,6 +17,7 @@ storiesOf('图层', module)
|
|||
.add('图片标注', () => <PointImage />)
|
||||
.add('面3d图层', () => <Polygon3D />)
|
||||
.add('线图层', () => <LineLayer />)
|
||||
.add('弧线', () => <ArcLineDemo />)
|
||||
.add('3D弧线', () => <ArcLineDemo />)
|
||||
.add('2D弧线', () => <Arc2DLineDemo />)
|
||||
.add('网格热力图', () => <GridHeatMap />)
|
||||
.add('图片', () => <ImageLayerDemo />);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import { Arc2DLineLayer } from '@l7/layers';
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Arc2DLineDemo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt',
|
||||
);
|
||||
const scene = new Scene({
|
||||
center: [116.2825, 39.9],
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/dark-v9',
|
||||
zoom: 2,
|
||||
});
|
||||
const lineLayer = new Arc2DLineLayer({})
|
||||
.source(await response.text(), {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng1',
|
||||
y: 'lat1',
|
||||
x1: 'lng2',
|
||||
y1: 'lat2',
|
||||
},
|
||||
})
|
||||
.size(0.5)
|
||||
.shape('arc')
|
||||
.color('rgb(13,64,140)');
|
||||
scene.addLayer(lineLayer);
|
||||
scene.render();
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import { ArcLineLayer } from '@l7/layers';
|
|||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class ArxLineDemo extends React.Component {
|
||||
export default class ArcLineDemo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
|
|
Loading…
Reference in New Issue