mirror of https://gitee.com/antv-l7/antv-l7
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:
parent
56ec1259af
commit
7e73477219
|
@ -70,7 +70,9 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
enableHighlight: false,
|
||||
enableSelect: false,
|
||||
highlightColor: '#2f54eb',
|
||||
activeMix: 0,
|
||||
selectColor: 'blue',
|
||||
selectMix: 0,
|
||||
enableTAA: false,
|
||||
jitterScale: 1,
|
||||
enableLighting: false,
|
||||
|
|
|
@ -87,6 +87,7 @@ export interface IPickedFeature {
|
|||
// 交互样式
|
||||
export interface IActiveOption {
|
||||
color: string | number[];
|
||||
mix?: number;
|
||||
}
|
||||
|
||||
type ILngLat = [number, number];
|
||||
|
@ -339,6 +340,8 @@ export interface ILayerConfig {
|
|||
selectColor: string | number[];
|
||||
active: boolean;
|
||||
activeColor: string | number[];
|
||||
activeMix?: number;
|
||||
selectMix?: number;
|
||||
/**
|
||||
* 开启 TAA
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,8 @@ uniform vec4 u_HighlightColor : [0, 0, 0, 0];
|
|||
uniform float u_PickingStage : 0.0;
|
||||
uniform float u_shaderPick;
|
||||
|
||||
uniform float u_activeMix: 0;
|
||||
|
||||
#define PICKING_NONE 0.0
|
||||
#define PICKING_ENCODE 1.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));
|
||||
|
||||
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 {
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -570,6 +570,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
if (options.color) {
|
||||
activeOption.highlightColor = options.color;
|
||||
}
|
||||
if (options.mix) {
|
||||
activeOption.activeMix = options.mix;
|
||||
}
|
||||
} else {
|
||||
activeOption.enableHighlight = !!options;
|
||||
}
|
||||
|
@ -586,6 +589,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
highlightColor: isObject(options)
|
||||
? options.color
|
||||
: this.getLayerConfig().highlightColor,
|
||||
activeMix: isObject(options)
|
||||
? options.mix
|
||||
: this.getLayerConfig().activeMix,
|
||||
});
|
||||
this.pick({ x, y });
|
||||
} else {
|
||||
|
@ -594,6 +600,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
highlightColor: isObject(options)
|
||||
? options.color
|
||||
: this.getLayerConfig().highlightColor,
|
||||
activeMix: isObject(options)
|
||||
? options.mix
|
||||
: this.getLayerConfig().activeMix,
|
||||
});
|
||||
this.hooks.beforeSelect
|
||||
.call(encodePickingColor(id as number) as number[])
|
||||
|
@ -614,6 +623,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
if (option.color) {
|
||||
activeOption.selectColor = option.color;
|
||||
}
|
||||
if (option.mix) {
|
||||
activeOption.selectMix = option.mix;
|
||||
}
|
||||
} else {
|
||||
activeOption.enableSelect = !!option;
|
||||
}
|
||||
|
@ -631,6 +643,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
selectColor: isObject(options)
|
||||
? options.color
|
||||
: this.getLayerConfig().selectColor,
|
||||
selectMix: isObject(options)
|
||||
? options.mix
|
||||
: this.getLayerConfig().selectMix,
|
||||
});
|
||||
this.pick({ x, y });
|
||||
} else {
|
||||
|
@ -639,6 +654,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
selectColor: isObject(options)
|
||||
? options.color
|
||||
: this.getLayerConfig().selectColor,
|
||||
selectMix: isObject(options)
|
||||
? options.mix
|
||||
: this.getLayerConfig().selectMix,
|
||||
});
|
||||
this.hooks.beforeSelect
|
||||
.call(encodePickingColor(id as number) as number[])
|
||||
|
|
|
@ -83,7 +83,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
layer.hooks.beforeHighlight.tap(
|
||||
'PixelPickingPlugin',
|
||||
(pickedColor: number[]) => {
|
||||
const { highlightColor } = layer.getLayerConfig();
|
||||
const { highlightColor, activeMix = 0 } = layer.getLayerConfig();
|
||||
const highlightColorInArray =
|
||||
typeof highlightColor === 'string'
|
||||
? rgb2arr(highlightColor)
|
||||
|
@ -96,6 +96,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
u_PickingStage: PickingStage.HIGHLIGHT,
|
||||
u_PickingColor: pickedColor,
|
||||
u_HighlightColor: highlightColorInArray.map((c) => c * 255),
|
||||
u_activeMix: activeMix,
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
@ -104,7 +105,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
layer.hooks.beforeSelect.tap(
|
||||
'PixelPickingPlugin',
|
||||
(pickedColor: number[]) => {
|
||||
const { selectColor } = layer.getLayerConfig();
|
||||
const { selectColor, selectMix = 0 } = layer.getLayerConfig();
|
||||
const highlightColorInArray =
|
||||
typeof selectColor === 'string'
|
||||
? rgb2arr(selectColor)
|
||||
|
@ -117,6 +118,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
u_PickingStage: PickingStage.HIGHLIGHT,
|
||||
u_PickingColor: pickedColor,
|
||||
u_HighlightColor: highlightColorInArray.map((c) => c * 255),
|
||||
u_activeMix: selectMix,
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ import pointFillVert from '../shaders/fill_vert.glsl';
|
|||
import { isNumber } from 'lodash';
|
||||
|
||||
import { mat4, vec3 } from 'gl-matrix';
|
||||
|
||||
import { Version } from '../../../../maps/src/version';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: styleSingle;
|
||||
strokeWidth: styleSingle;
|
||||
|
@ -32,9 +32,12 @@ interface IPointLayerStyleOptions {
|
|||
strokeOpacity: styleSingle;
|
||||
offsets: styleOffset;
|
||||
blend: string;
|
||||
unit: string;
|
||||
}
|
||||
// 判断当前使用的 style 中的变量属性是否需要进行数据映射
|
||||
export default class FillModel extends BaseModel {
|
||||
public meter2coord: number = 1;
|
||||
private isMeter: boolean = false;
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
opacity = 1,
|
||||
|
@ -92,8 +95,10 @@ export default class FillModel extends BaseModel {
|
|||
});
|
||||
}
|
||||
return {
|
||||
u_isMeter: Number(this.isMeter),
|
||||
|
||||
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_cellTypeLayout: this.getCellTypeLayout(),
|
||||
|
||||
|
@ -127,9 +132,38 @@ export default class FillModel extends BaseModel {
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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[] {
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
const isGlobel = this.mapService.version === 'GLOBEL';
|
||||
|
@ -246,7 +280,9 @@ export default class FillModel extends BaseModel {
|
|||
) => {
|
||||
const { size = 5 } = 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];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样
|
|||
uniform float u_globel;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float u_isMeter;
|
||||
|
||||
varying vec4 v_data;
|
||||
varying vec4 v_color;
|
||||
|
@ -124,14 +125,22 @@ void main() {
|
|||
// TODO: billboard
|
||||
// anti-alias
|
||||
// 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) 是为了兼容地球模式
|
||||
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));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));
|
||||
|
||||
|
|
|
@ -425,6 +425,22 @@ export default class AMapService
|
|||
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 {
|
||||
const renderCanvas = this.getContainer()?.getElementsByClassName(
|
||||
'amap-layer',
|
||||
|
|
|
@ -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 {
|
||||
const renderCanvas = this.getContainer()?.getElementsByClassName(
|
||||
'amap-layer',
|
||||
|
|
|
@ -401,6 +401,33 @@ export default class MapboxService
|
|||
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 {
|
||||
const renderCanvas = this.map.getCanvas();
|
||||
const layersPng =
|
||||
|
|
|
@ -32,18 +32,21 @@ export default class Amap2demo_citybuilding extends React.Component {
|
|||
.animate({
|
||||
enable: true,
|
||||
})
|
||||
.active(true)
|
||||
.active({
|
||||
color: '#0ff',
|
||||
mix: 0.5,
|
||||
})
|
||||
.style({
|
||||
opacity: 0.7,
|
||||
baseColor: 'rgb(16,16,16)',
|
||||
windowColor: 'rgb(30,60,89)',
|
||||
brightColor: 'rgb(255,176,38)',
|
||||
// sweep: {
|
||||
// enable: true,
|
||||
// sweepRadius: 4,
|
||||
// sweepColor: 'rgb(0, 100, 100)',
|
||||
// sweepSpeed: 0.5
|
||||
// }
|
||||
sweep: {
|
||||
enable: true,
|
||||
sweepRadius: 4,
|
||||
sweepColor: 'rgb(0, 100, 100)',
|
||||
sweepSpeed: 0.5,
|
||||
},
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
|
||||
|
|
|
@ -97,6 +97,16 @@ export default class Amap2demo_image extends React.Component {
|
|||
},
|
||||
})
|
||||
.shape('name', ['00', '01', '02'])
|
||||
// .active(true)
|
||||
.active({
|
||||
color: '#00f',
|
||||
mix: 0.6,
|
||||
})
|
||||
// .select(true)
|
||||
.select({
|
||||
color: '#00f',
|
||||
mix: 0.22,
|
||||
})
|
||||
.size(20);
|
||||
scene.addLayer(this.imageLayer);
|
||||
});
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
// @ts-ignore
|
||||
import { PointLayer, Scene, LineLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import { PointLayer, Scene, LineLayer, PolygonLayer } from '@antv/l7';
|
||||
import { GaodeMap, GaodeMapV2, Mapbox } from '@antv/l7-maps';
|
||||
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 {
|
||||
// @ts-ignore
|
||||
private scene: Scene;
|
||||
|
@ -15,11 +20,10 @@ export default class GaodeMapComponent extends React.Component {
|
|||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [121.107846, 30.267069],
|
||||
center: aspaceLnglat,
|
||||
pitch: 0,
|
||||
style: 'dark',
|
||||
zoom: 20,
|
||||
animateEnable: false,
|
||||
// style: 'dark',
|
||||
zoom: 17,
|
||||
}),
|
||||
});
|
||||
// normal = 'normal',
|
||||
|
@ -29,6 +33,29 @@ export default class GaodeMapComponent extends React.Component {
|
|||
// max = 'max',
|
||||
// none = 'none',
|
||||
// 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' })
|
||||
.source(
|
||||
|
@ -38,8 +65,8 @@ export default class GaodeMapComponent extends React.Component {
|
|||
lat: 30.267069,
|
||||
},
|
||||
{
|
||||
lng: 121.107,
|
||||
lat: 30.267069,
|
||||
lng: aspaceLnglat[0],
|
||||
lat: aspaceLnglat[1],
|
||||
},
|
||||
],
|
||||
{
|
||||
|
@ -51,20 +78,22 @@ export default class GaodeMapComponent extends React.Component {
|
|||
},
|
||||
)
|
||||
.shape('circle')
|
||||
.color('#1990FF')
|
||||
.size(40)
|
||||
.color('#00f')
|
||||
.size(circleRadius)
|
||||
.style({
|
||||
stroke: '#f00',
|
||||
strokeWidth: 3,
|
||||
// strokeWidth: 10,
|
||||
strokeOpacity: 1,
|
||||
unit: 'meter',
|
||||
})
|
||||
.animate(true)
|
||||
.active({ color: '#ff0' });
|
||||
// .animate(true)
|
||||
.active({ color: '#00f' });
|
||||
|
||||
this.scene = scene;
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
// scene.addLayer(trufCircle);
|
||||
});
|
||||
let c = 1;
|
||||
layer.on('click', () => {
|
||||
|
|
Loading…
Reference in New Issue