mirror of https://gitee.com/antv-l7/antv-l7
Merge pull request #134 from antvis/animate
feat(layer): add citybuildinglayer & add line add animate
This commit is contained in:
commit
8d6aadafea
|
@ -73,7 +73,8 @@ module.exports = [
|
||||||
'isFunction',
|
'isFunction',
|
||||||
'cloneDeep',
|
'cloneDeep',
|
||||||
'isString',
|
'isString',
|
||||||
'isNumber'
|
'isNumber',
|
||||||
|
'merge'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -26,6 +26,7 @@ fetch('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json')
|
||||||
.size('t', function(level) {
|
.size('t', function(level) {
|
||||||
return [ 1, 2, level * 2 + 20 ];
|
return [ 1, 2, level * 2 + 20 ];
|
||||||
})
|
})
|
||||||
|
.active(true)
|
||||||
.color('t', [
|
.color('t', [
|
||||||
'#094D4A',
|
'#094D4A',
|
||||||
'#146968',
|
'#146968',
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Ajv from 'ajv';
|
import Ajv from 'ajv';
|
||||||
import { injectable, postConstruct } from 'inversify';
|
import { injectable, postConstruct } from 'inversify';
|
||||||
|
import { merge } from 'lodash';
|
||||||
import { ILayerConfig } from '../layer/ILayerService';
|
import { ILayerConfig } from '../layer/ILayerService';
|
||||||
import { IGlobalConfigService, ISceneConfig } from './IConfigService';
|
import { IGlobalConfigService, ISceneConfig } from './IConfigService';
|
||||||
import mapConfigSchema from './mapConfigSchema';
|
import mapConfigSchema from './mapConfigSchema';
|
||||||
|
@ -63,6 +64,12 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
||||||
enableTAA: false,
|
enableTAA: false,
|
||||||
jitterScale: 1,
|
jitterScale: 1,
|
||||||
enableLighting: false,
|
enableLighting: false,
|
||||||
|
animateOption: {
|
||||||
|
enable: false,
|
||||||
|
interval: 0.2,
|
||||||
|
duration: 4,
|
||||||
|
trailLength: 0.15,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// @see https://github.com/epoberezkin/ajv#options
|
// @see https://github.com/epoberezkin/ajv#options
|
||||||
|
@ -141,9 +148,7 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
||||||
) {
|
) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.layerConfigCache[layerId] = {
|
this.layerConfigCache[layerId] = {
|
||||||
...this.sceneConfigCache[sceneId],
|
...merge({}, this.sceneConfigCache[sceneId], defaultLayerConfig, config),
|
||||||
...defaultLayerConfig,
|
|
||||||
...config,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ const VECTOR_TO_POINT_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];
|
||||||
@injectable()
|
@injectable()
|
||||||
export default class CoordinateSystemService
|
export default class CoordinateSystemService
|
||||||
implements ICoordinateSystemService {
|
implements ICoordinateSystemService {
|
||||||
|
public needRefresh: boolean = true;
|
||||||
@inject(TYPES.ICameraService)
|
@inject(TYPES.ICameraService)
|
||||||
private readonly cameraService: ICameraService;
|
private readonly cameraService: ICameraService;
|
||||||
|
|
||||||
|
@ -59,6 +60,9 @@ export default class CoordinateSystemService
|
||||||
* TODO: 使用 memoize 缓存参数以及计算结果
|
* TODO: 使用 memoize 缓存参数以及计算结果
|
||||||
*/
|
*/
|
||||||
public refresh(): void {
|
public refresh(): void {
|
||||||
|
// if (!this.needRefresh) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
const zoom = this.cameraService.getZoom();
|
const zoom = this.cameraService.getZoom();
|
||||||
const zoomScale = this.cameraService.getZoomScale();
|
const zoomScale = this.cameraService.getZoomScale();
|
||||||
const center = this.cameraService.getCenter();
|
const center = this.cameraService.getCenter();
|
||||||
|
@ -86,6 +90,7 @@ export default class CoordinateSystemService
|
||||||
} else if (this.coordinateSystem === CoordinateSystem.P20_OFFSET) {
|
} else if (this.coordinateSystem === CoordinateSystem.P20_OFFSET) {
|
||||||
this.calculateLnglatOffset(center, zoom, zoomScale, true);
|
this.calculateLnglatOffset(center, zoom, zoomScale, true);
|
||||||
}
|
}
|
||||||
|
this.needRefresh = false;
|
||||||
|
|
||||||
// TODO: 判断是否应用瓦片 & 常规坐标系
|
// TODO: 判断是否应用瓦片 & 常规坐标系
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ export const CoordinateUniform = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ICoordinateSystemService {
|
export interface ICoordinateSystemService {
|
||||||
|
needRefresh: boolean;
|
||||||
refresh(): void;
|
refresh(): void;
|
||||||
getCoordinateSystem(): CoordinateSystem;
|
getCoordinateSystem(): CoordinateSystem;
|
||||||
setCoordinateSystem(coordinateSystem: CoordinateSystem): void;
|
setCoordinateSystem(coordinateSystem: CoordinateSystem): void;
|
||||||
|
|
|
@ -68,7 +68,6 @@ export default class InteractionService extends EventEmitter
|
||||||
this.logger.debug('add event listeners on canvas');
|
this.logger.debug('add event listeners on canvas');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeEventListenerOnMap() {
|
private removeEventListenerOnMap() {
|
||||||
const $containter = this.mapService.getMapContainer();
|
const $containter = this.mapService.getMapContainer();
|
||||||
if ($containter) {
|
if ($containter) {
|
||||||
|
|
|
@ -53,6 +53,7 @@ export interface ILayerModel {
|
||||||
render(): void;
|
render(): void;
|
||||||
getUninforms(): IModelUniform;
|
getUninforms(): IModelUniform;
|
||||||
getDefaultStyle(): unknown;
|
getDefaultStyle(): unknown;
|
||||||
|
getAnimateUniforms(): IModelUniform;
|
||||||
buildModels(): IModel[];
|
buildModels(): IModel[];
|
||||||
}
|
}
|
||||||
export interface IModelUniform {
|
export interface IModelUniform {
|
||||||
|
@ -78,6 +79,7 @@ export interface ILayer {
|
||||||
zIndex: number;
|
zIndex: number;
|
||||||
plugins: ILayerPlugin[];
|
plugins: ILayerPlugin[];
|
||||||
layerModelNeedUpdate: boolean;
|
layerModelNeedUpdate: boolean;
|
||||||
|
layerModel: ILayerModel;
|
||||||
dataState: IDataState; // 数据流状态
|
dataState: IDataState; // 数据流状态
|
||||||
pickedFeatureID: number;
|
pickedFeatureID: number;
|
||||||
hooks: {
|
hooks: {
|
||||||
|
@ -116,7 +118,7 @@ export interface ILayer {
|
||||||
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||||
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||||
label(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
label(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||||
animate(option: IAnimateOption): ILayer;
|
animate(option: Partial<IAnimateOption> | boolean): ILayer;
|
||||||
// pattern(field: string, value: StyleAttributeOption): ILayer;
|
// pattern(field: string, value: StyleAttributeOption): ILayer;
|
||||||
filter(field: string, value: StyleAttributeOption): ILayer;
|
filter(field: string, value: StyleAttributeOption): ILayer;
|
||||||
active(option: IActiveOption | boolean): ILayer;
|
active(option: IActiveOption | boolean): ILayer;
|
||||||
|
@ -172,6 +174,8 @@ export interface ILayer {
|
||||||
pick(query: { x: number; y: number }): void;
|
pick(query: { x: number; y: number }): void;
|
||||||
|
|
||||||
updateLayerConfig(configToUpdate: Partial<ILayerConfig | unknown>): void;
|
updateLayerConfig(configToUpdate: Partial<ILayerConfig | unknown>): void;
|
||||||
|
setAnimateStartTime(): void;
|
||||||
|
getLayerAnimateTime(): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -242,6 +246,7 @@ export interface ILayerConfig {
|
||||||
* 开启光照
|
* 开启光照
|
||||||
*/
|
*/
|
||||||
enableLighting: boolean;
|
enableLighting: boolean;
|
||||||
|
animateOption: Partial<IAnimateOption>;
|
||||||
onHover(pickedFeature: IPickedFeature): void;
|
onHover(pickedFeature: IPickedFeature): void;
|
||||||
onClick(pickedFeature: IPickedFeature): void;
|
onClick(pickedFeature: IPickedFeature): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ export interface IAnimateOption {
|
||||||
interval?: number;
|
interval?: number;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
trailLength?: number;
|
trailLength?: number;
|
||||||
|
repeat?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEncodeFeature {
|
export interface IEncodeFeature {
|
||||||
|
@ -118,7 +119,7 @@ export interface IStyleAttributeInitializationOptions {
|
||||||
type: AttributeType;
|
type: AttributeType;
|
||||||
scale?: {
|
scale?: {
|
||||||
field: StyleAttributeField;
|
field: StyleAttributeField;
|
||||||
values: unknown[];
|
values: unknown[] | string;
|
||||||
names: string[];
|
names: string[];
|
||||||
type: StyleScaleType;
|
type: StyleScaleType;
|
||||||
callback?: (...args: any[]) => [];
|
callback?: (...args: any[]) => [];
|
||||||
|
|
|
@ -81,6 +81,7 @@ export default class LayerService implements ILayerService {
|
||||||
|
|
||||||
public startAnimate() {
|
public startAnimate() {
|
||||||
if (this.animateInstanceCount++ === 0) {
|
if (this.animateInstanceCount++ === 0) {
|
||||||
|
this.clock.start();
|
||||||
this.runRender();
|
this.runRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +89,7 @@ export default class LayerService implements ILayerService {
|
||||||
public stopAnimate() {
|
public stopAnimate() {
|
||||||
if (--this.animateInstanceCount === 0) {
|
if (--this.animateInstanceCount === 0) {
|
||||||
this.stopRender();
|
this.stopRender();
|
||||||
|
this.clock.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +104,7 @@ export default class LayerService implements ILayerService {
|
||||||
|
|
||||||
private runRender() {
|
private runRender() {
|
||||||
this.renderLayers();
|
this.renderLayers();
|
||||||
this.layerRenderID = requestAnimationFrame(this.renderLayers.bind(this));
|
this.layerRenderID = requestAnimationFrame(this.runRender.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private stopRender() {
|
private stopRender() {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { ICameraService, IViewport } from '../camera/ICameraService';
|
||||||
import { IControlService } from '../component/IControlService';
|
import { IControlService } from '../component/IControlService';
|
||||||
import { IMarkerService } from '../component/IMarkerService';
|
import { IMarkerService } from '../component/IMarkerService';
|
||||||
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
||||||
|
import { ICoordinateSystemService } from '../coordinate/ICoordinateSystemService';
|
||||||
import { IInteractionService } from '../interaction/IInteractionService';
|
import { IInteractionService } from '../interaction/IInteractionService';
|
||||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||||
import { ILogService } from '../log/ILogService';
|
import { ILogService } from '../log/ILogService';
|
||||||
|
@ -47,6 +48,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
@inject(TYPES.IMapService)
|
@inject(TYPES.IMapService)
|
||||||
private readonly map: IMapService;
|
private readonly map: IMapService;
|
||||||
|
|
||||||
|
@inject(TYPES.ICoordinateSystemService)
|
||||||
|
private readonly coordinateSystemService: ICoordinateSystemService;
|
||||||
|
|
||||||
@inject(TYPES.IRendererService)
|
@inject(TYPES.IRendererService)
|
||||||
private readonly rendererService: IRendererService;
|
private readonly rendererService: IRendererService;
|
||||||
|
|
||||||
|
@ -137,6 +141,8 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
this.map.addMarkerContainer();
|
this.map.addMarkerContainer();
|
||||||
// 初始化未加载的marker;
|
// 初始化未加载的marker;
|
||||||
this.markerService.addMarkers();
|
this.markerService.addMarkers();
|
||||||
|
// 地图初始化之后 才能初始化 container 上的交互
|
||||||
|
this.interactionService.init();
|
||||||
this.logger.debug('map loaded');
|
this.logger.debug('map loaded');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,8 +166,6 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
this.logger.error('容器 id 不存在');
|
this.logger.error('容器 id 不存在');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化 container 上的交互
|
|
||||||
this.interactionService.init();
|
|
||||||
this.logger.debug(`scene ${this.id} renderer loaded`);
|
this.logger.debug(`scene ${this.id} renderer loaded`);
|
||||||
});
|
});
|
||||||
// TODO:init worker, fontAtlas...
|
// TODO:init worker, fontAtlas...
|
||||||
|
@ -249,6 +253,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
||||||
});
|
});
|
||||||
// 触发 Map, canvas
|
// 触发 Map, canvas
|
||||||
DOM.triggerResize();
|
DOM.triggerResize();
|
||||||
|
this.coordinateSystemService.needRefresh = true;
|
||||||
// repaint layers
|
// repaint layers
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,3 +32,9 @@ vec2 unProjectFlat(vec2 px){
|
||||||
float lng=x/d;
|
float lng=x/d;
|
||||||
return vec2(lng,lat);
|
return vec2(lng,lat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float pixelDistance(vec2 from, vec2 to) {
|
||||||
|
vec2 a1 = ProjectFlat(from);
|
||||||
|
vec2 b1 = ProjectFlat(to);
|
||||||
|
return distance(a1, b1);
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export interface ICircleVertex {
|
||||||
color: number[];
|
color: number[];
|
||||||
radius: number;
|
radius: number;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
strokeColor: number[];
|
stroke: number[];
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
strokeOpacity: number;
|
strokeOpacity: number;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ export function packCircleVertex(
|
||||||
tileY,
|
tileY,
|
||||||
shape,
|
shape,
|
||||||
opacity, // packed buffer1
|
opacity, // packed buffer1
|
||||||
strokeColor,
|
stroke,
|
||||||
strokeWidth,
|
strokeWidth,
|
||||||
strokeOpacity, // packed buffer2
|
strokeOpacity, // packed buffer2
|
||||||
} = props;
|
} = props;
|
||||||
|
@ -81,8 +81,8 @@ export function packCircleVertex(
|
||||||
packUint8ToFloat(color[2], color[3]),
|
packUint8ToFloat(color[2], color[3]),
|
||||||
];
|
];
|
||||||
const packedStrokeColor: [number, number] = [
|
const packedStrokeColor: [number, number] = [
|
||||||
packUint8ToFloat(strokeColor[0], strokeColor[1]),
|
packUint8ToFloat(stroke[0], stroke[1]),
|
||||||
packUint8ToFloat(strokeColor[2], strokeColor[3]),
|
packUint8ToFloat(stroke[2], stroke[3]),
|
||||||
];
|
];
|
||||||
|
|
||||||
[
|
[
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { IEncodeFeature } from '@antv/l7-core';
|
||||||
|
import BaseLayer from '../core/BaseLayer';
|
||||||
|
import CityBuildModel from './models/build';
|
||||||
|
|
||||||
|
export default class CityBuildingLayer extends BaseLayer {
|
||||||
|
public type: string = 'PolygonLayer';
|
||||||
|
|
||||||
|
protected getConfigSchema() {
|
||||||
|
return {
|
||||||
|
properties: {
|
||||||
|
opacity: {
|
||||||
|
type: 'number',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected renderModels() {
|
||||||
|
this.models.forEach((model) =>
|
||||||
|
model.draw({
|
||||||
|
uniforms: this.layerModel.getUninforms(),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected buildModels() {
|
||||||
|
this.layerModel = new CityBuildModel(this);
|
||||||
|
this.models = this.layerModel.buildModels();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getModelType(): string {
|
||||||
|
return 'citybuilding';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core';
|
||||||
|
import { rgb2arr } from '@antv/l7-utils';
|
||||||
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { PolygonExtrudeTriangulation } from '../../core/triangulation';
|
||||||
|
import buildFrag from '../shaders/build_frag.glsl';
|
||||||
|
import buildVert from '../shaders/build_vert.glsl';
|
||||||
|
interface ICityBuildLayerStyleOptions {
|
||||||
|
opacity: number;
|
||||||
|
baseColor: string;
|
||||||
|
brightColor: string;
|
||||||
|
windowColor: string;
|
||||||
|
}
|
||||||
|
export default class CityBuildModel extends BaseModel {
|
||||||
|
public getUninforms() {
|
||||||
|
const {
|
||||||
|
opacity = 1,
|
||||||
|
baseColor = 'rgb(16,16,16)',
|
||||||
|
brightColor = 'rgb(255,176,38)',
|
||||||
|
windowColor = 'rgb(30,60,89)',
|
||||||
|
} = this.layer.getLayerConfig() as ICityBuildLayerStyleOptions;
|
||||||
|
return {
|
||||||
|
u_opacity: opacity,
|
||||||
|
u_baseColor: rgb2arr(baseColor),
|
||||||
|
u_brightColor: rgb2arr(brightColor),
|
||||||
|
u_windowColor: rgb2arr(windowColor),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public buildModels(): IModel[] {
|
||||||
|
this.startModelAnimate();
|
||||||
|
return [
|
||||||
|
this.layer.buildLayerModel({
|
||||||
|
moduleName: 'cityBuilding',
|
||||||
|
vertexShader: buildVert,
|
||||||
|
fragmentShader: buildFrag,
|
||||||
|
triangulation: PolygonExtrudeTriangulation,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected registerBuiltinAttributes() {
|
||||||
|
// point layer size;
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'normal',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Normal',
|
||||||
|
buffer: {
|
||||||
|
// give the WebGL driver a hint that this buffer may change
|
||||||
|
usage: gl.STATIC_DRAW,
|
||||||
|
data: [],
|
||||||
|
type: gl.FLOAT,
|
||||||
|
},
|
||||||
|
size: 3,
|
||||||
|
update: (
|
||||||
|
feature: IEncodeFeature,
|
||||||
|
featureIdx: number,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
normal: number[],
|
||||||
|
) => {
|
||||||
|
return normal;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'size',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Size',
|
||||||
|
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,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
) => {
|
||||||
|
const { size } = feature;
|
||||||
|
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'uv',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Uv',
|
||||||
|
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,
|
||||||
|
) => {
|
||||||
|
const { size } = feature;
|
||||||
|
return [vertex[3], vertex[4]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
uniform float u_opacity: 1.0;
|
||||||
|
uniform vec4 u_baseColor : [ 1.0, 0, 0, 1.0 ];
|
||||||
|
uniform vec4 u_brightColor : [ 1.0, 0, 0, 1.0 ];
|
||||||
|
uniform vec4 u_windowColor : [ 1.0, 0, 0, 1.0 ];
|
||||||
|
uniform float u_near : 0;
|
||||||
|
uniform float u_far : 1;
|
||||||
|
varying vec4 v_Color;
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
uniform float u_Zoom : 1;
|
||||||
|
uniform float u_time;
|
||||||
|
|
||||||
|
#pragma include "picking"
|
||||||
|
|
||||||
|
vec3 getWindowColor(float n, float hot, vec3 brightColor, vec3 darkColor) {
|
||||||
|
float s = step(hot, n);
|
||||||
|
vec3 color = mix(brightColor,vec3(0.9,0.9,1.0),n);
|
||||||
|
|
||||||
|
return mix(darkColor, color, s);
|
||||||
|
}
|
||||||
|
float random (vec2 st) {
|
||||||
|
return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float LinearizeDepth()
|
||||||
|
{
|
||||||
|
float z = gl_FragCoord.z * 2.0 - 1.0;
|
||||||
|
return (2.0 * u_near * u_far) / (u_far + u_near - z * (u_far - u_near));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fog(vec3 color, vec3 fogColor, float depth){
|
||||||
|
float fogFactor=clamp(depth,0.0,1.0);
|
||||||
|
vec3 output_color=mix(fogColor,color,fogFactor);
|
||||||
|
return output_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdRect(vec2 p, vec2 sz) {
|
||||||
|
vec2 d = abs(p) - sz;
|
||||||
|
float outside = length(max(d, 0.));
|
||||||
|
float inside = min(max(d.x, d.y), 0.);
|
||||||
|
return outside + inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = v_Color;
|
||||||
|
gl_FragColor.a *= u_opacity;
|
||||||
|
|
||||||
|
vec3 baseColor = u_baseColor.xyz;
|
||||||
|
vec3 brightColor = u_brightColor.xyz;
|
||||||
|
vec3 windowColor = u_windowColor.xyz;
|
||||||
|
float targetColId = 5.;
|
||||||
|
float depth = 1.0 - LinearizeDepth() / u_far * u_Zoom;
|
||||||
|
vec3 fogColor = vec3(23.0/255.0,31.0/255.0,51.0/255.0);
|
||||||
|
if(v_texCoord.x < 0.) { //顶部颜色
|
||||||
|
vec3 foggedColor = fog(baseColor.xyz + vec3(0.12*0.9,0.2*0.9,0.3*0.9),fogColor,depth);
|
||||||
|
gl_FragColor = vec4( foggedColor, v_Color.w);
|
||||||
|
}else { // 侧面颜色
|
||||||
|
vec2 st = v_texCoord;
|
||||||
|
vec2 UvScale = v_texCoord;
|
||||||
|
float tStep = min(0.08,max(0.05* (18.0-u_Zoom),0.02));
|
||||||
|
float tStart = 0.25 * tStep;
|
||||||
|
float tEnd = 0.75 * tStep;
|
||||||
|
float u = mod(UvScale.x, tStep);
|
||||||
|
float v = mod(UvScale.y, tStep);
|
||||||
|
float ux = floor(UvScale.x/tStep);
|
||||||
|
float uy = floor(UvScale.y/tStep);
|
||||||
|
float n = random(vec2(ux,uy));
|
||||||
|
float lightP = u_time;
|
||||||
|
float head = 1.0- step(0.005,st.y);
|
||||||
|
/*step3*/
|
||||||
|
// 将窗户颜色和墙面颜色区别开来
|
||||||
|
float sU = step(tStart, u) - step(tEnd, u);
|
||||||
|
float sV = step(tStart, v) - step(tEnd, v);
|
||||||
|
vec2 windowSize = vec2(abs(tEnd-tStart),abs(tEnd-tStart));
|
||||||
|
float dist = sdRect(vec2(u,v), windowSize);
|
||||||
|
float s = sU * sV;
|
||||||
|
|
||||||
|
float curColId = floor(UvScale.x / tStep);
|
||||||
|
float sCol = step(targetColId - 0.2, curColId) - step(targetColId + 0.2, curColId);
|
||||||
|
|
||||||
|
float mLightP = mod(lightP, 2.);
|
||||||
|
float sRow = step(mLightP - 0.2, st.y) - step(mLightP, st.y);
|
||||||
|
if(ux == targetColId){
|
||||||
|
n =0.;
|
||||||
|
}
|
||||||
|
float timeP = min(0.75, abs ( sin(u_time/6.0) ) );
|
||||||
|
float hot = smoothstep(1.0,0.0,timeP);
|
||||||
|
vec3 color = mix(baseColor, getWindowColor(n,hot,brightColor,windowColor), s);
|
||||||
|
//vec3 color = mix(baseColor, getWindowColor(n,hot,brightColor,windowColor), 1.0);
|
||||||
|
float sFinal = s * sCol * sRow;
|
||||||
|
color += mix(baseColor, brightColor, sFinal*n);
|
||||||
|
if (st.y<0.01){
|
||||||
|
color = baseColor;
|
||||||
|
}
|
||||||
|
if(head ==1.0) { // 顶部亮线
|
||||||
|
color = brightColor;
|
||||||
|
}
|
||||||
|
color = color * v_Color.rgb;
|
||||||
|
|
||||||
|
vec3 foggedColor = fog(color,fogColor,depth);
|
||||||
|
|
||||||
|
gl_FragColor = vec4(foggedColor,1.0);
|
||||||
|
}
|
||||||
|
gl_FragColor = filterColor(gl_FragColor);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#define ambientRatio 0.5
|
||||||
|
#define diffuseRatio 0.3
|
||||||
|
#define specularRatio 0.2
|
||||||
|
|
||||||
|
attribute vec4 a_Color;
|
||||||
|
attribute vec3 a_Position;
|
||||||
|
attribute vec3 a_Normal;
|
||||||
|
attribute float a_Size;
|
||||||
|
uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
|
attribute vec2 a_Uv;
|
||||||
|
varying vec2 v_texCoord;
|
||||||
|
|
||||||
|
varying vec4 v_Color;
|
||||||
|
|
||||||
|
#pragma include "projection"
|
||||||
|
#pragma include "light"
|
||||||
|
#pragma include "picking"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0);
|
||||||
|
vec4 project_pos = project_position(pos);
|
||||||
|
v_texCoord = a_Uv;
|
||||||
|
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||||
|
|
||||||
|
float lightWeight = calc_lighting(pos);
|
||||||
|
// v_Color = a_Color;
|
||||||
|
v_Color = vec4(a_Color.rgb * lightWeight, a_Color.w);
|
||||||
|
|
||||||
|
setPickingColor(a_PickingColor);
|
||||||
|
}
|
|
@ -55,7 +55,7 @@ let layerIdCounter = 0;
|
||||||
export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
implements ILayer {
|
implements ILayer {
|
||||||
public id: string = `${layerIdCounter++}`;
|
public id: string = `${layerIdCounter++}`;
|
||||||
public name: string;
|
public name: string = `${layerIdCounter++}`;
|
||||||
public type: string;
|
public type: string;
|
||||||
public visible: boolean = true;
|
public visible: boolean = true;
|
||||||
public zIndex: number = 0;
|
public zIndex: number = 0;
|
||||||
|
@ -103,6 +103,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
options?: ISourceCFG;
|
options?: ISourceCFG;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public layerModel: ILayerModel;
|
||||||
|
|
||||||
@lazyInject(TYPES.ILogService)
|
@lazyInject(TYPES.ILogService)
|
||||||
protected readonly logger: ILogService;
|
protected readonly logger: ILogService;
|
||||||
|
|
||||||
|
@ -133,8 +135,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
) => IPostProcessingPass<unknown>;
|
) => IPostProcessingPass<unknown>;
|
||||||
protected normalPassFactory: (name: string) => IPass<unknown>;
|
protected normalPassFactory: (name: string) => IPass<unknown>;
|
||||||
|
|
||||||
protected layerModel: ILayerModel;
|
|
||||||
|
|
||||||
protected animateOptions: IAnimateOption = { enable: false };
|
protected animateOptions: IAnimateOption = { enable: false };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,6 +165,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
|
|
||||||
private scaleOptions: IScaleOptions = {};
|
private scaleOptions: IScaleOptions = {};
|
||||||
|
|
||||||
|
private AnimateStartTime: number;
|
||||||
|
|
||||||
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
||||||
super();
|
super();
|
||||||
this.name = config.name || this.id;
|
this.name = config.name || this.id;
|
||||||
|
@ -298,11 +300,16 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
|
|
||||||
this.hooks.afterInit.call();
|
this.hooks.afterInit.call();
|
||||||
// 更新 module 样式
|
// 更新 model 样式
|
||||||
this.updateLayerConfig({
|
this.updateLayerConfig({
|
||||||
...this.rawConfig,
|
|
||||||
...(this.getDefaultConfig() as object),
|
...(this.getDefaultConfig() as object),
|
||||||
|
...this.rawConfig,
|
||||||
});
|
});
|
||||||
|
// 启动动画
|
||||||
|
const { animateOption } = this.getLayerConfig();
|
||||||
|
if (animateOption?.enable) {
|
||||||
|
this.layerService.startAnimate();
|
||||||
|
}
|
||||||
this.buildModels();
|
this.buildModels();
|
||||||
// 触发初始化完成事件;
|
// 触发初始化完成事件;
|
||||||
this.emit('inited');
|
this.emit('inited');
|
||||||
|
@ -381,8 +388,21 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public animate(options: IAnimateOption) {
|
public animate(options: IAnimateOption | boolean) {
|
||||||
this.animateOptions = options;
|
let rawAnimate: Partial<IAnimateOption> = {};
|
||||||
|
if (isObject(options)) {
|
||||||
|
rawAnimate.enable = true;
|
||||||
|
rawAnimate = {
|
||||||
|
...rawAnimate,
|
||||||
|
...options,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
rawAnimate.enable = options;
|
||||||
|
}
|
||||||
|
this.updateLayerConfig({
|
||||||
|
animateOption: rawAnimate,
|
||||||
|
});
|
||||||
|
// this.animateOptions = options;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,6 +726,16 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTime() {
|
||||||
|
return this.layerService.clock.getDelta();
|
||||||
|
}
|
||||||
|
public setAnimateStartTime() {
|
||||||
|
this.AnimateStartTime = this.layerService.clock.getElapsedTime();
|
||||||
|
}
|
||||||
|
public getLayerAnimateTime(): number {
|
||||||
|
return this.layerService.clock.getElapsedTime() - this.AnimateStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
protected getConfigSchema() {
|
protected getConfigSchema() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
@ -735,8 +765,4 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
callback: isFunction(valuesOrCallback) ? valuesOrCallback : undefined,
|
callback: isFunction(valuesOrCallback) ? valuesOrCallback : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private layerMapHander(type: string, data: any) {
|
|
||||||
this.emit(type, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
BlendType,
|
BlendType,
|
||||||
|
IAnimateOption,
|
||||||
IAttribute,
|
IAttribute,
|
||||||
IBlendOptions,
|
IBlendOptions,
|
||||||
ICameraService,
|
ICameraService,
|
||||||
|
@ -56,7 +57,10 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
|
||||||
this.cameraService = layer
|
this.cameraService = layer
|
||||||
.getContainer()
|
.getContainer()
|
||||||
.get<ICameraService>(TYPES.ICameraService);
|
.get<ICameraService>(TYPES.ICameraService);
|
||||||
|
// 注册 Attribute
|
||||||
this.registerBuiltinAttributes();
|
this.registerBuiltinAttributes();
|
||||||
|
// 开启动画
|
||||||
|
this.startModelAnimate();
|
||||||
}
|
}
|
||||||
public getBlend(): IBlendOptions {
|
public getBlend(): IBlendOptions {
|
||||||
const { blend = 'normal' } = this.layer.getLayerConfig();
|
const { blend = 'normal' } = this.layer.getLayerConfig();
|
||||||
|
@ -69,6 +73,10 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
public buildModels(): IModel[] {
|
public buildModels(): IModel[] {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
@ -86,4 +94,18 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
|
||||||
protected registerBuiltinAttributes() {
|
protected registerBuiltinAttributes() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
protected animateOption2Array(option: IAnimateOption): number[] {
|
||||||
|
return [
|
||||||
|
option.enable ? 0 : 1.0,
|
||||||
|
option.duration || 4.0,
|
||||||
|
option.interval || 0.2,
|
||||||
|
option.trailLength || 0.1,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
protected startModelAnimate() {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
if (animateOption.enable) {
|
||||||
|
this.layer.setAnimateStartTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export enum lineStyleType {
|
||||||
|
'solid' = 0.0,
|
||||||
|
'dash' = 1.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILineLayerStyleOptions {
|
||||||
|
opacity: number;
|
||||||
|
lineType?: keyof typeof lineStyleType;
|
||||||
|
dashArray?: [number, number];
|
||||||
|
segmentNumber: number;
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ export function fillPolygon(points: IPath[]) {
|
||||||
|
|
||||||
export function extrude_PolygonNormal(
|
export function extrude_PolygonNormal(
|
||||||
path: IPath[],
|
path: IPath[],
|
||||||
needFlat = false,
|
needFlat = false, // 是否需要转成平面坐标
|
||||||
): IExtrudeGeomety {
|
): IExtrudeGeomety {
|
||||||
const p1 = path[0][0];
|
const p1 = path[0][0];
|
||||||
const p2 = path[0][path[0].length - 1];
|
const p2 = path[0][path[0].length - 1];
|
||||||
|
@ -100,12 +100,12 @@ export function extrude_PolygonNormal(
|
||||||
const positions = [];
|
const positions = [];
|
||||||
const indexArray = [];
|
const indexArray = [];
|
||||||
const normals = [];
|
const normals = [];
|
||||||
// 设置顶部z值
|
// 设置顶部z值 position uv
|
||||||
for (let j = 0; j < vertices.length / dimensions; j++) {
|
for (let j = 0; j < vertices.length / dimensions; j++) {
|
||||||
if (dimensions === 2) {
|
if (dimensions === 2) {
|
||||||
positions.push(vertices[j * 2], vertices[j * 2 + 1], 1);
|
positions.push(vertices[j * 2], vertices[j * 2 + 1], 1, -1, -1);
|
||||||
} else {
|
} else {
|
||||||
positions.push(vertices[j * 3], vertices[j * 3 + 1], 1);
|
positions.push(vertices[j * 3], vertices[j * 3 + 1], 1, -1, -1);
|
||||||
}
|
}
|
||||||
normals.push(0, 0, 1);
|
normals.push(0, 0, 1);
|
||||||
}
|
}
|
||||||
|
@ -127,20 +127,28 @@ export function extrude_PolygonNormal(
|
||||||
if (nextPoint.length === 0) {
|
if (nextPoint.length === 0) {
|
||||||
nextPoint = flattengeo.vertices.slice(0, dimensions);
|
nextPoint = flattengeo.vertices.slice(0, dimensions);
|
||||||
}
|
}
|
||||||
const indexOffset = positions.length / 3;
|
const indexOffset = positions.length / 5;
|
||||||
positions.push(
|
positions.push(
|
||||||
prePoint[0],
|
prePoint[0],
|
||||||
prePoint[1],
|
prePoint[1],
|
||||||
1,
|
1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
nextPoint[0],
|
nextPoint[0],
|
||||||
nextPoint[1],
|
nextPoint[1],
|
||||||
1,
|
1,
|
||||||
|
0.1,
|
||||||
|
0,
|
||||||
prePoint[0],
|
prePoint[0],
|
||||||
prePoint[1],
|
prePoint[1],
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
|
0.8,
|
||||||
nextPoint[0],
|
nextPoint[0],
|
||||||
nextPoint[1],
|
nextPoint[1],
|
||||||
0,
|
0,
|
||||||
|
0.1,
|
||||||
|
0.8,
|
||||||
);
|
);
|
||||||
const normal = computeVertexNormals(
|
const normal = computeVertexNormals(
|
||||||
[nextPoint[0], nextPoint[1], 1],
|
[nextPoint[0], nextPoint[1], 1],
|
||||||
|
|
|
@ -47,7 +47,7 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
||||||
indices: index,
|
indices: index,
|
||||||
normals,
|
normals,
|
||||||
// normals: Array.from(computeVertexNormals(positions, index, 3, false)),
|
// normals: Array.from(computeVertexNormals(positions, index, 3, false)),
|
||||||
size: 3,
|
size: 5,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,10 +103,10 @@ export function PolygonExtrudeTriangulation(feature: IEncodeFeature) {
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
vertices: positions, // [ x, y, z ]
|
vertices: positions, // [ x, y, z, uv.x,uv.y ]
|
||||||
indices: index,
|
indices: index,
|
||||||
normals,
|
normals,
|
||||||
size: 3,
|
size: 5,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { container, ILayerPlugin, TYPES } from '@antv/l7-core';
|
import { container, ILayerPlugin, TYPES } from '@antv/l7-core';
|
||||||
|
import CityBuildingLayer from './citybuliding/building';
|
||||||
import BaseLayer from './core/BaseLayer';
|
import BaseLayer from './core/BaseLayer';
|
||||||
import './glsl.d';
|
import './glsl.d';
|
||||||
import HeatmapLayer from './heatmap';
|
import HeatmapLayer from './heatmap';
|
||||||
import DashLineLayer from './line/dash';
|
|
||||||
import LineLayer from './line/index';
|
import LineLayer from './line/index';
|
||||||
import PointLayer from './point';
|
import PointLayer from './point';
|
||||||
import PolygonLayer from './polygon';
|
import PolygonLayer from './polygon';
|
||||||
|
@ -13,6 +13,7 @@ import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin
|
||||||
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
||||||
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
||||||
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
|
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
|
||||||
|
import LayerAnimateStylePlugin from './plugins/LayerAnimateStylePlugin';
|
||||||
import LayerStylePlugin from './plugins/LayerStylePlugin';
|
import LayerStylePlugin from './plugins/LayerStylePlugin';
|
||||||
import LightingPlugin from './plugins/LightingPlugin';
|
import LightingPlugin from './plugins/LightingPlugin';
|
||||||
import MultiPassRendererPlugin from './plugins/MultiPassRendererPlugin';
|
import MultiPassRendererPlugin from './plugins/MultiPassRendererPlugin';
|
||||||
|
@ -87,6 +88,14 @@ container
|
||||||
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||||
.to(ShaderUniformPlugin)
|
.to(ShaderUniformPlugin)
|
||||||
.inRequestScope();
|
.inRequestScope();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入动画参数
|
||||||
|
*/
|
||||||
|
container
|
||||||
|
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||||
|
.to(LayerAnimateStylePlugin)
|
||||||
|
.inRequestScope();
|
||||||
/**
|
/**
|
||||||
* 传入光照相关参数
|
* 传入光照相关参数
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +116,7 @@ export {
|
||||||
PointLayer,
|
PointLayer,
|
||||||
PolygonLayer,
|
PolygonLayer,
|
||||||
LineLayer,
|
LineLayer,
|
||||||
DashLineLayer,
|
CityBuildingLayer,
|
||||||
ImageLayer,
|
ImageLayer,
|
||||||
RasterLayer,
|
RasterLayer,
|
||||||
HeatmapLayer,
|
HeatmapLayer,
|
||||||
|
|
|
@ -1,211 +0,0 @@
|
||||||
import { AttributeType, gl, IEncodeFeature } from '@antv/l7-core';
|
|
||||||
import BaseLayer from '../core/BaseLayer';
|
|
||||||
import { LineTriangulation } from '../core/triangulation';
|
|
||||||
import line_dash_frag from './shaders/line_dash_frag.glsl';
|
|
||||||
import line_dash_vert from './shaders/line_dash_vert.glsl';
|
|
||||||
interface IDashLineLayerStyleOptions {
|
|
||||||
opacity: number;
|
|
||||||
dashArray: [number, number];
|
|
||||||
lineType: string;
|
|
||||||
}
|
|
||||||
export default class DashLineLayer extends BaseLayer<
|
|
||||||
IDashLineLayerStyleOptions
|
|
||||||
> {
|
|
||||||
public type: string = 'LineLayer';
|
|
||||||
|
|
||||||
protected getConfigSchema() {
|
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
opacity: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
const {
|
|
||||||
opacity,
|
|
||||||
dashArray = [10, 5],
|
|
||||||
lineType = 'dash',
|
|
||||||
} = this.getLayerConfig();
|
|
||||||
this.models.forEach((model) =>
|
|
||||||
model.draw({
|
|
||||||
uniforms: {
|
|
||||||
u_opacity: opacity || 1.0,
|
|
||||||
u_dash_array: dashArray,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected buildModels() {
|
|
||||||
this.registerBuiltinAttributes();
|
|
||||||
this.models = [
|
|
||||||
this.buildLayerModel({
|
|
||||||
moduleName: 'line_dash',
|
|
||||||
vertexShader: line_dash_vert,
|
|
||||||
fragmentShader: line_dash_frag,
|
|
||||||
triangulation: LineTriangulation,
|
|
||||||
blend: {
|
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.SRC_ALPHA,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerBuiltinAttributes() {
|
|
||||||
// point layer size;
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'size',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Size',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
const { size } = feature;
|
|
||||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// point layer size;
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'normal',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Normal',
|
|
||||||
buffer: {
|
|
||||||
// give the WebGL driver a hint that this buffer may change
|
|
||||||
usage: gl.STATIC_DRAW,
|
|
||||||
data: [],
|
|
||||||
type: gl.FLOAT,
|
|
||||||
},
|
|
||||||
size: 3,
|
|
||||||
update: (
|
|
||||||
feature: IEncodeFeature,
|
|
||||||
featureIdx: number,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
normal: number[],
|
|
||||||
) => {
|
|
||||||
return normal;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'miter',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Miter',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
return [vertex[4]];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// this.styleAttributeService.registerStyleAttribute({
|
|
||||||
// name: 'startPos',
|
|
||||||
// type: AttributeType.Attribute,
|
|
||||||
// descriptor: {
|
|
||||||
// name: 'a_StartPos',
|
|
||||||
// buffer: {
|
|
||||||
// // give the WebGL driver a hint that this buffer may change
|
|
||||||
// usage: gl.DYNAMIC_DRAW,
|
|
||||||
// data: [],
|
|
||||||
// type: gl.FLOAT,
|
|
||||||
// },
|
|
||||||
// size: 3,
|
|
||||||
// update: (
|
|
||||||
// feature: IEncodeFeature,
|
|
||||||
// featureIdx: number,
|
|
||||||
// vertex: number[],
|
|
||||||
// attributeIdx: number,
|
|
||||||
// ) => {
|
|
||||||
// const coordinates = feature.coordinates as number[][];
|
|
||||||
// const coord = coordinates[0];
|
|
||||||
// return coord.length === 3 ? coord : [...coord, 0.0];
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'distance',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Distance',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
return [vertex[3]];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'total_distance',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Total_Distance',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
return [vertex[5]];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,7 @@
|
||||||
import BaseLayer from '../core/BaseLayer';
|
import BaseLayer from '../core/BaseLayer';
|
||||||
|
import { ILineLayerStyleOptions } from '../core/interface';
|
||||||
import LineModels, { LineModelType } from './models';
|
import LineModels, { LineModelType } from './models';
|
||||||
export enum LineType {
|
|
||||||
'solid' = 'solid',
|
|
||||||
'dash' = 'dash',
|
|
||||||
}
|
|
||||||
interface ILineLayerStyleOptions {
|
|
||||||
opacity: number;
|
|
||||||
lineType?: keyof typeof LineType;
|
|
||||||
dashArray?: [number, number];
|
|
||||||
}
|
|
||||||
export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
|
export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
|
||||||
public type: string = 'LineLayer';
|
public type: string = 'LineLayer';
|
||||||
|
|
||||||
|
@ -25,7 +18,16 @@ export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
protected getDefaultConfig() {
|
||||||
|
const type = this.getModelType();
|
||||||
|
const defaultConfig = {
|
||||||
|
line: {},
|
||||||
|
arc3d: { blend: 'additive' },
|
||||||
|
arc: { blend: 'additive' },
|
||||||
|
greatcircle: { blend: 'additive' },
|
||||||
|
};
|
||||||
|
return defaultConfig[type];
|
||||||
|
}
|
||||||
protected renderModels() {
|
protected renderModels() {
|
||||||
this.models.forEach((model) =>
|
this.models.forEach((model) =>
|
||||||
model.draw({
|
model.draw({
|
||||||
|
|
|
@ -1,31 +1,42 @@
|
||||||
import {
|
import {
|
||||||
AttributeType,
|
AttributeType,
|
||||||
gl,
|
gl,
|
||||||
|
IAnimateOption,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
IModel,
|
IModel,
|
||||||
IModelUniform,
|
IModelUniform,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
|
|
||||||
import BaseModel from '../../core/BaseModel';
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||||
import { LineArcTriangulation } from '../../core/triangulation';
|
import { LineArcTriangulation } from '../../core/triangulation';
|
||||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||||
import line_arc2d_vert from '../shaders/line_bezier_vert.glsl';
|
import line_arc2d_vert from '../shaders/line_bezier_vert.glsl';
|
||||||
|
const lineStyleObj: { [key: string]: number } = {
|
||||||
interface IArcLayerStyleOptions {
|
solid: 0.0,
|
||||||
opacity: number;
|
dash: 1.0,
|
||||||
segmentNumber: number;
|
};
|
||||||
blur: number;
|
|
||||||
}
|
|
||||||
export default class ArcModel extends BaseModel {
|
export default class ArcModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const {
|
const {
|
||||||
opacity,
|
opacity,
|
||||||
blur = 0.99,
|
lineType = 'solid',
|
||||||
} = this.layer.getLayerConfig() as IArcLayerStyleOptions;
|
dashArray = [10, 5],
|
||||||
|
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity || 1,
|
u_opacity: opacity || 1,
|
||||||
segmentNumber: 30,
|
segmentNumber: 30,
|
||||||
u_blur: blur,
|
u_line_type: lineStyleObj[lineType || 'solid'],
|
||||||
|
u_dash_array: dashArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
return {
|
||||||
|
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,15 +48,7 @@ export default class ArcModel extends BaseModel {
|
||||||
fragmentShader: line_arc_frag,
|
fragmentShader: line_arc_frag,
|
||||||
triangulation: LineArcTriangulation,
|
triangulation: LineArcTriangulation,
|
||||||
depth: { enable: false },
|
depth: { enable: false },
|
||||||
blend: {
|
blend: this.getBlend(),
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.ONE,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,51 @@
|
||||||
import {
|
import {
|
||||||
AttributeType,
|
AttributeType,
|
||||||
gl,
|
gl,
|
||||||
|
IAnimateOption,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
IModel,
|
IModel,
|
||||||
IModelUniform,
|
IModelUniform,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
import BaseModel from '../../core/BaseModel';
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||||
import { LineArcTriangulation } from '../../core/triangulation';
|
import { LineArcTriangulation } from '../../core/triangulation';
|
||||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||||
import line_arc_vert from '../shaders/line_arc_vert.glsl';
|
import line_arc_vert from '../shaders/line_arc_vert.glsl';
|
||||||
|
const lineStyleObj: { [key: string]: number } = {
|
||||||
interface IArcLayerStyleOptions {
|
solid: 0.0,
|
||||||
opacity: number;
|
dash: 1.0,
|
||||||
segmentNumber: number;
|
};
|
||||||
}
|
|
||||||
export default class Arc3DModel extends BaseModel {
|
export default class Arc3DModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const { opacity } = this.layer.getLayerConfig() as IArcLayerStyleOptions;
|
const {
|
||||||
|
opacity,
|
||||||
|
lineType = 'solid',
|
||||||
|
dashArray = [10, 5],
|
||||||
|
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity || 1,
|
u_opacity: opacity || 1,
|
||||||
segmentNumber: 30,
|
segmentNumber: 30,
|
||||||
|
u_line_type: lineStyleObj[lineType as string] || 0.0,
|
||||||
|
u_dash_array: dashArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
return {
|
||||||
|
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public buildModels(): IModel[] {
|
public buildModels(): IModel[] {
|
||||||
return [
|
return [
|
||||||
this.layer.buildLayerModel({
|
this.layer.buildLayerModel({
|
||||||
moduleName: 'arcline',
|
moduleName: 'arc3Dline',
|
||||||
vertexShader: line_arc_vert,
|
vertexShader: line_arc_vert,
|
||||||
fragmentShader: line_arc_frag,
|
fragmentShader: line_arc_frag,
|
||||||
triangulation: LineArcTriangulation,
|
triangulation: LineArcTriangulation,
|
||||||
blend: {
|
blend: this.getBlend(),
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.ONE,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import {
|
|
||||||
AttributeType,
|
|
||||||
gl,
|
|
||||||
IEncodeFeature,
|
|
||||||
ILayer,
|
|
||||||
ILayerModel,
|
|
||||||
IModel,
|
|
||||||
} from '@antv/l7-core';
|
|
||||||
|
|
||||||
import BaseModel from '../../core/BaseModel';
|
|
||||||
export default class ArcModel extends BaseModel {
|
|
||||||
public getUninforms() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public buildModels(): IModel[] {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected registerBuiltinAttributes() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +1,42 @@
|
||||||
import {
|
import {
|
||||||
AttributeType,
|
AttributeType,
|
||||||
gl,
|
gl,
|
||||||
|
IAnimateOption,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
IModel,
|
IModel,
|
||||||
IModelUniform,
|
IModelUniform,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
|
|
||||||
import BaseModel from '../../core/BaseModel';
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||||
import { LineArcTriangulation } from '../../core/triangulation';
|
import { LineArcTriangulation } from '../../core/triangulation';
|
||||||
import line_arc2d_vert from '../shaders/line_arc2d_vert.glsl';
|
import line_arc2d_vert from '../shaders/line_arc2d_vert.glsl';
|
||||||
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
import line_arc_frag from '../shaders/line_arc_frag.glsl';
|
||||||
|
const lineStyleObj: { [key: string]: number } = {
|
||||||
|
solid: 0.0,
|
||||||
|
dash: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
interface IArcLayerStyleOptions {
|
|
||||||
opacity: number;
|
|
||||||
segmentNumber: number;
|
|
||||||
blur: number;
|
|
||||||
}
|
|
||||||
export default class GreatCircleModel extends BaseModel {
|
export default class GreatCircleModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const {
|
const {
|
||||||
opacity,
|
opacity,
|
||||||
blur = 0.99,
|
lineType = 'solid',
|
||||||
} = this.layer.getLayerConfig() as IArcLayerStyleOptions;
|
dashArray = [10, 5],
|
||||||
|
} = this.layer.getLayerConfig() as Partial<ILineLayerStyleOptions>;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity || 1,
|
u_opacity: opacity || 1,
|
||||||
segmentNumber: 30,
|
segmentNumber: 30,
|
||||||
u_blur: blur,
|
u_line_type: lineStyleObj[lineType as string] || 0.0,
|
||||||
|
u_dash_array: dashArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
return {
|
||||||
|
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,20 +48,11 @@ export default class GreatCircleModel extends BaseModel {
|
||||||
fragmentShader: line_arc_frag,
|
fragmentShader: line_arc_frag,
|
||||||
triangulation: LineArcTriangulation,
|
triangulation: LineArcTriangulation,
|
||||||
depth: { enable: false },
|
depth: { enable: false },
|
||||||
blend: {
|
blend: this.getBlend(),
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.ONE,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
protected registerBuiltinAttributes() {
|
protected registerBuiltinAttributes() {
|
||||||
// point layer size;
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
name: 'size',
|
name: 'size',
|
||||||
type: AttributeType.Attribute,
|
type: AttributeType.Attribute,
|
||||||
|
|
|
@ -1,24 +1,40 @@
|
||||||
import {
|
import {
|
||||||
AttributeType,
|
AttributeType,
|
||||||
gl,
|
gl,
|
||||||
|
IAnimateOption,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
IModel,
|
IModel,
|
||||||
IModelUniform,
|
IModelUniform,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
|
|
||||||
import BaseModel from '../../core/BaseModel';
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
|
||||||
import { LineTriangulation } from '../../core/triangulation';
|
import { LineTriangulation } from '../../core/triangulation';
|
||||||
import line_frag from '../shaders/line_frag.glsl';
|
import line_frag from '../shaders/line_frag.glsl';
|
||||||
import line_vert from '../shaders/line_vert.glsl';
|
import line_vert from '../shaders/line_vert.glsl';
|
||||||
|
const lineStyleObj: { [key: string]: number } = {
|
||||||
interface ILineLayerStyleOptions {
|
solid: 0.0,
|
||||||
opacity: number;
|
dash: 1.0,
|
||||||
}
|
};
|
||||||
export default class LineModel extends BaseModel {
|
export default class LineModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const { opacity } = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
const {
|
||||||
|
opacity,
|
||||||
|
lineType = 'solid',
|
||||||
|
dashArray = [10, 5],
|
||||||
|
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity || 1.0,
|
u_opacity: opacity || 1.0,
|
||||||
|
u_line_type: lineStyleObj[lineType],
|
||||||
|
u_dash_array: dashArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
return {
|
||||||
|
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,21 +45,62 @@ export default class LineModel extends BaseModel {
|
||||||
vertexShader: line_vert,
|
vertexShader: line_vert,
|
||||||
fragmentShader: line_frag,
|
fragmentShader: line_frag,
|
||||||
triangulation: LineTriangulation,
|
triangulation: LineTriangulation,
|
||||||
blend: {
|
blend: this.getBlend(),
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.SRC_ALPHA,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
protected registerBuiltinAttributes() {
|
protected registerBuiltinAttributes() {
|
||||||
// const lineType = this
|
// const lineType = this
|
||||||
// point layer size;
|
// point layer size;
|
||||||
|
const {
|
||||||
|
lineType = 'solid',
|
||||||
|
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||||
|
// if (lineType === 'dash') {
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'distance',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Distance',
|
||||||
|
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,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
) => {
|
||||||
|
return [vertex[3]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'total_distance',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Total_Distance',
|
||||||
|
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,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
) => {
|
||||||
|
return [vertex[5]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// }
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
name: 'size',
|
name: 'size',
|
||||||
type: AttributeType.Attribute,
|
type: AttributeType.Attribute,
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
attribute vec4 a_Color;
|
attribute vec4 a_Color;
|
||||||
attribute vec3 a_Position;
|
attribute vec3 a_Position;
|
||||||
attribute vec4 a_Instance;
|
attribute vec4 a_Instance;
|
||||||
attribute float a_Size;
|
attribute float a_Size;
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
uniform float segmentNumber;
|
uniform float segmentNumber;
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
uniform float u_line_type: 0.0;
|
||||||
|
uniform vec2 u_dash_array: [10.0, 5.];
|
||||||
|
varying vec2 v_dash_array;
|
||||||
|
|
||||||
#pragma include "projection"
|
#pragma include "projection"
|
||||||
|
#pragma include "project"
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||||
|
@ -83,13 +93,22 @@ void main() {
|
||||||
float segmentIndex = a_Position.x;
|
float segmentIndex = a_Position.x;
|
||||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba);
|
||||||
|
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||||
|
}
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
}
|
||||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0));
|
vec4 curr = project_position(vec4(degrees(interpolate(source, target, angularDist, segmentRatio)), 0.0, 1.0));
|
||||||
vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0));
|
vec4 next = project_position(vec4(degrees(interpolate(source, target, angularDist, nextSegmentRatio)), 0.0, 1.0));
|
||||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||||
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
||||||
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
|
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
|
||||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
|
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, curr.z, 1.0));
|
||||||
setPickingColor(a_PickingColor);
|
setPickingColor(a_PickingColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
|
|
||||||
uniform float u_opacity;
|
uniform float u_opacity;
|
||||||
varying vec4 v_color;
|
uniform float u_blur : 0.9;
|
||||||
uniform float u_blur : 0.90;
|
uniform float u_line_type: 0.0;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
varying vec2 v_dash_array;
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
uniform float u_time;
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
|
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
|
@ -9,5 +19,17 @@ void main() {
|
||||||
gl_FragColor = v_color;
|
gl_FragColor = v_color;
|
||||||
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy));
|
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy));
|
||||||
gl_FragColor.a *= (blur * u_opacity);
|
gl_FragColor.a *= (blur * u_opacity);
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
gl_FragColor.a *= blur * (1.0- step(v_dash_array.x, mod(v_distance_ratio, v_dash_array.x +v_dash_array.y)));
|
||||||
|
// gl_FragColor.a =
|
||||||
|
}
|
||||||
|
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
float alpha =1.0 - fract( mod(1.0- v_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + u_time / u_aimate.y);
|
||||||
|
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
|
||||||
|
alpha = smoothstep(0., 1., alpha);
|
||||||
|
gl_FragColor.a *= alpha;
|
||||||
|
// gl_FragColor.a = fract(u_time);
|
||||||
|
}
|
||||||
gl_FragColor = filterColor(gl_FragColor);
|
gl_FragColor = filterColor(gl_FragColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
attribute vec3 a_Position;
|
attribute vec3 a_Position;
|
||||||
attribute vec4 a_Instance;
|
attribute vec4 a_Instance;
|
||||||
attribute vec4 a_Color;
|
attribute vec4 a_Color;
|
||||||
|
@ -5,10 +8,17 @@ attribute float a_Size;
|
||||||
|
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
uniform float segmentNumber;
|
uniform float segmentNumber;
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
uniform float u_line_type: 0.0;
|
||||||
|
uniform vec2 u_dash_array: [10.0, 5.];
|
||||||
|
|
||||||
|
varying vec2 v_dash_array;
|
||||||
|
|
||||||
#pragma include "projection"
|
#pragma include "projection"
|
||||||
|
#pragma include "project"
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||||
|
@ -61,6 +71,15 @@ void main() {
|
||||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||||
|
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba) / 2.0 * PI;
|
||||||
|
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||||
|
}
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
}
|
||||||
|
|
||||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||||
vec3 curr = getPos(source, target, segmentRatio);
|
vec3 curr = getPos(source, target, segmentRatio);
|
||||||
vec3 next = getPos(source, target, nextSegmentRatio);
|
vec3 next = getPos(source, target, nextSegmentRatio);
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
attribute vec4 a_Color;
|
attribute vec4 a_Color;
|
||||||
attribute vec3 a_Position;
|
attribute vec3 a_Position;
|
||||||
attribute vec4 a_Instance;
|
attribute vec4 a_Instance;
|
||||||
attribute float a_Size;
|
attribute float a_Size;
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
uniform float segmentNumber;
|
uniform float segmentNumber;
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
uniform float u_line_type: 0.0;
|
||||||
|
uniform vec2 u_dash_array: [10.0, 5.];
|
||||||
|
varying vec2 v_dash_array;
|
||||||
#pragma include "projection"
|
#pragma include "projection"
|
||||||
|
#pragma include "project"
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
float bezier3(vec3 arr, float t) {
|
float bezier3(vec3 arr, float t) {
|
||||||
|
@ -58,7 +67,14 @@ void main() {
|
||||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
float total_Distance = pixelDistance(a_Instance.rg, a_Instance.ba) / 2.0 * PI;
|
||||||
|
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / (total_Distance / segmentNumber * segmentIndex);
|
||||||
|
}
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
v_distance_ratio = segmentIndex / segmentNumber;
|
||||||
|
}
|
||||||
vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0));
|
vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0));
|
||||||
vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0));
|
vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0));
|
||||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||||
|
|
|
@ -1,29 +1,44 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
uniform float u_blur : 0.9;
|
uniform float u_blur : 0.9;
|
||||||
|
uniform float u_line_type: 0.0;
|
||||||
uniform float u_opacity : 1.0;
|
uniform float u_opacity : 1.0;
|
||||||
uniform float u_dash_offset : 0.0;
|
|
||||||
uniform float u_dash_ratio : 0.0;
|
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
|
||||||
|
|
||||||
|
// dash
|
||||||
|
uniform float u_dash_offset : 0.0;
|
||||||
|
uniform float u_dash_ratio : 0.1;
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
varying vec2 v_dash_array;
|
||||||
|
varying float v_side;
|
||||||
|
|
||||||
|
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
uniform float u_time;
|
uniform float u_time;
|
||||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
// [animate, duration, interval, trailLength],
|
// [animate, duration, interval, trailLength],
|
||||||
varying float v_distance_ratio;
|
|
||||||
varying float v_dash_array;
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_FragColor = v_color;
|
gl_FragColor = v_color;
|
||||||
// anti-alias
|
// anti-alias
|
||||||
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy)) * u_opacity;
|
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy)) * u_opacity;
|
||||||
// gl_FragColor.a *= blur;
|
// gl_FragColor.a *= blur;
|
||||||
|
|
||||||
#ifdef ANIMATE
|
if(u_aimate.x == Animate) {
|
||||||
float alpha =1.0 - fract( mod(1.0- v_distance_ratio,u_aimate.z)* (1.0/ u_aimate.z) + u_time / u_aimate.y);
|
float alpha =1.0 - fract( mod(1.0- v_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + u_time / u_aimate.y);
|
||||||
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
|
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
|
||||||
alpha = smoothstep(0., 1., alpha);
|
alpha = smoothstep(0., 1., alpha);
|
||||||
gl_FragColor.a *= alpha * blur;
|
float alpha2 = exp(-abs(v_side));
|
||||||
#endif
|
gl_FragColor.a *= alpha * blur * alpha2;
|
||||||
|
// gl_FragColor.a = fract(u_time);
|
||||||
|
}
|
||||||
|
// dash line
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
gl_FragColor.a *= blur * (1.0- step(v_dash_array.x, mod(v_distance_ratio, v_dash_array.x +v_dash_array.y)));
|
||||||
|
}
|
||||||
|
|
||||||
gl_FragColor = filterColor(gl_FragColor);
|
gl_FragColor = filterColor(gl_FragColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,46 @@
|
||||||
|
#define LineTypeSolid 0.0
|
||||||
|
#define LineTypeDash 1.0
|
||||||
|
#define Animate 0.0
|
||||||
|
|
||||||
attribute float a_Miter;
|
attribute float a_Miter;
|
||||||
attribute vec4 a_Color;
|
attribute vec4 a_Color;
|
||||||
attribute vec2 a_Size;
|
attribute vec2 a_Size;
|
||||||
attribute vec3 a_Normal;
|
attribute vec3 a_Normal;
|
||||||
attribute vec3 a_Position;
|
attribute vec3 a_Position;
|
||||||
|
|
||||||
|
// dash line
|
||||||
|
attribute float a_Total_Distance;
|
||||||
|
attribute float a_Distance;
|
||||||
|
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
|
uniform float u_line_type: 0.0;
|
||||||
|
uniform vec2 u_dash_array: [10.0, 5.];
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
|
|
||||||
#pragma include "projection"
|
#pragma include "projection"
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying float v_dash_array;
|
varying vec2 v_dash_array;
|
||||||
varying vec2 v_normal;
|
varying vec2 v_normal;
|
||||||
|
varying float v_distance_ratio;
|
||||||
|
varying float v_side;
|
||||||
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
|
if(u_line_type == LineTypeDash) {
|
||||||
|
v_distance_ratio = a_Distance / a_Total_Distance;
|
||||||
|
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / a_Total_Distance;
|
||||||
|
}
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
v_distance_ratio = a_Distance / a_Total_Distance;
|
||||||
|
}
|
||||||
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
|
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
|
||||||
v_color = a_Color;
|
v_color = a_Color;
|
||||||
vec3 size = a_Miter * a_Size.x * reverse_offset_normal(a_Normal); //v_normal * vec3(1., -1., 1.0);
|
vec3 size = a_Miter * a_Size.x * reverse_offset_normal(a_Normal); //v_normal * vec3(1., -1., 1.0);
|
||||||
vec2 offset = project_pixel(size.xy);
|
vec2 offset = project_pixel(size.xy);
|
||||||
|
v_side = a_Miter * a_Size.x;
|
||||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
|
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
|
||||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
|
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
|
||||||
public apply(layer: ILayer) {
|
public apply(layer: ILayer) {
|
||||||
layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
|
layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
|
||||||
this.configService.registerLayerConfigSchemaValidator(
|
this.configService.registerLayerConfigSchemaValidator(
|
||||||
layer.name,
|
layer.name as string,
|
||||||
layer.getConfigSchemaForValidation(),
|
layer.getConfigSchemaForValidation(),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { valid, errorText } = this.configService.validateLayerConfig(
|
const { valid, errorText } = this.configService.validateLayerConfig(
|
||||||
layer.name,
|
layer.name as string,
|
||||||
layer.getLayerConfig(),
|
layer.getLayerConfig(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
scales.forEach((scale) => {
|
scales.forEach((scale) => {
|
||||||
// 如果设置了回调, 这不需要设置让range
|
// 如果设置了回调, 这不需要设置让range
|
||||||
if (!attributeScale.callback) {
|
if (!attributeScale.callback) {
|
||||||
if (attributeScale.values) {
|
if (attributeScale.values && attributeScale.values !== 'text') {
|
||||||
if (
|
if (
|
||||||
scale.option?.type === 'linear' &&
|
scale.option?.type === 'linear' &&
|
||||||
attributeScale.values.length > 2
|
attributeScale.values.length > 2
|
||||||
|
@ -131,6 +131,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
scale.scale.range(attributeScale.values);
|
scale.scale.range(attributeScale.values);
|
||||||
} else if (scale.option?.type === 'cat') {
|
} else if (scale.option?.type === 'cat') {
|
||||||
// 如果没有设置初值且 类型为cat,range ==domain;
|
// 如果没有设置初值且 类型为cat,range ==domain;
|
||||||
|
|
||||||
scale.scale.range(scale.option.domain);
|
scale.scale.range(scale.option.domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,20 +160,13 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
dataArray: IParseDataItem[],
|
dataArray: IParseDataItem[],
|
||||||
) {
|
) {
|
||||||
const scalekey = [field, attribute.name].join('_');
|
const scalekey = [field, attribute.name].join('_');
|
||||||
|
const values = attribute.scale?.values;
|
||||||
if (this.scaleCache[scalekey]) {
|
if (this.scaleCache[scalekey]) {
|
||||||
return this.scaleCache[scalekey];
|
return this.scaleCache[scalekey];
|
||||||
}
|
}
|
||||||
const styleScale = this.createScale(field, dataArray);
|
const styleScale = this.createScale(field, values, dataArray);
|
||||||
this.scaleCache[scalekey] = styleScale;
|
this.scaleCache[scalekey] = styleScale;
|
||||||
|
|
||||||
// if (
|
|
||||||
// styleScale.type === StyleScaleType.VARIABLE &&
|
|
||||||
// attribute.scale?.values &&
|
|
||||||
// attribute.scale?.values.length > 0
|
|
||||||
// ) { // 只有变量初始化range
|
|
||||||
// styleScale.scale.range(attribute.scale?.values);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return this.scaleCache[scalekey];
|
return this.scaleCache[scalekey];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +185,11 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
return [field];
|
return [field];
|
||||||
}
|
}
|
||||||
|
|
||||||
private createScale(field: string, data?: IParseDataItem[]): IStyleScale {
|
private createScale(
|
||||||
|
field: string,
|
||||||
|
values: unknown[] | string | undefined,
|
||||||
|
data?: IParseDataItem[],
|
||||||
|
): IStyleScale {
|
||||||
// 首先查找全局默认配置例如 color
|
// 首先查找全局默认配置例如 color
|
||||||
const scaleOption: IScale | undefined = this.scaleOptions[field];
|
const scaleOption: IScale | undefined = this.scaleOptions[field];
|
||||||
const styleScale: IStyleScale = {
|
const styleScale: IStyleScale = {
|
||||||
|
@ -200,6 +198,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
type: StyleScaleType.VARIABLE,
|
type: StyleScaleType.VARIABLE,
|
||||||
option: scaleOption,
|
option: scaleOption,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!data || !data.length) {
|
if (!data || !data.length) {
|
||||||
if (scaleOption && scaleOption.type) {
|
if (scaleOption && scaleOption.type) {
|
||||||
styleScale.scale = this.createDefaultScale(scaleOption);
|
styleScale.scale = this.createDefaultScale(scaleOption);
|
||||||
|
@ -216,9 +215,12 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
||||||
styleScale.type = StyleScaleType.CONSTANT;
|
styleScale.type = StyleScaleType.CONSTANT;
|
||||||
} else {
|
} else {
|
||||||
// 根据数据类型判断 默认等分位,时间,和枚举类型
|
// 根据数据类型判断 默认等分位,时间,和枚举类型
|
||||||
const type =
|
let type =
|
||||||
(scaleOption && scaleOption.type) || this.getDefaultType(firstValue);
|
(scaleOption && scaleOption.type) || this.getDefaultType(firstValue);
|
||||||
|
if (values === 'text') {
|
||||||
|
// text 为内置变 如果是文本则为cat
|
||||||
|
type = ScaleTypes.CAT;
|
||||||
|
}
|
||||||
const cfg = this.createDefaultScaleConfig(type, field, data);
|
const cfg = this.createDefaultScaleConfig(type, field, data);
|
||||||
Object.assign(cfg, scaleOption);
|
Object.assign(cfg, scaleOption);
|
||||||
styleScale.scale = this.createDefaultScale(cfg);
|
styleScale.scale = this.createDefaultScale(cfg);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
import {
|
||||||
|
CameraUniform,
|
||||||
|
CoordinateUniform,
|
||||||
|
ICameraService,
|
||||||
|
ICoordinateSystemService,
|
||||||
|
ILayer,
|
||||||
|
ILayerPlugin,
|
||||||
|
IModel,
|
||||||
|
IRendererService,
|
||||||
|
TYPES,
|
||||||
|
} from '@antv/l7-core';
|
||||||
|
import { inject, injectable } from 'inversify';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export default class LayerAnimateStylePlugin implements ILayerPlugin {
|
||||||
|
@inject(TYPES.ICameraService)
|
||||||
|
private readonly cameraService: ICameraService;
|
||||||
|
|
||||||
|
@inject(TYPES.IRendererService)
|
||||||
|
private readonly rendererService: IRendererService;
|
||||||
|
|
||||||
|
public apply(layer: ILayer) {
|
||||||
|
layer.hooks.beforeRender.tap('LayerAnimateStylePlugin', () => {
|
||||||
|
// 重新计算坐标系参数
|
||||||
|
layer.models.forEach((model: IModel) => {
|
||||||
|
model.addUniforms({
|
||||||
|
...layer.layerModel.getAnimateUniforms(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,6 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
|
||||||
public apply(layer: ILayer) {
|
public apply(layer: ILayer) {
|
||||||
layer.hooks.beforeRender.tap('ShaderUniformPlugin', () => {
|
layer.hooks.beforeRender.tap('ShaderUniformPlugin', () => {
|
||||||
// 重新计算坐标系参数
|
// 重新计算坐标系参数
|
||||||
|
|
||||||
this.coordinateSystemService.refresh();
|
this.coordinateSystemService.refresh();
|
||||||
|
|
||||||
const { width, height } = this.rendererService.getViewportSize();
|
const { width, height } = this.rendererService.getViewportSize();
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PointModels, { PointType } from './models/index';
|
||||||
interface IPointLayerStyleOptions {
|
interface IPointLayerStyleOptions {
|
||||||
opacity: number;
|
opacity: number;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
strokeColor: string;
|
stroke: string;
|
||||||
}
|
}
|
||||||
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
|
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
|
||||||
public type: string = 'PointLayer';
|
public type: string = 'PointLayer';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import {
|
import {
|
||||||
AttributeType,
|
AttributeType,
|
||||||
gl,
|
gl,
|
||||||
|
IAnimateOption,
|
||||||
IAttribute,
|
IAttribute,
|
||||||
IElements,
|
IElements,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
IModel,
|
IModel,
|
||||||
IModelUniform,
|
IModelUniform,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
|
@ -15,19 +17,26 @@ import pointFillVert from '../shaders/fill_vert.glsl';
|
||||||
interface IPointLayerStyleOptions {
|
interface IPointLayerStyleOptions {
|
||||||
opacity: number;
|
opacity: number;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
strokeColor: string;
|
stroke: string;
|
||||||
}
|
}
|
||||||
export default class FillModel extends BaseModel {
|
export default class FillModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const {
|
const {
|
||||||
opacity = 1,
|
opacity = 1,
|
||||||
strokeColor = 'rgb(0,0,0,0)',
|
stroke = 'rgb(0,0,0,0)',
|
||||||
strokeWidth = 1,
|
strokeWidth = 1,
|
||||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity,
|
u_opacity: opacity,
|
||||||
u_stroke_width: strokeWidth,
|
u_stroke_width: strokeWidth,
|
||||||
u_stroke_color: rgb2arr(strokeColor),
|
u_stroke_color: rgb2arr(stroke),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getAnimateUniforms(): IModelUniform {
|
||||||
|
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
|
||||||
|
return {
|
||||||
|
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
|
||||||
|
u_time: this.layer.getLayerAnimateTime(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import ExtrudeModel from './extrude';
|
||||||
import FillModel from './fill';
|
import FillModel from './fill';
|
||||||
import IMageModel from './image';
|
import IMageModel from './image';
|
||||||
import NormalModel from './normal';
|
import NormalModel from './normal';
|
||||||
|
import TextModel from './text';
|
||||||
|
|
||||||
export type PointType = 'fill' | 'image' | 'normal' | 'extrude' | 'text';
|
export type PointType = 'fill' | 'image' | 'normal' | 'extrude' | 'text';
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ const PointModels: { [key in PointType]: any } = {
|
||||||
image: IMageModel,
|
image: IMageModel,
|
||||||
normal: NormalModel,
|
normal: NormalModel,
|
||||||
extrude: ExtrudeModel,
|
extrude: ExtrudeModel,
|
||||||
text: null,
|
text: TextModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PointModels;
|
export default PointModels;
|
||||||
|
|
|
@ -16,7 +16,7 @@ import normalVert from '../shaders/normal_vert.glsl';
|
||||||
interface IPointLayerStyleOptions {
|
interface IPointLayerStyleOptions {
|
||||||
opacity: number;
|
opacity: number;
|
||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
strokeColor: string;
|
stroke: string;
|
||||||
}
|
}
|
||||||
export function PointTriangulation(feature: IEncodeFeature) {
|
export function PointTriangulation(feature: IEncodeFeature) {
|
||||||
const coordinates = feature.coordinates as number[];
|
const coordinates = feature.coordinates as number[];
|
||||||
|
@ -36,13 +36,13 @@ export default class NormalModel extends BaseModel {
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
const {
|
const {
|
||||||
opacity = 1,
|
opacity = 1,
|
||||||
strokeColor = 'rgb(0,0,0,0)',
|
stroke = 'rgb(0,0,0,0)',
|
||||||
strokeWidth = 1,
|
strokeWidth = 1,
|
||||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||||
return {
|
return {
|
||||||
u_opacity: opacity,
|
u_opacity: opacity,
|
||||||
u_stroke_width: strokeWidth,
|
u_stroke_width: strokeWidth,
|
||||||
u_stroke_color: rgb2arr(strokeColor),
|
u_stroke_color: rgb2arr(stroke),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public buildModels(): IModel[] {
|
public buildModels(): IModel[] {
|
||||||
|
|
|
@ -1,15 +1,264 @@
|
||||||
import { IModel, IModelUniform } from '@antv/l7-core';
|
import {
|
||||||
|
AttributeType,
|
||||||
|
BlendType,
|
||||||
|
gl,
|
||||||
|
IEncodeFeature,
|
||||||
|
ILayerConfig,
|
||||||
|
IModel,
|
||||||
|
IModelUniform,
|
||||||
|
ITexture2D,
|
||||||
|
} from '@antv/l7-core';
|
||||||
|
import { rgb2arr } from '@antv/l7-utils';
|
||||||
import BaseModel from '../../core/BaseModel';
|
import BaseModel from '../../core/BaseModel';
|
||||||
|
import { PointFillTriangulation } from '../../core/triangulation';
|
||||||
|
import {
|
||||||
|
getGlyphQuads,
|
||||||
|
IGlyphQuad,
|
||||||
|
shapeText,
|
||||||
|
} from '../../utils/symbol-layout';
|
||||||
|
import textFrag from '../shaders/text_frag.glsl';
|
||||||
|
import textVert from '../shaders/text_vert.glsl';
|
||||||
|
interface IPointTextLayerStyleOptions {
|
||||||
|
opacity: number;
|
||||||
|
textAnchor: string;
|
||||||
|
spacing: number;
|
||||||
|
padding: [number, number];
|
||||||
|
stroke: string;
|
||||||
|
strokeWidth: number;
|
||||||
|
strokeOpacity: number;
|
||||||
|
fontWeight: string;
|
||||||
|
fontFamily: string;
|
||||||
|
textOffset: [number, number];
|
||||||
|
textAllowOverlap: boolean;
|
||||||
|
}
|
||||||
|
export function TextTriangulation(feature: IEncodeFeature) {
|
||||||
|
const coordinates = feature.coordinates as number[];
|
||||||
|
const { glyphQuads } = feature;
|
||||||
|
const vertices: number[] = [];
|
||||||
|
const indices: number[] = [];
|
||||||
|
const coord =
|
||||||
|
coordinates.length === 2
|
||||||
|
? [coordinates[0], coordinates[1], 0]
|
||||||
|
: coordinates;
|
||||||
|
glyphQuads.forEach((quad: IGlyphQuad, index: number) => {
|
||||||
|
vertices.push(
|
||||||
|
...coord,
|
||||||
|
quad.tex.x,
|
||||||
|
quad.tex.y + quad.tex.height,
|
||||||
|
quad.tl.x,
|
||||||
|
quad.tl.y,
|
||||||
|
...coord,
|
||||||
|
quad.tex.x + quad.tex.width,
|
||||||
|
quad.tex.y + quad.tex.height,
|
||||||
|
quad.tr.x,
|
||||||
|
quad.tr.y,
|
||||||
|
...coord,
|
||||||
|
quad.tex.x + quad.tex.width,
|
||||||
|
quad.tex.y,
|
||||||
|
quad.br.x,
|
||||||
|
quad.br.y,
|
||||||
|
...coord,
|
||||||
|
quad.tex.x,
|
||||||
|
quad.tex.y,
|
||||||
|
quad.bl.x,
|
||||||
|
quad.bl.y,
|
||||||
|
);
|
||||||
|
indices.push(
|
||||||
|
0 + index * 4,
|
||||||
|
1 + index * 4,
|
||||||
|
2 + index * 4,
|
||||||
|
2 + index * 4,
|
||||||
|
3 + index * 4,
|
||||||
|
0 + index * 4,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
vertices, // [ x, y, z, tex.x,tex.y, offset.x. offset.y]
|
||||||
|
indices,
|
||||||
|
size: 7,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default class ExtrudeModel extends BaseModel {
|
export default class TextModel extends BaseModel {
|
||||||
|
private texture: ITexture2D;
|
||||||
public getUninforms(): IModelUniform {
|
public getUninforms(): IModelUniform {
|
||||||
throw new Error('Method not implemented.');
|
const {
|
||||||
|
fontWeight = 'normal',
|
||||||
|
fontFamily,
|
||||||
|
stroke,
|
||||||
|
strokeWidth,
|
||||||
|
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||||
|
const { canvas, fontAtlas, mapping } = this.fontService;
|
||||||
|
return {
|
||||||
|
u_opacity: 1.0,
|
||||||
|
u_sdf_map: this.texture,
|
||||||
|
u_stroke: rgb2arr(stroke),
|
||||||
|
u_halo_blur: 0.5,
|
||||||
|
u_sdf_map_size: [canvas.width, canvas.height],
|
||||||
|
u_strokeWidth: strokeWidth,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public buildModels(): IModel[] {
|
public buildModels(): IModel[] {
|
||||||
throw new Error('Method not implemented.');
|
this.initTextFont();
|
||||||
|
this.generateGlyphLayout();
|
||||||
|
this.registerBuiltinAttributes();
|
||||||
|
this.updateTexture();
|
||||||
|
return [
|
||||||
|
this.layer.buildLayerModel({
|
||||||
|
moduleName: 'pointText',
|
||||||
|
vertexShader: textVert,
|
||||||
|
fragmentShader: textFrag,
|
||||||
|
triangulation: TextTriangulation,
|
||||||
|
depth: { enable: false },
|
||||||
|
blend: this.getBlend(),
|
||||||
|
}),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected registerBuiltinAttributes() {
|
protected registerBuiltinAttributes() {
|
||||||
throw new Error('Method not implemented.');
|
const viewProjection = this.cameraService.getViewProjectionMatrix();
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'textOffsets',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_textOffsets',
|
||||||
|
buffer: {
|
||||||
|
// give the WebGL driver a hint that this buffer may change
|
||||||
|
usage: gl.STATIC_DRAW,
|
||||||
|
data: [],
|
||||||
|
type: gl.FLOAT,
|
||||||
|
},
|
||||||
|
size: 2,
|
||||||
|
update: (
|
||||||
|
feature: IEncodeFeature,
|
||||||
|
featureIdx: number,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
) => {
|
||||||
|
return [vertex[5], vertex[6]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// point layer size;
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'size',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_Size',
|
||||||
|
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,
|
||||||
|
vertex: number[],
|
||||||
|
attributeIdx: number,
|
||||||
|
) => {
|
||||||
|
const { size } = feature;
|
||||||
|
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// point layer size;
|
||||||
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
name: 'textUv',
|
||||||
|
type: AttributeType.Attribute,
|
||||||
|
descriptor: {
|
||||||
|
name: 'a_tex',
|
||||||
|
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 [vertex[3], vertex[4]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private initTextFont() {
|
||||||
|
const {
|
||||||
|
fontWeight = 'normal',
|
||||||
|
fontFamily,
|
||||||
|
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||||
|
const data = this.layer.getEncodedData();
|
||||||
|
const characterSet: string[] = [];
|
||||||
|
data.forEach((item: IEncodeFeature) => {
|
||||||
|
let { shape = '' } = item;
|
||||||
|
shape = shape.toString();
|
||||||
|
for (const char of shape) {
|
||||||
|
// 去重
|
||||||
|
if (characterSet.indexOf(char) === -1) {
|
||||||
|
characterSet.push(char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.fontService.setFontOptions({
|
||||||
|
characterSet,
|
||||||
|
fontWeight,
|
||||||
|
fontFamily,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private generateGlyphLayout() {
|
||||||
|
const { canvas, fontAtlas, mapping } = this.fontService;
|
||||||
|
const {
|
||||||
|
spacing = 2,
|
||||||
|
textAnchor = 'center',
|
||||||
|
textOffset,
|
||||||
|
padding = [4, 4],
|
||||||
|
textAllowOverlap,
|
||||||
|
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||||
|
const data = this.layer.getEncodedData();
|
||||||
|
data.forEach((feature: IEncodeFeature) => {
|
||||||
|
const { coordinates, shape = '' } = feature;
|
||||||
|
const size = feature.size as number;
|
||||||
|
const fontScale = size / 24;
|
||||||
|
const shaping = shapeText(
|
||||||
|
shape.toString(),
|
||||||
|
mapping,
|
||||||
|
24,
|
||||||
|
textAnchor,
|
||||||
|
'center',
|
||||||
|
spacing,
|
||||||
|
textOffset,
|
||||||
|
);
|
||||||
|
const glyphQuads = getGlyphQuads(shaping, textOffset, false);
|
||||||
|
feature.shaping = shaping;
|
||||||
|
feature.glyphQuads = glyphQuads;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private drawGlyph() {
|
||||||
|
const {
|
||||||
|
spacing = 2,
|
||||||
|
textAnchor = 'center',
|
||||||
|
textOffset = [0, 0],
|
||||||
|
padding = [4, 4],
|
||||||
|
textAllowOverlap,
|
||||||
|
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||||
|
const viewProjection = this.cameraService.getViewProjectionMatrix();
|
||||||
|
}
|
||||||
|
private updateTexture() {
|
||||||
|
const { createTexture2D } = this.rendererService;
|
||||||
|
const { canvas } = this.fontService;
|
||||||
|
this.texture = createTexture2D({
|
||||||
|
data: canvas,
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#define Animate 0.0
|
||||||
|
|
||||||
uniform float u_blur : 0;
|
uniform float u_blur : 0;
|
||||||
uniform float u_opacity : 1;
|
uniform float u_opacity : 1;
|
||||||
uniform float u_stroke_width : 1;
|
uniform float u_stroke_width : 1;
|
||||||
|
@ -7,6 +9,8 @@ uniform float u_stroke_opacity : 1;
|
||||||
varying vec4 v_data;
|
varying vec4 v_data;
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying float v_radius;
|
varying float v_radius;
|
||||||
|
uniform float u_time;
|
||||||
|
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||||
|
|
||||||
#pragma include "sdf_2d"
|
#pragma include "sdf_2d"
|
||||||
#pragma include "picking"
|
#pragma include "picking"
|
||||||
|
@ -61,8 +65,19 @@ void main() {
|
||||||
inner_df
|
inner_df
|
||||||
);
|
);
|
||||||
vec4 strokeColor = u_stroke_color == vec4(0) ? v_color : u_stroke_color;
|
vec4 strokeColor = u_stroke_color == vec4(0) ? v_color : u_stroke_color;
|
||||||
|
float PI = 3.14159;
|
||||||
|
float N_RINGS = 3.0;
|
||||||
|
float FREQ = 1.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
gl_FragColor = opacity_t * mix(vec4(v_color.rgb, v_color.a * u_opacity), strokeColor * u_stroke_opacity, color_t);
|
gl_FragColor = opacity_t * mix(vec4(v_color.rgb, v_color.a * u_opacity), strokeColor * u_stroke_opacity, color_t);
|
||||||
|
|
||||||
|
if(u_aimate.x == Animate) {
|
||||||
|
float d = length(v_data.xy);
|
||||||
|
float intensity = clamp(cos(d * PI), 0.0, 1.0) * clamp(cos(2.0 * PI * (d * 2.0 * N_RINGS - FREQ * u_time)), 0.0, 1.0);
|
||||||
|
gl_FragColor = vec4(gl_FragColor.xyz * intensity, intensity);
|
||||||
|
}
|
||||||
|
|
||||||
gl_FragColor = filterColor(gl_FragColor);
|
gl_FragColor = filterColor(gl_FragColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ void main() {
|
||||||
float antialiasblur = 1.0 / (a_Size + u_stroke_width);
|
float antialiasblur = 1.0 / (a_Size + u_stroke_width);
|
||||||
|
|
||||||
// construct point coords
|
// construct point coords
|
||||||
v_data = vec4(extrude, antialiasblur, shape_type);
|
v_data = vec4(extrude, antialiasblur,shape_type);
|
||||||
|
|
||||||
setPickingColor(a_PickingColor);
|
setPickingColor(a_PickingColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#define SDF_PX 8.0
|
||||||
|
#define EDGE_GAMMA 0.105
|
||||||
uniform sampler2D u_sdf_map;
|
uniform sampler2D u_sdf_map;
|
||||||
uniform float u_gamma_scale : 0.5;
|
uniform float u_gamma_scale : 0.5;
|
||||||
uniform float u_font_size : 24;
|
uniform float u_font_size : 24;
|
||||||
|
@ -5,6 +7,7 @@ uniform float u_opacity : 1.0;
|
||||||
uniform vec4 u_stroke : [0, 0, 0, 1];
|
uniform vec4 u_stroke : [0, 0, 0, 1];
|
||||||
uniform float u_strokeWidth : 2.0;
|
uniform float u_strokeWidth : 2.0;
|
||||||
uniform float u_halo_blur : 0.5;
|
uniform float u_halo_blur : 0.5;
|
||||||
|
uniform float u_DevicePixelRatio;
|
||||||
|
|
||||||
varying vec4 v_color;
|
varying vec4 v_color;
|
||||||
varying vec2 v_uv;
|
varying vec2 v_uv;
|
||||||
|
@ -17,7 +20,7 @@ void main() {
|
||||||
float fontScale = u_font_size / 24.0;
|
float fontScale = u_font_size / 24.0;
|
||||||
|
|
||||||
lowp float buff = (6.0 - u_strokeWidth / fontScale) / SDF_PX;
|
lowp float buff = (6.0 - u_strokeWidth / fontScale) / SDF_PX;
|
||||||
highp float gamma = (u_halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
|
highp float gamma = (u_halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale) / 1.0;
|
||||||
|
|
||||||
highp float gamma_scaled = gamma * v_gamma_scale;
|
highp float gamma_scaled = gamma * v_gamma_scale;
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
|
#define SDF_PX 8.0
|
||||||
|
#define EDGE_GAMMA 0.105
|
||||||
attribute vec3 a_Position;
|
attribute vec3 a_Position;
|
||||||
attribute vec2 a_tex;
|
attribute vec2 a_tex;
|
||||||
attribute vec2 a_offset;
|
attribute vec2 a_textOffsets;
|
||||||
attribute vec4 a_color;
|
attribute vec4 a_Color;
|
||||||
attribute float a_size;
|
attribute float a_Size;
|
||||||
|
|
||||||
uniform vec2 u_sdf_map_size;
|
uniform vec2 u_sdf_map_size;
|
||||||
uniform vec2 u_viewport_size;
|
uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
uniform float u_activeId : 0;
|
|
||||||
uniform vec4 u_activeColor : [1.0, 0.0, 0.0, 1.0];
|
|
||||||
|
|
||||||
varying vec2 v_uv;
|
varying vec2 v_uv;
|
||||||
varying float v_gamma_scale;
|
varying float v_gamma_scale;
|
||||||
|
@ -17,18 +16,18 @@ varying vec4 v_color;
|
||||||
#pragma include "projection"
|
#pragma include "projection"
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_color = a_color;
|
v_color = a_Color;
|
||||||
v_uv = a_tex / u_sdf_map_size;
|
v_uv = a_tex / u_sdf_map_size;
|
||||||
|
|
||||||
// 文本缩放比例
|
// 文本缩放比例
|
||||||
float fontScale = a_size / 24.;
|
float fontScale = a_Size / 24.;
|
||||||
|
|
||||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||||
|
|
||||||
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||||
|
|
||||||
gl_Position = vec4(projected_position.xy / projected_position.w
|
gl_Position = vec4(projected_position.xy / projected_position.w
|
||||||
+ a_offset * fontScale / u_viewport_size * 2., 0.0, 1.0);
|
+ a_textOffsets * fontScale / u_ViewportSize * 2., 0.0, 1.0);
|
||||||
v_gamma_scale = gl_Position.w;
|
v_gamma_scale = gl_Position.w;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,177 +0,0 @@
|
||||||
import { AttributeType, gl, IEncodeFeature } from '@antv/l7-core';
|
|
||||||
import BaseLayer from '../core/BaseLayer';
|
|
||||||
import { getGlyphQuads, shapeText } from '../utils/symbol-layout';
|
|
||||||
import textFrag from './shaders/text_frag.glsl';
|
|
||||||
import textVert from './shaders/text_vert.glsl';
|
|
||||||
interface IPointTextLayerStyleOptions {
|
|
||||||
opacity: number;
|
|
||||||
textAnchor: string;
|
|
||||||
textOffset: [number, number];
|
|
||||||
spacing: number;
|
|
||||||
padding: [number, number];
|
|
||||||
stroke: string;
|
|
||||||
strokeWidth: number;
|
|
||||||
strokeOpacity: number;
|
|
||||||
fontWeight: string;
|
|
||||||
fontFamily: string;
|
|
||||||
|
|
||||||
textAllowOverlap: boolean;
|
|
||||||
}
|
|
||||||
export function PointTriangulation(feature: IEncodeFeature) {
|
|
||||||
const coordinates = feature.coordinates as number[];
|
|
||||||
return {
|
|
||||||
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
|
|
||||||
indices: [0, 1, 2, 2, 3, 0],
|
|
||||||
size: coordinates.length,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export default class TextLayer extends BaseLayer<IPointTextLayerStyleOptions> {
|
|
||||||
public type: string = 'PointLayer';
|
|
||||||
|
|
||||||
protected getConfigSchema() {
|
|
||||||
return {
|
|
||||||
properties: {
|
|
||||||
opacity: {
|
|
||||||
type: 'number',
|
|
||||||
minimum: 0,
|
|
||||||
maximum: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected renderModels() {
|
|
||||||
const { opacity } = this.getLayerConfig();
|
|
||||||
this.models.forEach((model) =>
|
|
||||||
model.draw({
|
|
||||||
uniforms: {
|
|
||||||
u_opacity: opacity || 1.0,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected buildModels() {
|
|
||||||
this.registerBuiltinAttributes();
|
|
||||||
this.models = [
|
|
||||||
this.buildLayerModel({
|
|
||||||
moduleName: 'pointText',
|
|
||||||
vertexShader: textVert,
|
|
||||||
fragmentShader: textFrag,
|
|
||||||
triangulation: PointTriangulation,
|
|
||||||
depth: { enable: false },
|
|
||||||
blend: {
|
|
||||||
enable: true,
|
|
||||||
func: {
|
|
||||||
srcRGB: gl.SRC_ALPHA,
|
|
||||||
srcAlpha: 1,
|
|
||||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
|
||||||
dstAlpha: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private registerBuiltinAttributes() {
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'textOffsets',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_textOffsets',
|
|
||||||
buffer: {
|
|
||||||
// give the WebGL driver a hint that this buffer may change
|
|
||||||
usage: gl.STATIC_DRAW,
|
|
||||||
data: [],
|
|
||||||
type: gl.FLOAT,
|
|
||||||
},
|
|
||||||
size: 2,
|
|
||||||
update: (
|
|
||||||
feature: IEncodeFeature,
|
|
||||||
featureIdx: number,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
const extrude = [-1, -1, 1, -1, 1, 1, -1, 1];
|
|
||||||
const extrudeIndex = (attributeIdx % 4) * 2;
|
|
||||||
return [extrude[extrudeIndex], extrude[extrudeIndex + 1]];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// point layer size;
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'size',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Size',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
const { size } = feature;
|
|
||||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// point layer size;
|
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
|
||||||
name: 'shape',
|
|
||||||
type: AttributeType.Attribute,
|
|
||||||
descriptor: {
|
|
||||||
name: 'a_Shape',
|
|
||||||
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,
|
|
||||||
vertex: number[],
|
|
||||||
attributeIdx: number,
|
|
||||||
) => {
|
|
||||||
const { shape = 2 } = feature;
|
|
||||||
const shape2d = this.getLayerConfig().shape2d as string[];
|
|
||||||
const shapeIndex = shape2d.indexOf(shape as string);
|
|
||||||
return [shapeIndex];
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private initTextFont() {
|
|
||||||
const { fontWeight = 'normal', fontFamily } = this.getLayerConfig();
|
|
||||||
const data = this.getEncodedData();
|
|
||||||
const characterSet: string[] = [];
|
|
||||||
data.forEach((item: IEncodeFeature) => {
|
|
||||||
let { shape = '' } = item;
|
|
||||||
shape = shape.toString();
|
|
||||||
for (const char of shape) {
|
|
||||||
// 去重
|
|
||||||
if (characterSet.indexOf(char) === -1) {
|
|
||||||
characterSet.push(char);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.fontService.setFontOptions({
|
|
||||||
characterSet,
|
|
||||||
fontWeight,
|
|
||||||
fontFamily,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
export interface ICollisionBox {
|
||||||
|
x1: number;
|
||||||
|
y1: number;
|
||||||
|
x2: number;
|
||||||
|
y2: number;
|
||||||
|
anchorPointX: number;
|
||||||
|
anchorPointY: number;
|
||||||
|
}
|
||||||
|
// @mapbox/grid-index 并没有类似 hitTest 的单纯获取碰撞检测结果的方法,query 将导致计算大量多余的包围盒结果,因此使用改良版
|
||||||
|
import { mat4, vec4 } from 'gl-matrix';
|
||||||
|
import GridIndex from './grid-index';
|
||||||
|
|
||||||
|
// 为 viewport 加上 buffer,避免边缘处的文本无法显示
|
||||||
|
const viewportPadding = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于网格实现文本避让,大幅提升包围盒碰撞检测效率
|
||||||
|
* @see https://zhuanlan.zhihu.com/p/74373214
|
||||||
|
*/
|
||||||
|
export default class CollisionIndex {
|
||||||
|
private width: number;
|
||||||
|
private height: number;
|
||||||
|
private grid: GridIndex;
|
||||||
|
private screenRightBoundary: number;
|
||||||
|
private screenBottomBoundary: number;
|
||||||
|
private gridRightBoundary: number;
|
||||||
|
private gridBottomBoundary: number;
|
||||||
|
constructor(width: number, height: number) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
// 创建网格索引
|
||||||
|
this.grid = new GridIndex(
|
||||||
|
width + 2 * viewportPadding,
|
||||||
|
height + 2 * viewportPadding,
|
||||||
|
25,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.screenRightBoundary = width + viewportPadding;
|
||||||
|
this.screenBottomBoundary = height + viewportPadding;
|
||||||
|
this.gridRightBoundary = width + 2 * viewportPadding;
|
||||||
|
this.gridBottomBoundary = height + 2 * viewportPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public placeCollisionBox(collisionBox: ICollisionBox, mvpMatrix: mat4) {
|
||||||
|
const projectedPoint = this.project(
|
||||||
|
mvpMatrix,
|
||||||
|
collisionBox.anchorPointX,
|
||||||
|
collisionBox.anchorPointY,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tlX = collisionBox.x1 + projectedPoint.x;
|
||||||
|
const tlY = collisionBox.y1 + projectedPoint.y;
|
||||||
|
const brX = collisionBox.x2 + projectedPoint.x;
|
||||||
|
const brY = collisionBox.y2 + projectedPoint.y;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.isInsideGrid(tlX, tlY, brX, brY) ||
|
||||||
|
this.grid.hitTest(tlX, tlY, brX, brY)
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
box: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
box: [tlX, tlY, brX, brY],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public insertCollisionBox(box: number[], featureIndex: number) {
|
||||||
|
const key = { featureIndex };
|
||||||
|
this.grid.insert(key, box[0], box[1], box[2], box[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后续碰撞检测都需要投影到 viewport 坐标系
|
||||||
|
* @param {THREE.Matrix4} mvpMatrix mvp矩阵
|
||||||
|
* @param {number} x P20 平面坐标X
|
||||||
|
* @param {number} y P20 平面坐标Y
|
||||||
|
* @return {Point} projectedPoint
|
||||||
|
*/
|
||||||
|
public project(mvpMatrix: mat4, x: number, y: number) {
|
||||||
|
const point = vec4.fromValues(x, y, 0, 1);
|
||||||
|
const out = vec4.create();
|
||||||
|
vec4.transformMat4(out, point, mvpMatrix);
|
||||||
|
// GL 坐标系[-1, 1] -> viewport 坐标系[width, height]
|
||||||
|
return {
|
||||||
|
x: ((out[0] / out[3] + 1) / 2) * this.width + viewportPadding,
|
||||||
|
y: ((-out[1] / out[3] + 1) / 2) * this.height + viewportPadding,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断包围盒是否在整个网格内,需要加上 buffer
|
||||||
|
* @param {number} x1 x1
|
||||||
|
* @param {number} y1 y1
|
||||||
|
* @param {number} x2 x2
|
||||||
|
* @param {number} y2 y2
|
||||||
|
* @return {Point} isInside
|
||||||
|
*/
|
||||||
|
public isInsideGrid(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
return (
|
||||||
|
x2 >= 0 &&
|
||||||
|
x1 < this.gridRightBoundary &&
|
||||||
|
y2 >= 0 &&
|
||||||
|
y1 < this.gridBottomBoundary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
interface IQueryArgs {
|
||||||
|
hitTest: boolean;
|
||||||
|
seenUids: { box: any; circle: any };
|
||||||
|
}
|
||||||
|
type CallBack = (...args: any[]) => any;
|
||||||
|
/**
|
||||||
|
* 网格索引,相比 @mapbox/grid-index,在简单计算碰撞检测结果时效率更高
|
||||||
|
* @see https://zhuanlan.zhihu.com/p/74373214
|
||||||
|
*/
|
||||||
|
class GridIndex {
|
||||||
|
private boxCells: number[][];
|
||||||
|
private xCellCount: number;
|
||||||
|
private yCellCount: number;
|
||||||
|
private boxKeys: string[];
|
||||||
|
private bboxes: number[];
|
||||||
|
private width: number;
|
||||||
|
private height: number;
|
||||||
|
private xScale: number;
|
||||||
|
private yScale: number;
|
||||||
|
private boxUid: number;
|
||||||
|
|
||||||
|
constructor(width: number, height: number, cellSize: number) {
|
||||||
|
const boxCells = this.boxCells;
|
||||||
|
|
||||||
|
this.xCellCount = Math.ceil(width / cellSize);
|
||||||
|
this.yCellCount = Math.ceil(height / cellSize);
|
||||||
|
|
||||||
|
for (let i = 0; i < this.xCellCount * this.yCellCount; i++) {
|
||||||
|
boxCells.push([]);
|
||||||
|
}
|
||||||
|
this.boxKeys = [];
|
||||||
|
this.bboxes = [];
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.xScale = this.xCellCount / width;
|
||||||
|
this.yScale = this.yCellCount / height;
|
||||||
|
this.boxUid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public insert(key: any, x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
this.forEachCell(x1, y1, x2, y2, this.insertBoxCell, this.boxUid++);
|
||||||
|
this.boxKeys.push(key);
|
||||||
|
this.bboxes.push(x1);
|
||||||
|
this.bboxes.push(y1);
|
||||||
|
this.bboxes.push(x2);
|
||||||
|
this.bboxes.push(y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public query(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
predicate?: CallBack,
|
||||||
|
) {
|
||||||
|
return this.queryHitTest(x1, y1, x2, y2, false, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hitTest(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
predicate?: CallBack,
|
||||||
|
) {
|
||||||
|
return this.queryHitTest(x1, y1, x2, y2, true, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private insertBoxCell(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
cellIndex: number,
|
||||||
|
uid: number,
|
||||||
|
) {
|
||||||
|
this.boxCells[cellIndex].push(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private queryHitTest(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
hitTest: boolean,
|
||||||
|
predicate?: CallBack,
|
||||||
|
) {
|
||||||
|
if (x2 < 0 || x1 > this.width || y2 < 0 || y1 > this.height) {
|
||||||
|
return hitTest ? false : [];
|
||||||
|
}
|
||||||
|
const result: any[] = [];
|
||||||
|
if (x1 <= 0 && y1 <= 0 && this.width <= x2 && this.height <= y2) {
|
||||||
|
// 这一步是高效的关键,后续精确碰撞检测结果在计算文本可见性时并不需要
|
||||||
|
if (hitTest) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (let boxUid = 0; boxUid < this.boxKeys.length; boxUid++) {
|
||||||
|
result.push({
|
||||||
|
key: this.boxKeys[boxUid],
|
||||||
|
x1: this.bboxes[boxUid * 4],
|
||||||
|
y1: this.bboxes[boxUid * 4 + 1],
|
||||||
|
x2: this.bboxes[boxUid * 4 + 2],
|
||||||
|
y2: this.bboxes[boxUid * 4 + 3],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return predicate ? result.filter(predicate) : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryArgs = {
|
||||||
|
hitTest,
|
||||||
|
seenUids: { box: {}, circle: {} },
|
||||||
|
};
|
||||||
|
this.forEachCell(
|
||||||
|
x1,
|
||||||
|
y1,
|
||||||
|
x2,
|
||||||
|
y2,
|
||||||
|
this.queryCell,
|
||||||
|
result,
|
||||||
|
queryArgs,
|
||||||
|
predicate,
|
||||||
|
);
|
||||||
|
return hitTest ? result.length > 0 : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private queryCell(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
cellIndex: number,
|
||||||
|
result: any[],
|
||||||
|
queryArgs?: any,
|
||||||
|
predicate?: CallBack,
|
||||||
|
) {
|
||||||
|
const seenUids = queryArgs.seenUids;
|
||||||
|
const boxCell = this.boxCells[cellIndex];
|
||||||
|
if (boxCell !== null) {
|
||||||
|
const bboxes = this.bboxes;
|
||||||
|
for (const boxUid of boxCell) {
|
||||||
|
if (!seenUids.box[boxUid]) {
|
||||||
|
seenUids.box[boxUid] = true;
|
||||||
|
const offset = boxUid * 4;
|
||||||
|
if (
|
||||||
|
x1 <= bboxes[offset + 2] &&
|
||||||
|
y1 <= bboxes[offset + 3] &&
|
||||||
|
x2 >= bboxes[offset + 0] &&
|
||||||
|
y2 >= bboxes[offset + 1] &&
|
||||||
|
(!predicate || predicate(this.boxKeys[boxUid]))
|
||||||
|
) {
|
||||||
|
if (queryArgs.hitTest) {
|
||||||
|
result.push(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
result.push({
|
||||||
|
key: this.boxKeys[boxUid],
|
||||||
|
x1: bboxes[offset],
|
||||||
|
y1: bboxes[offset + 1],
|
||||||
|
x2: bboxes[offset + 2],
|
||||||
|
y2: bboxes[offset + 3],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private forEachCell(
|
||||||
|
x1: number,
|
||||||
|
y1: number,
|
||||||
|
x2: number,
|
||||||
|
y2: number,
|
||||||
|
fn: CallBack,
|
||||||
|
arg1: any[] | number,
|
||||||
|
arg2?: IQueryArgs,
|
||||||
|
predicate?: CallBack,
|
||||||
|
) {
|
||||||
|
const cx1 = this.convertToXCellCoord(x1);
|
||||||
|
const cy1 = this.convertToYCellCoord(y1);
|
||||||
|
const cx2 = this.convertToXCellCoord(x2);
|
||||||
|
const cy2 = this.convertToYCellCoord(y2);
|
||||||
|
|
||||||
|
for (let x = cx1; x <= cx2; x++) {
|
||||||
|
for (let y = cy1; y <= cy2; y++) {
|
||||||
|
const cellIndex = this.xCellCount * y + x;
|
||||||
|
if (fn.call(this, x1, y1, x2, y2, cellIndex, arg1, arg2, predicate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertToXCellCoord(x: number) {
|
||||||
|
return Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(this.xCellCount - 1, Math.floor(x * this.xScale)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertToYCellCoord(y: number) {
|
||||||
|
return Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(this.yCellCount - 1, Math.floor(y * this.yScale)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GridIndex;
|
|
@ -1,3 +1,22 @@
|
||||||
|
interface IPoint {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
export interface IGlyphQuad {
|
||||||
|
tr: IPoint;
|
||||||
|
tl: IPoint;
|
||||||
|
bl: IPoint;
|
||||||
|
br: IPoint;
|
||||||
|
tex: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
advance: number;
|
||||||
|
};
|
||||||
|
glyphOffset: [number, number];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回文本相对锚点位置
|
* 返回文本相对锚点位置
|
||||||
* @param {string} anchor 锚点位置
|
* @param {string} anchor 锚点位置
|
||||||
|
@ -181,7 +200,7 @@ export function shapeText(
|
||||||
textAnchor: string,
|
textAnchor: string,
|
||||||
textJustify: string,
|
textJustify: string,
|
||||||
spacing: number,
|
spacing: number,
|
||||||
translate: [number, number],
|
translate: [number, number] = [0, 0],
|
||||||
) {
|
) {
|
||||||
// TODO:处理换行
|
// TODO:处理换行
|
||||||
const lines = text.split('\n');
|
const lines = text.split('\n');
|
||||||
|
@ -215,11 +234,11 @@ export function shapeText(
|
||||||
|
|
||||||
export function getGlyphQuads(
|
export function getGlyphQuads(
|
||||||
shaping: any,
|
shaping: any,
|
||||||
textOffset: [number, number],
|
textOffset: [number, number] = [0, 0],
|
||||||
alongLine: boolean,
|
alongLine: boolean,
|
||||||
) {
|
): IGlyphQuad[] {
|
||||||
const { positionedGlyphs } = shaping;
|
const { positionedGlyphs } = shaping;
|
||||||
const quads = [];
|
const quads: IGlyphQuad[] = [];
|
||||||
|
|
||||||
for (const positionedGlyph of positionedGlyphs) {
|
for (const positionedGlyph of positionedGlyphs) {
|
||||||
const rect = positionedGlyph.metrics;
|
const rect = positionedGlyph.metrics;
|
||||||
|
@ -229,7 +248,7 @@ export function getGlyphQuads(
|
||||||
|
|
||||||
const halfAdvance = (rect.advance * positionedGlyph.scale) / 2;
|
const halfAdvance = (rect.advance * positionedGlyph.scale) / 2;
|
||||||
|
|
||||||
const glyphOffset = alongLine
|
const glyphOffset: [number, number] = alongLine
|
||||||
? [positionedGlyph.x + halfAdvance, positionedGlyph.y]
|
? [positionedGlyph.x + halfAdvance, positionedGlyph.y]
|
||||||
: [0, 0];
|
: [0, 0];
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ export default class AMapService
|
||||||
}
|
}
|
||||||
public getZoom(): number {
|
public getZoom(): number {
|
||||||
// 统一返回 Mapbox 缩放等级
|
// 统一返回 Mapbox 缩放等级
|
||||||
return this.map.getZoom();
|
return this.map.getZoom() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setZoom(zoom: number): void {
|
public setZoom(zoom: number): void {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { storiesOf } from '@storybook/react';
|
import { storiesOf } from '@storybook/react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import AnimatePoint from './components/AnimatePoint';
|
||||||
import Arc2DLineDemo from './components/Arc2DLine';
|
import Arc2DLineDemo from './components/Arc2DLine';
|
||||||
import ArcLineDemo from './components/Arcline';
|
import ArcLineDemo from './components/Arcline';
|
||||||
|
import CityBuildingLayerDemo from './components/citybuilding';
|
||||||
import Column from './components/column';
|
import Column from './components/column';
|
||||||
import DashLineDemo from './components/dash';
|
import DashLineDemo from './components/dash';
|
||||||
import DataUpdate from './components/data_update';
|
import DataUpdate from './components/data_update';
|
||||||
|
@ -14,16 +16,20 @@ import PointImage from './components/PointImage';
|
||||||
import Polygon3D from './components/Polygon3D';
|
import Polygon3D from './components/Polygon3D';
|
||||||
import ImageLayerDemo from './components/RasterImage';
|
import ImageLayerDemo from './components/RasterImage';
|
||||||
import RasterLayerDemo from './components/RasterLayer';
|
import RasterLayerDemo from './components/RasterLayer';
|
||||||
|
import TextLayerDemo from './components/Text';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
storiesOf('图层', module)
|
storiesOf('图层', module)
|
||||||
.add('点图层', () => <PointDemo />)
|
.add('点图层', () => <PointDemo />)
|
||||||
.add('数据更新', () => <DataUpdate />)
|
.add('数据更新', () => <DataUpdate />)
|
||||||
.add('亮度图', () => <LightDemo />)
|
.add('亮度图', () => <LightDemo />)
|
||||||
|
.add('点动画', () => <AnimatePoint />)
|
||||||
.add('3D点', () => <Point3D />)
|
.add('3D点', () => <Point3D />)
|
||||||
|
.add('文字', () => <TextLayerDemo />)
|
||||||
.add('Column', () => <Column />)
|
.add('Column', () => <Column />)
|
||||||
.add('图片标注', () => <PointImage />)
|
.add('图片标注', () => <PointImage />)
|
||||||
.add('面3d图层', () => <Polygon3D />)
|
.add('面3d图层', () => <Polygon3D />)
|
||||||
|
.add('点亮城市', () => <CityBuildingLayerDemo />)
|
||||||
.add('线图层', () => <LineLayer />)
|
.add('线图层', () => <LineLayer />)
|
||||||
.add('虚线', () => <DashLineDemo />)
|
.add('虚线', () => <DashLineDemo />)
|
||||||
.add('3D弧线', () => <ArcLineDemo />)
|
.add('3D弧线', () => <ArcLineDemo />)
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { PointLayer, Scene } from '@antv/l7';
|
||||||
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
|
import * as React from 'react';
|
||||||
|
// @ts-ignore
|
||||||
|
import data from '../data/data.json';
|
||||||
|
export default class AnimatePoint 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({
|
||||||
|
pitch: 0,
|
||||||
|
style: 'dark',
|
||||||
|
center: [112, 23.69],
|
||||||
|
zoom: 2.5,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/basement_prod/9078fd36-ce8d-4ee2-91bc-605db8315fdf.csv',
|
||||||
|
)
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((data) => {
|
||||||
|
const pointLayer = new PointLayer({})
|
||||||
|
.source(data, {
|
||||||
|
parser: {
|
||||||
|
type: 'csv',
|
||||||
|
x: 'Longitude',
|
||||||
|
y: 'Latitude',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.shape('circle')
|
||||||
|
.active(true)
|
||||||
|
.animate(true)
|
||||||
|
.size(40)
|
||||||
|
.color('#ffa842')
|
||||||
|
.style({
|
||||||
|
opacity: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
scene.addLayer(pointLayer);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="map"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { LineLayer, Scene } from '@antv/l7';
|
import { LineLayer, Scene } from '@antv/l7';
|
||||||
import { Mapbox } from '@antv/l7-maps';
|
import { Mapbox, GaodeMap } from '@antv/l7-maps';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
export default class Arc2DLineDemo extends React.Component {
|
export default class Arc2DLineDemo extends React.Component {
|
||||||
|
@ -16,17 +16,14 @@ export default class Arc2DLineDemo extends React.Component {
|
||||||
);
|
);
|
||||||
const scene = new Scene({
|
const scene = new Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
map: new Mapbox({
|
map: new GaodeMap({
|
||||||
center: [116.2825, 39.9],
|
center: [116.2825, 39.9],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'mapbox://styles/mapbox/dark-v9',
|
style: 'dark',
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const lineLayer = new LineLayer({
|
const lineLayer = new LineLayer()
|
||||||
enablePicking: true,
|
|
||||||
enableHighlight: true,
|
|
||||||
})
|
|
||||||
.source(await response.text(), {
|
.source(await response.text(), {
|
||||||
parser: {
|
parser: {
|
||||||
type: 'csv',
|
type: 'csv',
|
||||||
|
@ -36,9 +33,17 @@ export default class Arc2DLineDemo extends React.Component {
|
||||||
y1: 'lat2',
|
y1: 'lat2',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.size(0.5)
|
.size(1.2)
|
||||||
.shape('arc')
|
.shape('greatcircle')
|
||||||
.color('rgb(13,64,140)');
|
.color('rgb(13,64,140)')
|
||||||
|
.animate({
|
||||||
|
interval: 0.5,
|
||||||
|
duration: 2,
|
||||||
|
trailLength: 0.4,
|
||||||
|
})
|
||||||
|
.style({
|
||||||
|
opacity: 0.6,
|
||||||
|
});
|
||||||
scene.addLayer(lineLayer);
|
scene.addLayer(lineLayer);
|
||||||
scene.render();
|
scene.render();
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
|
@ -19,14 +19,13 @@ export default class ArcLineDemo extends React.Component {
|
||||||
map: new Mapbox({
|
map: new Mapbox({
|
||||||
center: [116.2825, 39.9],
|
center: [116.2825, 39.9],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'mapbox://styles/mapbox/dark-v9',
|
style: 'dark',
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
const lineLayer = new LineLayer({
|
const lineLayer = new LineLayer({
|
||||||
enablePicking: true,
|
blend: 'normal',
|
||||||
enableHighlight: true,
|
|
||||||
})
|
})
|
||||||
.source(await response.text(), {
|
.source(await response.text(), {
|
||||||
parser: {
|
parser: {
|
||||||
|
@ -37,9 +36,18 @@ export default class ArcLineDemo extends React.Component {
|
||||||
y1: 'lat2',
|
y1: 'lat2',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.size(0.5)
|
.size(1)
|
||||||
.shape('arc')
|
.shape('arc3d')
|
||||||
.color('rgb(13,64,140)');
|
.active(true)
|
||||||
|
.color('rgb(13,64,140)')
|
||||||
|
.animate({
|
||||||
|
interval: 0.1,
|
||||||
|
duration: 2,
|
||||||
|
trailLength: 1.0,
|
||||||
|
})
|
||||||
|
.style({
|
||||||
|
lineType: 'dash',
|
||||||
|
});
|
||||||
scene.addLayer(lineLayer);
|
scene.addLayer(lineLayer);
|
||||||
scene.render();
|
scene.render();
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
|
@ -12,44 +12,34 @@ export default class LineDemo extends React.Component {
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
'https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json',
|
'https://arcgis.github.io/arcgis-samples-javascript/sample-data/custom-gl-animated-lines/lines.json',
|
||||||
);
|
);
|
||||||
const scene = new Scene({
|
const scene = new Scene({
|
||||||
id: 'map',
|
id: 'map',
|
||||||
map: new Mapbox({
|
map: new Mapbox({
|
||||||
center: [102.602992, 23.107329],
|
center: [-74.006, 40.7128],
|
||||||
pitch: 0,
|
zoom: 15,
|
||||||
style: 'mapbox://styles/mapbox/dark-v9',
|
style: 'dark',
|
||||||
zoom: 13,
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const lineLayer = new LineLayer({
|
const lineLayer = new LineLayer()
|
||||||
enableMultiPassRenderer: true,
|
.source(await response.json(), {
|
||||||
enablePicking: true,
|
parser: {
|
||||||
enableHighlight: true,
|
type: 'json',
|
||||||
// onHover: (pickedFeature: any) => {
|
coordinates: 'path',
|
||||||
// // tslint:disable-next-line:no-console
|
},
|
||||||
// console.log('Scene4', pickedFeature);
|
})
|
||||||
// },
|
.size(3)
|
||||||
})
|
|
||||||
.source(await response.json())
|
|
||||||
.size(1)
|
|
||||||
.shape('line')
|
.shape('line')
|
||||||
.color(
|
.color('color', (v) => {
|
||||||
'ELEV',
|
return `rgb(${v[0]})`;
|
||||||
[
|
});
|
||||||
'#E8FCFF',
|
// .animate({
|
||||||
'#CFF6FF',
|
// enable: false,
|
||||||
'#A1E9ff',
|
// interval: 0.5,
|
||||||
'#65CEF7',
|
// trailLength: 0.4,
|
||||||
'#3CB1F0',
|
// duration: 4,
|
||||||
'#2894E0',
|
// })
|
||||||
'#1772c2',
|
|
||||||
'#105CB3',
|
|
||||||
'#0D408C',
|
|
||||||
'#002466',
|
|
||||||
].reverse(),
|
|
||||||
);
|
|
||||||
|
|
||||||
scene.addLayer(lineLayer);
|
scene.addLayer(lineLayer);
|
||||||
scene.render();
|
scene.render();
|
||||||
|
|
|
@ -24,59 +24,59 @@ export default class Point3D extends React.Component {
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'dark',
|
style: 'dark',
|
||||||
zoom: 3,
|
zoom: 3,
|
||||||
token: 'test',
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
scene.on('loaded', () => {
|
// scene.on('loaded', () => {
|
||||||
const pointLayer = new PointLayer({})
|
const pointLayer = new PointLayer({})
|
||||||
.source(pointsData, {
|
.source(pointsData, {
|
||||||
cluster: true,
|
cluster: true,
|
||||||
})
|
})
|
||||||
.shape('circle')
|
.shape('circle')
|
||||||
.scale('point_count', {
|
.scale('point_count', {
|
||||||
type: 'quantile',
|
type: 'quantile',
|
||||||
})
|
})
|
||||||
.size('point_count', [5, 10, 15, 20, 25])
|
.size('point_count', [5, 10, 15, 20, 25])
|
||||||
.color('yellow')
|
.animate(false)
|
||||||
.style({
|
.color('yellow')
|
||||||
opacity: 0.5,
|
.style({
|
||||||
strokeWidth: 1,
|
opacity: 0.5,
|
||||||
});
|
strokeWidth: 1,
|
||||||
scene.addLayer(pointLayer);
|
|
||||||
pointLayer.on('mousemove', (e) => {
|
|
||||||
const id = e.featureId;
|
|
||||||
console.log(e.type);
|
|
||||||
pointLayer.setActive(id);
|
|
||||||
});
|
});
|
||||||
pointLayer.on('mousedown', (e) => {
|
scene.addLayer(pointLayer);
|
||||||
const id = e.featureId;
|
pointLayer.on('mousemove', (e) => {
|
||||||
console.log(e.type);
|
const id = e.featureId;
|
||||||
pointLayer.setActive(id);
|
console.log(e.type);
|
||||||
});
|
pointLayer.setActive(id);
|
||||||
pointLayer.on('mouseup', (e) => {
|
|
||||||
const id = e.featureId;
|
|
||||||
console.log(e.type);
|
|
||||||
pointLayer.setActive(id);
|
|
||||||
});
|
|
||||||
pointLayer.on('click', (e) => {
|
|
||||||
const id = e.featureId;
|
|
||||||
console.log(e.type);
|
|
||||||
pointLayer.setActive(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
pointLayer.on('contextmenu', (e) => {
|
|
||||||
const id = e.featureId;
|
|
||||||
console.log(e.type);
|
|
||||||
pointLayer.setActive(id);
|
|
||||||
});
|
|
||||||
pointLayer.on('unpick', (e) => {
|
|
||||||
const id = e.featureId;
|
|
||||||
console.log(e.type);
|
|
||||||
pointLayer.setActive(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.scene = scene;
|
|
||||||
});
|
});
|
||||||
|
pointLayer.on('mousedown', (e) => {
|
||||||
|
const id = e.featureId;
|
||||||
|
console.log(e.type);
|
||||||
|
pointLayer.setActive(id);
|
||||||
|
});
|
||||||
|
pointLayer.on('mouseup', (e) => {
|
||||||
|
const id = e.featureId;
|
||||||
|
console.log(e.type);
|
||||||
|
pointLayer.setActive(id);
|
||||||
|
});
|
||||||
|
pointLayer.on('click', (e) => {
|
||||||
|
const id = e.featureId;
|
||||||
|
console.log(e.type);
|
||||||
|
pointLayer.setActive(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
pointLayer.on('contextmenu', (e) => {
|
||||||
|
const id = e.featureId;
|
||||||
|
console.log(e.type);
|
||||||
|
pointLayer.setActive(id);
|
||||||
|
});
|
||||||
|
pointLayer.on('unpick', (e) => {
|
||||||
|
const id = e.featureId;
|
||||||
|
console.log(e.type);
|
||||||
|
pointLayer.setActive(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scene = scene;
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -1,61 +1,82 @@
|
||||||
import { PointLayer, Scene } from '@antv/l7';
|
import { PointLayer, Scene } from '@antv/l7';
|
||||||
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
// @ts-ignore
|
||||||
import data from '../data/data.json';
|
import data from '../data/data.json';
|
||||||
export default class Point3D extends React.Component {
|
export default class TextLayerDemo extends React.Component {
|
||||||
|
// @ts-ignore
|
||||||
private scene: Scene;
|
private scene: Scene;
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.scene.destroy();
|
this.scene.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public async componentDidMount() {
|
||||||
const scene = new Scene({
|
const data = {
|
||||||
center: [120.19382669582967, 30.258134],
|
|
||||||
id: 'map',
|
|
||||||
pitch: 0,
|
|
||||||
type: 'mapbox',
|
|
||||||
style: 'mapbox://styles/mapbox/streets-v9',
|
|
||||||
zoom: 1,
|
|
||||||
});
|
|
||||||
const pointLayer = new PointLayer({});
|
|
||||||
const p1 = {
|
|
||||||
type: 'FeatureCollection',
|
type: 'FeatureCollection',
|
||||||
features: [
|
features: [
|
||||||
{
|
{
|
||||||
type: 'Feature',
|
type: 'Feature',
|
||||||
properties: {},
|
properties: {
|
||||||
|
name: '中华人民共和国',
|
||||||
|
},
|
||||||
geometry: {
|
geometry: {
|
||||||
type: 'Point',
|
type: 'Point',
|
||||||
coordinates: [83.671875, 44.84029065139799],
|
coordinates: [103.0078125, 36.03133177633187],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'Feature',
|
||||||
|
properties: {
|
||||||
|
name: '中华人民共和国',
|
||||||
|
},
|
||||||
|
geometry: {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [122.6953125, 10.833305983642491],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
pointLayer
|
const response = await fetch(
|
||||||
.source(data)
|
'https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json',
|
||||||
.color('name', [
|
);
|
||||||
'#FFF5B8',
|
const pointsData = await response.json();
|
||||||
'#FFDC7D',
|
|
||||||
'#FFAB5C',
|
const scene = new Scene({
|
||||||
'#F27049',
|
id: 'map',
|
||||||
'#D42F31',
|
map: new GaodeMap({
|
||||||
'#730D1C',
|
center: [120.19382669582967, 30.258134],
|
||||||
])
|
pitch: 0,
|
||||||
.shape('subregion', [
|
style: 'dark',
|
||||||
'circle',
|
zoom: 3,
|
||||||
'triangle',
|
}),
|
||||||
'square',
|
});
|
||||||
'pentagon',
|
// scene.on('loaded', () => {
|
||||||
'hexagon',
|
const pointLayer = new PointLayer({})
|
||||||
'octogon',
|
.source(pointsData.list, {
|
||||||
'hexagram',
|
parser: {
|
||||||
'rhombus',
|
type: 'json',
|
||||||
'vesica',
|
x: 'j',
|
||||||
])
|
y: 'w',
|
||||||
.size('scalerank', [2, 4, 6, 8, 10]);
|
},
|
||||||
|
})
|
||||||
|
.shape('m', 'text')
|
||||||
|
.size(24)
|
||||||
|
.color('#fff')
|
||||||
|
.style({
|
||||||
|
fontWeight: 800,
|
||||||
|
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||||
|
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||||
|
spacing: 2, // 字符间距
|
||||||
|
padding: [4, 4], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||||
|
strokeColor: 'white', // 描边颜色
|
||||||
|
strokeWidth: 4, // 描边宽度
|
||||||
|
strokeOpacity: 1.0,
|
||||||
|
});
|
||||||
scene.addLayer(pointLayer);
|
scene.addLayer(pointLayer);
|
||||||
scene.render();
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { CityBuildingLayer, Scene } from '@antv/l7';
|
||||||
|
import { Mapbox } from '@antv/l7-maps';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export default class CityBuildingLayerDemo extends React.Component {
|
||||||
|
// @ts-ignore
|
||||||
|
private scene: Scene;
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
this.scene.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json',
|
||||||
|
);
|
||||||
|
const scene = new Scene({
|
||||||
|
id: 'map',
|
||||||
|
map: new Mapbox({
|
||||||
|
style: 'dark',
|
||||||
|
center: [121.507674, 31.223043],
|
||||||
|
pitch: 65.59312320916906,
|
||||||
|
zoom: 15.4,
|
||||||
|
minZoom: 15,
|
||||||
|
maxZoom: 18,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const pointLayer = new CityBuildingLayer();
|
||||||
|
pointLayer
|
||||||
|
.source(await response.json())
|
||||||
|
.size('floor', [0, 500])
|
||||||
|
.color('rgba(242,246,250,1.0)')
|
||||||
|
.animate({
|
||||||
|
enable: true,
|
||||||
|
})
|
||||||
|
.style({
|
||||||
|
opacity: 1.0,
|
||||||
|
baseColor: 'rgb(16,16,16)',
|
||||||
|
windowColor: 'rgb(30,60,89)',
|
||||||
|
brightColor: 'rgb(255,176,38)',
|
||||||
|
});
|
||||||
|
scene.addLayer(pointLayer);
|
||||||
|
scene.render();
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="map"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { DashLineLayer, Scene } from '@antv/l7';
|
import { LineLayer, Scene } from '@antv/l7';
|
||||||
import { Mapbox } from '@antv/l7-maps';
|
import { Mapbox } from '@antv/l7-maps';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ export default class DashLineDemo extends React.Component {
|
||||||
zoom: 14,
|
zoom: 14,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const lineLayer = new DashLineLayer()
|
const lineLayer = new LineLayer()
|
||||||
.source(await response.json())
|
.source(await response.json())
|
||||||
.size(1)
|
.size(1)
|
||||||
.shape('line')
|
.shape('line')
|
||||||
|
@ -41,7 +41,10 @@ export default class DashLineDemo extends React.Component {
|
||||||
'#0D408C',
|
'#0D408C',
|
||||||
'#002466',
|
'#002466',
|
||||||
].reverse(),
|
].reverse(),
|
||||||
);
|
)
|
||||||
|
.style({
|
||||||
|
lineType: 'dash',
|
||||||
|
});
|
||||||
|
|
||||||
scene.addLayer(lineLayer);
|
scene.addLayer(lineLayer);
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
|
@ -48,7 +48,7 @@ export default class DataUpdate extends React.Component {
|
||||||
.active(false)
|
.active(false)
|
||||||
.color('#2F54EB')
|
.color('#2F54EB')
|
||||||
.style({
|
.style({
|
||||||
strokeColor: '#fff',
|
stroke: '#fff',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,9 @@ export default class Light extends React.Component {
|
||||||
});
|
});
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
scene.on('loaded', async () => {
|
scene.on('loaded', async () => {
|
||||||
const pointLayer = new PointLayer()
|
const pointLayer = new PointLayer({
|
||||||
|
blend: 'normal',
|
||||||
|
})
|
||||||
.source(pointsData, {
|
.source(pointsData, {
|
||||||
parser: {
|
parser: {
|
||||||
type: 'csv',
|
type: 'csv',
|
||||||
|
|
Loading…
Reference in New Issue