Shihuidev (#887)

* 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: 点优化边缘锯齿
This commit is contained in:
YiQianYao 2021-12-21 13:57:48 +08:00 committed by GitHub
parent 56ec1259af
commit 7e73477219
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 203 additions and 30 deletions

View File

@ -70,7 +70,9 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
enableHighlight: false, enableHighlight: false,
enableSelect: false, enableSelect: false,
highlightColor: '#2f54eb', highlightColor: '#2f54eb',
activeMix: 0,
selectColor: 'blue', selectColor: 'blue',
selectMix: 0,
enableTAA: false, enableTAA: false,
jitterScale: 1, jitterScale: 1,
enableLighting: false, enableLighting: false,

View File

@ -87,6 +87,7 @@ export interface IPickedFeature {
// 交互样式 // 交互样式
export interface IActiveOption { export interface IActiveOption {
color: string | number[]; color: string | number[];
mix?: number;
} }
type ILngLat = [number, number]; type ILngLat = [number, number];
@ -339,6 +340,8 @@ export interface ILayerConfig {
selectColor: string | number[]; selectColor: string | number[];
active: boolean; active: boolean;
activeColor: string | number[]; activeColor: string | number[];
activeMix?: number;
selectMix?: number;
/** /**
* TAA * TAA
*/ */

View File

@ -3,6 +3,8 @@ uniform vec4 u_HighlightColor : [0, 0, 0, 0];
uniform float u_PickingStage : 0.0; uniform float u_PickingStage : 0.0;
uniform float u_shaderPick; uniform float u_shaderPick;
uniform float u_activeMix: 0;
#define PICKING_NONE 0.0 #define PICKING_NONE 0.0
#define PICKING_ENCODE 1.0 #define PICKING_ENCODE 1.0
#define PICKING_HIGHLIGHT 2.0 #define PICKING_HIGHLIGHT 2.0
@ -21,7 +23,7 @@ vec4 filterHighlightColor(vec4 color, float weight) {
float highLightRatio = highLightAlpha / (highLightAlpha + color.a * (1.0 - highLightAlpha)); float highLightRatio = highLightAlpha / (highLightAlpha + color.a * (1.0 - highLightAlpha));
vec3 resultRGB = mix(color.rgb, highLightColor.rgb, highLightRatio); vec3 resultRGB = mix(color.rgb, highLightColor.rgb, highLightRatio);
return vec4(resultRGB * weight, color.a); return vec4(mix(resultRGB * weight, color.rgb, u_activeMix), color.a);
} else { } else {
return color; return color;
} }

View File

@ -570,6 +570,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
if (options.color) { if (options.color) {
activeOption.highlightColor = options.color; activeOption.highlightColor = options.color;
} }
if (options.mix) {
activeOption.activeMix = options.mix;
}
} else { } else {
activeOption.enableHighlight = !!options; activeOption.enableHighlight = !!options;
} }
@ -586,6 +589,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
highlightColor: isObject(options) highlightColor: isObject(options)
? options.color ? options.color
: this.getLayerConfig().highlightColor, : this.getLayerConfig().highlightColor,
activeMix: isObject(options)
? options.mix
: this.getLayerConfig().activeMix,
}); });
this.pick({ x, y }); this.pick({ x, y });
} else { } else {
@ -594,6 +600,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
highlightColor: isObject(options) highlightColor: isObject(options)
? options.color ? options.color
: this.getLayerConfig().highlightColor, : this.getLayerConfig().highlightColor,
activeMix: isObject(options)
? options.mix
: this.getLayerConfig().activeMix,
}); });
this.hooks.beforeSelect this.hooks.beforeSelect
.call(encodePickingColor(id as number) as number[]) .call(encodePickingColor(id as number) as number[])
@ -614,6 +623,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
if (option.color) { if (option.color) {
activeOption.selectColor = option.color; activeOption.selectColor = option.color;
} }
if (option.mix) {
activeOption.selectMix = option.mix;
}
} else { } else {
activeOption.enableSelect = !!option; activeOption.enableSelect = !!option;
} }
@ -631,6 +643,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
selectColor: isObject(options) selectColor: isObject(options)
? options.color ? options.color
: this.getLayerConfig().selectColor, : this.getLayerConfig().selectColor,
selectMix: isObject(options)
? options.mix
: this.getLayerConfig().selectMix,
}); });
this.pick({ x, y }); this.pick({ x, y });
} else { } else {
@ -639,6 +654,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
selectColor: isObject(options) selectColor: isObject(options)
? options.color ? options.color
: this.getLayerConfig().selectColor, : this.getLayerConfig().selectColor,
selectMix: isObject(options)
? options.mix
: this.getLayerConfig().selectMix,
}); });
this.hooks.beforeSelect this.hooks.beforeSelect
.call(encodePickingColor(id as number) as number[]) .call(encodePickingColor(id as number) as number[])

