Shihuidev (#890)

* feat: 增加着色器的拾取计算控制、完善 arcmini

* feat: 完善 enableShaderPick/disableShaderPick 功能

* style: lint style

* feat: 补充调用高德地图公交线路查询 demo

* style: lint style

* feat: 优化弧线的纹理动画

* style: lint style

* feat: 去除greatCircle 的纹理动画优化

* feat: 扩展点图层圆柱效果

* feat: 增加几何体的径向渐变配置

* style: lint style

* fix: 修复bug 图层触发的事件跟图层设置的zIndex无关,只跟插入图层先后顺序有关

* style: lint style

* feat: 补全挤出几何体拾取颜色的光照配置

* style: lint style

* fix: 修复圆柱 cull 问题 mapbox amap 不同

* feat: 图层销毁时的内存泄漏

* style: lint style

* feat: 平面弧线新增弧线偏移量的数据映射能力

* style: lint style

* fix: 修复重复销毁bug

* style: lint style

* feat: 修复 texture 重复销毁问题

* style: lint style

* fix: 修复图层叠加模式下的拾取失效问题

* style: lint style

* fix: 修复纹理贴图在 zoom 大于 12 时存在的问题

* fix: 修复水波点颜色偏暗

* feat: 优化点图层的渲染效果,叠加渲染效果

* style: lint style

* fix: 修复 layer contextmenu 事件丢失

* fix: 修复 map 类型 resize 失效

* style: lint style

* feat: 增加瓦片地图的请求节流

* style: lint style

* feat: 优化热力图在 radius 数值比较大时热力点边缘发生裁剪的现象

* style: lint style

* fix: 修复resize 后 picking shiqu 拾取失败的问题

* feat: 优化 marker/popup 在容器边缘的表现

* feat: 增加 setEnableRender 方法

* style: lint style

* feat: 增加城市图层扫光特效

* style: lint style

* feat: 补全拾取色混合配置

* style: lint style

* feat: 增加高德地图的面积大小点

* style: lint style

* feat: 点优化边缘锯齿

* fix: 修复pointLayer stroke 变暗问题

* fix: 修复混合导致的拾取错误

* feat: add simple point 1.0

* style: lint style

* feat: simple point support stroke

* style: lint style
This commit is contained in:
YiQianYao 2021-12-22 15:01:19 +08:00 committed by GitHub
parent c381840dba
commit 28ebfefea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 408 additions and 0 deletions

View File

@ -33,6 +33,7 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
normal: {
blend: 'additive',
},
simplePoint: {},
fill: { blend: 'normal' },
extrude: {},
image: {},
@ -60,6 +61,9 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
if (shape === 'dot') {
return 'normal';
}
if (shape === 'simple') {
return 'simplePoint';
}
if (shape2d?.indexOf(shape as string) !== -1) {
return 'fill';
}

View File

@ -4,12 +4,14 @@ import FillModel from './fill';
import IconModel from './icon-font';
import IMageModel from './image';
import NormalModel from './normal';
import SimplePopint from './simplePoint';
import TextModel from './text';
export type PointType =
| 'fill'
| 'image'
| 'normal'
| 'simplePoint'
| 'extrude'
| 'text'
| 'icon';
@ -18,6 +20,7 @@ const PointModels: { [key in PointType]: any } = {
fill: FillModel,
image: IMageModel,
normal: NormalModel,
simplePoint: SimplePopint,
extrude: ExtrudeModel,
text: TextModel,
icon: IconModel,

View File

@ -0,0 +1,164 @@
import {
AttributeType,
BlendType,
gl,
IEncodeFeature,
ILayerConfig,
IModel,
IModelUniform,
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import { isNumber } from 'lodash';
import BaseModel, {
styleColor,
styleOffset,
styleSingle,
} from '../../core/BaseModel';
import { BlendTypes } from '../../utils/blend';
import simplePointFrag from '../shaders/simplePoint_frag.glsl';
import simplePointVert from '../shaders/simplePoint_vert.glsl';
interface IPointLayerStyleOptions {
opacity: styleSingle;
offsets: styleOffset;
blend: string;
strokeOpacity: styleSingle;
strokeWidth: styleSingle;
stroke: styleColor;
}
export function PointTriangulation(feature: IEncodeFeature) {
const coordinates = feature.coordinates as number[];
return {
vertices: [...coordinates],
indices: [0],
size: coordinates.length,
};
}
export default class SimplePointModel extends BaseModel {
public getDefaultStyle(): Partial<IPointLayerStyleOptions & ILayerConfig> {
return {
blend: 'additive',
};
}
public getUninforms(): IModelUniform {
const {
opacity = 1,
offsets = [0, 0],
blend,
strokeOpacity = 1,
strokeWidth = 0,
stroke = '#fff',
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
if (
this.dataTextureTest &&
this.dataTextureNeedUpdate({
opacity,
offsets,
})
) {
// 判断当前的样式中哪些是需要进行数据映射的,哪些是常量,同时计算用于构建数据纹理的一些中间变量
this.judgeStyleAttributes({
opacity,
offsets,
});
const encodeData = this.layer.getEncodedData();
const { data, width, height } = this.calDataFrame(
this.cellLength,
encodeData,
this.cellProperties,
);
this.rowCount = height; // 当前数据纹理有多少行
this.dataTexture =
this.cellLength > 0 && data.length > 0
? this.createTexture2D({
flipY: true,
data,
format: gl.LUMINANCE,
type: gl.FLOAT,
width,
height,
})
: this.createTexture2D({
flipY: true,
data: [1],
format: gl.LUMINANCE,
type: gl.FLOAT,
width: 1,
height: 1,
});
}
return {
u_additive: blend === 'additive' ? 1.0 : 0.0,
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
u_cellTypeLayout: this.getCellTypeLayout(),
u_opacity: isNumber(opacity) ? opacity : 1.0,
u_offsets: this.isOffsetStatic(offsets)
? (offsets as [number, number])
: [0, 0],
u_stroke_opacity: isNumber(strokeOpacity) ? strokeOpacity : 1.0,
u_stroke_width: isNumber(strokeWidth) ? strokeWidth : 0.0,
u_stroke_color: this.getStrokeColor(stroke),
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({
moduleName: 'simplepoint',
vertexShader: simplePointVert,
fragmentShader: simplePointFrag,
triangulation: PointTriangulation,
depth: { enable: false },
primitive: gl.POINTS,
blend: this.getBlend(),
}),
];
}
public clearModels() {
this.dataTexture?.destroy();
}
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];
},
},
});
}
private defaultStyleOptions(): Partial<
IPointLayerStyleOptions & ILayerConfig
> {
return {
blend: BlendType.additive,
};
}
}

