feat: 栅格表达式添加 min/max/log10/log2/计算逻辑&文本更新避让能力完善 (#1594)

* feat: 栅格表示添加 min/max/log10/log2/计算逻辑

* fix: lint format

* fix: 文本避让

* fix: utils some error

* fix: 文本支持 fontFamily,fontweight,padding 更新

* chore: 图片标注图层空数据改为空图标

* chore: fillImange 默认shape 为透明
This commit is contained in:
@thinkinggis 2023-02-13 11:07:47 +08:00 committed by GitHub
parent faf6c7719f
commit ffee682445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 3715 additions and 462 deletions

View File

@ -33,14 +33,14 @@ export default () => {
'https://gw.alipayobjects.com/zos/bmw-prod/904d047a-16a5-461b-a921-98fa537fc04a.svg', 'https://gw.alipayobjects.com/zos/bmw-prod/904d047a-16a5-461b-a921-98fa537fc04a.svg',
); );
const data = await response.json(); const data = await response.json();
const newData = data.map((item: any) => { const newData = data.map((item: any,index: number) => {
item.type = ['00', '01', '02'][Math.floor(Math.random() * 3)]; item.type = ['00', '01', '02',''][index % 4];
return item; return item;
}); });
const imageLayer = new PointLayer({ const imageLayer = new PointLayer({
autoFit:false autoFit:false
}) })
.source(newData, { .source(newData.slice(0,4), {
parser: { parser: {
type: 'json', type: 'json',
x: 'longitude', x: 'longitude',
@ -52,25 +52,9 @@ export default () => {
}) })
.active(false) .active(false)
.size(20); .size(20);
scene.addLayer(imageLayer); scene.addLayer(imageLayer);
setInterval(()=>{
scene.addImage(
'00',
'https://gw.alipayobjects.com/mdn/rms_fcd5b3/afts/img/A*g8cUQ7pPT9YAAAAAAAAAAAAAARQnAQ',
);
scene.addImage(
'01',
'https://gw.alipayobjects.com/mdn/rms_fcd5b3/afts/img/A*LTcXTLBM7kYAAAAAAAAAAAAAARQnAQ',
);
scene.addImage(
'02',
'https://gw.alipayobjects.com/zos/bmw-prod/904d047a-16a5-461b-a921-98fa537fc04a.svg',
);
const data = newData.slice(0,5+ Math.round(Math.random()*10));
imageLayer.setData(data)
console.log(imageLayer)
console.log('更新')
},3000)
}, []); }, []);

File diff suppressed because it is too large Load Diff

View File

