improvement: update l7-react

This commit is contained in:
thinkinggis 2020-02-20 14:18:15 +08:00
parent 8900aec8fc
commit cfdb0bae8a
21 changed files with 212 additions and 40 deletions

View File

@ -1,8 +1,14 @@
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core'; import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
import { bindAll, DOM } from '@antv/l7-utils'; import {
anchorTranslate,
anchorType,
applyAnchorClass,
bindAll,
DOM,
} from '@antv/l7-utils';
import { EventEmitter } from 'eventemitter3'; import { EventEmitter } from 'eventemitter3';
import { Container } from 'inversify'; import { Container } from 'inversify';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
// marker 支持 dragger 未完成 // marker 支持 dragger 未完成
export interface IMarkerOption { export interface IMarkerOption {

View File

@ -1,19 +1,23 @@
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core'; import {
import { bindAll, DOM } from '@antv/l7-utils'; ILngLat,
IMapService,
IPoint,
IPopup,
IPopupOption,
TYPES,
} from '@antv/l7-core';
import {
anchorTranslate,
anchorType,
applyAnchorClass,
bindAll,
DOM,
} from '@antv/l7-utils';
import { EventEmitter } from 'eventemitter3'; import { EventEmitter } from 'eventemitter3';
import { Container } from 'inversify'; import { Container } from 'inversify';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
/** colse event */ /** colse event */
export interface IPopupOption {
closeButton: boolean;
closeOnClick: boolean;
maxWidth: string;
anchor: anchorType;
className: string;
offsets: number[];
}
export default class Popup extends EventEmitter implements IPopup { export default class Popup extends EventEmitter implements IPopup {
private popupOption: IPopupOption; private popupOption: IPopupOption;
private mapsService: IMapService<unknown>; private mapsService: IMapService<unknown>;

View File

@ -1,6 +1,15 @@
import { anchorType } from '@antv/l7-utils';
import { Container } from 'inversify'; import { Container } from 'inversify';
import { ILngLat, IMapService } from '../map/IMapService'; import { ILngLat, IMapService } from '../map/IMapService';
export interface IPopupOption {
closeButton: boolean;
closeOnClick: boolean;
maxWidth: string;
anchor: anchorType;
className: string;
offsets: number[];
}
export interface IPopup { export interface IPopup {
addTo(scene: Container): this; addTo(scene: Container): this;
remove(): void; remove(): void;

View File

@ -18,7 +18,7 @@ import { gl } from '../renderer/gl';
import { IFramebuffer } from '../renderer/IFramebuffer'; import { IFramebuffer } from '../renderer/IFramebuffer';
import { IPickingService } from './IPickingService'; import { IPickingService } from './IPickingService';
const PICKSCALE = 10.0; const PICKSCALE = 1.0;
@injectable() @injectable()
export default class PickingService implements IPickingService { export default class PickingService implements IPickingService {
@inject(TYPES.IRendererService) @inject(TYPES.IRendererService)
@ -155,9 +155,9 @@ export default class PickingService implements IPickingService {
} }
let pickedColors: Uint8Array | undefined; let pickedColors: Uint8Array | undefined;
pickedColors = readPixels({ pickedColors = readPixels({
x: Math.round(xInDevicePixel / PICKSCALE), x: Math.floor(xInDevicePixel / PICKSCALE),
// 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴 // 视口坐标系原点在左上,而 WebGL 在左下,需要翻转 Y 轴
y: Math.round((height - (y + 1) * window.devicePixelRatio) / PICKSCALE), y: Math.floor((height - (y + 1) * window.devicePixelRatio) / PICKSCALE),
width: 1, width: 1,
height: 1, height: 1,
data: new Uint8Array(1 * 1 * 4), data: new Uint8Array(1 * 1 * 4),

View File

@ -108,14 +108,14 @@ float project_pixel(float pixel) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1 // P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom)); return pixel * pow(2.0, (19.0 - u_Zoom));
} }
return pixel; return pixel * -1.;
} }
vec2 project_pixel(vec2 pixel) { vec2 project_pixel(vec2 pixel) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 || u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) { if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 || u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1 // P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom)); return pixel * pow(2.0, (19.0 - u_Zoom));
} }
return pixel; return pixel * -1.;
} }
vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatrix, vec4 center) { vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatrix, vec4 center) {

View File

@ -24,7 +24,7 @@ void main() {
// radius(16-bit) // radius(16-bit)
v_radius = a_Size; v_radius = a_Size;
vec2 offset = project_pixel(extrude * (a_Size + u_stroke_width)) * -1.; vec2 offset = project_pixel(extrude * (a_Size + u_stroke_width));
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0)); 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)); gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));

