mirror of https://gitee.com/antv-l7/antv-l7
commit
a44551f284
|
@ -14,7 +14,7 @@
|
|||
"message": "chore: publish"
|
||||
}
|
||||
},
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"publishConfig": {
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
"stylelint-config-styled-components": "^0.1.1",
|
||||
"stylelint-processor-styled-components": "^1.3.2",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"tapable": "^1.1.3",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-config-prettier": "^1.15.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-component",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,8 +24,8 @@
|
|||
"author": "lzxue",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"inversify": "^5.0.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-core",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -22,7 +22,7 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@mapbox/tiny-sdf": "^1.1.1",
|
||||
"ajv": "^6.10.2",
|
||||
|
|
|
@ -17,6 +17,7 @@ import { IControlService } from './services/component/IControlService';
|
|||
import { IGlobalConfigService } from './services/config/IConfigService';
|
||||
import { ICoordinateSystemService } from './services/coordinate/ICoordinateSystemService';
|
||||
import { IInteractionService } from './services/interaction/IInteractionService';
|
||||
import { IPickingService } from './services/interaction/IPickingService';
|
||||
import { ILayerService } from './services/layer/ILayerService';
|
||||
import { IStyleAttributeService } from './services/layer/IStyleAttributeService';
|
||||
import { ILogService } from './services/log/ILogService';
|
||||
|
@ -33,6 +34,7 @@ import PopupService from './services/component/PopupService';
|
|||
import GlobalConfigService from './services/config/ConfigService';
|
||||
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
|
||||
import InteractionService from './services/interaction/InteractionService';
|
||||
import PickingService from './services/interaction/PickingService';
|
||||
import LayerService from './services/layer/LayerService';
|
||||
import StyleAttributeService from './services/layer/StyleAttributeService';
|
||||
import LogService from './services/log/LogService';
|
||||
|
@ -180,6 +182,10 @@ export function createSceneContainer() {
|
|||
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||
.to(InteractionService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IPickingService>(TYPES.IPickingService)
|
||||
.to(PickingService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IControlService>(TYPES.IControlService)
|
||||
.to(ControlService)
|
||||
|
|
|
@ -55,7 +55,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
zIndex: 0,
|
||||
blend: 'normal',
|
||||
pickedFeatureID: -1,
|
||||
enableMultiPassRenderer: true,
|
||||
enableMultiPassRenderer: false,
|
||||
enablePicking: true,
|
||||
active: false,
|
||||
activeColor: '#2f54eb',
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export interface IPickingService {
|
||||
init(): void;
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
import { decodePickingColor, encodePickingColor } from '@antv/l7-utils';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import {
|
||||
IMapService,
|
||||
IRendererService,
|
||||
IShaderModuleService,
|
||||
} from '../../index';
|
||||
import { TYPES } from '../../types';
|
||||
import { ICameraService } from '../camera/ICameraService';
|
||||
import {
|
||||
IInteractionService,
|
||||
IInteractionTarget,
|
||||
InteractionEvent,
|
||||
} from '../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILngLat } from '../map/IMapService';
|
||||
import { gl } from '../renderer/gl';
|
||||
import { IFramebuffer } from '../renderer/IFramebuffer';
|
||||
import { IPickingService } from './IPickingService';
|
||||
|
||||
const PICKSCALE = 10.0;
|
||||
@injectable()
|
||||
export default class PickingService implements IPickingService {
|
||||
@inject(TYPES.IRendererService)
|
||||
private rendererService: IRendererService;
|
||||
|
||||
@inject(TYPES.IInteractionService)
|
||||
private interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.ILayerService)
|
||||
private layerService: ILayerService;
|
||||
private pickingFBO: IFramebuffer;
|
||||
|
||||
private width: number = 0;
|
||||
|
||||
private height: number = 0;
|
||||
|
||||
private alreadyInPicking: boolean = false;
|
||||
|
||||
public init() {
|
||||
const {
|
||||
createTexture2D,
|
||||
createFramebuffer,
|
||||
getViewportSize,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
// 创建 picking framebuffer,后续实时 resize
|
||||
this.pickingFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width,
|
||||
height,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
|
||||
// 监听 hover 事件
|
||||
this.interactionService.on(
|
||||
InteractionEvent.Hover,
|
||||
this.pickingAllLayer.bind(this),
|
||||
);
|
||||
}
|
||||
private async pickingAllLayer(target: IInteractionTarget) {
|
||||
if (this.alreadyInPicking || this.layerService.alreadyInRendering) {
|
||||
return;
|
||||
}
|
||||
this.alreadyInPicking = true;
|
||||
await this.pickingLayers(target);
|
||||
this.layerService.renderLayers();
|
||||
this.alreadyInPicking = false;
|
||||
}
|
||||
private async pickingLayers(target: IInteractionTarget) {
|
||||
const { getViewportSize, useFramebuffer, clear } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.pickingFBO.resize({
|
||||
width: Math.round(width / PICKSCALE),
|
||||
height: Math.round(height / PICKSCALE),
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
useFramebuffer(this.pickingFBO, () => {
|
||||
const layers = this.layerService.getLayers();
|
||||
layers
|
||||
.filter((layer) => layer.needPick())
|
||||
.reverse()
|
||||
.forEach((layer) => {
|
||||
clear({
|
||||
framebuffer: this.pickingFBO,
|
||||
color: [0, 0, 0, 0],
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
layer.hooks.beforePickingEncode.call();
|
||||
layer.renderModels();
|
||||
layer.hooks.afterPickingEncode.call();
|
||||
this.pickFromPickingFBO(layer, target);
|
||||
});
|
||||
});
|
||||
}
|
||||
private async pickingLayer(layer: ILayer, target: IInteractionTarget) {
|
||||
const { getViewportSize, useFramebuffer, clear } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.pickingFBO.resize({
|
||||
width: Math.round(width / PICKSCALE),
|
||||
height: Math.round(height / PICKSCALE),
|
||||
});
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
useFramebuffer(this.pickingFBO, () => {
|
||||
clear({
|
||||
framebuffer: this.pickingFBO,
|
||||
color: [0, 0, 0, 0],
|
||||
stencil: 0,
|
||||
depth: 1,
|
||||
});
|
||||
|
||||
layer.hooks.beforePickingEncode.call();
|
||||
layer.renderModels();
|
||||
layer.hooks.afterPickingEncode.call();
|
||||
this.pickFromPickingFBO(layer, target);
|
||||
});
|
||||
}
|
||||
|
||||
private pickFromPickingFBO = (
|
||||
layer: ILayer,
|
||||
{ x, y, lngLat, type }: IInteractionTarget,
|
||||
) => {
|
||||
const {
|
||||
getViewportSize,
|
||||
readPixels,
|
||||
useFramebuffer,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
const { enableHighlight, enableSelect } = layer.getLayerConfig();
|
||||
|
||||
const xInDevicePixel = x * window.devicePixelRatio;
|
||||
const yInDevicePixel = y * window.devicePixelRatio;
|
||||
if (
|
||||
xInDevicePixel > width ||
|
||||
xInDevicePixel < 0 ||
|
||||
yInDevicePixel > height ||
|
||||
yInDevicePixel < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let pickedColors: Uint8Array | undefined;
|
||||
pickedColors = readPixels({
|
||||
x: Math.round(xInDevicePixel / PICKSCALE),
|
||||
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
|
||||
y: Math.round((height - (y + 1) * window.devicePixelRatio) / PICKSCALE),
|
||||
width: 1,
|
||||
height: 1,
|
||||
data: new Uint8Array(1 * 1 * 4),
|
||||
framebuffer: this.pickingFBO,
|
||||
});
|
||||
if (
|
||||
pickedColors[0] !== 0 ||
|
||||
pickedColors[1] !== 0 ||
|
||||
pickedColors[2] !== 0
|
||||
) {
|
||||
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||
const rawFeature = layer.getSource().getFeatureById(pickedFeatureIdx);
|
||||
const target = {
|
||||
x,
|
||||
y,
|
||||
type,
|
||||
lngLat,
|
||||
featureId: pickedFeatureIdx,
|
||||
feature: rawFeature,
|
||||
};
|
||||
if (!rawFeature) {
|
||||
// this.logger.error(
|
||||
// '未找到颜色编码解码后的原始 feature,请检查 fragment shader 中末尾是否添加了 `gl_FragColor = filterColor(gl_FragColor);`',
|
||||
// );
|
||||
} else {
|
||||
// trigger onHover/Click callback on layer
|
||||
layer.setCurrentPickId(pickedFeatureIdx);
|
||||
this.triggerHoverOnLayer(layer, target);
|
||||
}
|
||||
} else {
|
||||
const target = {
|
||||
x,
|
||||
y,
|
||||
lngLat,
|
||||
type: layer.getCurrentPickId() === null ? 'un' + type : 'mouseout',
|
||||
featureId: null,
|
||||
feature: null,
|
||||
};
|
||||
this.triggerHoverOnLayer(layer, {
|
||||
...target,
|
||||
type: 'unpick',
|
||||
});
|
||||
this.triggerHoverOnLayer(layer, target);
|
||||
layer.setCurrentPickId(null);
|
||||
}
|
||||
|
||||
if (enableHighlight) {
|
||||
this.highlightPickedFeature(layer, pickedColors);
|
||||
}
|
||||
if (
|
||||
enableSelect &&
|
||||
type === 'click' &&
|
||||
pickedColors?.toString() !== [0, 0, 0, 0].toString()
|
||||
) {
|
||||
this.selectFeature(layer, pickedColors);
|
||||
}
|
||||
};
|
||||
private triggerHoverOnLayer(
|
||||
layer: ILayer,
|
||||
target: {
|
||||
x: number;
|
||||
y: number;
|
||||
type: string;
|
||||
lngLat: ILngLat;
|
||||
feature: unknown;
|
||||
featureId: number | null;
|
||||
},
|
||||
) {
|
||||
layer.emit(target.type, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* highlight 如果直接修改选中 feature 的 buffer,存在两个问题:
|
||||
* 1. 鼠标移走时无法恢复
|
||||
* 2. 无法实现高亮颜色与原始原色的 alpha 混合
|
||||
* 因此高亮还是放在 shader 中做比较好
|
||||
* @example
|
||||
* this.layer.color('name', ['#000000'], {
|
||||
* featureRange: {
|
||||
* startIndex: pickedFeatureIdx,
|
||||
* endIndex: pickedFeatureIdx + 1,
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
private highlightPickedFeature(
|
||||
layer: ILayer,
|
||||
pickedColors: Uint8Array | undefined,
|
||||
) {
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeHighlight.call([r, g, b]);
|
||||
// this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
private selectFeature(layer: ILayer, pickedColors: Uint8Array | undefined) {
|
||||
const [r, g, b] = pickedColors;
|
||||
layer.hooks.beforeSelect.call([r, g, b]);
|
||||
// this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
private selectFeatureHandle(
|
||||
layer: ILayer,
|
||||
{ featureId }: Partial<IInteractionTarget>,
|
||||
) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.selectFeature(layer, new Uint8Array(pickedColors));
|
||||
}
|
||||
|
||||
private highlightFeatureHandle(
|
||||
layer: ILayer,
|
||||
{ featureId }: Partial<IInteractionTarget>,
|
||||
) {
|
||||
const pickedColors = encodePickingColor(featureId as number);
|
||||
this.highlightPickedFeature(layer, new Uint8Array(pickedColors));
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import {
|
|||
IScale,
|
||||
IScaleOptions,
|
||||
IStyleAttributeService,
|
||||
ScaleAttributeType,
|
||||
StyleAttrField,
|
||||
StyleAttributeOption,
|
||||
Triangulation,
|
||||
|
@ -111,13 +112,14 @@ export interface ILayer {
|
|||
setCurrentPickId(id: number | null): void;
|
||||
getCurrentPickId(): number | null;
|
||||
prepareBuildModel(): void;
|
||||
renderModels(): void;
|
||||
buildModels(): void;
|
||||
buildLayerModel(
|
||||
options: ILayerModelInitializationOptions &
|
||||
Partial<IModelInitializationOptions>,
|
||||
): IModel;
|
||||
init(): ILayer;
|
||||
scale(field: string | IScaleOptions, cfg?: IScale): ILayer;
|
||||
scale(field: string | number | IScaleOptions, cfg?: IScale): ILayer;
|
||||
size(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
|
@ -138,6 +140,7 @@ export interface ILayer {
|
|||
style(options: unknown): ILayer;
|
||||
hide(): ILayer;
|
||||
show(): ILayer;
|
||||
getLegendItems(name: string): any;
|
||||
setIndex(index: number): ILayer;
|
||||
isVisible(): boolean;
|
||||
setMaxZoom(min: number): ILayer;
|
||||
|
@ -263,6 +266,7 @@ export interface ILayerConfig {
|
|||
*/
|
||||
export interface ILayerService {
|
||||
clock: Clock;
|
||||
alreadyInRendering: boolean;
|
||||
add(layer: ILayer): void;
|
||||
initLayers(): void;
|
||||
startAnimate(): void;
|
||||
|
|
|
@ -35,8 +35,11 @@ export type ScaleTypeName =
|
|||
| 'quantize'
|
||||
| 'threshold'
|
||||
| 'cat';
|
||||
|
||||
export type ScaleAttributeType = 'color' | 'size' | 'shape';
|
||||
export interface IScale {
|
||||
type: ScaleTypeName;
|
||||
field?: string;
|
||||
ticks?: any[];
|
||||
nice?: boolean;
|
||||
format?: () => any;
|
||||
|
@ -49,6 +52,7 @@ export enum StyleScaleType {
|
|||
}
|
||||
export interface IScaleOption {
|
||||
field?: string;
|
||||
attr?: ScaleAttributeType;
|
||||
type: ScaleTypeName;
|
||||
ticks?: any[];
|
||||
nice?: boolean;
|
||||
|
@ -115,6 +119,11 @@ type CallBack = (...args: any[]) => any;
|
|||
export type StyleAttributeField = string | string[] | number[];
|
||||
export type StyleAttributeOption = string | number | boolean | any[] | CallBack;
|
||||
export type StyleAttrField = string | string[] | number | number[];
|
||||
export interface IAttributeScale {
|
||||
field: string | number;
|
||||
func: unknown;
|
||||
option: IScaleOption | undefined;
|
||||
}
|
||||
|
||||
export interface IStyleAttributeInitializationOptions {
|
||||
name: string;
|
||||
|
@ -125,10 +134,7 @@ export interface IStyleAttributeInitializationOptions {
|
|||
names: string[] | number[];
|
||||
type: StyleScaleType;
|
||||
callback?: (...args: any[]) => [];
|
||||
scalers?: Array<{
|
||||
field: string | number;
|
||||
func: unknown;
|
||||
}>;
|
||||
scalers?: IAttributeScale[];
|
||||
};
|
||||
descriptor: IVertexAttributeDescriptor;
|
||||
}
|
||||
|
@ -186,6 +192,7 @@ export interface IStyleAttributeService {
|
|||
): void;
|
||||
getLayerStyleAttributes(): IStyleAttribute[] | undefined;
|
||||
getLayerStyleAttribute(attributeName: string): IStyleAttribute | undefined;
|
||||
getLayerAttributeScale(attributeName: string): any;
|
||||
createAttributesAndIndices(
|
||||
encodedFeatures: IEncodeFeature[],
|
||||
triangulation?: Triangulation,
|
||||
|
|
|
@ -10,6 +10,8 @@ import { ILayerModel, ILayerService } from './ILayerService';
|
|||
export default class LayerService implements ILayerService {
|
||||
public clock = new Clock();
|
||||
|
||||
public alreadyInRendering: boolean = false;
|
||||
|
||||
private layers: ILayer[] = [];
|
||||
|
||||
private layerRenderID: number;
|
||||
|
@ -18,8 +20,6 @@ export default class LayerService implements ILayerService {
|
|||
|
||||
private animateInstanceCount: number = 0;
|
||||
|
||||
private alreadyInRendering: boolean = false;
|
||||
|
||||
@inject(TYPES.IRendererService)
|
||||
private readonly renderService: IRendererService;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { isNil } from 'lodash';
|
||||
import {
|
||||
IAttributeScale,
|
||||
IScaleOption,
|
||||
IStyleAttribute,
|
||||
StyleScaleType,
|
||||
} from '../layer/IStyleAttributeService';
|
||||
|
@ -22,10 +24,7 @@ export default class StyleAttribute implements IStyleAttribute {
|
|||
field: string | string[];
|
||||
values: unknown[];
|
||||
callback?: (...args: any[]) => [];
|
||||
scalers?: Array<{
|
||||
field: string;
|
||||
func: unknown;
|
||||
}>;
|
||||
scalers?: IAttributeScale[];
|
||||
};
|
||||
public descriptor: IVertexAttributeDescriptor;
|
||||
public featureBufferLayout: Array<{
|
||||
|
|
|
@ -7,6 +7,7 @@ import { IRendererService } from '../renderer/IRendererService';
|
|||
import { IParseDataItem } from '../source/ISourceService';
|
||||
import { ILayer } from './ILayerService';
|
||||
import {
|
||||
IAttributeScale,
|
||||
IEncodeFeature,
|
||||
IStyleAttribute,
|
||||
IStyleAttributeInitializationOptions,
|
||||
|
@ -108,6 +109,15 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
);
|
||||
}
|
||||
|
||||
public getLayerAttributeScale(name: string) {
|
||||
const attribute = this.getLayerStyleAttribute(name);
|
||||
const scale = attribute?.scale?.scalers as IAttributeScale[];
|
||||
if (scale && scale[0]) {
|
||||
return scale[0].func;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public updateAttributeByFeatureRange(
|
||||
attributeName: string,
|
||||
features: IEncodeFeature[],
|
||||
|
|
|
@ -38,6 +38,10 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
|||
private layer: ILayer;
|
||||
private renderFlag: boolean;
|
||||
|
||||
private width: number = 0;
|
||||
|
||||
private height: number = 0;
|
||||
|
||||
public setLayer(layer: ILayer) {
|
||||
this.layer = layer;
|
||||
}
|
||||
|
@ -58,11 +62,16 @@ export default class MultiPassRenderer implements IMultiPassRenderer {
|
|||
for (const pass of this.passes) {
|
||||
await pass.render(this.layer);
|
||||
}
|
||||
await this.postProcessor.render(this.layer);
|
||||
this.layer.renderModels();
|
||||
// await this.postProcessor.render(this.layer);
|
||||
}
|
||||
|
||||
public resize(width: number, height: number) {
|
||||
this.postProcessor.resize(width, height);
|
||||
if (this.width !== width || this.height !== height) {
|
||||
this.postProcessor.resize(width, height);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
public add<T>(pass: IPass<T>, config?: Partial<T>) {
|
||||
|
|
|
@ -60,7 +60,6 @@ export default class PixelPickingPass<
|
|||
getViewportSize,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
// 创建 picking framebuffer,后续实时 resize
|
||||
this.pickingFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
|
|
|
@ -14,4 +14,9 @@ export interface ISceneService {
|
|||
destroy(): void;
|
||||
}
|
||||
// scene 事件
|
||||
export const SceneEventList = ['loaded', 'maploaded', 'resize', 'destroy'];
|
||||
export const SceneEventList: string[] = [
|
||||
'loaded',
|
||||
'maploaded',
|
||||
'resize',
|
||||
'destroy',
|
||||
];
|
||||
|
|
|
@ -14,6 +14,7 @@ import { IPopupService } from '../component/IPopupService';
|
|||
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
||||
import { ICoordinateSystemService } from '../coordinate/ICoordinateSystemService';
|
||||
import { IInteractionService } from '../interaction/IInteractionService';
|
||||
import { IPickingService } from '../interaction/IPickingService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILogService } from '../log/ILogService';
|
||||
import { IMapCamera, IMapService } from '../map/IMapService';
|
||||
|
@ -64,6 +65,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
@inject(TYPES.IInteractionService)
|
||||
private readonly interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.IPickingService)
|
||||
private readonly pickingService: IPickingService;
|
||||
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
|
@ -150,6 +154,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.popupService.initPopup();
|
||||
// 地图初始化之后 才能初始化 container 上的交互
|
||||
this.interactionService.init();
|
||||
|
||||
this.logger.debug(`map ${this.id} loaded`);
|
||||
});
|
||||
|
||||
|
@ -174,6 +179,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
} else {
|
||||
this.logger.error('容器 id 不存在');
|
||||
}
|
||||
this.pickingService.init();
|
||||
|
||||
this.logger.debug(`scene ${this.id} renderer loaded`);
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ const TYPES = {
|
|||
IIconService: Symbol.for('IIconService'),
|
||||
IFontService: Symbol.for('IFontService'),
|
||||
IInteractionService: Symbol.for('IInteractionService'),
|
||||
IPickingService: Symbol.for('IPickingService'),
|
||||
IControlService: Symbol.for('IControlService'),
|
||||
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
|
||||
ILayer: Symbol.for('ILayer'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "A Large-scale WebGL-powered Geospatial Data Visualization",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,11 +24,11 @@
|
|||
"author": "antv",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antv/l7-component": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-layers": "^2.0.22",
|
||||
"@antv/l7-maps": "^2.0.22",
|
||||
"@antv/l7-scene": "^2.0.22",
|
||||
"@antv/l7-component": "^2.0.23-alpha.0",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-layers": "^2.0.23-alpha.0",
|
||||
"@antv/l7-maps": "^2.0.23-alpha.0",
|
||||
"@antv/l7-scene": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-layers",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "L7's collection of built-in layers",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -22,9 +22,9 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-source": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-source": "^2.0.23-alpha.0",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@mapbox/martini": "^0.1.0",
|
||||
"@turf/meta": "^6.0.2",
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
IStyleAttributeService,
|
||||
IStyleAttributeUpdateOptions,
|
||||
lazyInject,
|
||||
ScaleAttributeType,
|
||||
ScaleTypeName,
|
||||
ScaleTypes,
|
||||
StyleAttributeField,
|
||||
|
@ -170,6 +171,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
|
||||
private aniamateStatus: boolean = false;
|
||||
|
||||
// private pickingPassRender: IPass<'pixelPicking'>;
|
||||
|
||||
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions> = {}) {
|
||||
super();
|
||||
this.name = config.name || this.id;
|
||||
|
@ -228,7 +231,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
// 设置配置项
|
||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||
// 初始化图层配置项
|
||||
this.configService.setLayerConfig(sceneId, this.id, {});
|
||||
const { enableMultiPassRenderer = false } = this.rawConfig;
|
||||
this.configService.setLayerConfig(sceneId, this.id, {
|
||||
enableMultiPassRenderer,
|
||||
});
|
||||
|
||||
// 全局容器服务
|
||||
|
||||
|
@ -297,6 +303,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
|
||||
// 触发 init 生命周期插件
|
||||
this.hooks.init.call();
|
||||
|
||||
// this.pickingPassRender = this.normalPassFactory('pixelPicking');
|
||||
// this.pickingPassRender.init(this);
|
||||
this.hooks.afterInit.call();
|
||||
|
||||
// 触发初始化完成事件;
|
||||
|
@ -360,9 +369,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.updateStyleAttribute('filter', field, values, updateOptions);
|
||||
// if (this.inited) {
|
||||
// this.layerModelNeedUpdate = true;
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -453,7 +459,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
return this;
|
||||
}
|
||||
public scale(field: ScaleTypeName | IScaleOptions, cfg: IScale) {
|
||||
public scale(field: string | IScaleOptions, cfg: IScale) {
|
||||
if (isObject(field)) {
|
||||
this.scaleOptions = {
|
||||
...this.scaleOptions,
|
||||
|
@ -465,11 +471,21 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
public render(): ILayer {
|
||||
if (this.multiPassRenderer && this.multiPassRenderer.getRenderFlag()) {
|
||||
this.multiPassRenderer.render();
|
||||
} else {
|
||||
this.renderModels();
|
||||
}
|
||||
// if (
|
||||
// this.needPick() &&
|
||||
// this.multiPassRenderer &&
|
||||
// this.multiPassRenderer.getRenderFlag()
|
||||
// ) {
|
||||
// this.multiPassRenderer.render();
|
||||
// } else if (this.needPick() && this.multiPassRenderer) {
|
||||
// this.renderModels();
|
||||
// } else {
|
||||
// this.renderModels();
|
||||
// }
|
||||
|
||||
this.renderModels();
|
||||
// this.multiPassRenderer.render();
|
||||
// this.renderModels();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -730,6 +746,30 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
return this.configSchema;
|
||||
}
|
||||
public getLegendItems(name: string): any {
|
||||
const scale = this.styleAttributeService.getLayerAttributeScale(name);
|
||||
if (scale) {
|
||||
if (scale.ticks) {
|
||||
const items = scale.ticks().map((item: any) => {
|
||||
return {
|
||||
value: item,
|
||||
[name]: scale(item),
|
||||
};
|
||||
});
|
||||
return items;
|
||||
} else if (scale.invertExtent) {
|
||||
const items = scale.range().map((item: any) => {
|
||||
return {
|
||||
value: scale.invertExtent(item),
|
||||
[name]: item,
|
||||
};
|
||||
});
|
||||
return items;
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public pick({ x, y }: { x: number; y: number }) {
|
||||
this.interactionService.triggerHover({ x, y });
|
||||
|
@ -806,11 +846,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
if (this.layerModelNeedUpdate) {
|
||||
this.models = this.layerModel.buildModels();
|
||||
this.hooks.beforeRender.call();
|
||||
|
@ -824,6 +860,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected getModelType(): unknown {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
|
|
@ -12,19 +12,7 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
|||
this.layerModel = new HeatMapModels[shape](this);
|
||||
this.models = this.layerModel.buildModels();
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const shape = this.getModelType();
|
||||
if (shape === 'heatmap') {
|
||||
// if (this.layerModelNeedUpdate) {
|
||||
|
@ -49,6 +37,18 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
|
|||
);
|
||||
return this;
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected getModelType(): HeatMapModelType {
|
||||
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
|
||||
'shape',
|
||||
|
|
|
@ -64,7 +64,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
this.caculateScalesForAttributes(attributes || [], dataArray);
|
||||
});
|
||||
|
||||
// 检测数据是不否需要更新
|
||||
// 检测数据是否需要更新
|
||||
layer.hooks.beforeRenderData.tap('FeatureScalePlugin', (flag) => {
|
||||
if (flag) {
|
||||
this.scaleOptions = layer.getScaleOptions();
|
||||
|
@ -146,6 +146,7 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
return {
|
||||
field: scale.field,
|
||||
func: scale.scale,
|
||||
option: scale.option,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -160,13 +161,17 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
) {
|
||||
const scalekey = [field, attribute.name].join('_');
|
||||
const values = attribute.scale?.values;
|
||||
if (this.scaleCache[scalekey]) {
|
||||
return this.scaleCache[scalekey];
|
||||
}
|
||||
const styleScale = this.createScale(field, values, dataArray);
|
||||
this.scaleCache[scalekey] = styleScale;
|
||||
|
||||
return this.scaleCache[scalekey];
|
||||
// if (this.scaleCache[scalekey]) {
|
||||
// return this.scaleCache[scalekey];
|
||||
// }
|
||||
const styleScale = this.createScale(
|
||||
field,
|
||||
attribute.name,
|
||||
values,
|
||||
dataArray,
|
||||
);
|
||||
// this.scaleCache[scalekey] = styleScale;
|
||||
return styleScale;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,11 +193,15 @@ export default class FeatureScalePlugin implements ILayerPlugin {
|
|||
|
||||
private createScale(
|
||||
field: string | number,
|
||||
name: string,
|
||||
values: unknown[] | string | undefined,
|
||||
data?: IParseDataItem[],
|
||||
): IStyleScale {
|
||||
// 首先查找全局默认配置例如 color
|
||||
const scaleOption: IScale | undefined = this.scaleOptions[field];
|
||||
// scale 支持根据视觉通道和字段
|
||||
const scaleOption: IScale | undefined =
|
||||
this.scaleOptions[name] && this.scaleOptions[name].field === field
|
||||
? this.scaleOptions[name]
|
||||
: this.scaleOptions[field];
|
||||
const styleScale: IStyleScale = {
|
||||
field,
|
||||
scale: undefined,
|
||||
|
|
|
@ -76,11 +76,11 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
|||
});
|
||||
|
||||
layer.hooks.beforeRender.tap('MultiPassRendererPlugin', () => {
|
||||
if (this.enabled) {
|
||||
// 渲染前根据 viewport 调整 FBO size
|
||||
const { width, height } = rendererService.getViewportSize();
|
||||
layer.multiPassRenderer.resize(width, height);
|
||||
}
|
||||
// if (this.enabled) {
|
||||
// // 渲染前根据 viewport 调整 FBO size
|
||||
// const { width, height } = rendererService.getViewportSize();
|
||||
// layer.multiPassRenderer.resize(width, height);
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -103,26 +103,26 @@ export default class MultiPassRendererPlugin implements ILayerPlugin {
|
|||
}
|
||||
|
||||
// use TAA pass if enabled instead of render pass
|
||||
if (enableTAA) {
|
||||
multiPassRenderer.add(normalPassFactory('taa'));
|
||||
} else {
|
||||
// render all layers in this pass
|
||||
multiPassRenderer.add(normalPassFactory('render'));
|
||||
}
|
||||
// if (enableTAA) {
|
||||
// multiPassRenderer.add(normalPassFactory('taa'));
|
||||
// } else {
|
||||
// // render all layers in this pass
|
||||
// multiPassRenderer.add(normalPassFactory('render'));
|
||||
// }
|
||||
|
||||
// post processing
|
||||
normalizePasses(passes).forEach(
|
||||
(pass: [string, { [key: string]: unknown }]) => {
|
||||
const [passName, initializationOptions] = pass;
|
||||
multiPassRenderer.add(
|
||||
postProcessingPassFactory(passName),
|
||||
initializationOptions,
|
||||
);
|
||||
},
|
||||
);
|
||||
// normalizePasses(passes).forEach(
|
||||
// (pass: [string, { [key: string]: unknown }]) => {
|
||||
// const [passName, initializationOptions] = pass;
|
||||
// multiPassRenderer.add(
|
||||
// postProcessingPassFactory(passName),
|
||||
// initializationOptions,
|
||||
// );
|
||||
// },
|
||||
// );
|
||||
|
||||
// 末尾为固定的 CopyPass
|
||||
multiPassRenderer.add(postProcessingPassFactory('copy'));
|
||||
// multiPassRenderer.add(postProcessingPassFactory('copy'));
|
||||
|
||||
return multiPassRenderer;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,11 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
|
|||
) {
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
|
||||
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
||||
if (filter && filter.needRegenerateVertices) {
|
||||
const shape = styleAttributeService.getLayerStyleAttribute('shape');
|
||||
if (
|
||||
(filter && filter.needRegenerateVertices) ||
|
||||
(shape && shape.needRegenerateVertices) // TODO:Shape 更新重新build
|
||||
) {
|
||||
layer.layerModelNeedUpdate = true;
|
||||
attributes.forEach((attr) => (attr.needRegenerateVertices = false));
|
||||
return;
|
||||
|
|
|
@ -18,6 +18,7 @@ interface IPointLayerStyleOptions {
|
|||
opacity: number;
|
||||
strokeWidth: number;
|
||||
stroke: string;
|
||||
strokeOpacity: number;
|
||||
}
|
||||
export default class FillModel extends BaseModel {
|
||||
public getUninforms(): IModelUniform {
|
||||
|
@ -25,11 +26,13 @@ export default class FillModel extends BaseModel {
|
|||
opacity = 1,
|
||||
stroke = 'rgb(0,0,0,0)',
|
||||
strokeWidth = 1,
|
||||
strokeOpacity = 1,
|
||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity,
|
||||
u_stroke_width: strokeWidth,
|
||||
u_stroke_color: rgb2arr(stroke),
|
||||
u_stroke_opacity: strokeOpacity,
|
||||
};
|
||||
}
|
||||
public getAnimateUniforms(): IModelUniform {
|
||||
|
@ -84,7 +87,7 @@ export default class FillModel extends BaseModel {
|
|||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const extrude = [-1, -1, 1, -1, 1, 1, -1, 1];
|
||||
const extrude = [1, 1, -1, 1, -1, -1, 1, -1];
|
||||
const extrudeIndex = (attributeIdx % 4) * 2;
|
||||
return [extrude[extrudeIndex], extrude[extrudeIndex + 1]];
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ void main() {
|
|||
// radius(16-bit)
|
||||
v_radius = a_Size;
|
||||
|
||||
vec2 offset = project_pixel(extrude * (a_Size + u_stroke_width));
|
||||
vec2 offset = project_pixel(extrude * (a_Size + u_stroke_width)) * -1.;
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
|
|
|
@ -57,19 +57,7 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
});
|
||||
this.models = [this.buildRasterModel()];
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const { opacity, heightRatio = 10 } = this.getLayerConfig();
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { coordinates, width, height, min, max } = parserDataItem;
|
||||
|
@ -91,6 +79,18 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
|
||||
return this;
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private buildRasterModel() {
|
||||
const source = this.getSource();
|
||||
const sourceFeature = source.data.dataArray[0];
|
||||
|
|
|
@ -57,20 +57,7 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
public renderModels() {
|
||||
const { opacity } = this.getLayerConfig();
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { min, max } = parserDataItem;
|
||||
|
@ -91,6 +78,18 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
return this;
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-maps",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -23,8 +23,8 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"gl-matrix": "^3.1.0",
|
||||
"inversify": "^5.0.1",
|
||||
|
|
|
@ -240,6 +240,7 @@ export default class AMapService
|
|||
if (mapInstance) {
|
||||
this.map = mapInstance as AMap.Map & IAMapInstance;
|
||||
this.$mapContainer = this.map.getContainer();
|
||||
this.removeLogoControl();
|
||||
setTimeout(() => {
|
||||
this.map.on('camerachange', this.handleCameraChanged);
|
||||
resolve();
|
||||
|
@ -255,6 +256,10 @@ export default class AMapService
|
|||
viewMode: '3D',
|
||||
...rest,
|
||||
});
|
||||
map.on('complete', () => {
|
||||
this.removeLogoControl();
|
||||
});
|
||||
|
||||
// 监听地图相机事件
|
||||
map.on('camerachange', this.handleCameraChanged);
|
||||
// @ts-ignore
|
||||
|
@ -390,4 +395,12 @@ export default class AMapService
|
|||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
private removeLogoControl(): void {
|
||||
// @ts-ignore
|
||||
const logo = document.getElementsByClassName('amap-logo');
|
||||
if (logo) {
|
||||
logo[0].setAttribute('style', 'display: none !important');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,6 @@ export const MapTheme: {
|
|||
glyphs:
|
||||
'https://gw.alipayobjects.com/os/antvdemo/assets/mapbox/glyphs/{fontstack}/{range}.pbf',
|
||||
sources: {},
|
||||
layers: [
|
||||
{
|
||||
id: 'background',
|
||||
type: 'background',
|
||||
paint: {
|
||||
'background-color': 'white',
|
||||
},
|
||||
},
|
||||
],
|
||||
layers: [],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-react",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,10 +24,12 @@
|
|||
"author": "lzxue",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7": "^2.0.22",
|
||||
"@antv/l7-maps": "^2.0.22",
|
||||
"@antv/l7": "^2.0.23-alpha.0",
|
||||
"@antv/l7-maps": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"react": "^16.8.6"
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.10.2",
|
||||
"load-styles": "^2.0.0"
|
||||
},
|
||||
"gitHead": "f2bd3c6473df79d815467b1677c6f985cf68800e",
|
||||
"publishConfig": {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { IMapConfig, Scene } from '@antv/l7';
|
||||
// @ts-ignore
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import GaodeMap from '@antv/l7-maps/lib/amap';
|
||||
import React, { createElement, createRef, useEffect, useState } from 'react';
|
||||
import { SceneContext } from './SceneContext';
|
||||
interface IMapSceneConig {
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
map: IMapConfig;
|
||||
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||
}
|
||||
const AMapScene = React.memo((props: IMapSceneConig) => {
|
||||
const { style, className, map } = props;
|
||||
const container = createRef();
|
||||
const [scene, setScene] = useState();
|
||||
useEffect(() => {
|
||||
const sceneInstance = new Scene({
|
||||
id: container.current as HTMLDivElement,
|
||||
map: new GaodeMap(map),
|
||||
});
|
||||
sceneInstance.on('loaded', () => {
|
||||
setScene(sceneInstance);
|
||||
});
|
||||
return () => {
|
||||
sceneInstance.destroy();
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
scene.setMapStyle(map.style);
|
||||
}, [map.style]);
|
||||
|
||||
return (
|
||||
<SceneContext.Provider value={scene}>
|
||||
{createElement(
|
||||
'div',
|
||||
{
|
||||
ref: container,
|
||||
style,
|
||||
className,
|
||||
},
|
||||
scene && props.children,
|
||||
)}
|
||||
</SceneContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export default AMapScene;
|
|
@ -0,0 +1,39 @@
|
|||
import { IControl, Logo, PositionType, Scale, Scene, Zoom } from '@antv/l7';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSceneValue } from './SceneContext';
|
||||
interface IControlProps {
|
||||
type: 'scale' | 'zoom' | 'logo';
|
||||
position: PositionType;
|
||||
[key: string]: any;
|
||||
}
|
||||
export default React.memo(function MapControl(props: IControlProps) {
|
||||
const scene = (useSceneValue() as unknown) as Scene;
|
||||
const [, setControl] = useState();
|
||||
const { type, position } = props;
|
||||
useEffect(() => {
|
||||
let ctr: IControl;
|
||||
switch (type) {
|
||||
case 'scale':
|
||||
ctr = new Scale({
|
||||
position,
|
||||
});
|
||||
break;
|
||||
case 'zoom':
|
||||
ctr = new Zoom({
|
||||
position,
|
||||
});
|
||||
break;
|
||||
case 'logo':
|
||||
ctr = new Logo({
|
||||
position,
|
||||
});
|
||||
}
|
||||
setControl(ctr);
|
||||
scene.addControl(ctr);
|
||||
return () => {
|
||||
scene.removeControl(ctr);
|
||||
};
|
||||
}, [type, position]);
|
||||
|
||||
return null;
|
||||
});
|
|
@ -0,0 +1,44 @@
|
|||
import { Control, PositionName, Scene } from '@antv/l7';
|
||||
import * as React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { useSceneValue } from './SceneContext';
|
||||
const { useEffect, useState } = React;
|
||||
|
||||
interface IColorLegendProps {
|
||||
position: PositionName;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||
}
|
||||
|
||||
export default function CustoonConrol(props: IColorLegendProps) {
|
||||
const { className, style, children, position } = props;
|
||||
const mapScene = (useSceneValue() as unknown) as Scene;
|
||||
const el = document.createElement('div');
|
||||
useEffect(() => {
|
||||
const custom = new Control({
|
||||
position,
|
||||
});
|
||||
custom.onAdd = () => {
|
||||
if (className) {
|
||||
el.className = className;
|
||||
}
|
||||
if (style) {
|
||||
const cssText = Object.keys(style)
|
||||
.map((key: string) => {
|
||||
// @ts-ignore
|
||||
return `${key}:${style[key]}`;
|
||||
})
|
||||
.join(';');
|
||||
el.style.cssText = cssText;
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
mapScene.addControl(custom);
|
||||
return () => {
|
||||
mapScene.removeControl(custom);
|
||||
};
|
||||
}, []);
|
||||
return createPortal(children, el);
|
||||
}
|
|
@ -12,7 +12,8 @@ export default React.memo(function Chart(props: ILayerProps) {
|
|||
useEffect(() => {
|
||||
color.field
|
||||
? layer.color(color.field as StyleAttrField, color.values)
|
||||
: layer.color(color.value as StyleAttrField);
|
||||
}, [color.value, color.field, JSON.stringify(color.values), color.values]);
|
||||
: layer.color(color.values as StyleAttrField);
|
||||
}, [color.field, color.scale, JSON.stringify(color.values)]);
|
||||
|
||||
return null;
|
||||
});
|
||||
|
|
|
@ -2,13 +2,12 @@ import { ILayer, LineLayer, PointLayer, PolygonLayer, Scene } from '@antv/l7';
|
|||
import * as React from 'react';
|
||||
import { LayerContext } from '../LayerContext';
|
||||
import { useSceneValue } from '../SceneContext';
|
||||
|
||||
import {
|
||||
Active,
|
||||
Color,
|
||||
Filter,
|
||||
ILayerProps,
|
||||
Scales,
|
||||
Scale,
|
||||
Shape,
|
||||
Size,
|
||||
Source,
|
||||
|
@ -17,17 +16,14 @@ import {
|
|||
|
||||
const { useEffect, useState } = React;
|
||||
|
||||
export default function BaseLayer(
|
||||
type: string,
|
||||
props: ILayerProps & { children?: any },
|
||||
) {
|
||||
export default function BaseLayer(type: string, props: ILayerProps) {
|
||||
const {
|
||||
source,
|
||||
color,
|
||||
shape,
|
||||
style,
|
||||
size,
|
||||
scales,
|
||||
scale,
|
||||
active,
|
||||
filter,
|
||||
options,
|
||||
|
@ -66,7 +62,7 @@ export default function BaseLayer(
|
|||
return (
|
||||
<LayerContext.Provider value={layer}>
|
||||
<Source layer={layer} source={source} />
|
||||
{scales && <Scales layer={layer} scales={scales} />}
|
||||
{scale && <Scale layer={layer} scale={scale} />}
|
||||
<Color layer={layer} color={color} />
|
||||
{size && <Size layer={layer} size={size} />}
|
||||
<Shape layer={layer} shape={shape} />
|
||||
|
|
|
@ -5,14 +5,12 @@ import { IScaleAttributeOptions } from './';
|
|||
const { useEffect } = React;
|
||||
interface ILayerProps {
|
||||
layer: ILayer;
|
||||
scales: Partial<IScaleAttributeOptions>;
|
||||
scale: Partial<IScaleAttributeOptions>;
|
||||
}
|
||||
export default React.memo(function Chart(props: ILayerProps) {
|
||||
const { layer, scales } = props;
|
||||
const { layer, scale } = props;
|
||||
useEffect(() => {
|
||||
scales.field
|
||||
? layer.scale(scales.field as string, scales.value as IScale)
|
||||
: layer.scale(scales.values as IScaleOptions);
|
||||
}, [scales.value, scales.field, JSON.stringify(scales.values)]);
|
||||
layer.scale(scale.values as IScaleOptions);
|
||||
}, [scale.values]);
|
||||
return null;
|
||||
});
|
|
@ -12,7 +12,7 @@ export default React.memo(function Chart(props: ILayerProps) {
|
|||
useEffect(() => {
|
||||
shape.field
|
||||
? layer.shape(shape.field, shape.values)
|
||||
: layer.shape(shape.value as StyleAttrField);
|
||||
}, [shape.field, shape.value, JSON.stringify(shape.values), shape.values]);
|
||||
: layer.shape(shape.values as StyleAttrField);
|
||||
}, [shape.field, JSON.stringify(shape.values)]);
|
||||
return null;
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ export default React.memo(function Chart(props: ILayerProps) {
|
|||
useEffect(() => {
|
||||
size.field
|
||||
? layer.size(size.field, size.values)
|
||||
: layer.size(size.value as StyleAttrField);
|
||||
}, [size.field, size.value, JSON.stringify(size.values), size.values]);
|
||||
: layer.size(size.values as StyleAttrField);
|
||||
}, [size.field, size.values, size.scale]);
|
||||
return null;
|
||||
});
|
||||
|
|
|
@ -16,11 +16,7 @@ export default React.memo(function Chart(props: ISourceProps) {
|
|||
layer.source(data, sourceOption);
|
||||
} else {
|
||||
layer.setData(data, sourceOption);
|
||||
if (layer.type === 'PolygonLayer') {
|
||||
// 重新设置data之后,自适应处理
|
||||
layer.fitBounds();
|
||||
}
|
||||
}
|
||||
}, [data]);
|
||||
}, [data, sourceOption]);
|
||||
return null;
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ import { IActiveOption, IScale, IScaleOptions, ISourceCFG } from '@antv/l7';
|
|||
import Active from './Active';
|
||||
import Color from './Color';
|
||||
import Filter from './Filter';
|
||||
import Scales from './Scales';
|
||||
import Scale from './Scale';
|
||||
import Shape from './Shape';
|
||||
import Size from './Size';
|
||||
import Source from './Source';
|
||||
|
@ -12,14 +12,19 @@ type CallBack = (...args: any[]) => any;
|
|||
|
||||
export interface IAttributeOptions {
|
||||
field: string;
|
||||
value: string | number | CallBack;
|
||||
values: string[] | number[] | string | CallBack;
|
||||
value: string | number;
|
||||
values: string[] | number[] | string | number;
|
||||
scale?: string;
|
||||
}
|
||||
|
||||
export interface IScaleAttributeOptions {
|
||||
field: string;
|
||||
field: string | IScaleOptions;
|
||||
value: IScale;
|
||||
values: IScaleOptions;
|
||||
values: IScaleOptions | IScale;
|
||||
}
|
||||
|
||||
export interface IScaleOption {
|
||||
[key: string]: IScaleAttributeOptions;
|
||||
}
|
||||
export interface IStyleOptions {
|
||||
opacity: number;
|
||||
|
@ -40,11 +45,12 @@ export interface ILayerProps {
|
|||
source: ISourceOptions;
|
||||
color: Partial<IAttributeOptions>;
|
||||
shape: Partial<IAttributeOptions>;
|
||||
scales?: Partial<IScaleAttributeOptions>;
|
||||
scale?: Partial<IScaleAttributeOptions>;
|
||||
size?: Partial<IAttributeOptions>;
|
||||
style?: Partial<IStyleOptions>;
|
||||
active?: IActiveOptions;
|
||||
filter?: Partial<IAttributeOptions>;
|
||||
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||
}
|
||||
|
||||
export { Active, Color, Filter, Source, Size, Shape, Style, Scales };
|
||||
export { Active, Color, Filter, Source, Size, Shape, Style, Scale };
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import * as React from 'react';
|
||||
interface IColorLegendProps {
|
||||
items?: any[];
|
||||
title: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
import './style.css';
|
||||
export const ColorComponent = React.memo((props: IColorLegendProps) => {
|
||||
const { className, style, title } = props;
|
||||
const items = [
|
||||
{ title: '1', color: 'rgb(239,243,255)' },
|
||||
{ title: '10', color: 'rgb(198,219,239)' },
|
||||
{ title: '30', color: 'rgb(158,202,225)' },
|
||||
{ title: '50', color: 'rgb(107,174,214)' },
|
||||
{ title: '60', color: 'rgb(49,130,189)' },
|
||||
{ title: '100', color: 'rgb(8,81,156)' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
{items.map((c, i) => {
|
||||
return (
|
||||
<div
|
||||
key={i.toString()}
|
||||
style={{
|
||||
background: c.color,
|
||||
height: '100%',
|
||||
display: 'inline-block',
|
||||
cursor: 'pointer',
|
||||
width: '' + (100.0 - items.length) / items.length + '%',
|
||||
marginRight: '1%',
|
||||
padding: 5,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
{items.map((c, i) => {
|
||||
return (
|
||||
<div
|
||||
key={i.toString() + '122'}
|
||||
style={{
|
||||
background: '#fff',
|
||||
height: '100%',
|
||||
display: 'inline-block',
|
||||
textAlign: 'left',
|
||||
cursor: 'pointer',
|
||||
width: '' + (100.0 - items.length) / items.length + '%',
|
||||
marginRight: '1%',
|
||||
}}
|
||||
>
|
||||
{c.title}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
.color {
|
||||
color:'red';
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import { IMapConfig, Scene } from '@antv/l7';
|
||||
// @ts-ignore
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import Mapbox from '@antv/l7-maps/lib/mapbox';
|
||||
import React, { createElement, createRef, useEffect, useState } from 'react';
|
||||
import { SceneContext } from './SceneContext';
|
||||
interface IMapSceneConig {
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
map: IMapConfig;
|
||||
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
|
||||
}
|
||||
const MapboxScene = React.memo((props: IMapSceneConig) => {
|
||||
const { style, className, map } = props;
|
||||
const container = createRef();
|
||||
const [scene, setScene] = useState();
|
||||
useEffect(() => {
|
||||
const sceneInstance = new Scene({
|
||||
id: container.current as HTMLDivElement,
|
||||
map: new Mapbox(map),
|
||||
});
|
||||
sceneInstance.on('loaded', () => {
|
||||
setScene(sceneInstance);
|
||||
});
|
||||
return () => {
|
||||
sceneInstance.destroy();
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
scene.setMapStyle(map.style);
|
||||
}, [map.style]);
|
||||
|
||||
return (
|
||||
<SceneContext.Provider value={scene}>
|
||||
{createElement(
|
||||
'div',
|
||||
{
|
||||
ref: container,
|
||||
style,
|
||||
className,
|
||||
},
|
||||
scene && props.children,
|
||||
)}
|
||||
</SceneContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export default MapboxScene;
|
|
@ -36,6 +36,12 @@ const MapScene = React.memo((props: IMapSceneConig) => {
|
|||
sceneInstance.destroy();
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
scene.setMapStyle(style);
|
||||
}, [style]);
|
||||
|
||||
return (
|
||||
<SceneContext.Provider value={scene}>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
export * from './component/SceneContext';
|
||||
export { default as Scene } from './component/Scene';
|
||||
export { default as AMapScene } from './component/AMapScene';
|
||||
export { default as MapboxScene } from './component/MapboxScene';
|
||||
export * from './component/Layer';
|
||||
export { default as Control } from './component/Control';
|
||||
export { default as CustomControl } from './component/CustomControl';
|
||||
export { MapScene } from './component/Scene';
|
||||
export { PolygonLayer, LineLayer, PointLayer } from './component/Layer';
|
||||
export { LayerEvent } from './component/LayerEvent';
|
||||
export { useSceneValue, SceneContext } from './component/SceneContext';
|
||||
export { useLayerValue, LayerContext } from './component/LayerContext';
|
||||
export { ColorComponent } from './component/Legend/color';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-renderer",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -25,7 +25,7 @@
|
|||
"gl": "^4.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"inversify": "^5.0.1",
|
||||
"lodash": "^4.17.15",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-scene",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -22,11 +22,11 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-component": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-maps": "^2.0.22",
|
||||
"@antv/l7-renderer": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-component": "^2.0.23-alpha.0",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-maps": "^2.0.23-alpha.0",
|
||||
"@antv/l7-renderer": "^2.0.23-alpha.0",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"inversify": "^5.0.1",
|
||||
"mapbox-gl": "^1.2.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-source",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,8 +24,8 @@
|
|||
"author": "lzxue",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@antv/l7-core": "^2.0.22",
|
||||
"@antv/l7-utils": "^2.0.22",
|
||||
"@antv/l7-core": "^2.0.23-alpha.0",
|
||||
"@antv/l7-utils": "^2.0.23-alpha.0",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@mapbox/geojson-rewind": "^0.4.0",
|
||||
"@turf/helpers": "^6.1.4",
|
||||
|
|
|
@ -3,7 +3,10 @@ import Supercluster from 'supercluster';
|
|||
export function cluster(data: IParserData, option: ITransform): IParserData {
|
||||
const { radius = 80, maxZoom = 18, minZoom = 0, field, zoom = 2 } = option;
|
||||
if (data.pointIndex) {
|
||||
const clusterData = data.pointIndex.getClusters(data.extent, zoom);
|
||||
const clusterData = data.pointIndex.getClusters(
|
||||
data.extent,
|
||||
Math.floor(zoom),
|
||||
);
|
||||
data.dataArray = formatData(clusterData);
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@antv/l7-utils",
|
||||
"version": "2.0.22",
|
||||
"version": "2.0.23-alpha.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
|
|
@ -62,7 +62,7 @@ export default class ScaleComponent extends React.Component {
|
|||
})
|
||||
.size('point_count', [5, 10, 15, 20, 25])
|
||||
.animate(false)
|
||||
.select(true)
|
||||
.active(true)
|
||||
.color('yellow')
|
||||
.style({
|
||||
opacity: 0.5,
|
||||
|
|
|
@ -14,6 +14,7 @@ import LineLayer from './components/Line';
|
|||
import PointDemo from './components/Point';
|
||||
import Point3D from './components/Point3D';
|
||||
import PointImage from './components/PointImage';
|
||||
import PolygonDemo from './components/polygon';
|
||||
import Polygon3D from './components/Polygon3D';
|
||||
import ImageLayerDemo from './components/RasterImage';
|
||||
import RasterLayerDemo from './components/RasterLayer';
|
||||
|
@ -30,6 +31,7 @@ storiesOf('图层', module)
|
|||
.add('Column', () => <Column />)
|
||||
.add('图片标注', () => <PointImage />)
|
||||
.add('面3d图层', () => <Polygon3D />)
|
||||
.add('面图层', () => <PolygonDemo />)
|
||||
.add('点亮城市', () => <CityBuildingLayerDemo />)
|
||||
.add('线图层', () => <LineLayer />)
|
||||
.add('虚线', () => <DashLineDemo />)
|
||||
|
|
|
@ -19,40 +19,50 @@ export default class Point3D extends React.Component {
|
|||
|
||||
const scene = new Scene({
|
||||
id: document.getElementById('map') as HTMLDivElement,
|
||||
map: new Mapbox({
|
||||
map: new GaodeMap({
|
||||
center: [120.19382669582967, 30.258134],
|
||||
pitch: 0,
|
||||
style: 'dark',
|
||||
zoom: 0,
|
||||
}),
|
||||
});
|
||||
// scene.on('loaded', () => {
|
||||
const pointLayer = new PointLayer({})
|
||||
.source(pointsData, {
|
||||
cluster: false,
|
||||
})
|
||||
.shape('circle')
|
||||
// .scale('point_count', {
|
||||
// type: 'quantile',
|
||||
// })
|
||||
.size('mag', [5, 10, 15, 20, 25])
|
||||
.animate(false)
|
||||
.active(true)
|
||||
.color('yellow')
|
||||
.style({
|
||||
opacity: 0.5,
|
||||
strokeWidth: 1,
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
scene.on('loaded', () => {
|
||||
const newData = {
|
||||
type: 'FeatureCollection',
|
||||
features: pointsData.features.slice(0, 100),
|
||||
};
|
||||
pointLayer.setData(newData);
|
||||
const pointLayer = new PointLayer({})
|
||||
.source(pointsData, {
|
||||
cluster: false,
|
||||
})
|
||||
.scale({
|
||||
size: {
|
||||
type: 'power',
|
||||
field: 'mag',
|
||||
},
|
||||
color: {
|
||||
type: 'linear',
|
||||
field: 'mag',
|
||||
},
|
||||
})
|
||||
.shape('circle')
|
||||
.size('mag', [2, 8, 14, 20, 26, 32, 40])
|
||||
.animate(false)
|
||||
.active(true)
|
||||
.color('mag', ['red', 'blue', 'yellow', 'green'])
|
||||
.style({
|
||||
opacity: 0.5,
|
||||
strokeWidth: 1,
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
const items = pointLayer.getLegendItems('color');
|
||||
console.log(items);
|
||||
console.log(pointLayer.getLegendItems('size'));
|
||||
// scene.on('loaded', () => {
|
||||
// const newData = {
|
||||
// type: 'FeatureCollection',
|
||||
// features: pointsData.features.slice(0, 100),
|
||||
// };
|
||||
// pointLayer.setData(newData);
|
||||
// });
|
||||
this.scene = scene;
|
||||
});
|
||||
this.scene = scene;
|
||||
// });
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
|
@ -35,22 +35,24 @@ export default class PointImage extends React.Component {
|
|||
'02',
|
||||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*o16fSIvcKdUAAAAAAAAAAABkARQnAQ',
|
||||
);
|
||||
|
||||
const imageLayer = new PointLayer({})
|
||||
.source(await response.json(), {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'longitude',
|
||||
y: 'latitude',
|
||||
},
|
||||
})
|
||||
.shape('name', ['00', '01', '02'])
|
||||
.active(true)
|
||||
.size(30);
|
||||
scene.addLayer(imageLayer);
|
||||
imageLayer.on('click', (e) => {
|
||||
console.log(e);
|
||||
});
|
||||
let i = 0;
|
||||
const data = await response.json();
|
||||
while (i < 50) {
|
||||
const imageLayer = new PointLayer()
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'longitude',
|
||||
y: 'latitude',
|
||||
},
|
||||
})
|
||||
.shape('triangle')
|
||||
.color('red')
|
||||
.active(true)
|
||||
.size(20);
|
||||
scene.addLayer(imageLayer);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
|
@ -39,7 +39,7 @@ export default class TextLayerDemo extends React.Component {
|
|||
y: 'w',
|
||||
},
|
||||
})
|
||||
.shape('m', 'text')
|
||||
.shape('w', 'text')
|
||||
// .shape('circle')
|
||||
.size(12)
|
||||
.filter('t', (t) => {
|
||||
|
@ -63,7 +63,7 @@ export default class TextLayerDemo extends React.Component {
|
|||
const gui = new dat.GUI();
|
||||
this.gui = gui;
|
||||
const styleOptions = {
|
||||
textAnchor: 'center',
|
||||
field: 'w',
|
||||
strokeWidth: 1,
|
||||
textAllowOverlap: false,
|
||||
opacity: 1,
|
||||
|
@ -71,21 +71,10 @@ export default class TextLayerDemo extends React.Component {
|
|||
};
|
||||
const rasterFolder = gui.addFolder('文本可视化');
|
||||
rasterFolder
|
||||
.add(styleOptions, 'textAnchor', [
|
||||
'center',
|
||||
'left',
|
||||
'right',
|
||||
'top',
|
||||
'bottom',
|
||||
'top-left',
|
||||
'bottom-right',
|
||||
'bottom-left',
|
||||
'top-right',
|
||||
])
|
||||
.add(styleOptions, 'field', ['w', 's', 'l', 'm', 'j', 'h'])
|
||||
.onChange((anchor: string) => {
|
||||
pointLayer.style({
|
||||
textAnchor: anchor,
|
||||
});
|
||||
console.log(anchor);
|
||||
pointLayer.shape(anchor, 'text');
|
||||
scene.render();
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
import { PolygonLayer, Scene } from '@antv/l7';
|
||||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||
import * as dat from 'dat.gui';
|
||||
import * as React from 'react';
|
||||
// @ts-ignore
|
||||
const Spectral: {
|
||||
[key: string]: string[];
|
||||
} = {
|
||||
3: ['rgb(252,141,89)', 'rgb(255,255,191)', 'rgb(153,213,148)'],
|
||||
4: [
|
||||
'rgb(215,25,28)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(43,131,186)',
|
||||
],
|
||||
5: [
|
||||
'rgb(215,25,28)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(255,255,191)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(43,131,186)',
|
||||
],
|
||||
6: [
|
||||
'rgb(213,62,79)',
|
||||
'rgb(252,141,89)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(153,213,148)',
|
||||
'rgb(50,136,189)',
|
||||
],
|
||||
7: [
|
||||
'rgb(213,62,79)',
|
||||
'rgb(252,141,89)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(255,255,191)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(153,213,148)',
|
||||
'rgb(50,136,189)',
|
||||
],
|
||||
8: [
|
||||
'rgb(213,62,79)',
|
||||
'rgb(244,109,67)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(102,194,165)',
|
||||
'rgb(50,136,189)',
|
||||
],
|
||||
9: [
|
||||
'rgb(213,62,79)',
|
||||
'rgb(244,109,67)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(255,255,191)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(102,194,165)',
|
||||
'rgb(50,136,189)',
|
||||
],
|
||||
10: [
|
||||
'rgb(158,1,66)',
|
||||
'rgb(213,62,79)',
|
||||
'rgb(244,109,67)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(102,194,165)',
|
||||
'rgb(50,136,189)',
|
||||
'rgb(94,79,162)',
|
||||
],
|
||||
11: [
|
||||
'rgb(158,1,66)',
|
||||
'rgb(213,62,79)',
|
||||
'rgb(244,109,67)',
|
||||
'rgb(253,174,97)',
|
||||
'rgb(254,224,139)',
|
||||
'rgb(255,255,191)',
|
||||
'rgb(230,245,152)',
|
||||
'rgb(171,221,164)',
|
||||
'rgb(102,194,165)',
|
||||
'rgb(50,136,189)',
|
||||
'rgb(94,79,162)',
|
||||
],
|
||||
};
|
||||
export default class TextLayerDemo extends React.Component {
|
||||
// @ts-ignore
|
||||
private scene: Scene;
|
||||
private gui: dat.GUI;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
if (this.gui) {
|
||||
this.gui.destroy();
|
||||
}
|
||||
}
|
||||
public async componentDidMount() {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new Mapbox({
|
||||
center: [120.19382669582967, 30.258134],
|
||||
pitch: 0,
|
||||
style: 'dark',
|
||||
zoom: 3,
|
||||
}),
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
const layer = new PolygonLayer({})
|
||||
.source(data)
|
||||
.shape('fill')
|
||||
.color('childrenNum', [
|
||||
'rgb(247,252,240)',
|
||||
'rgb(224,243,219)',
|
||||
'rgb(204,235,197)',
|
||||
'rgb(168,221,181)',
|
||||
'rgb(123,204,196)',
|
||||
'rgb(78,179,211)',
|
||||
'rgb(43,140,190)',
|
||||
'rgb(8,88,158)',
|
||||
])
|
||||
.style({
|
||||
opacity: 1.0,
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
this.scene = scene;
|
||||
|
||||
const gui = new dat.GUI();
|
||||
this.gui = gui;
|
||||
const styleOptions = {
|
||||
textAnchor: 'center',
|
||||
filter: 1,
|
||||
textAllowOverlap: 4,
|
||||
opacity: 1,
|
||||
color: '#ffffff',
|
||||
};
|
||||
const rasterFolder = gui.addFolder('面图层可视化');
|
||||
|
||||
rasterFolder
|
||||
.add(styleOptions, 'filter', 0, 50)
|
||||
.onChange((strokeWidth: number) => {
|
||||
layer.filter('childrenNum', (t: number) => {
|
||||
return t > strokeWidth;
|
||||
});
|
||||
scene.render();
|
||||
});
|
||||
rasterFolder
|
||||
.add(styleOptions, 'textAllowOverlap', 3, 10, 1)
|
||||
.onChange((v: string) => {
|
||||
layer.color('childrenNum', Spectral[v]);
|
||||
scene.render();
|
||||
});
|
||||
rasterFolder
|
||||
.add(styleOptions, 'opacity', 0, 1)
|
||||
.onChange((opacity: number) => {
|
||||
layer.style({
|
||||
opacity,
|
||||
});
|
||||
scene.render();
|
||||
setTimeout(() => {
|
||||
scene.render();
|
||||
}, 10);
|
||||
});
|
||||
rasterFolder.addColor(styleOptions, 'color').onChange((color: string) => {
|
||||
layer.color(color);
|
||||
scene.render();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||
import { LineLayer, Scene } from '@antv/l7-react';
|
||||
import { LineLayer, MapScene } from '@antv/l7-react';
|
||||
import * as React from 'react';
|
||||
|
||||
export default React.memo(function Map() {
|
||||
|
@ -23,7 +23,7 @@ export default React.memo(function Map() {
|
|||
}, []);
|
||||
return (
|
||||
<>
|
||||
<Scene
|
||||
<MapScene
|
||||
map={amap}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
|
@ -53,7 +53,7 @@ export default React.memo(function Map() {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
</Scene>
|
||||
</MapScene>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -22411,8 +22411,8 @@ table@^5.0.0, table@^5.2.3:
|
|||
|
||||
tapable@^1.0.0, tapable@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npm.taobao.org/tapable/download/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
integrity sha1-ofzMBrWNth/XpF2i2kT186Pme6I=
|
||||
resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||
|
||||
tapable@^2.0.0-beta.8:
|
||||
version "2.0.0-beta.9"
|
||||
|
|
Loading…
Reference in New Issue