View File

@ -83,7 +83,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
layer.hooks.beforeHighlight.tap( layer.hooks.beforeHighlight.tap(
'PixelPickingPlugin', 'PixelPickingPlugin',
(pickedColor: number[]) => { (pickedColor: number[]) => {
const { highlightColor } = layer.getLayerConfig(); const { highlightColor, activeMix = 0 } = layer.getLayerConfig();
const highlightColorInArray = const highlightColorInArray =
typeof highlightColor === 'string' typeof highlightColor === 'string'
? rgb2arr(highlightColor) ? rgb2arr(highlightColor)
@ -96,6 +96,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
u_PickingStage: PickingStage.HIGHLIGHT, u_PickingStage: PickingStage.HIGHLIGHT,
u_PickingColor: pickedColor, u_PickingColor: pickedColor,
u_HighlightColor: highlightColorInArray.map((c) => c * 255), u_HighlightColor: highlightColorInArray.map((c) => c * 255),
u_activeMix: activeMix,
}), }),
); );
}, },
@ -104,7 +105,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
layer.hooks.beforeSelect.tap( layer.hooks.beforeSelect.tap(
'PixelPickingPlugin', 'PixelPickingPlugin',
(pickedColor: number[]) => { (pickedColor: number[]) => {
const { selectColor } = layer.getLayerConfig(); const { selectColor, selectMix = 0 } = layer.getLayerConfig();
const highlightColorInArray = const highlightColorInArray =
typeof selectColor === 'string' typeof selectColor === 'string'
? rgb2arr(selectColor) ? rgb2arr(selectColor)
@ -117,6 +118,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
u_PickingStage: PickingStage.HIGHLIGHT, u_PickingStage: PickingStage.HIGHLIGHT,
u_PickingColor: pickedColor, u_PickingColor: pickedColor,
u_HighlightColor: highlightColorInArray.map((c) => c * 255), u_HighlightColor: highlightColorInArray.map((c) => c * 255),
u_activeMix: selectMix,
}), }),
); );
}, },

View File