@ -298,20 +298,8 @@ export default class FontService extends EventEmitter implements IFontService {
} }
private getKey() { private getKey() {
return 'key'; const { fontFamily, fontWeight } = this.fontOptions;
const { return `${fontFamily}_${fontWeight}`;
fontFamily,
fontWeight,
fontSize,
buffer,
sdf,
radius,
cutoff,
} = this.fontOptions;
if (sdf) {
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer} ${radius} ${cutoff} `;
}
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer}`;
} }
/** /**

View File

@ -5,12 +5,7 @@ import 'reflect-metadata';
import { buildIconMaping } from '../../utils/font_util'; import { buildIconMaping } from '../../utils/font_util';
import { ITexture2D } from '../renderer/ITexture2D'; import { ITexture2D } from '../renderer/ITexture2D';
import { ISceneService } from '../scene/ISceneService'; import { ISceneService } from '../scene/ISceneService';
import { import { IIcon, IICONMap, IIconService, IImage } from './IIconService';
IIcon,
IICONMap,
IIconService,
IImage,
} from './IIconService';
const BUFFER = 3; const BUFFER = 3;
const MAX_CANVAS_WIDTH = 1024; const MAX_CANVAS_WIDTH = 1024;
const imageSize = 64; const imageSize = 64;
@ -48,7 +43,7 @@ export default class IconService extends EventEmitter implements IIconService {
}); });
} }
this.updateIconMap(); // 先存储 ID this.updateIconMap(); // 先存储 ID
imagedata = await this.loadImage(image) as HTMLImageElement; imagedata = (await this.loadImage(image)) as HTMLImageElement;
const iconImage = this.iconData.find((icon: IIcon) => { const iconImage = this.iconData.find((icon: IIcon) => {
return icon.id === id; return icon.id === id;
}); });
@ -58,7 +53,6 @@ export default class IconService extends EventEmitter implements IIconService {
iconImage.height = imagedata.height; iconImage.height = imagedata.height;
} }
this.update(); this.update();
} }
/** /**

View File

@ -12,17 +12,14 @@ import {
import { getMask, PointFillTriangulation } from '@antv/l7-utils'; import { getMask, PointFillTriangulation } from '@antv/l7-utils';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel'; import BaseModel from '../../core/BaseModel';
import { IPointLayerStyleOptions } from '../../core/interface'; import { IPointLayerStyleOptions, SizeUnitType } from '../../core/interface';
// animate pointLayer shader - support animate // animate pointLayer shader - support animate
import waveFillFrag from '../shaders/animate/wave_frag.glsl'; import waveFillFrag from '../shaders/animate/wave_frag.glsl';
// static pointLayer shader - not support animate // static pointLayer shader - not support animate
import pointFillFrag from '../shaders/fill_frag.glsl'; import pointFillFrag from '../shaders/fill_frag.glsl';
import pointFillVert from '../shaders/fill_vert.glsl'; import pointFillVert from '../shaders/fill_vert.glsl';
import { SizeUnitType } from '../../core/interface'
export default class FillModel extends BaseModel { export default class FillModel extends BaseModel {
public getUninforms(): IModelUniform { public getUninforms(): IModelUniform {
const { const {
opacity = 1, opacity = 1,
@ -100,9 +97,8 @@ export default class FillModel extends BaseModel {
}; };
} }
public getAnimateUniforms(): IModelUniform { public getAnimateUniforms(): IModelUniform {
const { const { animateOption = { enable: false } } =
animateOption = { enable: false }, this.layer.getLayerConfig() as ILayerConfig;
} = this.layer.getLayerConfig() as ILayerConfig;
return { return {
u_animate: this.animateOption2Array(animateOption), u_animate: this.animateOption2Array(animateOption),
u_time: this.layer.getLayerAnimateTime(), u_time: this.layer.getLayerAnimateTime(),
@ -122,7 +118,7 @@ export default class FillModel extends BaseModel {
} }
public async initModels(): Promise<IModel[]> { public async initModels(): Promise<IModel[]> {
return await this.buildModels(); return this.buildModels();
} }
public async buildModels(): Promise<IModel[]> { public async buildModels(): Promise<IModel[]> {
@ -139,8 +135,7 @@ export default class FillModel extends BaseModel {
const { frag, vert, type } = this.getShaders(animateOption); const { frag, vert, type } = this.getShaders(animateOption);
this.layer.triangulation = PointFillTriangulation; this.layer.triangulation = PointFillTriangulation;
const model = await this.layer const model = await this.layer.buildLayerModel({
.buildLayerModel({
moduleName: type, moduleName: type,
vertexShader: vert, vertexShader: vert,
fragmentShader: frag, fragmentShader: frag,
@ -162,9 +157,11 @@ export default class FillModel extends BaseModel {
* animateOption shader * animateOption shader
* @returns * @returns
*/ */
public getShaders( public getShaders(animateOption: Partial<IAnimateOption>): {
animateOption: Partial<IAnimateOption>, frag: string;
): { frag: string; vert: string; type: string } { vert: string;
type: string;
} {
if (animateOption.enable) { if (animateOption.enable) {
switch (animateOption.type) { switch (animateOption.type) {
case 'wave': case 'wave':
@ -242,9 +239,7 @@ export default class FillModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { size = 5 } = feature; const { size = 5 } = feature;
return Array.isArray(size) ? [size[0]] : [size]; return Array.isArray(size) ? [size[0]] : [size];
}, },
@ -264,9 +259,7 @@ export default class FillModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { shape = 2 } = feature; const { shape = 2 } = feature;
const shapeIndex = shape2d.indexOf(shape as string); const shapeIndex = shape2d.indexOf(shape as string);
return [shapeIndex]; return [shapeIndex];
@ -274,6 +267,4 @@ export default class FillModel extends BaseModel {
}, },
}); });
} }
} }

View File

