mirror of https://gitee.com/antv-l7/antv-l7
feat(schema-validation): support validation for layer's options
implement with JSON Schema (ajv)
This commit is contained in:
parent
3e22f21a5c
commit
9c5766d0e3
|
@ -0,0 +1,68 @@
|
|||
# ConfigSchemaValidation 设计
|
||||
|
||||
用户在使用 L7 的 Scene/Layer API 时,由于参数配置项众多难免会误传。需要在运行时通过校验提前发现并给出友好的提示。
|
||||
另外由于 L7 允许用户自定义 Layer 与 LayerPlugin,规范化参数配置项也能提升易用性和质量。
|
||||
|
||||
这方面 Webpack 做的很好,使用 [schema-utils](https://github.com/webpack/schema-utils) 基于 JSON Schema 对 Plugin 和 Loader 进行校验。如果传入了错误的配置项,会给出友好的提示:
|
||||
```
|
||||
Invalid configuration object. MyPlugin has been initialised using a configuration object that does not match the API schema.
|
||||
- configuration.optionName should be a integer.
|
||||
```
|
||||
|
||||
和 Webpack 一样,我们也选择 [ajv](https://github.com/epoberezkin/ajv) 作为 JSON Schema 校验器。
|
||||
目前我们只在 Layer 初始阶段进行校验,一旦校验失败会中断后续初始化插件的处理,并在控制台给出校验失败信息。后续需要在属性更新时同样进行校验。
|
||||
|
||||
## Layer 基类配置项 Schema
|
||||
|
||||
目前在基类中我们声明了如下属性及其对应的校验规则:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
properties: {
|
||||
// 开启拾取
|
||||
enablePicking: {
|
||||
type: 'boolean',
|
||||
},
|
||||
// 开启高亮
|
||||
enableHighlight: {
|
||||
type: 'boolean',
|
||||
},
|
||||
// 高亮颜色:例如 [0, 0, 1, 1] 或者 '#ffffff'
|
||||
highlightColor: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
如果传入了错误的配置项则会在控制台给出提示。
|
||||
|
||||
## Layer 子类配置项 Schema
|
||||
|
||||
Layer 子类可以通过重载 `getConfigSchema()` 方法定义自身的特有属性。例如 `PolygonLayer` 需要定义透明度:
|
||||
|
||||
```javascript
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
|
@ -19,18 +19,20 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/tiny-sdf": "^1.1.1",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"@l7/utils": "0.0.1",
|
||||
"@mapbox/tiny-sdf": "^1.1.1",
|
||||
"ajv": "^6.10.2",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"gl-matrix": "^3.1.0",
|
||||
"hammerjs": "^2.0.8",
|
||||
"inversify": "^5.0.1",
|
||||
"inversify-inject-decorators": "^3.1.0",
|
||||
"lodash": "^4.17.15",
|
||||
"mapbox-gl": "^1.2.1",
|
||||
"merge-json-schemas": "^1.0.0",
|
||||
"probe.gl": "^3.1.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"tapable": "^2.0.0-beta.8",
|
||||
"mapbox-gl": "^1.2.1",
|
||||
"viewport-mercator-project": "^6.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import Ajv from 'ajv';
|
||||
import { injectable } from 'inversify';
|
||||
import { IGlobalConfig, IGlobalConfigService } from './IConfigService';
|
||||
|
||||
const defaultGlobalConfig: Partial<IGlobalConfig> = {
|
||||
|
@ -26,10 +27,23 @@ const defaultGlobalConfig: Partial<IGlobalConfig> = {
|
|||
scales: {},
|
||||
};
|
||||
|
||||
// @see https://github.com/epoberezkin/ajv#options
|
||||
const ajv = new Ajv({
|
||||
allErrors: true,
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
@injectable()
|
||||
export default class GlobalConfigService implements IGlobalConfigService {
|
||||
private config: Partial<IGlobalConfig> = defaultGlobalConfig;
|
||||
|
||||
/**
|
||||
* 保存每个 Layer 配置项的校验器
|
||||
*/
|
||||
private layerConfigValidatorCache: {
|
||||
[layerName: string]: Ajv.ValidateFunction;
|
||||
} = {};
|
||||
|
||||
public getConfig() {
|
||||
return this.config;
|
||||
}
|
||||
|
@ -47,4 +61,29 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
public reset() {
|
||||
this.config = defaultGlobalConfig;
|
||||
}
|
||||
|
||||
public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
|
||||
if (!this.layerConfigValidatorCache[layerName]) {
|
||||
this.layerConfigValidatorCache[layerName] = ajv.compile(schema);
|
||||
}
|
||||
}
|
||||
|
||||
public validateLayerConfig(layerName: string, data: object) {
|
||||
const validate = this.layerConfigValidatorCache[layerName];
|
||||
if (validate) {
|
||||
const valid = validate(data);
|
||||
if (!valid) {
|
||||
return {
|
||||
valid,
|
||||
errors: validate.errors,
|
||||
errorText: ajv.errorsText(validate.errors),
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
valid: true,
|
||||
errors: null,
|
||||
errorText: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import Ajv from 'ajv';
|
||||
import { ILayerGlobalConfig } from '../layer/ILayerService';
|
||||
import { IMapConfig } from '../map/IMapService';
|
||||
import { IRenderConfig } from '../renderer/IRendererService';
|
||||
|
@ -8,4 +9,13 @@ export interface IGlobalConfigService {
|
|||
getConfig(): Partial<IGlobalConfig>;
|
||||
setAndCheckConfig(config: Partial<IGlobalConfig>): boolean;
|
||||
reset(): void;
|
||||
registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
|
||||
validateLayerConfig(
|
||||
layerName: string,
|
||||
data: object,
|
||||
): {
|
||||
valid: boolean;
|
||||
errors: Ajv.ErrorObject[] | null | undefined;
|
||||
errorText: string | null;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import 'reflect-metadata';
|
||||
import ConfigService from '../ConfigService';
|
||||
import { IGlobalConfigService } from '../IConfigService';
|
||||
|
||||
describe('ConfigService', () => {
|
||||
let configService: IGlobalConfigService;
|
||||
|
||||
beforeEach(() => {
|
||||
configService = new ConfigService();
|
||||
});
|
||||
|
||||
it("should validate layer's options according to JSON schema", () => {
|
||||
configService.registerLayerConfigSchemaValidator('testLayer', {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
enablePicking: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { valid, errorText } = configService.validateLayerConfig(
|
||||
'testLayer',
|
||||
{ opacity: 'invalid' },
|
||||
);
|
||||
expect(valid).toBeFalsy();
|
||||
expect(errorText).toMatch('opacity should be number');
|
||||
|
||||
expect(
|
||||
configService.validateLayerConfig('testLayer', {
|
||||
opacity: 1.5,
|
||||
}).valid,
|
||||
).toBeFalsy();
|
||||
|
||||
expect(
|
||||
configService.validateLayerConfig('testLayer', {
|
||||
enablePicking: 1.5,
|
||||
}).valid,
|
||||
).toBeFalsy();
|
||||
|
||||
expect(
|
||||
configService.validateLayerConfig('testLayer', {
|
||||
opacity: 1.0,
|
||||
}).valid,
|
||||
).toBeTruthy();
|
||||
|
||||
expect(
|
||||
configService.validateLayerConfig('testLayer', {
|
||||
opacity: 0.0,
|
||||
}).valid,
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
import { AsyncParallelHook, SyncHook } from 'tapable';
|
||||
import { SyncBailHook, SyncHook } from 'tapable';
|
||||
import { IModel } from '../renderer/IModel';
|
||||
import { IMultiPassRenderer } from '../renderer/IMultiPassRenderer';
|
||||
import { ISource, ISourceCFG } from '../source/ISourceService';
|
||||
|
@ -31,19 +31,17 @@ export interface ILayer {
|
|||
name: string; // 代表 Layer 的类型
|
||||
// visible: boolean;
|
||||
// zIndex: number;
|
||||
// type: string;
|
||||
// id: number;
|
||||
plugins: ILayerPlugin[];
|
||||
hooks: {
|
||||
init: SyncHook<unknown>;
|
||||
beforeRender: SyncHook<unknown>;
|
||||
afterRender: SyncHook<unknown>;
|
||||
beforePickingEncode: SyncHook<unknown>;
|
||||
afterPickingEncode: SyncHook<unknown>;
|
||||
beforeHighlight: SyncHook<unknown>;
|
||||
afterHighlight: SyncHook<unknown>;
|
||||
beforeDestroy: SyncHook<unknown>;
|
||||
afterDestroy: SyncHook<unknown>;
|
||||
init: SyncBailHook<void, boolean | void>;
|
||||
beforeRender: SyncBailHook<void, boolean | void>;
|
||||
afterRender: SyncHook<void>;
|
||||
beforePickingEncode: SyncHook<void>;
|
||||
afterPickingEncode: SyncHook<void>;
|
||||
beforeHighlight: SyncHook<[number[]]>;
|
||||
afterHighlight: SyncHook<void>;
|
||||
beforeDestroy: SyncHook<void>;
|
||||
afterDestroy: SyncHook<void>;
|
||||
};
|
||||
models: IModel[];
|
||||
sourceOption: {
|
||||
|
@ -72,6 +70,10 @@ export interface ILayer {
|
|||
setEncodedData(encodedData: IEncodeFeature[]): void;
|
||||
getEncodedData(): IEncodeFeature[];
|
||||
getStyleOptions(): Partial<ILayerInitializationOptions>;
|
||||
/**
|
||||
* JSON Schema 用于校验配置项
|
||||
*/
|
||||
getConfigSchemaForValidation(): object;
|
||||
isDirty(): boolean;
|
||||
/**
|
||||
* 直接调用拾取方法,在非鼠标交互场景中使用
|
||||
|
|
|
@ -35,9 +35,9 @@ export default class LayerService implements ILayerService {
|
|||
// .filter((layer) => layer.isDirty())
|
||||
.forEach((layer) => {
|
||||
// trigger hooks
|
||||
layer.hooks.beforeRender.call(layer);
|
||||
layer.hooks.beforeRender.call();
|
||||
layer.render();
|
||||
layer.hooks.afterRender.call(layer);
|
||||
layer.hooks.afterRender.call();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import {
|
||||
IInteractionService,
|
||||
InteractionEvent,
|
||||
} from '../../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../../layer/ILayerService';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { ILogService } from '../../log/ILogService';
|
||||
import { gl } from '../gl';
|
||||
import { IFramebuffer } from '../IFramebuffer';
|
||||
|
@ -104,9 +104,9 @@ export default class PixelPickingPass implements IPass {
|
|||
const originRenderFlag = this.layer.multiPassRenderer.getRenderFlag();
|
||||
this.layer.multiPassRenderer.setRenderFlag(false);
|
||||
// trigger hooks
|
||||
layer.hooks.beforeRender.call(layer);
|
||||
layer.hooks.beforeRender.call();
|
||||
layer.render();
|
||||
layer.hooks.afterRender.call(layer);
|
||||
layer.hooks.afterRender.call();
|
||||
this.layer.multiPassRenderer.setRenderFlag(originRenderFlag);
|
||||
|
||||
this.alreadyInRendering = false;
|
||||
|
@ -145,8 +145,6 @@ export default class PixelPickingPass implements IPass {
|
|||
framebuffer: this.pickingFBO,
|
||||
});
|
||||
|
||||
this.logger.info('try to picking');
|
||||
|
||||
if (
|
||||
pickedColors[0] !== 0 ||
|
||||
pickedColors[1] !== 0 ||
|
||||
|
@ -213,12 +211,11 @@ export default class PixelPickingPass implements IPass {
|
|||
// TODO: highlight pass 需要 multipass
|
||||
const originRenderFlag = this.layer.multiPassRenderer.getRenderFlag();
|
||||
this.layer.multiPassRenderer.setRenderFlag(false);
|
||||
this.layer.hooks.beforeRender.call(this.layer);
|
||||
// @ts-ignore
|
||||
this.layer.hooks.beforeHighlight.call(this.layer, [r, g, b]);
|
||||
this.layer.hooks.beforeRender.call();
|
||||
this.layer.hooks.beforeHighlight.call([r, g, b]);
|
||||
this.layer.render();
|
||||
this.layer.hooks.afterHighlight.call(this.layer);
|
||||
this.layer.hooks.afterRender.call(this.layer);
|
||||
this.layer.hooks.afterHighlight.call();
|
||||
this.layer.hooks.afterRender.call();
|
||||
this.layer.multiPassRenderer.setRenderFlag(originRenderFlag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
IMapService,
|
||||
IModel,
|
||||
IMultiPassRenderer,
|
||||
InteractionEvent,
|
||||
IRendererService,
|
||||
IShaderModuleService,
|
||||
ISourceCFG,
|
||||
|
@ -24,7 +23,10 @@ import {
|
|||
} from '@l7/core';
|
||||
import Source from '@l7/source';
|
||||
import { isFunction } from 'lodash';
|
||||
import { SyncHook } from 'tapable';
|
||||
// @ts-ignore
|
||||
import mergeJsonSchemas from 'merge-json-schemas';
|
||||
import { SyncBailHook, SyncHook } from 'tapable';
|
||||
import ConfigSchemaValidationPlugin from '../plugins/ConfigSchemaValidationPlugin';
|
||||
import DataMappingPlugin from '../plugins/DataMappingPlugin';
|
||||
import DataSourcePlugin from '../plugins/DataSourcePlugin';
|
||||
import FeatureScalePlugin from '../plugins/FeatureScalePlugin';
|
||||
|
@ -33,6 +35,7 @@ import PixelPickingPlugin from '../plugins/PixelPickingPlugin';
|
|||
import RegisterStyleAttributePlugin from '../plugins/RegisterStyleAttributePlugin';
|
||||
import ShaderUniformPlugin from '../plugins/ShaderUniformPlugin';
|
||||
import UpdateStyleAttributePlugin from '../plugins/UpdateStyleAttributePlugin';
|
||||
import baseLayerSchema from './schema';
|
||||
|
||||
export interface ILayerModelInitializationOptions {
|
||||
moduleName: string;
|
||||
|
@ -64,16 +67,15 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
|
||||
// 生命周期钩子
|
||||
public hooks = {
|
||||
init: new SyncHook(['layer']),
|
||||
beforeRender: new SyncHook(['layer']),
|
||||
afterRender: new SyncHook(['layer']),
|
||||
beforePickingEncode: new SyncHook(['layer']),
|
||||
afterPickingEncode: new SyncHook(['layer']),
|
||||
// @ts-ignore
|
||||
beforeHighlight: new SyncHook(['layer', 'pickedColor']),
|
||||
afterHighlight: new SyncHook(['layer']),
|
||||
beforeDestroy: new SyncHook(['layer']),
|
||||
afterDestroy: new SyncHook(['layer']),
|
||||
init: new SyncBailHook<void, boolean | void>(),
|
||||
beforeRender: new SyncBailHook<void, boolean | void>(),
|
||||
afterRender: new SyncHook<void>(),
|
||||
beforePickingEncode: new SyncHook<void>(),
|
||||
afterPickingEncode: new SyncHook<void>(),
|
||||
beforeHighlight: new SyncHook<[number[]]>(['pickedColor']),
|
||||
afterHighlight: new SyncHook<void>(),
|
||||
beforeDestroy: new SyncHook<void>(),
|
||||
afterDestroy: new SyncHook<void>(),
|
||||
};
|
||||
|
||||
// 待渲染 model 列表
|
||||
|
@ -84,6 +86,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
|
||||
// 插件集
|
||||
public plugins: ILayerPlugin[] = [
|
||||
/**
|
||||
* 校验传入参数配置项的正确性
|
||||
* @see /dev-docs/ConfigSchemaValidation.md
|
||||
*/
|
||||
new ConfigSchemaValidationPlugin(),
|
||||
/**
|
||||
* 获取 Source
|
||||
*/
|
||||
new DataSourcePlugin(),
|
||||
/**
|
||||
* 根据 StyleAttribute 创建 VertexAttribute
|
||||
|
@ -132,6 +142,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
|
||||
private encodedData: IEncodeFeature[];
|
||||
|
||||
private configSchema: object;
|
||||
|
||||
/**
|
||||
* 保存样式属性
|
||||
*/
|
||||
|
@ -174,7 +186,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
}
|
||||
|
||||
public init() {
|
||||
this.hooks.init.call(this);
|
||||
this.hooks.init.call();
|
||||
this.buildModels();
|
||||
return this;
|
||||
}
|
||||
|
@ -244,14 +256,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
}
|
||||
|
||||
public destroy() {
|
||||
this.hooks.beforeDestroy.call(this);
|
||||
this.hooks.beforeDestroy.call();
|
||||
|
||||
// 清除所有属性以及关联的 vao
|
||||
this.styleAttributeService.clearAllAttributes();
|
||||
// 销毁所有 model
|
||||
this.models.forEach((model) => model.destroy());
|
||||
|
||||
this.hooks.afterDestroy.call(this);
|
||||
this.hooks.afterDestroy.call();
|
||||
}
|
||||
|
||||
public isDirty() {
|
||||
|
@ -283,6 +295,18 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
return this.encodedData;
|
||||
}
|
||||
|
||||
public getConfigSchemaForValidation() {
|
||||
if (!this.configSchema) {
|
||||
// 相比 allOf, merge 有一些优势
|
||||
// @see https://github.com/goodeggs/merge-json-schemas
|
||||
this.configSchema = mergeJsonSchemas([
|
||||
baseLayerSchema,
|
||||
this.getConfigSchema(),
|
||||
]);
|
||||
}
|
||||
return this.configSchema;
|
||||
}
|
||||
|
||||
public pick({ x, y }: { x: number; y: number }) {
|
||||
this.interactionService.triggerHover({ x, y });
|
||||
}
|
||||
|
@ -313,6 +337,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
});
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
protected buildModels() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* BaseLayer Schema
|
||||
*/
|
||||
export default {
|
||||
properties: {
|
||||
enablePicking: {
|
||||
type: 'boolean',
|
||||
},
|
||||
enableHighlight: {
|
||||
type: 'boolean',
|
||||
},
|
||||
highlightColor: {
|
||||
oneOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
import {
|
||||
IGlobalConfigService,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
ILogService,
|
||||
lazyInject,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
|
||||
/**
|
||||
* Layer 初始化阶段以及重绘阶段首先校验传入参数,如果校验失败则中断后续插件处理。
|
||||
*/
|
||||
export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
|
||||
@lazyInject(TYPES.IGlobalConfigService)
|
||||
private readonly configService: IGlobalConfigService;
|
||||
|
||||
@lazyInject(TYPES.ILogService)
|
||||
private readonly logger: ILogService;
|
||||
|
||||
public apply(layer: ILayer) {
|
||||
layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
|
||||
this.configService.registerLayerConfigSchemaValidator(
|
||||
layer.name,
|
||||
layer.getConfigSchemaForValidation(),
|
||||
);
|
||||
|
||||
const { valid, errorText } = this.configService.validateLayerConfig(
|
||||
layer.name,
|
||||
layer.getStyleOptions(),
|
||||
);
|
||||
|
||||
if (!valid) {
|
||||
this.logger.error(errorText || '');
|
||||
// 中断 init 过程
|
||||
return false;
|
||||
}
|
||||
});
|
||||
layer.hooks.beforeRender.tap('ConfigSchemaValidationPlugin', () => {
|
||||
// TODO: 配置项发生变化,需要重新校验
|
||||
});
|
||||
}
|
||||
}
|
|
@ -71,8 +71,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
|
||||
layer.hooks.beforeHighlight.tap(
|
||||
'PixelPickingPlugin',
|
||||
// @ts-ignore
|
||||
(l: unknown, pickedColor: unknown) => {
|
||||
(pickedColor: number[]) => {
|
||||
const { highlightColor } = layer.getStyleOptions();
|
||||
const highlightColorInArray =
|
||||
typeof highlightColor === 'string'
|
||||
|
@ -81,7 +80,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
|||
layer.models.forEach((model) =>
|
||||
model.addUniforms({
|
||||
u_PickingStage: PickingStage.HIGHLIGHT,
|
||||
u_PickingColor: pickedColor as number[],
|
||||
u_PickingColor: pickedColor,
|
||||
u_HighlightColor: highlightColorInArray.map((c) => c * 255),
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -23,6 +23,18 @@ export function polygonTriangulation(feature: IEncodeFeature) {
|
|||
export default class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
|
||||
public name: string = 'PolygonLayer';
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
const { opacity } = this.getStyleOptions();
|
||||
this.models.forEach((model) =>
|
||||
|
|
|
@ -85,13 +85,11 @@ export default class AdvancedAPI extends React.Component {
|
|||
.add(styleOptions, 'pickingX', 0, window.innerWidth)
|
||||
.onChange((pickingX: number) => {
|
||||
layer.pick({ x: pickingX, y: styleOptions.pickingY });
|
||||
// scene.render();
|
||||
});
|
||||
pointFolder
|
||||
.add(styleOptions, 'pickingY', 0, window.innerHeight)
|
||||
.onChange((pickingY: number) => {
|
||||
layer.pick({ x: styleOptions.pickingX, y: pickingY });
|
||||
// scene.render();
|
||||
});
|
||||
pointFolder
|
||||
.addColor(styleOptions, 'highlightColor')
|
||||
|
|
31
yarn.lock
31
yarn.lock
|
@ -9618,6 +9618,11 @@ lodash.get@^4.4.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash.isarray@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403"
|
||||
integrity sha1-KspJayjEym1yZxUxNZDALm6jRAM=
|
||||
|
||||
lodash.isequal@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
|
||||
|
@ -9628,6 +9633,16 @@ lodash.ismatch@^4.4.0:
|
|||
resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37"
|
||||
integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=
|
||||
|
||||
lodash.isnil@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isnil/-/lodash.isnil-4.0.0.tgz#49e28cd559013458c814c5479d3c663a21bfaa6c"
|
||||
integrity sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw=
|
||||
|
||||
lodash.isplainobject@^4.0.6:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
|
||||
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
|
||||
|
||||
lodash.map@^4.5.1:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
|
||||
|
@ -9638,6 +9653,11 @@ lodash.memoize@^4.1.2:
|
|||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||
|
||||
lodash.mergewith@^4.6.0:
|
||||
version "4.6.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
||||
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
||||
|
||||
lodash.set@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
|
||||
|
@ -10070,6 +10090,17 @@ merge-descriptors@1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
|
||||
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||
|
||||
merge-json-schemas@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-json-schemas/-/merge-json-schemas-1.0.0.tgz#2d635eaa8401c5fa3d03f30f89349fc7cafee62f"
|
||||
integrity sha1-LWNeqoQBxfo9A/MPiTSfx8r+5i8=
|
||||
dependencies:
|
||||
lodash.isarray "^4.0.0"
|
||||
lodash.isnil "^4.0.0"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
lodash.mergewith "^4.6.0"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
|
||||
|
|
Loading…
Reference in New Issue