@ -24,7 +24,7 @@ import pointFillVert from '../shaders/fill_vert.glsl';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import { mat4, vec3 } from 'gl-matrix'; import { mat4, vec3 } from 'gl-matrix';
import { Version } from '../../../../maps/src/version';
interface IPointLayerStyleOptions { interface IPointLayerStyleOptions {
opacity: styleSingle; opacity: styleSingle;
strokeWidth: styleSingle; strokeWidth: styleSingle;
@ -32,9 +32,12 @@ interface IPointLayerStyleOptions {
strokeOpacity: styleSingle; strokeOpacity: styleSingle;
offsets: styleOffset; offsets: styleOffset;
blend: string; blend: string;
unit: string;
} }
// 判断当前使用的 style 中的变量属性是否需要进行数据映射 // 判断当前使用的 style 中的变量属性是否需要进行数据映射
export default class FillModel extends BaseModel { export default class FillModel extends BaseModel {
public meter2coord: number = 1;
private isMeter: boolean = false;
public getUninforms(): IModelUniform { public getUninforms(): IModelUniform {
const { const {
opacity = 1, opacity = 1,
@ -92,8 +95,10 @@ export default class FillModel extends BaseModel {
}); });
} }
return { return {
u_isMeter: Number(this.isMeter),
u_additive: blend === 'additive' ? 1.0 : 0.0, u_additive: blend === 'additive' ? 1.0 : 0.0,
u_globel: this.mapService.version === 'GLOBEL' ? 1 : 0, u_globel: this.mapService.version === Version.GLOBEL ? 1 : 0,
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1] u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
u_cellTypeLayout: this.getCellTypeLayout(), u_cellTypeLayout: this.getCellTypeLayout(),
@ -127,9 +132,38 @@ export default class FillModel extends BaseModel {
} }
public initModels(): IModel[] { public initModels(): IModel[] {
const {
unit = 'l7size',
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
const { version } = this.mapService;
if (
unit === 'meter' &&
version !== Version.L7MAP &&
version !== Version.GLOBEL &&
version !== Version.MAPBOX
) {
this.isMeter = true;
this.calMeter2Coord();
}
return this.buildModels(); return this.buildModels();
} }
public calMeter2Coord() {
// @ts-ignore
const [minLng, minLat, maxLng, maxLat] = this.layer.getSource().extent;
const center = [(minLng + maxLng) / 2, (minLat + maxLat) / 2];
// @ts-ignore
const m1 = this.mapService.meterToCoord(center, [minLng, minLat]);
// @ts-ignore
const m2 = this.mapService.meterToCoord(center, [
maxLng === minLng ? maxLng + 0.1 : maxLng,
maxLat === minLat ? minLat + 0.1 : maxLat,
]);
this.meter2coord = (m1 + m2) / 2;
}
public buildModels(): IModel[] { public buildModels(): IModel[] {
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式 // TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
const isGlobel = this.mapService.version === 'GLOBEL'; const isGlobel = this.mapService.version === 'GLOBEL';
@ -246,7 +280,9 @@ export default class FillModel extends BaseModel {
) => { ) => {
const { size = 5 } = feature; const { size = 5 } = feature;
// console.log('featureIdx', featureIdx, feature) // console.log('featureIdx', featureIdx, feature)
return Array.isArray(size) ? [size[0]] : [size as number]; return Array.isArray(size)
? [size[0] * this.meter2coord]
: [(size as number) * this.meter2coord];
}, },
}, },
}); });

View File

@ -9,6 +9,7 @@ varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样
uniform float u_globel; uniform float u_globel;
uniform mat4 u_ModelMatrix; uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp; uniform mat4 u_Mvp;
uniform float u_isMeter;
varying vec4 v_data; varying vec4 v_data;
varying vec4 v_color; varying vec4 v_color;
@ -124,14 +125,22 @@ void main() {
// TODO: billboard // TODO: billboard
// anti-alias // anti-alias
// float antialiased_blur = -max(u_blur, antialiasblur); // float antialiased_blur = -max(u_blur, antialiasblur);
float antialiasblur = -max(1.0 / u_DevicePixelRatio / (newSize + u_stroke_width), u_blur); float antialiasblur = -max(2.0 / u_DevicePixelRatio / a_Size, u_blur);
vec2 offset = (extrude.xy * (newSize + u_stroke_width) + textrueOffsets);
if(u_isMeter < 1.0) {
// 不以米为实际单位
offset = project_pixel(offset);
} else {
// 以米为实际单位
antialiasblur *= pow(19.0 - u_Zoom, 2.0);
}
// construct point coords
// TODP: /abs(extrude.x) 是为了兼容地球模式 // TODP: /abs(extrude.x) 是为了兼容地球模式
v_data = vec4(extrude.x/abs(extrude.x), extrude.y/abs(extrude.y), antialiasblur,shape_type); v_data = vec4(extrude.x/abs(extrude.x), extrude.y/abs(extrude.y), antialiasblur,shape_type);
// vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
vec2 offset = project_pixel(extrude.xy * (newSize + u_stroke_width) + textrueOffsets);
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0)); vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0)); // gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));