@ -11,12 +11,11 @@ import {
import { getCullFace, getMask } from '@antv/l7-utils'; import { getCullFace, getMask } from '@antv/l7-utils';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel'; import BaseModel from '../../core/BaseModel';
import { IPointLayerStyleOptions } from '../../core/interface'; import { IPointLayerStyleOptions, SizeUnitType } from '../../core/interface';
import { PointFillTriangulation } from '../../core/triangulation'; import { PointFillTriangulation } from '../../core/triangulation';
// static pointLayer shader - not support animate // static pointLayer shader - not support animate
import pointFillFrag from '../shaders/image/fillImage_frag.glsl'; import pointFillFrag from '../shaders/image/fillImage_frag.glsl';
import pointFillVert from '../shaders/image/fillImage_vert.glsl'; import pointFillVert from '../shaders/image/fillImage_vert.glsl';
import { SizeUnitType } from '../../core/interface'
export default class FillImageModel extends BaseModel { export default class FillImageModel extends BaseModel {
private meter2coord: number = 1; private meter2coord: number = 1;
@ -135,18 +134,13 @@ export default class FillImageModel extends BaseModel {
public async initModels(): Promise<IModel[]> { public async initModels(): Promise<IModel[]> {
this.iconService.on('imageUpdate', this.updateTexture); this.iconService.on('imageUpdate', this.updateTexture);
this.updateTexture(); this.updateTexture();
return await this.buildModels(); return this.buildModels();
} }
public async buildModels(): Promise<IModel[]> { public async buildModels(): Promise<IModel[]> {
const { const { mask = false, maskInside = true } =
mask = false, this.layer.getLayerConfig() as IPointLayerStyleOptions;
maskInside = true, const model = await this.layer.buildLayerModel({
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
const model = await this.layer
.buildLayerModel({
moduleName: 'pointFillImage', moduleName: 'pointFillImage',
vertexShader: pointFillVert, vertexShader: pointFillVert,
fragmentShader: pointFillFrag, fragmentShader: pointFillFrag,
@ -159,8 +153,7 @@ export default class FillImageModel extends BaseModel {
face: getCullFace(this.mapService.version), face: getCullFace(this.mapService.version),
}, },
}); });
return [model] return [model];
} }
public clearModels() { public clearModels() {
@ -182,9 +175,7 @@ export default class FillImageModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { rotate = 0 } = feature; const { rotate = 0 } = feature;
return Array.isArray(rotate) ? [rotate[0]] : [rotate as number]; return Array.isArray(rotate) ? [rotate[0]] : [rotate as number];
}, },
@ -202,12 +193,10 @@ export default class FillImageModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 2, size: 2,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const iconMap = this.iconService.getIconMap(); const iconMap = this.iconService.getIconMap();
const { shape } = feature; const { shape } = feature;
const { x, y } = iconMap[shape as string] || { x: 0, y: 0 }; const { x, y } = iconMap[shape as string] || { x: -64, y: -64 };
return [x, y]; return [x, y];
}, },
}, },
@ -256,13 +245,9 @@ export default class FillImageModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { size = 5 } = feature; const { size = 5 } = feature;
return Array.isArray(size) return Array.isArray(size) ? [size[0]] : [size as number];
? [size[0]]
: [(size as number)];
}, },
}, },
}); });

View File

@ -83,7 +83,7 @@ export default class ImageModel extends BaseModel {
public async initModels(): Promise<IModel[]> { public async initModels(): Promise<IModel[]> {
this.iconService.on('imageUpdate', this.updateTexture); this.iconService.on('imageUpdate', this.updateTexture);
this.updateTexture(); this.updateTexture();
return await this.buildModels(); return this.buildModels();
} }
public clearModels() { public clearModels() {
@ -93,13 +93,10 @@ export default class ImageModel extends BaseModel {
} }
public async buildModels(): Promise<IModel[]> { public async buildModels(): Promise<IModel[]> {
const { const { mask = false, maskInside = true } =
mask = false, this.layer.getLayerConfig() as IPointLayerStyleOptions;
maskInside = true,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
const model = await this.layer const model = await this.layer.buildLayerModel({
.buildLayerModel({
moduleName: 'pointImage', moduleName: 'pointImage',
vertexShader: pointImageVert, vertexShader: pointImageVert,
fragmentShader: pointImageFrag, fragmentShader: pointImageFrag,
@ -110,8 +107,7 @@ export default class ImageModel extends BaseModel {
stencil: getMask(mask, maskInside), stencil: getMask(mask, maskInside),
}); });
return [model] return [model];
} }
protected registerBuiltinAttributes() { protected registerBuiltinAttributes() {
// point layer size; // point layer size;
@ -127,9 +123,7 @@ export default class ImageModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { size = 5 } = feature; const { size = 5 } = feature;
return Array.isArray(size) ? [size[0]] : [size as number]; return Array.isArray(size) ? [size[0]] : [size as number];
}, },
@ -149,12 +143,10 @@ export default class ImageModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 2, size: 2,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const iconMap = this.iconService.getIconMap(); const iconMap = this.iconService.getIconMap();
const { shape } = feature; const { shape } = feature;
const { x, y } = iconMap[shape as string] || { x: 0, y: 0 }; const { x, y } = iconMap[shape as string] || { x: -64, y: -64 }; // 非画布区域,默认的图标改为透明
return [x, y]; return [x, y];
}, },
}, },
@ -172,9 +164,10 @@ export default class ImageModel extends BaseModel {
}); });
// 更新完纹理后在更新的图层的时候需要更新所有的图层 // 更新完纹理后在更新的图层的时候需要更新所有的图层
// this.layer.layerModelNeedUpdate = true; // this.layer.layerModelNeedUpdate = true;
setTimeout(() => { // 延迟渲染 setTimeout(() => {
// 延迟渲染
this.layerService.throttleRenderLayers(); this.layerService.throttleRenderLayers();
}) });
return; return;
} }

View File

