mirror of https://gitee.com/antv-l7/antv-l7
feat: 新增pointLayer 对 style 参数 opacity 对数据映射支持
This commit is contained in:
parent
b431ad72c3
commit
bbe559f990
|
@ -28,6 +28,11 @@ import {
|
|||
StyleAttributeOption,
|
||||
Triangulation,
|
||||
} from './IStyleAttributeService';
|
||||
|
||||
import {
|
||||
IStyleAttributeUpdateOptions,
|
||||
StyleAttributeField,
|
||||
} from '@antv/l7-core';
|
||||
export enum BlendType {
|
||||
normal = 'normal',
|
||||
additive = 'additive',
|
||||
|
@ -126,10 +131,17 @@ export interface ILayer {
|
|||
options: ILayerModelInitializationOptions &
|
||||
Partial<IModelInitializationOptions>,
|
||||
): IModel;
|
||||
updateStyleAttribute(
|
||||
type: string,
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
): void;
|
||||
init(): ILayer;
|
||||
scale(field: string | number | IScaleOptions, cfg?: IScale): ILayer;
|
||||
size(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
// opacity(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
texture(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
label(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
|
|
|
@ -940,6 +940,40 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
|
||||
public updateStyleAttribute(
|
||||
type: string,
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
if (!this.inited) {
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: type,
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
updateOptions,
|
||||
});
|
||||
} else {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
type,
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
// @ts-ignore
|
||||
this.getLayerConfig()[field],
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
updateOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
@ -978,38 +1012,4 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
callback: isFunction(valuesOrCallback) ? valuesOrCallback : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private updateStyleAttribute(
|
||||
type: string,
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
if (!this.inited) {
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: type,
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
updateOptions,
|
||||
});
|
||||
} else {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
type,
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
// @ts-ignore
|
||||
this.getLayerConfig()[field],
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
updateOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
data: IParseDataItem[],
|
||||
predata?: IEncodeFeature[],
|
||||
): IEncodeFeature[] {
|
||||
// console.log('data', data[0])
|
||||
// console.log('data', data)
|
||||
const mappedData = data.map((record: IParseDataItem, i) => {
|
||||
const preRecord = predata ? predata[i] : {};
|
||||
const encodeRecord: IEncodeFeature = {
|
||||
|
@ -117,12 +117,14 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
coordinates: record.coordinates,
|
||||
...preRecord,
|
||||
};
|
||||
// console.log('encodeRecord', encodeRecord)
|
||||
// console.log('attributes', attributes)
|
||||
attributes
|
||||
.filter((attribute) => attribute.scale !== undefined)
|
||||
.forEach((attribute: IStyleAttribute) => {
|
||||
// console.log('attribute', attribute)
|
||||
// console.log('record', record)
|
||||
let values = this.applyAttributeMapping(attribute, record);
|
||||
// console.log('values', values)
|
||||
attribute.needRemapping = false;
|
||||
|
||||
// TODO: 支持每个属性配置 postprocess
|
||||
|
@ -145,7 +147,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
});
|
||||
return encodeRecord;
|
||||
}) as IEncodeFeature[];
|
||||
// console.log('mappedData', mappedData[0])
|
||||
// console.log('mappedData', mappedData)
|
||||
|
||||
// 根据地图的类型判断是否需要对点位数据进行处理, 若是高德2.0则需要对坐标进行相对偏移
|
||||
if (mappedData.length > 0 && this.mapService.version === 'GAODE2.x') {
|
||||
|
@ -194,6 +196,9 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
params.push(record[field]);
|
||||
}
|
||||
});
|
||||
// console.log('params', params)
|
||||
// console.log('attribute', attribute)
|
||||
// console.log('mapping',attribute.mapping ? attribute.mapping(params) : [])
|
||||
return attribute.mapping ? attribute.mapping(params) : [];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { isNumber } from 'lodash';
|
||||
|
||||
/**
|
||||
* 在初始化阶段完成属性的注册,以及首次根据 Layer 指定的三角化方法完成 indices 和 attribute 的创建
|
||||
|
@ -90,5 +91,25 @@ export default class RegisterStyleAttributePlugin implements ILayerPlugin {
|
|||
},
|
||||
},
|
||||
});
|
||||
styleAttributeService.registerStyleAttribute({
|
||||
name: 'opacity',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Opacity',
|
||||
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) => {
|
||||
const { opacity } = feature;
|
||||
// console.log('feature', feature)
|
||||
// console.log('opacity', opacity)
|
||||
return !isNumber(opacity) ? [1.0] : [opacity];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,24 +14,37 @@ import BaseModel from '../../core/BaseModel';
|
|||
import { PointFillTriangulation } from '../../core/triangulation';
|
||||
import pointFillFrag from '../shaders/fill_frag.glsl';
|
||||
import pointFillVert from '../shaders/fill_vert.glsl';
|
||||
|
||||
import { isNumber } from 'lodash';
|
||||
import { handleStyleOpacity } from '../../utils/dataMappingStyle';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: number;
|
||||
opacity: any;
|
||||
strokeWidth: number;
|
||||
stroke: string;
|
||||
strokeOpacity: number;
|
||||
offsets: [number, number];
|
||||
}
|
||||
|
||||
// 用于判断 opacity 的值是否发生该改变
|
||||
let curretnOpacity: any = '';
|
||||
export default class FillModel extends BaseModel {
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
opacity = 1,
|
||||
opacity = 1.0,
|
||||
stroke = 'rgb(0,0,0,0)',
|
||||
strokeWidth = 1,
|
||||
strokeOpacity = 1,
|
||||
offsets = [0, 0],
|
||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
|
||||
// style 中 opacity 属性的处理(数据映射)
|
||||
if (curretnOpacity !== JSON.stringify(opacity)) {
|
||||
handleStyleOpacity(this.layer, opacity);
|
||||
curretnOpacity = JSON.stringify(opacity);
|
||||
}
|
||||
|
||||
return {
|
||||
u_opacity: opacity,
|
||||
u_opacity: isNumber(opacity) ? opacity : 1.0,
|
||||
u_stroke_width: strokeWidth,
|
||||
u_stroke_color: rgb2arr(stroke),
|
||||
u_stroke_opacity: strokeOpacity,
|
||||
|
@ -58,6 +71,8 @@ export default class FillModel extends BaseModel {
|
|||
);
|
||||
}
|
||||
public initModels(): IModel[] {
|
||||
this.getUninforms();
|
||||
|
||||
return this.buildModels();
|
||||
}
|
||||
public buildModels(): IModel[] {
|
||||
|
@ -76,6 +91,7 @@ export default class FillModel extends BaseModel {
|
|||
return [option.enable ? 0 : 1.0, option.speed || 1, option.rings || 3, 0];
|
||||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
const { opacity } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'extrude',
|
||||
type: AttributeType.Attribute,
|
||||
|
|
|
@ -8,6 +8,7 @@ uniform float u_stroke_opacity : 1;
|
|||
|
||||
varying vec4 v_data;
|
||||
varying vec4 v_color;
|
||||
varying float v_opacity;
|
||||
varying float v_radius;
|
||||
uniform float u_time;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
|
@ -67,7 +68,14 @@ void main() {
|
|||
|
||||
// gl_FragColor = v_color * color_t;
|
||||
// gl_FragColor = mix(vec4(v_color.rgb, v_color.a * u_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||
gl_FragColor = mix(vec4(v_color.rgb, v_color.a * u_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||
// gl_FragColor = mix(vec4(v_color.rgb, v_color.a * v_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||
|
||||
if(v_opacity < 0.0) { // style 中的 opacity 为 number
|
||||
gl_FragColor = mix(vec4(v_color.rgb, v_color.a * u_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||
} else { // style 中的 opacity 为 string | function
|
||||
gl_FragColor = mix(vec4(v_color.rgb, v_color.a * v_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||
}
|
||||
|
||||
gl_FragColor.a = gl_FragColor.a * opacity_t;
|
||||
if(u_aimate.x == Animate) {
|
||||
float d = length(v_data.xy);
|
||||
|
|
|
@ -2,6 +2,7 @@ attribute vec4 a_Color;
|
|||
attribute vec3 a_Position;
|
||||
attribute vec2 a_Extrude;
|
||||
attribute float a_Size;
|
||||
attribute float a_Opacity;
|
||||
attribute float a_Shape;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
@ -12,6 +13,7 @@ uniform vec2 u_offsets;
|
|||
varying vec4 v_data;
|
||||
varying vec4 v_color;
|
||||
varying float v_radius;
|
||||
varying float v_opacity;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "picking"
|
||||
|
@ -23,6 +25,7 @@ void main() {
|
|||
|
||||
// unpack color(vec2)
|
||||
v_color = a_Color;
|
||||
v_opacity = a_Opacity;
|
||||
|
||||
// radius(16-bit)
|
||||
v_radius = newSize;
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
import {
|
||||
ILayer,
|
||||
IStyleAttributeUpdateOptions,
|
||||
StyleAttributeField,
|
||||
StyleAttributeOption,
|
||||
} from '@antv/l7-core';
|
||||
import { isArray, isFunction, isNumber, isString } from 'lodash';
|
||||
/**
|
||||
* 该文件中的工具方法主要用于对 style 中的属性进行 数据映射
|
||||
*/
|
||||
|
||||
/**
|
||||
* 当 style 中使用的 opacity 不是常数的时候根据数据进行映射
|
||||
* @param field
|
||||
* @param values
|
||||
* @param updateOptions
|
||||
*/
|
||||
function registerOpacityAttribute(
|
||||
layer: ILayer,
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
layer.updateStyleAttribute('opacity', field, values, updateOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入参数 opacity 的类型和值做相应的操作
|
||||
*/
|
||||
function handleStyleOpacity(layer: ILayer, opacity: any) {
|
||||
if (isString(opacity)) {
|
||||
// opacity = 'string'
|
||||
registerOpacityAttribute(layer, opacity, (value: any) => {
|
||||
return value;
|
||||
});
|
||||
} else if (isNumber(opacity)) {
|
||||
// opacity = 0.4 -> opacity 传入数字、u_Opacity 生效、v_Opacity 不生效
|
||||
registerOpacityAttribute(layer, [-1], undefined);
|
||||
} else if (isArray(opacity) && opacity.length === 2) {
|
||||
if (isString(opacity[0]) && isFunction(opacity[1])) {
|
||||
// opacity = ['string', callback]
|
||||
registerOpacityAttribute(layer, opacity[0], opacity[1]);
|
||||
} else if (
|
||||
isString(opacity[0]) &&
|
||||
isArray(opacity[1]) &&
|
||||
isNumber(opacity[1][0]) &&
|
||||
isNumber(opacity[1][1])
|
||||
) {
|
||||
// opacity = ['string', [start: number, end: nuber]]
|
||||
registerOpacityAttribute(layer, opacity[0], opacity[1]);
|
||||
} else {
|
||||
registerOpacityAttribute(layer, [1.0], undefined);
|
||||
}
|
||||
} else {
|
||||
registerOpacityAttribute(layer, [1.0], undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export { handleStyleOpacity };
|
|
@ -1,6 +1,6 @@
|
|||
//@ts-ignore
|
||||
import { PointLayer, Scene } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import { GaodeMapV2 } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
export default class Amap2demo extends React.Component {
|
||||
// @ts-ignore
|
||||
|
@ -13,7 +13,7 @@ export default class Amap2demo extends React.Component {
|
|||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
map: new GaodeMapV2({
|
||||
center: [121.107846, 30.267069],
|
||||
pitch: 0,
|
||||
style: 'normal',
|
||||
|
@ -25,28 +25,27 @@ export default class Amap2demo extends React.Component {
|
|||
{
|
||||
lng: 121.107846,
|
||||
lat: 30.267069,
|
||||
opacity2: 0.2,
|
||||
},
|
||||
{
|
||||
lng: 121.107,
|
||||
lat: 30.267069,
|
||||
opacity2: 0.4,
|
||||
},
|
||||
{
|
||||
lng: 120.107846,
|
||||
lat: 30.267069,
|
||||
},
|
||||
{
|
||||
lng: 38.54,
|
||||
lat: 77.02,
|
||||
lng: 121.107846,
|
||||
lat: 30.26718,
|
||||
opacity2: 0.6,
|
||||
},
|
||||
// {
|
||||
// lng: 38.54,
|
||||
// lat: 77.02,
|
||||
// opacity: 0.5
|
||||
// },
|
||||
];
|
||||
this.scene = scene;
|
||||
|
||||
scene.on('loaded', () => {
|
||||
// console.log('event test');
|
||||
// @ts-ignore
|
||||
// console.log(scene.map.getProjection().project);
|
||||
// @ts-ignore
|
||||
// console.log(scene.map.customCoords.lngLatToCoord);
|
||||
const layer = new PointLayer()
|
||||
.source(originData, {
|
||||
parser: {
|
||||
|
@ -55,15 +54,21 @@ export default class Amap2demo extends React.Component {
|
|||
y: 'lat',
|
||||
},
|
||||
})
|
||||
// .shape('circle')
|
||||
.shape('circle')
|
||||
// .shape('normal')
|
||||
.shape('fill')
|
||||
// .shape('fill')
|
||||
.color('rgba(255, 0, 0, 0.9)')
|
||||
.size(10)
|
||||
.style({
|
||||
stroke: '#fff',
|
||||
storkeWidth: 2,
|
||||
offsets: [100, 100],
|
||||
// offsets: [100, 100],
|
||||
// opacity: 'opacity2'
|
||||
// opacity: 0.2
|
||||
// opacity: ['opacity2', (d: any) => {
|
||||
// return d
|
||||
// }]
|
||||
opacity: ['opacity2', [0.2, 0.6]],
|
||||
})
|
||||
.active(true);
|
||||
scene.addLayer(layer);
|
||||
|
|
|
@ -58,7 +58,7 @@ export default class GaodeMapComponent extends React.Component {
|
|||
.style({
|
||||
stroke: '#fff',
|
||||
storkeWidth: 2,
|
||||
offsets: [100, 100],
|
||||
// offsets: [100, 100],
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
scene.render();
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
// @ts-ignore
|
||||
import { LineLayer, Scene } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Line 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: [120.19382669582967, 30.258134],
|
||||
pitch: 0,
|
||||
zoom: 8,
|
||||
viewMode: '3D',
|
||||
}),
|
||||
});
|
||||
this.scene = scene;
|
||||
|
||||
scene.on('loaded', () => {
|
||||
// @ts-ignore
|
||||
const layer = new LineLayer({})
|
||||
.source({
|
||||
type: 'FeatureCollection',
|
||||
name: 'dl2',
|
||||
crs: {
|
||||
type: 'name',
|
||||
properties: {
|
||||
name: 'urn:ogc:def:crs:OGC:1.3:CRS84',
|
||||
},
|
||||
},
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'MultiLineString',
|
||||
coordinates: [
|
||||
[
|
||||
[120, 32],
|
||||
[121, 32],
|
||||
[121, 30],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
.size(5)
|
||||
.shape('line')
|
||||
.color('#25d8b7');
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
|
||||
|
||||
import Line from './components/line';
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
storiesOf('functions', module)
|
||||
|
||||
.add('line', () => <Line />)
|
||||
|
||||
|
Loading…
Reference in New Issue