View File

@ -425,6 +425,22 @@ export default class AMapService
this.viewport = new Viewport(); this.viewport = new Viewport();
} }
public meterToCoord(center: [number, number], outer: [number, number]) {
// 统一根据经纬度来转化
// Tip: 实际米距离 unit meter
const meterDis = AMap.GeometryUtil.distance(
new AMap.LngLat(...center),
new AMap.LngLat(...outer),
);
// Tip: 三维世界坐标距离
const [x1, y1] = this.lngLatToCoord(center);
const [x2, y2] = this.lngLatToCoord(outer);
const coordDis = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
return coordDis / meterDis;
}
public exportMap(type: 'jpg' | 'png'): string { public exportMap(type: 'jpg' | 'png'): string {
const renderCanvas = this.getContainer()?.getElementsByClassName( const renderCanvas = this.getContainer()?.getElementsByClassName(
'amap-layer', 'amap-layer',

View File

@ -517,6 +517,22 @@ export default class AMapService
}); });
} }
public meterToCoord(center: [number, number], outer: [number, number]) {
// 统一根据经纬度来转化
// Tip: 实际米距离 unit meter
const meterDis = AMap.GeometryUtil.distance(
new AMap.LngLat(...center),
new AMap.LngLat(...outer),
);
// Tip: 三维世界坐标距离
const [x1, y1] = this.lngLatToCoord(center);
const [x2, y2] = this.lngLatToCoord(outer);
const coordDis = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
return coordDis / meterDis;
}
public exportMap(type: 'jpg' | 'png'): string { public exportMap(type: 'jpg' | 'png'): string {
const renderCanvas = this.getContainer()?.getElementsByClassName( const renderCanvas = this.getContainer()?.getElementsByClassName(
'amap-layer', 'amap-layer',

View File

@ -401,6 +401,33 @@ export default class MapboxService
return this.$mapContainer; return this.$mapContainer;
} }
public meterToCoord(center: [number, number], outer: [number, number]) {
// 统一根据经纬度来转化
// Tip: 实际米距离 unit meter
const centerLnglat = new mapboxgl.LngLat(center[0], center[1]);
const outerLnglat = new mapboxgl.LngLat(outer[0], outer[1]);
const meterDis = centerLnglat.distanceTo(outerLnglat);
// Tip: 三维世界坐标距离
const centerMercator = mapboxgl.MercatorCoordinate.fromLngLat({
lng: center[0],
lat: center[1],
});
const outerMercator = mapboxgl.MercatorCoordinate.fromLngLat({
lng: outer[0],
lat: outer[1],
});
const { x: x1, y: y1 } = centerMercator;
const { x: x2, y: y2 } = outerMercator;
// Math.pow(2, 22) 4194304
const coordDis =
Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) * 4194304 * 2;
return coordDis / meterDis;
}
public exportMap(type: 'jpg' | 'png'): string { public exportMap(type: 'jpg' | 'png'): string {
const renderCanvas = this.map.getCanvas(); const renderCanvas = this.map.getCanvas();
const layersPng = const layersPng =

View File

@ -32,18 +32,21 @@ export default class Amap2demo_citybuilding extends React.Component {
.animate({ .animate({
enable: true, enable: true,
}) })
.active(true) .active({
color: '#0ff',
mix: 0.5,
})
.style({ .style({
opacity: 0.7, opacity: 0.7,
baseColor: 'rgb(16,16,16)', baseColor: 'rgb(16,16,16)',
windowColor: 'rgb(30,60,89)', windowColor: 'rgb(30,60,89)',
brightColor: 'rgb(255,176,38)', brightColor: 'rgb(255,176,38)',
// sweep: { sweep: {
// enable: true, enable: true,
// sweepRadius: 4, sweepRadius: 4,
// sweepColor: 'rgb(0, 100, 100)', sweepColor: 'rgb(0, 100, 100)',
// sweepSpeed: 0.5 sweepSpeed: 0.5,
// } },
}); });
scene.addLayer(pointLayer); scene.addLayer(pointLayer);

View File

@ -97,6 +97,16 @@ export default class Amap2demo_image extends React.Component {
}, },
}) })
.shape('name', ['00', '01', '02']) .shape('name', ['00', '01', '02'])
// .active(true)
.active({
color: '#00f',
mix: 0.6,
})
// .select(true)
.select({
color: '#00f',
mix: 0.22,
})
.size(20); .size(20);
scene.addLayer(this.imageLayer); scene.addLayer(this.imageLayer);
}); });