@ -12,7 +12,7 @@ import {
getMask, getMask,
padBounds, padBounds,
} from '@antv/l7-utils'; } from '@antv/l7-utils';
import { isNumber } from 'lodash'; import { isEqual, isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel'; import BaseModel from '../../core/BaseModel';
import { IPointLayerStyleOptions } from '../../core/interface'; import { IPointLayerStyleOptions } from '../../core/interface';
import CollisionIndex from '../../utils/collision-index'; import CollisionIndex from '../../utils/collision-index';
@ -102,9 +102,6 @@ export default class TextModel extends BaseModel {
opacity = 1.0, opacity = 1.0,
stroke = '#fff', stroke = '#fff',
strokeWidth = 0, strokeWidth = 0,
textAnchor = 'center',
textOffset,
textAllowOverlap = false,
halo = 0.5, halo = 0.5,
gamma = 2.0, gamma = 2.0,
raisingHeight = 0, raisingHeight = 0,
@ -116,11 +113,7 @@ export default class TextModel extends BaseModel {
this.textCount = Object.keys(mapping).length; this.textCount = Object.keys(mapping).length;
} }
this.preTextStyle = { this.preTextStyle = this.getTextStyle();
textAnchor,
textAllowOverlap,
textOffset,
};
if ( if (
this.dataTextureTest && this.dataTextureTest &&
@ -181,39 +174,27 @@ export default class TextModel extends BaseModel {
} }
public async initModels(): Promise<IModel[]> { public async initModels(): Promise<IModel[]> {
// 绑定事件 // 绑定事件
this.bindEvent(); this.bindEvent();
this.extent = this.textExtent(); this.extent = this.textExtent();
const { this.preTextStyle = this.getTextStyle();
textAnchor = 'center', return this.buildModels();
textAllowOverlap = true,
textOffset,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
this.preTextStyle = {
textAnchor,
textAllowOverlap,
textOffset
};
return await this.buildModels();
} }
public async buildModels(): Promise<IModel[]> { public async buildModels(): Promise<IModel[]> {
const { const {
mask = false, mask = false,
maskInside = true, maskInside = true,
textAllowOverlap = false textAllowOverlap = false,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions; } = this.layer.getLayerConfig() as IPointLayerStyleOptions;
// this.mapping(); 重复调用 // this.mapping(); 重复调用
this.initGlyph(); // this.initGlyph(); //
this.updateTexture(); this.updateTexture();
if (!textAllowOverlap) { if (!textAllowOverlap) {
this.filterGlyphs(); this.filterGlyphs();
} }
const model = await this.layer const model = await this.layer.buildLayerModel({
.buildLayerModel({
moduleName: 'pointText', moduleName: 'pointText',
vertexShader: textVert, vertexShader: textVert,
fragmentShader: textFrag, fragmentShader: textFrag,
@ -222,22 +203,44 @@ export default class TextModel extends BaseModel {
blend: this.getBlend(), blend: this.getBlend(),
stencil: getMask(mask, maskInside), stencil: getMask(mask, maskInside),
}); });
return [model] return [model];
} }
// 需要更新的场景
// 1. 文本偏移量发生改变
// 2. 文本锚点发生改变
// 3. 文本允许重叠发生改变
// 4. 文本字体发生改变
// 5. 文本字体粗细发生改变
public async needUpdate(): Promise<boolean> { public async needUpdate(): Promise<boolean> {
const { const {
textAllowOverlap = false, textAllowOverlap = false,
textAnchor = 'center', textAnchor = 'center',
textOffset textOffset,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions; padding,
const data = this.layer.getEncodedData(); fontFamily,
if(JSON.stringify(textOffset) !==JSON.stringify(this.preTextStyle.textOffset) ||textAnchor!==this.preTextStyle.textAnchor ) { fontWeight,
} = this.getTextStyle() as IPointLayerStyleOptions;
if (
!isEqual(padding, this.preTextStyle.padding) ||
!isEqual(textOffset, this.preTextStyle.textOffset) ||
!isEqual(textAnchor, this.preTextStyle.textAnchor) ||
!isEqual(fontFamily, this.preTextStyle.fontFamily) ||
!isEqual(fontWeight, this.preTextStyle.fontWeight)
) {
await this.mapping(); await this.mapping();
return true; return true;
} }
if(data.length < 5 || textAllowOverlap) { // 小于不做避让
// if (
// JSON.stringify(textOffset) !==
// JSON.stringify(this.preTextStyle.textOffset) ||
// textAnchor !== this.preTextStyle.textAnchor
// ) {
// await this.mapping();
// return true;
// }
if (textAllowOverlap) {
// 小于不做避让
return false; return false;
} }
@ -247,7 +250,8 @@ export default class TextModel extends BaseModel {
const flag = boundsContains(this.extent, extent); const flag = boundsContains(this.extent, extent);
// 文本不能压盖则进行过滤 // 文本不能压盖则进行过滤
if ( if (
((Math.abs(this.currentZoom - zoom) > 1 || !flag)) || Math.abs(this.currentZoom - zoom) > 0.5 ||
!flag ||
textAllowOverlap !== this.preTextStyle.textAllowOverlap textAllowOverlap !== this.preTextStyle.textAllowOverlap
) { ) {
// TODO this.mapping 数据未变化,避让 // TODO this.mapping 数据未变化,避让
@ -277,9 +281,7 @@ export default class TextModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { rotate = 0 } = feature; const { rotate = 0 } = feature;
return Array.isArray(rotate) ? [rotate[0]] : [rotate as number]; return Array.isArray(rotate) ? [rotate[0]] : [rotate as number];
}, },
@ -320,9 +322,7 @@ export default class TextModel extends BaseModel {
type: gl.FLOAT, type: gl.FLOAT,
}, },
size: 1, size: 1,
update: ( update: (feature: IEncodeFeature) => {
feature: IEncodeFeature,
) => {
const { size = 12 } = feature; const { size = 12 } = feature;
return Array.isArray(size) ? [size[0]] : [size as number]; return Array.isArray(size) ? [size[0]] : [size as number];
}, },
@ -362,7 +362,7 @@ export default class TextModel extends BaseModel {
this.initGlyph(); // this.initGlyph(); //
this.updateTexture(); this.updateTexture();
await this.reBuildModel(); await this.reBuildModel();
} };
private textExtent(): [[number, number], [number, number]] { private textExtent(): [[number, number], [number, number]] {
const bounds = this.mapService.getBounds(); const bounds = this.mapService.getBounds();
@ -372,10 +372,7 @@ export default class TextModel extends BaseModel {
* *
*/ */
private initTextFont() { private initTextFont() {
const { const { fontWeight, fontFamily } = this.getTextStyle();
fontWeight = '400',
fontFamily = 'sans-serif',
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
const data = this.layer.getEncodedData(); const data = this.layer.getEncodedData();
const characterSet: string[] = []; const characterSet: string[] = [];
data.forEach((item: IEncodeFeature) => { data.forEach((item: IEncodeFeature) => {
@ -400,10 +397,7 @@ export default class TextModel extends BaseModel {
* iconfont * iconfont
*/ */
private initIconFontTex() { private initIconFontTex() {
const { const { fontWeight, fontFamily } = this.getTextStyle();
fontWeight = '400',
fontFamily = 'sans-serif',
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
const data = this.layer.getEncodedData(); const data = this.layer.getEncodedData();
const characterSet: string[] = []; const characterSet: string[] = [];
data.forEach((item: IEncodeFeature) => { data.forEach((item: IEncodeFeature) => {
@ -421,6 +415,33 @@ export default class TextModel extends BaseModel {
}); });
} }
private getTextStyle() {
const {
fontWeight = '400',
fontFamily = 'sans-serif',
textAllowOverlap = false,
padding = [0, 0],
textAnchor = 'center',
textOffset = [0, 0],
opacity = 1,
strokeOpacity = 1,
strokeWidth = 0,
stroke = '#000',
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
return {
fontWeight,
fontFamily,
textAllowOverlap,
padding,
textAnchor,
textOffset,
opacity,
strokeOpacity,
strokeWidth,
stroke,
};
}
/** /**
* *
*/ */
@ -435,7 +456,7 @@ export default class TextModel extends BaseModel {
const data = this.layer.getEncodedData(); const data = this.layer.getEncodedData();
this.glyphInfo = data.map((feature: IEncodeFeature) => { this.glyphInfo = data.map((feature: IEncodeFeature) => {
const { shape = '', id, size = 1, } = feature; const { shape = '', id, size = 1 } = feature;
const shaping = shapeText( const shaping = shapeText(
shape.toString(), shape.toString(),
@ -473,13 +494,10 @@ export default class TextModel extends BaseModel {
* depend on originCentorid * depend on originCentorid
*/ */
private filterGlyphs() { private filterGlyphs() {
const { const { padding = [0, 0], textAllowOverlap = false } =
padding = [0, 0], this.layer.getLayerConfig() as IPointLayerStyleOptions;
textAllowOverlap = false,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
if (textAllowOverlap) { if (textAllowOverlap) {
// 如果允许文本覆盖 // 如果允许文本覆盖
// this.layer.setEncodedData(this.glyphInfo);
return; return;
} }
this.glyphInfoMap = {}; this.glyphInfoMap = {};
@ -491,9 +509,11 @@ export default class TextModel extends BaseModel {
const { shaping, id = 0 } = feature; const { shaping, id = 0 } = feature;
// const centroid = feature.centroid as [number, number]; // const centroid = feature.centroid as [number, number];
// const centroid = feature.originCentroid as [number, number]; // const centroid = feature.originCentroid as [number, number];
const centroid = (feature.version === 'GAODE2.x' const centroid = (
feature.version === 'GAODE2.x'
? feature.originCentroid ? feature.originCentroid
: feature.centroid) as [number, number]; : feature.centroid
) as [number, number];
const size = feature.size as number; const size = feature.size as number;
const fontScale: number = size / 16; const fontScale: number = size / 16;
const pixels = this.mapService.lngLatToContainer(centroid); const pixels = this.mapService.lngLatToContainer(centroid);
@ -525,8 +545,6 @@ export default class TextModel extends BaseModel {
const { iconfont = false } = this.layer.getLayerConfig(); const { iconfont = false } = this.layer.getLayerConfig();
// 1.生成文字纹理(或是生成 iconfont // 1.生成文字纹理(或是生成 iconfont
iconfont ? this.initIconFontTex() : this.initTextFont(); iconfont ? this.initIconFontTex() : this.initTextFont();
// this.initTextFont();
// 2.生成文字布局 // 2.生成文字布局
this.generateGlyphLayout(iconfont); this.generateGlyphLayout(iconfont);
} }
@ -550,13 +568,10 @@ export default class TextModel extends BaseModel {
} }
private async reBuildModel() { private async reBuildModel() {
const { const { mask = false, maskInside = true } =
mask = false, this.layer.getLayerConfig() as IPointLayerStyleOptions;
maskInside = true,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
this.filterGlyphs(); this.filterGlyphs();
const model = await this.layer const model = await this.layer.buildLayerModel({
.buildLayerModel({
moduleName: 'pointText', moduleName: 'pointText',
vertexShader: textVert, vertexShader: textVert,
fragmentShader: textFrag, fragmentShader: textFrag,

View File

@ -212,7 +212,7 @@ layer.scale('value'); // L7 能够自动推断为 identify
```ts ```ts
pointLayer.size('type', (type) => { pointLayer.filter('type', (type) => {
// 回调函数 // 回调函数
if (type === 'a') { if (type === 'a') {
return false; return false;

View File

@ -1,4 +1,3 @@
import { IRasterData } from '../../interface'; import { IRasterData } from '../../interface';
/** /**
@ -19,21 +18,41 @@ import { IRasterData } from '../../interface';
*/ */
export function mathematical(symbol: string, n1: number, n2: number) { export function mathematical(symbol: string, n1: number, n2: number) {
switch (symbol) { switch (symbol) {
case '+': return n1 + n2; case '+':
case '-': return n1 - n2; return n1 + n2;
case '*': return n1 * n2; case '-':
case '/': return n1 / n2; return n1 - n2;
case '%': return n1 % n2; case '*':
return n1 * n2;
case '^': return Math.pow(n1, n2); case '/':
case 'abs': return Math.abs(n1); return n1 / n2;
case 'floor': return Math.floor(n1); case '%':
case 'round': return Math.round(n1); return n1 % n2;
case 'ceil': return Math.ceil(n1);
case 'sin': return Math.sin(n1);
case 'cos': return Math.cos(n1);
case 'atan': return (n2 === -1) ? Math.atan(n1): Math.atan2(n1, n2);
case '^':
return Math.pow(n1, n2);
case 'abs':
return Math.abs(n1);
case 'floor':
return Math.floor(n1);
case 'round':
return Math.round(n1);
case 'ceil':
return Math.ceil(n1);
case 'sin':
return Math.sin(n1);
case 'cos':
return Math.cos(n1);
case 'atan':
return n2 === -1 ? Math.atan(n1) : Math.atan2(n1, n2);
case 'min':
return Math.min(n1, n2);
case 'max':
return Math.max(n1, n2);
case 'log10':
return Math.log(n1);
case 'log2':
return Math.log2(n1);
default: default:
console.warn('Calculate symbol err! Return default 0'); console.warn('Calculate symbol err! Return default 0');
return 0; return 0;
@ -47,7 +66,7 @@ export function mathematical(symbol: string, n1: number, n2: number) {
*/ */
export function calculate(express: any[], bandsData: IRasterData[]) { export function calculate(express: any[], bandsData: IRasterData[]) {
const { width, height } = bandsData[0]; const { width, height } = bandsData[0];
const dataArray = bandsData.map(band => band.rasterData) as Uint8Array[]; const dataArray = bandsData.map((band) => band.rasterData) as Uint8Array[];
const length = width * height; const length = width * height;
const rasterData = []; const rasterData = [];
const originExp = JSON.stringify(express); const originExp = JSON.stringify(express);
@ -63,7 +82,6 @@ export function calculate(express: any[], bandsData: IRasterData[]) {
const result = calculateExpress(exp); const result = calculateExpress(exp);
rasterData.push(result); rasterData.push(result);
} }
} }
return rasterData as unknown as Uint8Array; return rasterData as unknown as Uint8Array;
} }
@ -76,11 +94,19 @@ type IExpress = any[];
* @param dataArray * @param dataArray
* @param index * @param index
*/ */
export function spellExpress(express: IExpress, dataArray: Uint8Array[], index: number) { export function spellExpress(
express: IExpress,
dataArray: Uint8Array[],
index: number,
) {
/** /**
* *
*/ */
if(express.length === 2 && express[0] === 'band' && typeof express[1] === 'number') { if (
express.length === 2 &&
express[0] === 'band' &&
typeof express[1] === 'number'
) {
try { try {
return dataArray[express[1]][index]; return dataArray[express[1]][index];
} catch (err) { } catch (err) {
@ -103,13 +129,13 @@ export function spellExpress(express: IExpress, dataArray: Uint8Array[], index:
spellExpress(e, dataArray, index); spellExpress(e, dataArray, index);
} }
} }
}) });
} }
export function formatExpress(express: IExpress) { export function formatExpress(express: IExpress) {
const [symbol1, symbol2 = -1, symbol3 = -1] = express; const [symbol1, symbol2 = -1, symbol3 = -1] = express;
if (symbol1 === undefined) { if (symbol1 === undefined) {
console.warn('Express err!') console.warn('Express err!');
return ['+', 0, 0]; return ['+', 0, 0];
} }
const symbol = symbol1.replace(/\s+/g, ''); const symbol = symbol1.replace(/\s+/g, '');

View File

@ -2,7 +2,7 @@ import * as d3 from 'd3-color';
import { Context } from 'vm'; import { Context } from 'vm';
import { $window, isMini } from './mini-adapter'; import { $window, isMini } from './mini-adapter';
export interface IColorRamp { export interface IColorRamp {
type?: 'cat' | 'linear' | 'quantize' | 'custom' type?: 'cat' | 'linear' | 'quantize' | 'custom';
positions: number[]; positions: number[];
colors: string[]; colors: string[];
} }
@ -74,7 +74,6 @@ export function generateColorRamp(
ctx.fillStyle = gradient; ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1); ctx.fillRect(0, 0, 256, 1);
if (!isMini) { if (!isMini) {
data = ctx.getImageData(0, 0, 256, 1).data; data = ctx.getImageData(0, 0, 256, 1).data;
// 使用 createImageData 替代 new ImageData、兼容 IE11 // 使用 createImageData 替代 new ImageData、兼容 IE11
@ -115,7 +114,6 @@ export function generateLinearRamp(
for (let i = 0; i < colorRamp.colors.length; ++i) { for (let i = 0; i < colorRamp.colors.length; ++i) {
const value = Math.max((colorRamp.positions[i] - domain[0]) / step, 0); const value = Math.max((colorRamp.positions[i] - domain[0]) / step, 0);
console.log(value)
gradient.addColorStop(value, colorRamp.colors[i]); gradient.addColorStop(value, colorRamp.colors[i]);
} }
ctx.fillStyle = gradient; ctx.fillStyle = gradient;
@ -127,16 +125,11 @@ export function generateLinearRamp(
canvas = null; canvas = null;
// @ts-ignore // @ts-ignore
ctx = null; ctx = null;
return imageData return imageData;
} }
// 枚举类型 // 枚举类型
export function generateCatRamp( export function generateCatRamp(colorRamp: IColorRamp): ImageData | IImagedata {
colorRamp: IColorRamp,
): ImageData | IImagedata {
let canvas = $window.document.createElement('canvas'); let canvas = $window.document.createElement('canvas');
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D; let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
canvas.width = 256; canvas.width = 256;
@ -144,12 +137,12 @@ export function generateCatRamp(
const imageData = ctx.createImageData(256, 1); const imageData = ctx.createImageData(256, 1);
imageData.data.fill(0); imageData.data.fill(0);
colorRamp.positions.forEach((p: number, index: number) => { colorRamp.positions.forEach((p: number, index: number) => {
const colorArray = rgb2arr(colorRamp.colors[index]) const colorArray = rgb2arr(colorRamp.colors[index]);
imageData.data[p * 4 + 0] = colorArray[0] * 255; imageData.data[p * 4 + 0] = colorArray[0] * 255;
imageData.data[p * 4 + 1] = colorArray[1] * 255; imageData.data[p * 4 + 1] = colorArray[1] * 255;
imageData.data[p * 4 + 2] = colorArray[2] * 255; imageData.data[p * 4 + 2] = colorArray[2] * 255;
imageData.data[p * 4 + 3] = colorArray[3] * 255; imageData.data[p * 4 + 3] = colorArray[3] * 255;
}) });
// @ts-ignore // @ts-ignore
canvas = null; canvas = null;
// @ts-ignore // @ts-ignore
@ -163,7 +156,7 @@ export function generateQuantizeRamp(
): ImageData | IImagedata { ): ImageData | IImagedata {
let canvas = $window.document.createElement('canvas'); let canvas = $window.document.createElement('canvas');
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D; let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
ctx.globalAlpha = 1.0 ctx.globalAlpha = 1.0;
canvas.width = 256; canvas.width = 256;
canvas.height = 1; canvas.height = 1;
const step = 256 / colorRamp.colors.length; // TODO 精度问题 const step = 256 / colorRamp.colors.length; // TODO 精度问题
@ -176,14 +169,12 @@ export function generateQuantizeRamp(
ctx.moveTo(i * step, 0); // positioned at 50,25 ctx.moveTo(i * step, 0); // positioned at 50,25
ctx.lineTo((i + 1) * step, 0); ctx.lineTo((i + 1) * step, 0);
ctx.stroke(); ctx.stroke();
} }
const data = ctx.getImageData(0, 0, 256, 1).data; const data = ctx.getImageData(0, 0, 256, 1).data;
// 使用 createImageData 替代 new ImageData、兼容 IE11 // 使用 createImageData 替代 new ImageData、兼容 IE11
const imageData = toIEIMageData(ctx, data); const imageData = toIEIMageData(ctx, data);
// @ts-ignore // @ts-ignore
canvas = null; canvas = null;
// @ts-ignore // @ts-ignore
@ -197,25 +188,25 @@ export function generateCustomRamp(
colorRamp: IColorRamp, colorRamp: IColorRamp,
domain: [number, number], domain: [number, number],
): ImageData | IImagedata { ): ImageData | IImagedata {
let canvas = $window.document.createElement('canvas'); let canvas = $window.document.createElement('canvas');
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D; let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
ctx.globalAlpha = 1.0 ctx.globalAlpha = 1.0;
canvas.width = 256; canvas.width = 256;
canvas.height = 1; canvas.height = 1;
const step = domain[1] - domain[0]; const step = domain[1] - domain[0];
if (colorRamp.positions.length - colorRamp.colors.length !== 1) { if (colorRamp.positions.length - colorRamp.colors.length !== 1) {
console.warn('positions 的数字个数应当比 colors 的样式多一个,poisitions 的首尾值一般为数据的最大最新值') console.warn(
'positions 的数字个数应当比 colors 的样式多一个,poisitions 的首尾值一般为数据的最大最新值',
);
} }
for (let i = 0; i < colorRamp.colors.length; i++) { for (let i = 0; i < colorRamp.colors.length; i++) {
ctx.beginPath(); ctx.beginPath();
ctx.lineWidth = 2; ctx.lineWidth = 2;
ctx.strokeStyle = colorRamp.colors[i]; ctx.strokeStyle = colorRamp.colors[i];
ctx.moveTo((colorRamp.positions[i] - domain[0]) / step * 255, 0); // positioned at 50,25 ctx.moveTo(((colorRamp.positions[i] - domain[0]) / step) * 255, 0); // positioned at 50,25
ctx.lineTo((colorRamp.positions[i + 1]- domain[0]) / step * 255, 0); ctx.lineTo(((colorRamp.positions[i + 1] - domain[0]) / step) * 255, 0);
ctx.stroke(); ctx.stroke();
} }
const data = ctx.getImageData(0, 0, 256, 1).data; const data = ctx.getImageData(0, 0, 256, 1).data;
const imageData = toIEIMageData(ctx, data); const imageData = toIEIMageData(ctx, data);
@ -233,15 +224,15 @@ function toIEIMageData(ctx: Context, data: Uint8ClampedArray) {
imageData.data[i + 2] = data[i + 2]; imageData.data[i + 2] = data[i + 2];
imageData.data[i + 3] = data[i + 3]; imageData.data[i + 3] = data[i + 3];
} }
return imageData return imageData;
} }
export function getDefaultDomain(rampColors: IColorRamp) { export function getDefaultDomain(rampColors: IColorRamp) {
switch (rampColors.type) { switch (rampColors.type) {
case 'cat': case 'cat':
return [0,255] return [0, 255];
default: default:
[0,1] [0, 1];
}
} }
}

View File

@ -1,22 +1,19 @@
// @ts-ignore // @ts-ignore
export { djb2hash, BKDRHash } from './hash';
import * as DOM from './dom';
import * as Satistics from './statistics';
export { DOM, Satistics };
export * from './mini-adapter/index';
export * from './ajax'; export * from './ajax';
export * from './geo';
export * from './lru_cache';
export * from './event';
export * from './color';
export * from './anchor'; export * from './anchor';
export * from './stencli'; export * from './color';
export * from './worker-helper';
export * from './cull'; export * from './cull';
export * as DOM from './dom';
export * from './env'; export * from './env';
export * from './tileset-manager'; export * from './event';
export * from './workers/triangulation'; export * from './geo';
export { BKDRHash, djb2hash } from './hash';
export * from './lineAtOffset'; export * from './lineAtOffset';
export * from './lru_cache';
export * from './mini-adapter/index';
export * as Satistics from './statistics';
export * from './stencli';
export * from './tileset-manager';
export * from './worker-helper';
export * from './workers/triangulation';