feat: 新增样式数据分析(直接赋值/纹理传值)

This commit is contained in:
2912401452 2021-06-16 21:41:05 +08:00
parent bbe559f990
commit 56f6f8fe71
11 changed files with 260 additions and 41 deletions

View File

@ -79,6 +79,7 @@ export default class LayerService implements ILayerService {
.filter((layer) => layer.inited)
.filter((layer) => layer.isVisible())
.forEach((layer) => {
// trigger hooks
layer.hooks.beforeRenderData.call();
layer.hooks.beforeRender.call();

View File

@ -267,6 +267,7 @@ export default class Scene extends EventEmitter implements ISceneService {
// 尝试初始化未初始化的图层
this.layerService.renderLayers();
// 组件需要等待layer 初始化完成之后添加
this.logger.debug(`scene ${this.id} render`);
this.rendering = false;

View File

@ -53,6 +53,7 @@ import mergeJsonSchemas from 'merge-json-schemas';
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
import { BlendTypes } from '../utils/blend';
import baseLayerSchema from './schema';
import { handleStyleOpacity, handleStyleStrokeOpacity } from '../utils/dataMappingStyle'
/**
* layer id
*/
@ -206,6 +207,16 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
};
} else {
const sceneId = this.container.get<string>(TYPES.SceneID);
// @ts-ignore
if(configToUpdate.opacity){
// @ts-ignore
handleStyleOpacity('opacity', this, configToUpdate.opacity);
}
// @ts-ignore
if(configToUpdate.strokeOpacity){
// @ts-ignore
handleStyleStrokeOpacity('strokeOpacity', this, configToUpdate.strokeOpacity);
}
this.configService.setLayerConfig(sceneId, this.id, {
...this.configService.getLayerConfig(this.id),
...this.needUpdateConfig,

View File

@ -83,6 +83,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
// 处理文本更新
layer.emit('remapping', null);
}
});
}
private generateMaping(
@ -174,6 +175,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
});
}
}
// console.log('mappedData', mappedData)
return mappedData;
}

View File

@ -92,10 +92,10 @@ export default class RegisterStyleAttributePlugin implements ILayerPlugin {
},
});
styleAttributeService.registerStyleAttribute({
name: 'opacity',
name: 'strokeOpacity',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Opacity',
name: 'a_stroke_opacity',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
@ -104,10 +104,10 @@ export default class RegisterStyleAttributePlugin implements ILayerPlugin {
},
size: 1,
update: (feature: IEncodeFeature, featureIdx: number) => {
const { opacity } = feature;
const { strokeOpacity } = feature;
// console.log('feature', feature)
// console.log('opacity', opacity)
return !isNumber(opacity) ? [1.0] : [opacity];
// console.log('strokeOpacity', strokeOpacity)
return !isNumber(strokeOpacity) ? [1.0] : [strokeOpacity];
},
},
});

View File