View File

@ -1,8 +1,13 @@
// @ts-ignore // @ts-ignore
import { PointLayer, Scene, LineLayer } from '@antv/l7'; import { PointLayer, Scene, LineLayer, PolygonLayer } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps'; import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps';
import * as React from 'react'; import * as React from 'react';
import * as turf from '@turf/turf';
const aspaceLnglat = [120.1019811630249, 30.264701434772807] as [
number,
number,
];
export default class GaodeMapComponent extends React.Component { export default class GaodeMapComponent extends React.Component {
// @ts-ignore // @ts-ignore
private scene: Scene; private scene: Scene;
@ -15,11 +20,10 @@ export default class GaodeMapComponent extends React.Component {
const scene = new Scene({ const scene = new Scene({
id: 'map', id: 'map',
map: new GaodeMap({ map: new GaodeMap({
center: [121.107846, 30.267069], center: aspaceLnglat,
pitch: 0, pitch: 0,
style: 'dark', // style: 'dark',
zoom: 20, zoom: 17,
animateEnable: false,
}), }),
}); });
// normal = 'normal', // normal = 'normal',
@ -29,6 +33,29 @@ export default class GaodeMapComponent extends React.Component {
// max = 'max', // max = 'max',
// none = 'none', // none = 'none',
// blend: 'additive' // blend: 'additive'
var circleRadius = 100;
var radius = circleRadius;
var data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: turf.circle(aspaceLnglat, radius, {
steps: 10,
units: 'meters',
}).geometry.coordinates,
},
},
],
};
let trufCircle = new PolygonLayer()
.size('name', [0, 10000, 50000, 30000, 100000])
.source(data)
.color('#f00')
.shape('fill');
let layer = new PointLayer({ zIndex: 2, blend: 'additive' }) let layer = new PointLayer({ zIndex: 2, blend: 'additive' })
.source( .source(
@ -38,8 +65,8 @@ export default class GaodeMapComponent extends React.Component {
lat: 30.267069, lat: 30.267069,
}, },
{ {
lng: 121.107, lng: aspaceLnglat[0],
lat: 30.267069, lat: aspaceLnglat[1],
}, },
], ],
{ {
@ -51,20 +78,22 @@ export default class GaodeMapComponent extends React.Component {
}, },
) )
.shape('circle') .shape('circle')
.color('#1990FF') .color('#00f')
.size(40) .size(circleRadius)
.style({ .style({
stroke: '#f00', stroke: '#f00',
strokeWidth: 3, // strokeWidth: 10,
strokeOpacity: 1, strokeOpacity: 1,
unit: 'meter',
}) })
.animate(true) // .animate(true)
.active({ color: '#ff0' }); .active({ color: '#00f' });
this.scene = scene; this.scene = scene;
scene.on('loaded', () => { scene.on('loaded', () => {
scene.addLayer(layer); scene.addLayer(layer);
// scene.addLayer(trufCircle);
}); });
let c = 1; let c = 1;
layer.on('click', () => { layer.on('click', () => {