Merge pull request #216 from antvis/react

React
This commit is contained in:
@thinkinggis 2020-02-20 00:31:49 +08:00 committed by GitHub
commit a44551f284
62 changed files with 1090 additions and 246 deletions

View File

@ -14,7 +14,7 @@
"message": "chore: publish"
}
},
"version": "2.0.22",
"version": "2.0.23-alpha.0",
"npmClient": "yarn",
"useWorkspaces": true,
"publishConfig": {

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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)

View File

@ -55,7 +55,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
zIndex: 0,
blend: 'normal',
pickedFeatureID: -1,
enableMultiPassRenderer: true,
enableMultiPassRenderer: false,
enablePicking: true,
active: false,
activeColor: '#2f54eb',

View File

@ -0,0 +1,3 @@
export interface IPickingService {
init(): void;
}

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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<{

View File

@ -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[],

View File

@ -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>) {

View File

@ -60,7 +60,6 @@ export default class PixelPickingPass<
getViewportSize,
} = this.rendererService;
const { width, height } = getViewportSize();
// 创建 picking framebuffer后续实时 resize
this.pickingFBO = createFramebuffer({
color: createTexture2D({

View File

@ -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',
];

View File

@ -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`);
});

View File

@ -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'),

View File

@ -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",

View File

@ -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",

View File

@ -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.');
}

View File

@ -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',

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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]];
},

View File

@ -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));

View File

@ -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];

View File

@ -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({

View File

@ -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",

View File

@ -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');
}
}
}

View File

@ -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: [],
},
};

View File

@ -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": {

View File

@ -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;

View File

@ -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;
});

View File

@ -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);
}

View File

@ -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;
});

View File

@ -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} />

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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 };

View File

@ -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>
);
});

View File

@ -0,0 +1,3 @@
.color {
color:'red';
}

View File

@ -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;

View File

@ -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}>

View File

@ -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';

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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;
}

View File

@ -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",

View File

@ -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,

View File

@ -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 />)

View File

@ -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() {

View File

@ -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() {

View File

@ -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();
});

View File

View File

@ -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,
}}
/>
);
}
}

View File

@ -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>
</>
);
});

View File

@ -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"