feat: add popup add marker

This commit is contained in:
thinkinggis 2020-03-05 22:40:41 +08:00
parent cd44449cb6
commit 0679435c14
24 changed files with 537 additions and 319 deletions

View File

@ -0,0 +1,4 @@
---
title: Get Started
order: 0
---

View File

@ -0,0 +1,71 @@
---
title: 快速开始
order: 0
---
### 安装
```bash
npm i @antv/l7-react
```
### 示例
```javascript
import { LineLayer, AMapScene } from '@antv/l7-react';
export default React.memo(function Map() {
const [data, setData] = React.useState();
React.useEffect(() => {
const fetchData = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/32e1f3ab-8588-46cb-8a47-75afb692117d.json',
);
const raw = await response.json();
setData(raw);
};
fetchData();
}, []);
return (
<>
<AMapScene
map={{
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',
zoom: 1,
}}
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
>
{data && (
<LineLayer
key={'2'}
source={{
data,
}}
size={{
values: 1,
}}
color={{
values: '#fff',
}}
shape={{
values: 'line',
}}
style={{
opacity: 1,
}}
/>
)}
</AMapScene>
</>
);
});
```

View File

@ -1,4 +1,11 @@
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
import {
ILngLat,
IMapService,
IMarkerOption,
IPoint,
IPopup,
TYPES,
} from '@antv/l7-core';
import {
anchorTranslate,
anchorType,
@ -10,15 +17,6 @@ import { EventEmitter } from 'eventemitter3';
import { Container } from 'inversify';
// marker 支持 dragger 未完成
export interface IMarkerOption {
element: HTMLElement | undefined;
anchor: anchorType;
color: string;
offsets: number[];
draggable: boolean;
extData?: any;
}
export default class Marker extends EventEmitter {
private markerOption: IMarkerOption;
private defaultMarker: boolean;

View File

@ -76,7 +76,7 @@ export default class Popup extends EventEmitter implements IPopup {
return this.setDOMContent(frag);
}
public setLnglat(lngLat: ILngLat): this {
public setLnglat(lngLat: ILngLat | number[]): this {
this.lngLat = lngLat as ILngLat;
if (Array.isArray(lngLat)) {
this.lngLat = {

View File

@ -1,3 +1,4 @@
import { anchorType } from '@antv/l7-utils';
import { Container, injectable } from 'inversify';
import { ILngLat, IMapService, IPoint } from '../map/IMapService';
import { IPopup } from './IPopupService';
@ -9,6 +10,14 @@ export interface IMarkerScene {
export interface IMarkerServiceCfg {
container: HTMLElement;
}
export interface IMarkerOption {
element: HTMLElement | undefined;
anchor: anchorType;
color: string;
offsets: number[];
draggable: boolean;
extData?: any;
}
export interface IMarker {
addTo(scene: Container): void;
remove(): void;

View File

@ -1,4 +1,4 @@
import Ajv from 'ajv';
// import Ajv from 'ajv';
import { injectable, postConstruct } from 'inversify';
import { merge } from 'lodash';
import { ILayerConfig } from '../layer/ILayerService';
@ -78,10 +78,10 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
};
// @see https://github.com/epoberezkin/ajv#options
const ajv = new Ajv({
allErrors: true,
verbose: true,
});
// const ajv = new Ajv({
// allErrors: true,
// verbose: true,
// });
@injectable()
export default class GlobalConfigService implements IGlobalConfigService {
@ -95,12 +95,12 @@ export default class GlobalConfigService implements IGlobalConfigService {
/**
*
*/
private sceneConfigValidator: Ajv.ValidateFunction;
// private sceneConfigValidator: Ajv.ValidateFunction;
/**
*
*/
private mapConfigValidator: Ajv.ValidateFunction;
// private mapConfigValidator: Ajv.ValidateFunction;
/**
*
@ -112,9 +112,9 @@ export default class GlobalConfigService implements IGlobalConfigService {
/**
* Layer
*/
private layerConfigValidatorCache: {
[layerName: string]: Ajv.ValidateFunction;
} = {};
// private layerConfigValidatorCache: {
// [layerName: string]: Ajv.ValidateFunction;
// } = {};
public getSceneConfig(sceneId: string) {
return this.sceneConfigCache[sceneId];
@ -131,13 +131,13 @@ export default class GlobalConfigService implements IGlobalConfigService {
};
}
public validateSceneConfig(data: object) {
return this.validate(this.sceneConfigValidator, data);
}
// public validateSceneConfig(data: object) {
// return this.validate(this.sceneConfigValidator, data);
// }
public validateMapConfig(data: object) {
return this.validate(this.mapConfigValidator, data);
}
// public validateMapConfig(data: object) {
// return this.validate(this.mapConfigValidator, data);
// }
public getLayerConfig<IChildLayerConfig>(
layerId: string,
@ -157,45 +157,45 @@ export default class GlobalConfigService implements IGlobalConfigService {
};
}
public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
if (!this.layerConfigValidatorCache[layerName]) {
this.layerConfigValidatorCache[layerName] = ajv.compile(schema);
}
}
// public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
// if (!this.layerConfigValidatorCache[layerName]) {
// this.layerConfigValidatorCache[layerName] = ajv.compile(schema);
// }
// }
public validateLayerConfig(layerName: string, data: object) {
return this.validate(this.layerConfigValidatorCache[layerName], data);
}
// public validateLayerConfig(layerName: string, data: object) {
// return this.validate(this.layerConfigValidatorCache[layerName], data);
// }
public clean() {
this.sceneConfigCache = {};
this.layerConfigCache = {};
}
@postConstruct()
private registerSceneConfigSchemaValidator() {
this.sceneConfigValidator = ajv.compile(sceneConfigSchema);
this.mapConfigValidator = ajv.compile(mapConfigSchema);
}
// @postConstruct()
// private registerSceneConfigSchemaValidator() {
// this.sceneConfigValidator = ajv.compile(sceneConfigSchema);
// this.mapConfigValidator = ajv.compile(mapConfigSchema);
// }
private validate(
validateFunc: Ajv.ValidateFunction | undefined,
data: object,
) {
if (validateFunc) {
const valid = validateFunc(data);
if (!valid) {
return {
valid,
errors: validateFunc.errors,
errorText: ajv.errorsText(validateFunc.errors),
};
}
}
return {
valid: true,
errors: null,
errorText: null,
};
}
// private validate(
// validateFunc: Ajv.ValidateFunction | undefined,
// data: object,
// ) {
// if (validateFunc) {
// const valid = validateFunc(data);
// if (!valid) {
// return {
// valid,
// errors: validateFunc.errors,
// errorText: ajv.errorsText(validateFunc.errors),
// };
// }
// }
// return {
// valid: true,
// errors: null,
// errorText: null,
// };
// }
}

View File

@ -1,4 +1,4 @@
import Ajv from 'ajv';
// import Ajv from 'ajv';
import { PositionName } from '../component/IControlService';
import { ILayerConfig } from '../layer/ILayerService';
import { IMapWrapper } from '../map/IMapService';
@ -10,11 +10,11 @@ export interface ISceneConfig extends IRenderConfig {
logoVisible?: boolean;
}
interface IValidateResult {
valid: boolean;
errors: Ajv.ErrorObject[] | null | undefined;
errorText: string | null;
}
// interface IValidateResult {
// valid: boolean;
// errors: Ajv.ErrorObject[] | null | undefined;
// errorText: string | null;
// }
export interface IGlobalConfigService {
/**
@ -28,13 +28,13 @@ export interface IGlobalConfigService {
*
* @param data
*/
validateSceneConfig(data: object): IValidateResult;
// validateSceneConfig(data: object): IValidateResult;
/**
*
* @param data
*/
validateMapConfig(data: object): IValidateResult;
// validateMapConfig(data: object): IValidateResult;
/**
*
@ -66,13 +66,13 @@ export interface IGlobalConfigService {
* @param layerName
* @param schema
*/
registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
// registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
/**
*
* @param data
*/
validateLayerConfig(layerName: string, data: object): IValidateResult;
// validateLayerConfig(layerName: string, data: object): IValidateResult;
/**
* Cache

View File

@ -1,144 +1,144 @@
import { Container } from 'inversify';
import 'reflect-metadata';
import { TYPES } from '../../../index';
import GlobalConfigService from '../ConfigService';
import { IGlobalConfigService } from '../IConfigService';
// import { Container } from 'inversify';
// import 'reflect-metadata';
// import { TYPES } from '../../../index';
// import GlobalConfigService from '../ConfigService';
// import { IGlobalConfigService } from '../IConfigService';
describe('ConfigService', () => {
let container: Container;
let configService: IGlobalConfigService;
// describe('ConfigService', () => {
// let container: Container;
// let configService: IGlobalConfigService;
beforeAll(() => {
container = new Container();
container
.bind<IGlobalConfigService>(TYPES.IGlobalConfigService)
.to(GlobalConfigService);
configService = container.get<IGlobalConfigService>(
TYPES.IGlobalConfigService,
);
});
// beforeAll(() => {
// container = new Container();
// container
// .bind<IGlobalConfigService>(TYPES.IGlobalConfigService)
// .to(GlobalConfigService);
// configService = container.get<IGlobalConfigService>(
// TYPES.IGlobalConfigService,
// );
// });
afterAll(() => {
container.unbind(TYPES.IGlobalConfigService);
});
// afterAll(() => {
// container.unbind(TYPES.IGlobalConfigService);
// });
it("should validate scene's options according to JSON schema", () => {
// const { valid, errorText } = configService.validateSceneConfig({
// id: 0,
// });
// expect(valid).toBeFalsy();
// expect(errorText).toMatch('id should be string');
// it("should validate scene's options according to JSON schema", () => {
// // const { valid, errorText } = configService.validateSceneConfig({
// // id: 0,
// // });
// // expect(valid).toBeFalsy();
// // expect(errorText).toMatch('id should be string');
expect(
configService.validateSceneConfig({
id: 'map',
}).valid,
).toBeTruthy();
});
// expect(
// configService.validateSceneConfig({
// id: 'map',
// }).valid,
// ).toBeTruthy();
// });
it("should validate map's `zoom` option", () => {
const { valid, errorText } = configService.validateMapConfig({
zoom: 100,
minZoom: 100,
maxZoom: -2,
});
expect(valid).toBeFalsy();
expect(errorText).toMatch('zoom should be <= 24');
expect(errorText).toMatch('minZoom should be <= 24');
expect(errorText).toMatch('maxZoom should be >= -1');
// it("should validate map's `zoom` option", () => {
// const { valid, errorText } = configService.validateMapConfig({
// zoom: 100,
// minZoom: 100,
// maxZoom: -2,
// });
// expect(valid).toBeFalsy();
// expect(errorText).toMatch('zoom should be <= 24');
// expect(errorText).toMatch('minZoom should be <= 24');
// expect(errorText).toMatch('maxZoom should be >= -1');
expect(
configService.validateMapConfig({
zoom: 10,
minZoom: 1,
maxZoom: 15,
}).valid,
).toBeTruthy();
});
// expect(
// configService.validateMapConfig({
// zoom: 10,
// minZoom: 1,
// maxZoom: 15,
// }).valid,
// ).toBeTruthy();
// });
it("should validate map's `pitch` option", () => {
const { valid, errorText } = configService.validateMapConfig({
pitch: '1',
});
expect(valid).toBeFalsy();
expect(errorText).toMatch('pitch should be number');
// it("should validate map's `pitch` option", () => {
// const { valid, errorText } = configService.validateMapConfig({
// pitch: '1',
// });
// expect(valid).toBeFalsy();
// expect(errorText).toMatch('pitch should be number');
expect(
configService.validateMapConfig({
pitch: 10,
}).valid,
).toBeTruthy();
});
// expect(
// configService.validateMapConfig({
// pitch: 10,
// }).valid,
// ).toBeTruthy();
// });
it("should validate map's `center` option", () => {
const { valid, errorText } = configService.validateMapConfig({
center: [1, 2, 3],
});
expect(valid).toBeFalsy();
expect(errorText).toMatch('center should NOT have more than 2 items');
// it("should validate map's `center` option", () => {
// const { valid, errorText } = configService.validateMapConfig({
// center: [1, 2, 3],
// });
// expect(valid).toBeFalsy();
// expect(errorText).toMatch('center should NOT have more than 2 items');
const { valid: v2, errorText: e2 } = configService.validateMapConfig({
center: [1],
});
expect(v2).toBeFalsy();
expect(e2).toMatch('center should NOT have fewer than 2 items');
// const { valid: v2, errorText: e2 } = configService.validateMapConfig({
// center: [1],
// });
// expect(v2).toBeFalsy();
// expect(e2).toMatch('center should NOT have fewer than 2 items');
const { valid: v3, errorText: e3 } = configService.validateMapConfig({
center: 100,
});
expect(v3).toBeFalsy();
expect(e3).toMatch('center should be array');
// const { valid: v3, errorText: e3 } = configService.validateMapConfig({
// center: 100,
// });
// expect(v3).toBeFalsy();
// expect(e3).toMatch('center should be array');
expect(
configService.validateMapConfig({
center: [100, 100],
}).valid,
).toBeTruthy();
});
// expect(
// configService.validateMapConfig({
// center: [100, 100],
// }).valid,
// ).toBeTruthy();
// });
it("should validate layer's options according to JSON schema", () => {
configService.registerLayerConfigSchemaValidator('testLayer', {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
enablePicking: {
type: 'boolean',
},
},
});
// 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');
// 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', {
// opacity: 1.5,
// }).valid,
// ).toBeFalsy();
expect(
configService.validateLayerConfig('testLayer', {
enablePicking: 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: 1.0,
// }).valid,
// ).toBeTruthy();
expect(
configService.validateLayerConfig('testLayer', {
opacity: 0.0,
}).valid,
).toBeTruthy();
});
});
// expect(
// configService.validateLayerConfig('testLayer', {
// opacity: 0.0,
// }).valid,
// ).toBeTruthy();
// });
// });

View File

@ -117,13 +117,13 @@ export default class Scene extends EventEmitter implements ISceneService {
this.configService.setSceneConfig(this.id, sceneConfig);
// 校验场景配置项,失败则终止初始化过程
const { valid, errorText } = this.configService.validateSceneConfig(
this.configService.getSceneConfig(this.id),
);
if (!valid) {
this.logger.error(errorText || '');
return;
}
// const { valid, errorText } = this.configService.validateSceneConfig(
// this.configService.getSceneConfig(this.id),
// );
// if (!valid) {
// this.logger.error(errorText || '');
// return;
// }
// 初始化 ShaderModule
this.shaderModuleService.registerBuiltinModules();

View File

@ -9,7 +9,7 @@ import PointLayer from './point';
import PolygonLayer from './polygon';
import RasterLayer from './raster';
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
// import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
import DataMappingPlugin from './plugins/DataMappingPlugin';
import DataSourcePlugin from './plugins/DataSourcePlugin';
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
@ -27,10 +27,10 @@ import UpdateStyleAttributePlugin from './plugins/UpdateStyleAttributePlugin';
*
* @see /dev-docs/ConfigSchemaValidation.md
*/
container
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
.to(ConfigSchemaValidationPlugin)
.inRequestScope();
// container
// .bind<ILayerPlugin>(TYPES.ILayerPlugin)
// .to(ConfigSchemaValidationPlugin)
// .inRequestScope();
/**
* Source
*/

View File

@ -1,43 +1,43 @@
import {
IGlobalConfigService,
ILayer,
ILayerPlugin,
ILogService,
TYPES,
} from '@antv/l7-core';
import { inject, injectable } from 'inversify';
// import {
// IGlobalConfigService,
// ILayer,
// ILayerPlugin,
// ILogService,
// TYPES,
// } from '@antv/l7-core';
// import { inject, injectable } from 'inversify';
/**
* Layer
*/
@injectable()
export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
@inject(TYPES.IGlobalConfigService)
private readonly configService: IGlobalConfigService;
// /**
// * Layer 初始化阶段以及重绘阶段首先校验传入参数,如果校验失败则中断后续插件处理。
// */
// @injectable()
// export default class ConfigSchemaValidationPlugin implements ILayerPlugin {
// @inject(TYPES.IGlobalConfigService)
// private readonly configService: IGlobalConfigService;
@inject(TYPES.ILogService)
private readonly logger: ILogService;
// @inject(TYPES.ILogService)
// private readonly logger: ILogService;
public apply(layer: ILayer) {
layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
this.configService.registerLayerConfigSchemaValidator(
layer.name as string,
layer.getConfigSchemaForValidation(),
);
// public apply(layer: ILayer) {
// layer.hooks.init.tap('ConfigSchemaValidationPlugin', () => {
// this.configService.registerLayerConfigSchemaValidator(
// layer.name as string,
// layer.getConfigSchemaForValidation(),
// );
const { valid, errorText } = this.configService.validateLayerConfig(
layer.name as string,
layer.getLayerConfig(),
);
// const { valid, errorText } = this.configService.validateLayerConfig(
// layer.name as string,
// layer.getLayerConfig(),
// );
if (!valid) {
this.logger.error(errorText || '');
// 中断 init 过程
return false;
}
});
layer.hooks.beforeRender.tap('ConfigSchemaValidationPlugin', () => {
// TODO: 配置项发生变化,需要重新校验
});
}
}
// if (!valid) {
// this.logger.error(errorText || '');
// // 中断 init 过程
// return false;
// }
// });
// layer.hooks.beforeRender.tap('ConfigSchemaValidationPlugin', () => {
// // TODO: 配置项发生变化,需要重新校验
// });
// }
// }

View File

@ -23,14 +23,14 @@ export default class BaseMapWrapper<RawMap> implements IMapWrapper {
public setContainer(sceneContainer: Container, id: string | HTMLDivElement) {
// // 首先使用全局配置服务校验地图参数
const { valid, errorText } = this.configService.validateMapConfig(
this.config,
);
// const { valid, errorText } = this.configService.validateMapConfig(
// this.config,
// );
if (!valid) {
this.logger.error(errorText || '');
return;
}
// if (!valid) {
// this.logger.error(errorText || '');
// return;
// }
// 绑定用户传入的原始地图参数
sceneContainer.bind<Partial<IMapConfig>>(TYPES.MapConfig).toConstantValue({
...this.config,

View File

@ -9,7 +9,7 @@ interface IMapSceneConig {
className?: string;
map: Partial<IMapConfig>;
option?: Partial<ISceneConfig>;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
children?: React.ReactNode;
onSceneLoaded?: (scene: Scene) => void;
}
const AMapScene = React.memo((props: IMapSceneConig) => {

View File

@ -18,4 +18,16 @@ const PointLayer = React.memo(function Layer(
return BaseLayer('pointLayer', props);
});
export { PolygonLayer, LineLayer, PointLayer };
const HeatMapLayer = React.memo(function Layer(
props: ILayerProps & { children?: any },
) {
return BaseLayer('heatmapLayer', props);
});
const RasterLayer = React.memo(function Layer(
props: ILayerProps & { children?: any },
) {
return BaseLayer('rasterLayer', props);
});
export { PolygonLayer, LineLayer, PointLayer, HeatMapLayer, RasterLayer };

View File

@ -1,4 +1,12 @@
import { ILayer, LineLayer, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import {
HeatmapLayer,
ILayer,
LineLayer,
PointLayer,
PolygonLayer,
RasterLayer,
Scene,
} from '@antv/l7';
import * as React from 'react';
import { LayerContext } from '../LayerContext';
import { useSceneValue } from '../SceneContext';
@ -27,6 +35,7 @@ export default function BaseLayer(type: string, props: ILayerProps) {
active,
filter,
options,
onLayerLoad,
} = props;
const mapScene = (useSceneValue() as unknown) as Scene;
const [layer, setLayer] = useState<ILayer>();
@ -42,9 +51,20 @@ export default function BaseLayer(type: string, props: ILayerProps) {
case 'pointLayer':
l = new PointLayer(options);
break;
case 'heatmapLayer':
l = new HeatmapLayer(options);
break;
case 'rasterLayer':
l = new RasterLayer(options);
break;
default:
l = new PolygonLayer(options);
}
l.on('inited', () => {
if (onLayerLoad) {
onLayerLoad(l, mapScene);
}
});
setLayer(l);
}

View File

@ -1,10 +1,13 @@
import {
BlendType,
IActiveOption,
ILayer,
IScale,
IScaleOptions,
ISourceCFG,
Scene,
} from '@antv/l7';
import * as React from 'react';
import Active from './Active';
import Color from './Color';
import Filter from './Filter';
@ -69,7 +72,8 @@ export interface ILayerProps {
style?: Partial<IStyleOptions>;
active?: IActiveOptions;
filter?: Partial<IAttributeOptions>;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
onLayerLoad?: (layer: ILayer, scene: Scene) => void;
children?: React.ReactNode;
}
export { Active, Color, Filter, Source, Size, Shape, Style, Scale };

View File

@ -9,7 +9,7 @@ interface IMapSceneConig {
className?: string;
map: Partial<IMapConfig>;
option?: Partial<ISceneConfig>;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
children?: React.ReactNode;
onSceneLoaded?: (scene: Scene) => void;
}
const MapboxScene = React.memo((props: IMapSceneConig) => {

View File

@ -0,0 +1,73 @@
import {
IActiveOption,
IImage,
ILayer,
ILngLat,
IMarker,
IMarkerOption,
IPoint,
Marker,
Popup,
Scene,
} from '@antv/l7';
import * as React from 'react';
import { createPortal } from 'react-dom';
import { SceneContext } from './SceneContext';
interface IMarkerProps {
option?: IMarkerOption;
lnglat: ILngLat | number[];
onMarkerLoad?: (marker: IMarker) => void;
children?: React.ReactNode;
}
export default class MarkerComponet extends React.PureComponent<IMarkerProps> {
private el: HTMLDivElement;
private scene: Scene;
private marker: IMarker;
constructor(props: IMarkerProps) {
super(props);
this.el = document.createElement('div');
}
public componentDidMount() {
const { lnglat, children, option, onMarkerLoad } = this.props;
const marker = new Marker(option);
if (lnglat) {
marker.setLnglat(lnglat as ILngLat | IPoint);
}
if (children) {
marker.setElement(this.el);
}
this.marker = marker;
if (onMarkerLoad) {
onMarkerLoad(marker);
}
this.scene.addMarker(marker);
}
public componentDidUpdate(prevProps: IMarkerProps) {
const positionChanged =
prevProps?.lnglat.toString() !== this.props?.lnglat.toString();
if (positionChanged) {
this.marker.setLnglat(this.props.lnglat as ILngLat | IPoint);
}
}
public componentWillUnmount() {
if (this.marker) {
this.marker.remove();
}
}
public render() {
return React.createElement(
SceneContext.Consumer,
// @ts-ignore
{},
(scene: Scene) => {
if (scene) {
this.scene = scene;
}
return createPortal(this.props.children, this.el);
},
);
}
}

View File

@ -9,36 +9,59 @@ import {
} from '@antv/l7';
import * as React from 'react';
import { createPortal } from 'react-dom';
import { useSceneValue } from './SceneContext';
const { useEffect } = React;
import { SceneContext } from './SceneContext';
interface IPopupProps {
option: IPopupOption;
lnglat: ILngLat;
text: string;
html: string;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
option?: IPopupOption;
lnglat: number[];
children?: React.ReactNode;
}
export default React.memo(function LoadImage(props: IPopupProps) {
const mapScene = (useSceneValue() as unknown) as Scene;
const { lnglat, html, text, children } = props;
const [popup, setPopup] = React.useState<Popup>();
const el = document.createElement('div');
useEffect(() => {
const p = new Popup(props.option);
export default class PopupComponet extends React.PureComponent<IPopupProps> {
private el: HTMLDivElement;
private scene: Scene;
private popup: Popup;
constructor(props: IPopupProps) {
super(props);
this.el = document.createElement('div');
}
public componentDidMount() {
const { lnglat, children, option } = this.props;
const p = new Popup(option);
if (lnglat) {
p.setLnglat(lnglat);
}
if (html) {
p.setHTML(html);
}
if (text) {
p.setText(text);
}
if (children) {
p.setDOMContent(el);
p.setDOMContent(this.el);
}
setPopup(p);
}, []);
return createPortal(children, el);
});
this.popup = p;
this.scene.addPopup(p);
}
public componentDidUpdate(prevProps: IPopupProps) {
const positionChanged =
prevProps?.lnglat.toString() !== this.props?.lnglat.toString();
if (positionChanged) {
this.popup.setLnglat(this.props.lnglat);
}
}
public componentWillUnmount() {
this.popup.remove();
}
public render() {
return React.createElement(
SceneContext.Consumer,
// @ts-ignore
{},
(scene: Scene) => {
if (scene) {
this.scene = scene;
}
return createPortal(this.props.children, this.el);
},
);
}
}

View File

@ -5,7 +5,7 @@ interface IMapSceneConig {
style?: Partial<React.CSSProperties>;
className?: string;
map: IMapWrapper;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
children?: React.ReactNode;
}
export default React.memo((props: IMapSceneConig) => {
const { style, className, map } = props;

View File

@ -10,3 +10,5 @@ export { LayerEvent } from './component/LayerEvent';
export { useSceneValue, SceneContext } from './component/SceneContext';
export { useLayerValue, LayerContext } from './component/LayerContext';
export { ColorComponent } from './component/Legend/color';
export { default as Popup } from './component/Popup';
export { default as Marker } from './component/Marker';

View File

@ -31,7 +31,7 @@ export default class World extends React.Component {
id: 'map',
logoVisible: false,
map: new Mapbox({
style: 'dark',
style: 'light',
center: [110.19382669582967, 30.258134],
pitch: 0,
zoom: 0,
@ -55,7 +55,7 @@ export default class World extends React.Component {
.shape('fill')
.select(true)
.style({
opacity: 1.0,
opacity: 0.8,
});
scene.addLayer(layer);

View File

@ -1,30 +1,27 @@
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import { LineLayer, Scene } from '@antv/l7-react';
import { AMapScene, LineLayer, Marker, Popup } from '@antv/l7-react';
import * as React from 'react';
export default React.memo(function Map() {
// @ts-ignore
const amap = new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',
zoom: 3,
});
const [data, setData] = React.useState();
React.useEffect(() => {
const fetchData = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/32e1f3ab-8588-46cb-8a47-75afb692117d.json',
);
const data = await response.json();
setData(data);
const raw = await response.json();
setData(raw);
};
fetchData();
}, []);
return (
<>
<Scene
map={amap}
<AMapScene
map={{
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',
zoom: 1,
}}
style={{
position: 'absolute',
top: 0,
@ -33,27 +30,32 @@ export default React.memo(function Map() {
bottom: 0,
}}
>
{data && (
<LineLayer
key={'2'}
source={{
data,
}}
size={{
values: 1,
}}
color={{
values: '#fff',
}}
shape={{
values: 'line',
}}
style={{
opacity: 1,
}}
/>
<Popup lnglat={[110.1938, 50.25] as number[]}>
<p>122222</p>
</Popup>
<Marker lnglat={[110.1938, 30.25] as number[]}>
<p>122222</p>
</Marker>
<LineLayer
key={'2'}
source={{
data,
}}
size={{
values: 1,
}}
color={{
values: '#fff',
}}
shape={{
values: 'line',
}}
style={{
opacity: 1,
}}
/>
)}
</Scene>
</AMapScene>
</>
);
});