View File

@ -0,0 +1,57 @@
uniform float u_opacity : 1;
uniform vec2 u_offsets;
uniform float u_additive;
uniform float u_stroke_opacity : 1;
uniform vec4 u_stroke_color : [0.0, 0.0, 0.0, 0.0];
varying vec4 v_color;
varying mat4 styleMappingMat; // 传递从片元中传递的映射数据
varying float v_blur;
varying float v_innerRadius;
#pragma include "picking"
void main() {
vec2 center = vec2(0.5);
float opacity = styleMappingMat[0][0];
// Tip: 片元到中心点的距离 0 - 1
float fragmengTocenter = distance(center, gl_PointCoord) * 2.0;
// Tip: 片元的剪切成圆形
float circleClipOpacity = 1.0 - smoothstep(v_blur, 1.0, fragmengTocenter);
if(v_innerRadius < 0.99) {
// 当存在 stroke 且 stroke > 0.01
float blurWidth = (1.0 - v_blur)/2.0;
vec4 stroke = vec4(u_stroke_color.rgb, u_stroke_opacity);
if(fragmengTocenter > v_innerRadius + blurWidth) {
gl_FragColor = stroke;
} else if(fragmengTocenter > v_innerRadius - blurWidth){
float mixR = (fragmengTocenter - (v_innerRadius - blurWidth)) / (blurWidth * 2.0);
gl_FragColor = mix(v_color, stroke, mixR);
} else {
gl_FragColor = v_color;
}
} else {
// 当不存在 stroke 或 stroke <= 0.01
gl_FragColor = v_color;
}
gl_FragColor.a *= opacity;
gl_FragColor = filterColor(gl_FragColor);
if(u_additive > 0.0) {
gl_FragColor *= circleClipOpacity;
} else {
gl_FragColor.a *= circleClipOpacity;
}
}

View File