View File

@ -59,6 +59,25 @@ export default function BaseLayer(type: string, props: ILayerProps) {
mapScene.render(); mapScene.render();
} }
}); });
useEffect(() => {
if (layer && layer.inited) {
layer.updateLayerConfig(options);
}
}, [options?.maxZoom, options?.maxZoom, options?.visible, options?.autoFit]);
useEffect(() => {
if (layer && layer.inited && options && options.zIndex) {
layer.setIndex(options.zIndex);
}
}, [options?.zIndex]);
useEffect(() => {
if (layer && layer.inited && options && options.blend) {
layer.setBlend(options.blend);
}
}, [options?.blend]);
return ( return (
<LayerContext.Provider value={layer}> <LayerContext.Provider value={layer}>
<Source layer={layer} source={source} /> <Source layer={layer} source={source} />

View File

@ -1,4 +1,10 @@
import { IActiveOption, IScale, IScaleOptions, ISourceCFG } from '@antv/l7'; import {
BlendType,
IActiveOption,
IScale,
IScaleOptions,
ISourceCFG,
} from '@antv/l7';
import Active from './Active'; import Active from './Active';
import Color from './Color'; import Color from './Color';
import Filter from './Filter'; import Filter from './Filter';
@ -13,8 +19,9 @@ type CallBack = (...args: any[]) => any;
export interface IAttributeOptions { export interface IAttributeOptions {
field: string; field: string;
value: string | number; value: string | number;
values: string[] | number[] | string | number; values: string[] | number[] | string | number | CallBack;
scale?: string; scale?: string;
blend: keyof typeof BlendType;
} }
export interface IScaleAttributeOptions { export interface IScaleAttributeOptions {
@ -22,7 +29,16 @@ export interface IScaleAttributeOptions {
value: IScale; value: IScale;
values: IScaleOptions | IScale; values: IScaleOptions | IScale;
} }
export interface ILayerOption {
name?: string;
visible: boolean;
zIndex: number;
minZoom: number;
maxZoom: number;
autoFit: boolean;
blend: keyof typeof BlendType;
[key: string]: any;
}
export interface IScaleOption { export interface IScaleOption {
[key: string]: IScaleAttributeOptions; [key: string]: IScaleAttributeOptions;
} }
@ -39,9 +55,7 @@ export interface IActiveOptions {
option: IActiveOption | boolean; option: IActiveOption | boolean;
} }
export interface ILayerProps { export interface ILayerProps {
options?: { options?: Partial<ILayerOption>;
[key: string]: any;
};
source: ISourceOptions; source: ISourceOptions;
color: Partial<IAttributeOptions>; color: Partial<IAttributeOptions>;
shape: Partial<IAttributeOptions>; shape: Partial<IAttributeOptions>;

View File

@ -13,6 +13,9 @@ export const LayerEvent = React.memo((props: ILayerProps) => {
useEffect(() => { useEffect(() => {
layer.on(type, handler); layer.on(type, handler);
return () => {
layer.off('type', handler);
};
}, [type]); }, [type]);
return null; return null;
}); });

View File

@ -0,0 +1,17 @@
import { IActiveOption, IImage, ILayer, Scene } from '@antv/l7';
import * as React from 'react';
import { useSceneValue } from './SceneContext';
const { useEffect } = React;
interface ILoadImageProps {
name: string;
url: IImage;
}
export default React.memo(function LoadImage(props: ILoadImageProps) {
const { name, url } = props;
const mapScene = (useSceneValue() as unknown) as Scene;
useEffect(() => {
mapScene.addImage(name, url);
}, [name, url]);
return null;
});

View File

@ -1,4 +1,4 @@
import { IMapConfig, Scene } from '@antv/l7'; import { IMapConfig, Scene, Zoom } from '@antv/l7';
// @ts-ignore // @ts-ignore
// tslint:disable-next-line:no-submodule-imports // tslint:disable-next-line:no-submodule-imports
import Mapbox from '@antv/l7-maps/lib/mapbox'; import Mapbox from '@antv/l7-maps/lib/mapbox';
@ -14,6 +14,8 @@ const MapboxScene = React.memo((props: IMapSceneConig) => {
const { style, className, map } = props; const { style, className, map } = props;
const container = createRef(); const container = createRef();
const [scene, setScene] = useState(); const [scene, setScene] = useState();
// 地图初始
useEffect(() => { useEffect(() => {
const sceneInstance = new Scene({ const sceneInstance = new Scene({
id: container.current as HTMLDivElement, id: container.current as HTMLDivElement,
@ -26,6 +28,8 @@ const MapboxScene = React.memo((props: IMapSceneConig) => {
sceneInstance.destroy(); sceneInstance.destroy();
}; };
}, []); }, []);
// 更新地图样式
useEffect(() => { useEffect(() => {
if (!scene) { if (!scene) {
return; return;
@ -33,6 +37,32 @@ const MapboxScene = React.memo((props: IMapSceneConig) => {
scene.setMapStyle(map.style); scene.setMapStyle(map.style);
}, [map.style]); }, [map.style]);
useEffect(() => {
if (!scene) {
return;
}
scene.setZoom(map.zoom);
}, [map.zoom, map.center, map.pitch, map.rotation]);
useEffect(() => {
if (!scene) {
return;
}
scene.setCenter(map.center);
}, [map.center]);
useEffect(() => {
if (!scene) {
return;
}
scene.setPitch(map.pitch);
}, [map.pitch]);
useEffect(() => {
if (!scene) {
return;
}
scene.setRotation(map.rotation);
}, [map.rotation]);
return ( return (
<SceneContext.Provider value={scene}> <SceneContext.Provider value={scene}>
{createElement( {createElement(

View File

View File

@ -0,0 +1,44 @@
import {
IActiveOption,
IImage,
ILayer,
ILngLat,
IPopupOption,
Popup,
Scene,
} from '@antv/l7';
import * as React from 'react';
import { createPortal } from 'react-dom';
import { useSceneValue } from './SceneContext';
const { useEffect } = React;
interface IPopupProps {
option: IPopupOption;
lnglat: ILngLat;
text: string;
html: string;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
}
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();
const el = document.createElement('div');
useEffect(() => {
const p = new Popup(props.option);
if (lnglat) {
p.setLnglat(lnglat);
}
if (html) {
p.setHTML(html);
}
if (text) {
p.setText(text);
}
if (children) {
p.setDOMContent(el);
}
setPopup(p);
}, []);
return createPortal(children, el);
});

View File

@ -12,7 +12,7 @@ interface IMapSceneConig {
map: IMapWrapper; map: IMapWrapper;
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>; children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>;
} }
const MapScene = React.memo((props: IMapSceneConig) => { export default React.memo((props: IMapSceneConig) => {
const { style, className, map, options } = props; const { style, className, map, options } = props;
const container = createRef(); const container = createRef();
const [scene, setScene] = useState(); const [scene, setScene] = useState();
@ -36,6 +36,8 @@ const MapScene = React.memo((props: IMapSceneConig) => {
sceneInstance.destroy(); sceneInstance.destroy();
}; };
}, []); }, []);
// 更新地图
useEffect(() => { useEffect(() => {
if (!scene) { if (!scene) {
return; return;
@ -57,5 +59,3 @@ const MapScene = React.memo((props: IMapSceneConig) => {
</SceneContext.Provider> </SceneContext.Provider>
); );
}); });
export { MapScene };

View File

@ -0,0 +1,21 @@
import { ILayer, Scene } from '@antv/l7';
import * as React from 'react';
import { useSceneValue } from './SceneContext';
const { useEffect } = React;
interface ILayerProps {
type: string;
handler: (...args: any[]) => void;
}
export const SceneEvent = React.memo((props: ILayerProps) => {
const { type, handler } = props;
const mapScene = (useSceneValue() as unknown) as Scene;
useEffect(() => {
mapScene.on(type, handler);
return () => {
mapScene.off('type', handler);
};
}, [type]);
return null;
});

View File

@ -1,11 +1,10 @@
export * from './component/SceneContext'; export * from './component/SceneContext';
export { default as Scene } from './component/Scene';
export { default as AMapScene } from './component/AMapScene'; export { default as AMapScene } from './component/AMapScene';
export { default as MapboxScene } from './component/MapboxScene'; export { default as MapboxScene } from './component/MapboxScene';
export { default as Scene } from './component/Scene';
export * from './component/Layer'; export * from './component/Layer';
export { default as Control } from './component/Control'; export { default as Control } from './component/Control';
export { default as CustomControl } from './component/CustomControl'; export { default as CustomControl } from './component/CustomControl';
export { MapScene } from './component/Scene';
export { PolygonLayer, LineLayer, PointLayer } from './component/Layer'; export { PolygonLayer, LineLayer, PointLayer } from './component/Layer';
export { LayerEvent } from './component/LayerEvent'; export { LayerEvent } from './component/LayerEvent';
export { useSceneValue, SceneContext } from './component/SceneContext'; export { useSceneValue, SceneContext } from './component/SceneContext';

View File

@ -5,5 +5,6 @@ export * from './geo';
export * from './lru_cache'; export * from './lru_cache';
export * from './event'; export * from './event';
export * from './color'; export * from './color';
export * from './anchor';
import * as Satistics from './statistics'; import * as Satistics from './statistics';
export { DOM, Satistics }; export { DOM, Satistics };

View File

@ -46,10 +46,14 @@ export default class PointImage extends React.Component {
y: 'latitude', y: 'latitude',
}, },
}) })
.shape('triangle') // .shape('name', ['00', '01', '02'])
.shape('name', 'text')
.color('red') .color('red')
.active(true) .active(false)
.size(20); .size(20);
// imageLayer.on('click', (e) => {
// console.log(e);
// });
scene.addLayer(imageLayer); scene.addLayer(imageLayer);
i++; i++;
} }

View File

@ -27,6 +27,7 @@ export default class DashLineDemo extends React.Component {
.source(await response.json()) .source(await response.json())
.size(1) .size(1)
.shape('line') .shape('line')
.active({ color: 'red' })
.color( .color(
'ELEV', 'ELEV',
[ [
@ -44,7 +45,7 @@ export default class DashLineDemo extends React.Component {
) )
.style({ .style({
// lineType: 'dash', // lineType: 'dash',
opacity: 0.5, opacity: 1.0,
}); });
scene.addLayer(lineLayer); scene.addLayer(lineLayer);

View File

@ -1,5 +1,5 @@
import { GaodeMap, Mapbox } from '@antv/l7-maps'; import { GaodeMap, Mapbox } from '@antv/l7-maps';
import { LineLayer, MapScene } from '@antv/l7-react'; import { LineLayer, Scene } from '@antv/l7-react';
import * as React from 'react'; import * as React from 'react';
export default React.memo(function Map() { export default React.memo(function Map() {
@ -23,7 +23,7 @@ export default React.memo(function Map() {
}, []); }, []);
return ( return (
<> <>
<MapScene <Scene
map={amap} map={amap}
style={{ style={{
position: 'absolute', position: 'absolute',
@ -40,20 +40,20 @@ export default React.memo(function Map() {
data, data,
}} }}
size={{ size={{
value: 1, values: 1,
}} }}
color={{ color={{
value: '#fff', values: '#fff',
}} }}
shape={{ shape={{
value: 'line', values: 'line',
}} }}
style={{ style={{
opacity: 1, opacity: 1,
}} }}
/> />
)} )}
</MapScene> </Scene>
</> </>
); );
}); });