@ -31,6 +31,7 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
// });
layer.hooks.beforeRender.tap('UpdateStyleAttributePlugin', () => {
if (layer.layerModelNeedUpdate) {
return;
}

View File

@ -8,6 +8,7 @@ import {
ILayerConfig,
IModel,
IModelUniform,
ITexture2D
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import BaseModel from '../../core/BaseModel';
@ -15,8 +16,8 @@ import { PointFillTriangulation } from '../../core/triangulation';
import pointFillFrag from '../shaders/fill_frag.glsl';
import pointFillVert from '../shaders/fill_vert.glsl';
import { getSize, getUvPosition, initTextureData, initDefaultTextureData } from '../../utils/dataMappingStyle'
import { isNumber } from 'lodash';
import { handleStyleOpacity } from '../../utils/dataMappingStyle';
interface IPointLayerStyleOptions {
opacity: any;
strokeWidth: number;
@ -25,29 +26,61 @@ interface IPointLayerStyleOptions {
offsets: [number, number];
}
interface IDataLayout {
widthCount: number;
heightCount: number;
widthStep: number;
widthStart: number;
heightStep: number;
heightStart: number;
}
// 用于判断 opacity 的值是否发生该改变
let curretnOpacity: any = '';
let curretnStrokeOpacity: any = ''
export default class FillModel extends BaseModel {
protected opacityTexture: ITexture2D;
public dataLayout: IDataLayout = { // 默认值
widthCount: 1024,
heightCount: 1,
widthStep: 1/1024,
widthStart: 1/2048,
heightStep: 1,
heightStart: 0.5
};
public getUninforms(): IModelUniform {
const {
opacity = 1.0,
opacity,
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);
if ( curretnOpacity !== JSON.stringify(opacity)) {
const { createTexture2D } = this.rendererService;
// 从 encodeData 数据的 opacity 字段上取值,并将值按照排布写入到纹理中
this.opacityTexture = initTextureData(this.dataLayout.heightCount, createTexture2D, this.layer.getEncodedData(), 'opacity')
curretnOpacity = JSON.stringify(opacity);
}
if(curretnStrokeOpacity !== JSON.stringify(strokeOpacity)) {
curretnStrokeOpacity = JSON.stringify(strokeOpacity)
}
return {
u_opacity: isNumber(opacity) ? opacity : 1.0,
u_opacity_texture: this.opacityTexture,
u_opacity: opacity ? -1.0 : 1.0,
u_stroke_width: strokeWidth,
u_stroke_color: rgb2arr(stroke),
u_stroke_opacity: strokeOpacity,
u_stroke_opacity: isNumber(strokeOpacity)?strokeOpacity: 1.0,
u_offsets: [-offsets[0], offsets[1]],
};
}
@ -70,8 +103,21 @@ export default class FillModel extends BaseModel {
PointFillTriangulation,
);
}
public initEncodeDataLayout(dataLength: number) {
let { width: widthCount, height: heightCount } = getSize(dataLength)
this.dataLayout.widthCount = widthCount
this.dataLayout.heightCount = heightCount
this.dataLayout.widthStep = 1/widthCount
this.dataLayout.widthStart = this.dataLayout.widthStep/2
this.dataLayout.heightStep = 1/heightCount
this.dataLayout.heightStart = this.dataLayout.heightStep/2
}
public initModels(): IModel[] {
this.getUninforms();
this.initEncodeDataLayout(this.layer.getEncodedData().length)
return this.buildModels();
}
@ -91,7 +137,6 @@ 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,
@ -137,11 +182,41 @@ export default class FillModel extends BaseModel {
attributeIdx: number,
) => {
const { size = 5 } = feature;
// console.log('featureIdx', featureIdx, feature)
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
// point feature id
this.styleAttributeService.registerStyleAttribute({
name: 'featureId',
type: AttributeType.Attribute,
descriptor: {
name: 'a_featureId',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 2,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return getUvPosition(
this.dataLayout.widthStep,
this.dataLayout.widthStart,
this.dataLayout.heightStep,
this.dataLayout.heightStart,
featureIdx)
},
},
});
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'shape',

View File

@ -5,10 +5,13 @@ uniform float u_opacity : 1;
uniform float u_stroke_width : 1;
uniform vec4 u_stroke_color : [0, 0, 0, 0];
uniform float u_stroke_opacity : 1;
varying float v_stroke_opacity;
uniform sampler2D u_opacity_texture;
varying vec2 v_featureId;
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 ];
@ -18,6 +21,17 @@ uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
void main() {
int shape = int(floor(v_data.w + 0.5));
// 处理透明度
// float opacity = texture2D(u_opacity_texture, v_featureId).a?texture2D(u_opacity_texture, v_featureId).a:1.0;
float opacity = u_opacity;
if(u_opacity < 0.0) {
opacity = texture2D(u_opacity_texture, v_featureId).a;
}
float stroke_opacity = u_stroke_opacity;
if(v_stroke_opacity > 0.0) {
stroke_opacity = v_stroke_opacity;
}
lowp float antialiasblur = v_data.z;
float antialiased_blur = -max(u_blur, antialiasblur);
@ -68,13 +82,8 @@ 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 * v_opacity), strokeColor * u_stroke_opacity, color_t);
gl_FragColor = mix(vec4(v_color.rgb, v_color.a * opacity), strokeColor * 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) {
@ -84,4 +93,6 @@ void main() {
}
gl_FragColor = filterColor(gl_FragColor);
}

View File

@ -2,8 +2,12 @@ attribute vec4 a_Color;
attribute vec3 a_Position;
attribute vec2 a_Extrude;
attribute float a_Size;
attribute float a_Opacity;
attribute float a_stroke_opacity;
attribute float a_Shape;
attribute vec2 a_featureId;
varying vec2 v_featureId;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
@ -13,7 +17,7 @@ uniform vec2 u_offsets;
varying vec4 v_data;
varying vec4 v_color;
varying float v_radius;
varying float v_opacity;
varying float v_stroke_opacity;
#pragma include "projection"
#pragma include "picking"
@ -25,7 +29,9 @@ void main() {
// unpack color(vec2)
v_color = a_Color;
v_opacity = a_Opacity;
v_stroke_opacity = a_stroke_opacity;
v_featureId = a_featureId;
// radius(16-bit)
v_radius = newSize;

View File

@ -1,5 +1,6 @@
import {
ILayer,
ITexture2D,
IStyleAttributeUpdateOptions,
StyleAttributeField,
StyleAttributeOption,
@ -9,6 +10,9 @@ import { isArray, isFunction, isNumber, isString } from 'lodash';
* style
*/
// 画布默认的宽度
const WIDTH = 1024
/**
* style 使 opacity
* @param field
@ -16,30 +20,31 @@ import { isArray, isFunction, isNumber, isString } from 'lodash';
* @param updateOptions
*/
function registerOpacityAttribute(
layer: ILayer,
field: StyleAttributeField,
values?: StyleAttributeOption,
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
fieldName: string,
layer: ILayer,
field: StyleAttributeField,
values?: StyleAttributeOption,
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
) {
layer.updateStyleAttribute('opacity', field, values, updateOptions);
layer.updateStyleAttribute(fieldName, field, values, updateOptions);
}
/**
* opacity
*/
function handleStyleOpacity(layer: ILayer, opacity: any) {
function handleStyleOpacity(fieldName: string, layer: ILayer, opacity: any) {
if (isString(opacity)) {
// opacity = 'string'
registerOpacityAttribute(layer, opacity, (value: any) => {
registerOpacityAttribute(fieldName, layer, opacity, (value: any) => {
return value;
});
} else if (isNumber(opacity)) {
// opacity = 0.4 -> opacity 传入数字、u_Opacity 生效、v_Opacity 不生效
registerOpacityAttribute(layer, [-1], undefined);
// opacity = 0.4 -> opacity 传入数字
registerOpacityAttribute(fieldName, layer, [opacity], undefined);
} else if (isArray(opacity) && opacity.length === 2) {
if (isString(opacity[0]) && isFunction(opacity[1])) {
// opacity = ['string', callback]
registerOpacityAttribute(layer, opacity[0], opacity[1]);
registerOpacityAttribute(fieldName, layer, opacity[0], opacity[1]);
} else if (
isString(opacity[0]) &&
isArray(opacity[1]) &&
@ -47,13 +52,110 @@ function handleStyleOpacity(layer: ILayer, opacity: any) {
isNumber(opacity[1][1])
) {
// opacity = ['string', [start: number, end: nuber]]
registerOpacityAttribute(layer, opacity[0], opacity[1]);
registerOpacityAttribute(fieldName, layer, opacity[0], opacity[1]);
} else {
registerOpacityAttribute(layer, [1.0], undefined);
registerOpacityAttribute(fieldName, layer, [1.0], undefined);
}
} else {
registerOpacityAttribute(layer, [1.0], undefined);
registerOpacityAttribute(fieldName, layer, [1.0], undefined);
}
}
export { handleStyleOpacity };
/**
* strokeOpacity
*/
function handleStyleStrokeOpacity(fieldName: string, layer: ILayer, strokeOpacity: any) {
handleStyleOpacity(fieldName, layer, strokeOpacity)
}
/**
* feature
* @param encodeDatalength
* @returns
*/
function getSize(encodeDatalength: number) {
let width = WIDTH;
let height = Math.ceil(encodeDatalength / width);
return { width, height }
}
/**
* index feature uv
* @param widthStep
* @param widthStart
* @param heightStep
* @param heightStart
* @param id
* @returns
*/
function getUvPosition(widthStep: number, widthStart: number, heightStep: number, heightStart: number, index: number) {
// index 从零开始
let row = Math.ceil((index + 1)/WIDTH); // 当前 index 所在的行
let column = (index + 1) % WIDTH
if(column === 0) { // 取余等于零
column = WIDTH
}
let u = widthStart + (column - 1) * widthStep
let v = 1 - (heightStart + (row - 1) * heightStep)
return [u, v]
}
/**
* 1 field originData style
* 2 heightCount WIDTH
* 3 createTexture2D
* @param heightCount
* @param createTexture2D
* @param originData
* @param field
* @returns
*/
function initTextureData(heightCount: number, createTexture2D: any, originData: any, field: string): ITexture2D {
let d = []
for(let i = 0; i < WIDTH * heightCount; i++) {
if(originData[i] && originData[i][field]) {
let v = originData[i][field] * 255
d.push( v, v, v, v )
}else {
d.push( 0, 0, 0, 0 )
}
}
let arr = new Uint8ClampedArray(d)
let imageData = new ImageData(arr, WIDTH, heightCount) // (arr, width, height)
let texture = createTexture2D({
flipY: true,
data: new Uint8Array(imageData.data),
width: imageData.width,
height: imageData.height
});
return texture
}
function initDefaultTextureData(heightCount: number, createTexture2D: any): ITexture2D {
let d = []
for(let i = 0; i < WIDTH * heightCount; i++) {
d.push( 255, 255, 255, 255 )
}
let arr = new Uint8ClampedArray(d)
let imageData = new ImageData(arr, WIDTH, heightCount) // (arr, width, height)
let texture = createTexture2D({
flipY: true,
data: new Uint8Array(imageData.data),
width: imageData.width,
height: imageData.height
});
return texture
}
export {
handleStyleOpacity,
handleStyleStrokeOpacity,
getSize,
getUvPosition,
initTextureData,
initDefaultTextureData
};

View File

@ -26,16 +26,19 @@ export default class Amap2demo extends React.Component {
lng: 121.107846,
lat: 30.267069,
opacity2: 0.2,
strokeOpacity2: 0.2
},
{
lng: 121.107,
lat: 30.267069,
opacity2: 0.4,
strokeOpacity2: 0.4
},
{
lng: 121.107846,
lat: 30.26718,
opacity2: 0.6,
strokeOpacity2: 0.6
},
// {
// lng: 38.54,
@ -60,15 +63,21 @@ export default class Amap2demo extends React.Component {
.color('rgba(255, 0, 0, 0.9)')
.size(10)
.style({
stroke: '#fff',
stroke: '#000',
storkeWidth: 2,
// strokeOpacity: 0.2,
// strokeOpacity: 'strokeOpacity2',
strokeOpacity: ['strokeOpacity2', (d: any) => {
return d
}],
// strokeOpacity: ['opacity2', [0.2, 0.6]],
// offsets: [100, 100],
// opacity: 'opacity2'
opacity: 'opacity2'
// opacity: 0.2
// opacity: ['opacity2', (d: any) => {
// return d
// }]
opacity: ['opacity2', [0.2, 0.6]],
// opacity: ['opacity2', [0.2, 0.6]],
})
.active(true);
scene.addLayer(layer);