@ -0,0 +1,84 @@
attribute vec3 a_Position;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
attribute float a_Size;
attribute vec4 a_Color;
varying vec4 v_color;
uniform float u_opacity : 1;
uniform vec2 u_offsets;
uniform float u_stroke_width;
varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样式值传递给片元
varying float v_blur;
varying float v_innerRadius;
#pragma include "styleMapping"
#pragma include "styleMappingCalOpacity"
#pragma include "projection"
#pragma include "picking"
#pragma include "project"
void main() {
v_color = a_Color;
v_blur = 1.0 - 0.05;
v_innerRadius = max((a_Size - u_stroke_width) / a_Size, 0.0);
// cal style mapping - 数据纹理映射部分的计算
styleMappingMat = mat4(
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
float columnCount = u_cellTypeLayout[0][1]; // 当看到数据纹理有几列
float columnWidth = 1.0/columnCount; // 列宽
float rowHeight = 1.0/rowCount; // 行高
float cellCount = calCellCount(); // opacity - strokeOpacity - strokeWidth - stroke - offsets
float id = a_vertexId; // 第n个顶点
float cellCurrentRow = floor(id * cellCount / columnCount) + 1.0; // 起始点在第几行
float cellCurrentColumn = mod(id * cellCount, columnCount) + 1.0; // 起始点在第几列
// cell 固定顺序 opacity -> strokeOpacity -> strokeWidth -> stroke ...
// 按顺序从 cell 中取值、若没有则自动往下取值
float textureOffset = 0.0; // 在 cell 中取值的偏移量
vec2 opacityAndOffset = calOpacityAndOffset(cellCurrentRow, cellCurrentColumn, columnCount, textureOffset, columnWidth, rowHeight);
styleMappingMat[0][0] = opacityAndOffset.r;
textureOffset = opacityAndOffset.g;
vec2 textrueOffsets = vec2(0.0, 0.0);
if(hasOffsets()) {
vec2 valueXPos = nextPos(cellCurrentRow, cellCurrentColumn, columnCount, textureOffset);
textrueOffsets.r = pos2value(valueXPos, columnWidth, rowHeight); // x
textureOffset += 1.0;
vec2 valueYPos = nextPos(cellCurrentRow, cellCurrentColumn, columnCount, textureOffset);
textrueOffsets.g = pos2value(valueYPos, columnWidth, rowHeight); // x
textureOffset += 1.0;
} else {
textrueOffsets = u_offsets;
}
// cal style mapping
// vec2 offset = project_pixel(u_offsets);
vec2 offset = project_pixel(textrueOffsets);
// vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
// gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));\
//
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
// vec2 offset = project_pixel((u_offsets));
gl_Position = u_Mvp * vec4(a_Position.xy + offset, a_Position.z, 1.0);
} else { // else
// vec2 offset = project_pixel(u_offsets);
vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));
}
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
setPickingColor(a_PickingColor);
}

View File

@ -95,6 +95,14 @@ export default class GaodeMapComponent extends React.Component {
scene.on('loaded', () => {
scene.addLayer(layer);
// scene.addLayer(trufCircle);
// scene.on('movestart', e => console.log('e', e))
// scene.on('mapmove', e => console.log('e', e))
// scene.on('moveend', e => console.log('e', e))
// scene.on('zoomstart', e => console.log('e', e))
// scene.on('zoomchange', e => console.log('e', e))
// scene.on('zoomend', e => console.log('e', e))
// scene.on('mousedown', e => console.log('e', e))
});
let c = 1;
layer.on('click', () => {

View File

@ -0,0 +1,86 @@
// @ts-ignore
import { PointLayer, Scene, LineLayer, PolygonLayer } from '@antv/l7';
import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps';
import * as React from 'react';
export default class SimplePoint extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [121.107846, 30.267069],
pitch: 0,
// style: 'dark',
zoom: 15,
}),
});
// normal = 'normal',
// additive = 'additive',
// subtractive = 'subtractive',
// min = 'min',
// max = 'max',
// none = 'none',
// blend: 'additive'
let layer = new PointLayer({ blend: 'additive' })
.source(
[
{
lng: 121.107846,
lat: 30.267069,
},
{
lng: 121.1,
lat: 30.267069,
},
],
{
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
},
)
.shape('simple')
.color('#800')
.size(50)
.style({
stroke: '#f00',
strokeOpacity: 0.5,
strokeWidth: 10,
opacity: 0.5,
})
.active({ color: '#00f' });
this.scene = scene;
scene.on('loaded', () => {
scene.addLayer(layer);
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -69,6 +69,7 @@ import DestroyClear from './components/destroyClear'
import PlaneLine from './components/planeLine'
import Slider from './components/slider'
import WindMap from './components/amap2demo_wind'
import SimplePoint from './components/simplePoint';
// @ts-ignore
storiesOf('地图方法', module)
@ -142,3 +143,4 @@ storiesOf('地图方法', module)
.add('DestroyClear', () => <DestroyClear/>)
.add('PlaneLine', () => <PlaneLine/>)
.add('Slider', () => <Slider/>)
.add('SimplePoint', () => <SimplePoint/>)