* feat: 修改 CanvasLayer drawingOnCanvas 的 参数

* style: lint style

* feat: 新增 geometryLayer plane

* feat: 新增简单坐标系能力

* style: lint style
This commit is contained in:
YiQianYao 2022-03-23 11:01:54 +08:00 committed by GitHub
parent 5c1fbee30e
commit 27e54e7a1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 685 additions and 57 deletions

View File

@ -114,7 +114,7 @@ export interface IVertexAttributeDescriptor
) => number[];
}
type Position = number[];
export type Position = number[];
type Color = [number, number, number, number];
type CallBack = (...args: any[]) => any;
export type StyleAttributeField = string | string[] | number[];

View File

@ -1,3 +1,4 @@
import { SimpleCoordinate } from '@antv/l7-maps';
import { Container } from 'inversify';
import { IViewport } from '../camera/ICameraService';
export type Point = [number, number];
@ -36,6 +37,7 @@ export interface IMapWrapper {
export interface IMapService<RawMap = {}> {
version?: string;
simpleMapCoord: SimpleCoordinate;
map: RawMap;
bgColor: string;
setBgColor(color: string): void;

View File

@ -11,6 +11,7 @@ import {
IStyleAttributeService,
TYPES,
} from '@antv/l7-core';
import { Version } from '@antv/l7-maps';
import { isColor, rgb2arr, unProjectFlat } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
import { cloneDeep } from 'lodash';
@ -157,8 +158,21 @@ export default class DataMappingPlugin implements ILayerPlugin {
}) as IEncodeFeature[];
// console.log('mappedData', mappedData)
// 调整数据兼容 Amap2.0
this.adjustData2Amap2Coordinates(mappedData);
// 调整数据兼容 SimpleCoordinates
this.adjustData2SimpleCoordinates(mappedData);
// console.log('mappedData', mappedData)
return mappedData;
}
private adjustData2Amap2Coordinates(mappedData: IEncodeFeature[]) {
// 根据地图的类型判断是否需要对点位数据进行处理, 若是高德2.0则需要对坐标进行相对偏移
if (mappedData.length > 0 && this.mapService.version === 'GAODE2.x') {
if (
mappedData.length > 0 &&
this.mapService.version === Version['GAODE2.x']
) {
if (typeof mappedData[0].coordinates[0] === 'number') {
// 单个的点数据
// @ts-ignore
@ -171,7 +185,6 @@ export default class DataMappingPlugin implements ILayerPlugin {
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
// @ts-ignore
d.coordinates = this.mapService.lngLatToCoord(d.coordinates);
// d.coordinates = this.mapService.lngLatToCoord(unProjectFlat(d.coordinates));
});
} else {
// 连续的线、面数据
@ -188,8 +201,51 @@ export default class DataMappingPlugin implements ILayerPlugin {
});
}
}
// console.log('mappedData', mappedData)
return mappedData;
}
private adjustData2SimpleCoordinates(mappedData: IEncodeFeature[]) {
if (mappedData.length > 0 && this.mapService.version === Version.SIMPLE) {
mappedData.map((d) => {
d.coordinates = this.unProjectCoordinates(d.coordinates);
});
}
}
private unProjectCoordinates(coordinates: any) {
if (typeof coordinates[0] === 'number') {
return this.mapService.simpleMapCoord.unproject(
coordinates as [number, number],
);
}
if (coordinates[0] && coordinates[0][0] instanceof Array) {
// @ts-ignore
const coords = [];
coordinates.map((coord: any) => {
// @ts-ignore
const c1 = [];
coord.map((co: any) => {
c1.push(
this.mapService.simpleMapCoord.unproject(co as [number, number]),
);
});
// @ts-ignore
coords.push(c1);
});
// @ts-ignore
return coords;
} else {
// @ts-ignore
const coords = [];
// @ts-ignore
coordinates.map((coord) => {
coords.push(
this.mapService.simpleMapCoord.unproject(coord as [number, number]),
);
});
// @ts-ignore
return coords;
}
}
private applyAttributeMapping(

View File

@ -23,6 +23,7 @@ import { DOM } from '@antv/l7-utils';
import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
import { SimpleCoordinate } from '..';
import { IAMapEvent, IAMapInstance } from '../../typings/index';
import { toPaddingOptions } from '../utils';
import { Version } from '../version';
@ -56,6 +57,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12; // 暂时关闭 fix 统一不同坐标
export default class AMapService
implements IMapService<AMap.Map & IAMapInstance> {
public version: string = Version['GAODE1.x'];
public simpleMapCoord: SimpleCoordinate;
/**
*
*/

View File

@ -24,6 +24,7 @@ import { DOM } from '@antv/l7-utils';
import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
import { SimpleCoordinate } from '..';
import { IAMapEvent, IAMapInstance } from '../../typings/index';
import { toPaddingOptions } from '../utils';
import { Version } from '../version';
@ -59,6 +60,7 @@ let pendingResolveQueue: Array<() => void> = [];
export default class AMapService
implements IMapService<AMap.Map & IAMapInstance> {
public version: string = Version['GAODE2.x'];
public simpleMapCoord: SimpleCoordinate;
/**
*
*/

View File

@ -31,6 +31,7 @@ const EventMap: {
zoomchange: 'zoom',
dragging: 'drag',
};
import { SimpleCoordinate } from '..';
import { MapTheme } from './theme';
const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
@ -41,6 +42,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
export default class L7EarthService implements IEarthService<Map> {
public version: string = Version.GLOBEL;
public map: Map;
public simpleMapCoord: SimpleCoordinate;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;

View File

@ -4,9 +4,10 @@ import GaodeMapV2 from './amap2/';
import Earth from './earth/';
// import GaodeMapV2 from './amap2/';
import Map from './map/';
import SimpleCoordinate from './map/simpleMapCoord';
import Mapbox from './mapbox/';
import { Version } from './version';
export { Version, GaodeMap, GaodeMapV2, Mapbox, Map, Earth };
export { SimpleCoordinate, Version, GaodeMap, GaodeMapV2, Mapbox, Map, Earth };
// export { GaodeMap, GaodeMapV2, Mapbox, Map };
// export { Map };

View File

@ -22,6 +22,7 @@ import { $window, DOM } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
import { Version } from '../version';
import SimpleMapCoord from './simpleMapCoord';
import Viewport from './Viewport';
const EventMap: {
[key: string]: any;
@ -41,7 +42,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
export default class L7MapService implements IMapService<Map> {
public version: string = Version.L7MAP;
public map: Map;
public simpleMapCoord: SimpleMapCoord = new SimpleMapCoord();
// 背景色
public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)';
@ -98,6 +99,9 @@ export default class L7MapService implements IMapService<Map> {
}
public getSize(): [number, number] {
if (this.version === Version.SIMPLE) {
return this.simpleMapCoord.getSize();
}
const size = this.map.transform;
return [size.width, size.height];
}
@ -258,11 +262,29 @@ export default class L7MapService implements IMapService<Map> {
style = 'light',
rotation = 0,
mapInstance,
version = 'L7MAP',
mapSize = 10000,
...rest
} = this.config;
this.viewport = new Viewport();
this.version = version;
this.simpleMapCoord.setSize(mapSize);
// console.log('this.config.center', this.config.center)
if (version === Version.SIMPLE && rest.center) {
rest.center = this.simpleMapCoord.unproject(
rest.center as [number, number],
);
}
// console.log(this.simpleMapCoord.project(this.config.center as [number, number]))
// console.log(this.simpleMapCoord.unproject([500, 500]))
// console.log(this.simpleMapCoord.project([0, 0]))
// console.log(this.simpleMapCoord.unproject([5000, 5000]))
// console.log(this.simpleMapCoord.unproject([200, 200]))
// console.log(this.simpleMapCoord.unproject([1000, 1000]))
if (mapInstance) {
// @ts-ignore
this.map = mapInstance;
@ -277,6 +299,7 @@ export default class L7MapService implements IMapService<Map> {
...rest,
});
}
this.map.on('load', this.handleCameraChanged);
this.map.on('move', this.handleCameraChanged);

View File

@ -0,0 +1,67 @@
export default class SimpleMapCoord {
private size: number = 10000;
constructor(size?: number) {
this.size = size ? size : 10000;
}
public setSize(size: number) {
this.size = size;
}
public getSize(): [number, number] {
return [this.size, this.size];
}
/**
* coord
* ^ y (y > 0)
* |
* |
* |
* |(x = 0, y = 0)
* ---------------> x (x > 0)
*/
/***
* lng: [-180, 180] 360
* lat: [-85.05112877980659, 85.05112877980659] 170.10225755961318
*/
public mercatorXfromLng(lng: number): number {
// (0 - 1) * this.size
return ((180 + lng) / 360) * this.size;
}
public mercatorYfromLat(lat: number): number {
// (0 - 1) * this.size
return (
(1 -
(180 -
(180 / Math.PI) *
Math.log(Math.tan(Math.PI / 4 + (lat * Math.PI) / 360))) /
360) *
this.size
);
}
public lngFromMercatorX(x: number): number {
return (x / this.size) * 360 - 180;
}
public latFromMercatorY(y: number): number {
const y2 = 180 - (1 - y / this.size) * 360;
return (360 / Math.PI) * Math.atan(Math.exp((y2 * Math.PI) / 180)) - 90;
}
public project(lnglat: [number, number]): [number, number] {
const x = this.mercatorXfromLng(lnglat[0]);
const y = this.mercatorYfromLat(lnglat[1]);
return [x, y];
}
public unproject(xy: [number, number]): [number, number] {
const lng = this.lngFromMercatorX(xy[0]);
const lat = this.latFromMercatorY(xy[1]);
return [lng, lat];
}
}

View File

@ -36,6 +36,7 @@ const EventMap: {
zoomchange: 'zoom',
dragging: 'drag',
};
import { SimpleCoordinate } from '..';
import { MapTheme } from './theme';
let mapdivCount = 0;
const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
@ -49,6 +50,7 @@ export default class MapboxService
implements IMapService<Map & IMapboxInstance> {
public version: string = Version.MAPBOX;
public map: Map & IMapboxInstance;
public simpleMapCoord: SimpleCoordinate;
// 背景色
public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)';

View File

@ -6,5 +6,6 @@ export enum Version {
'GAODE2.x' = 'GAODE2.x',
'MAPBOX' = 'MAPBOX',
'L7MAP' = 'L7MAP',
'SIMPLE' = 'SIMPLE',
'GLOBEL' = 'GLOBEL',
}

View File

@ -10,61 +10,54 @@ export default class ScaleComponent extends React.Component {
const scene = new Scene({
id: 'map',
map: new Map({
center: [105, 32],
// center: [0, 0],
center: [5000, 5000],
pitch: 0,
zoom: 3,
zoom: 0,
version: 'SIMPLE',
// zoom: 13,
// zoom: 10,
}),
});
// scene.setBgColor('#000');
const data = [
{ x: 5000, y: 5000 },
// { lng: 120, lat: 30 },
// { lng: 0, lat: 0 },
// { lng: 0, lat: 85.05112 },
// { lng: 0, lat: -85.05112 },
// { lng: -90, lat: 0 },
// { lng: -180, lat: 0 },
// { lng: 90, lat: 0 },
// { lng: 180, lat: 0 },
// { lng: -90, lat: 85.05112 },
// { lng: -180, lat: 85.05112 },
// { lng: 90, lat: 85.05112 },
// { lng: 180, lat: 85.05112 },
// { lng: -90, lat: -85.05112 },
// { lng: -180, lat: -85.05112 },
// { lng: 90, lat: -85.05112 },
// { lng: 180, lat: -85.05112 },
];
const layer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'x',
y: 'y',
},
})
.shape('circle')
.size(20)
.color('#f00');
scene.on('loaded', () => {
fetch(
// 'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
'https://gw.alipayobjects.com/os/bmw-prod/5dbc5dbf-76f1-47e6-b9e3-d2a1b7581f93.json',
// 'https://gw.alipayobjects.com/os/alisis/geo-data-v0.1.1/choropleth-data/country/100000_country_province.json'
)
.then((res) => res.json())
.then((data) => {
let layer = new PolygonLayer({ blend: 'normal' }) // autoFit: true
.source(data)
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
// .color('#000')
.shape('fill')
// .shape('line')
// .select(true)
.style({
opacity: 0.8,
});
scene.addLayer(layer);
});
// layer.setBottomColor('#f00');
// let layer2 = new PolygonLayer({ blend: 'normal' })
// .source(data)
// .size(1)
// .color('name', [
// '#2E8AE6',
// '#69D1AB',
// '#DAF291',
// '#FFD591',
// '#FF7A45',
// '#CF1D49',
// ])
// .shape('line')
// .select(true)
// .style({
// opacity: 1.0,
// });
// scene.addLayer(layer2);
scene.addLayer(layer);
});
}

View File

@ -0,0 +1,78 @@
// @ts-nocheck
import { Scene, PolygonLayer, PointLayer, Map, ImageLayer } from '@antv/l7';
import * as React from 'react';
export default class Demo extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Map({
center: [5000, 5000],
pitch: 0,
zoom: 2,
version: 'SIMPLE',
// zoom: 13,
// zoom: 10,
}),
});
const data = [];
for (let i = 0; i <= 10; i++) {
for (let j = 0; j <= 10; j++) {
data.push({ x: i * 1000, y: j * 1000 });
}
}
// const data = [
// {x: 200, y: 200},
// {x: 1000, y: 1000}
// ]
const layer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'x',
y: 'y',
},
})
.shape('circle')
.size(20)
.color('#f00');
const imagelayer = new ImageLayer({}).source(
'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*KrvXTrIAnWEAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image',
// extent: [
// 100, 100,
// 200, 500
// ],
extent: [4000, 3500, 6000, 6500],
// extent: [
// -172.8, -84.38946720916285,
// -144, -80.73800862798672
// ],
},
},
);
scene.on('loaded', () => {
scene.addLayer(layer);
scene.addLayer(imagelayer);
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -0,0 +1,101 @@
// @ts-nocheck
import { Scene, LineLayer, PointLayer, Map } from '@antv/l7';
import * as React from 'react';
export default class Demo extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Map({
center: [10000, 10000],
pitch: 0,
zoom: 0,
version: 'SIMPLE',
mapSize: 20000,
}),
});
const data = [];
for (let i = 0; i <= 10; i++) {
for (let j = 0; j <= 10; j++) {
data.push({ x: i * 1000, y: j * 1000 });
}
}
const layer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'x',
y: 'y',
},
})
.shape('circle')
.size(20)
.color('#f00');
const lineData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
testOpacity: 0.8,
},
geometry: {
type: 'Polygon',
coordinates: [
[
[6000, 6000],
[6000, 7000],
[7000, 7000],
[7000, 6000],
],
],
},
},
],
};
const linelayer = new LineLayer()
.source(lineData)
.shape('line')
.size(10)
.color('#0f0')
.active(true);
const linelayer2 = new LineLayer()
.source([{ x: 5000, y: 5000, x2: 5000, y2: 4000 }], {
parser: {
type: 'json',
x: 'x',
y: 'y',
x1: 'x2',
y1: 'y2',
},
})
.shape('line')
.color('#0ff')
.size(5)
.active(true);
scene.on('loaded', () => {
scene.addLayer(layer);
scene.addLayer(linelayer);
scene.addLayer(linelayer2);
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -0,0 +1,108 @@
// @ts-nocheck
import {
Scene,
PolygonLayer,
ImageLayer,
PointLayer,
Map,
} from '@antv/l7-mini';
import * as React from 'react';
export default class Demo extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Map({
center: [500, 500],
pitch: 0,
zoom: 2.5,
version: 'SIMPLE',
mapSize: 1000,
maxZoom: 4,
minZoom: 2,
}),
});
scene.setBgColor('rgb(216, 209, 86)');
const textlayer = new PointLayer()
.source(
[
{
x: 470,
y: 520,
t: '库布齐',
},
{
x: 490,
y: 580,
t: '阿拉善',
},
{
x: 530,
y: 530,
t: '鄂尔多斯',
},
{
x: 545,
y: 480,
t: '武威',
},
{
x: 490,
y: 470,
t: '黄山洋湖',
},
],
{
parser: {
type: 'json',
x: 'x',
y: 'y',
},
},
)
.shape('t', 'text')
.size(14)
.active(true)
.color('#000')
.style({
textAllowOverlap: true,
});
const imagelayer = new ImageLayer({}).source(
'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*M1v5TKxzrHoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image',
extent: [450, 400, 550, 600],
},
},
);
scene.on('loaded', () => {
scene.addLayer(imagelayer);
scene.addLayer(textlayer);
// console.log(scene.mapService.getSize())
// setTimeout(() => {
// console.log(scene.mapService.getSize())
// }, 2000 )
console.log(scene.mapService.getCenter());
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -0,0 +1,57 @@
// @ts-nocheck
import { Scene, PolygonLayer, PointLayer, Map } from '@antv/l7-mini';
import * as React from 'react';
export default class Demo extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Map({
center: [500, 500],
pitch: 0,
zoom: 0,
version: 'SIMPLE',
mapSize: 1000,
// zoom: 13,
// zoom: 10,
}),
});
// scene.setBgColor('#000');
const data = [];
for (let i = 0; i <= 10; i++) {
for (let j = 0; j <= 10; j++) {
data.push({ x: i * 100, y: j * 100 });
}
}
const layer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'x',
y: 'y',
},
})
.shape('circle')
.size(20)
.color('#f00');
scene.on('loaded', () => {
scene.addLayer(layer);
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -0,0 +1,118 @@
// @ts-nocheck
import { Scene, PolygonLayer, PointLayer, Map, ImageLayer } from '@antv/l7';
import * as React from 'react';
export default class Demo extends React.Component {
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new Map({
center: [5000, 5000],
pitch: 0,
zoom: 2,
version: 'SIMPLE',
}),
});
const data = [];
for (let i = 0; i <= 10; i++) {
for (let j = 0; j <= 10; j++) {
data.push({ x: i * 1000, y: j * 1000 });
}
}
const layer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'x',
y: 'y',
},
})
.shape('circle')
.size(20)
.active(true)
.color('#f00');
const imagelayer = new ImageLayer({}).source(
'https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*KrvXTrIAnWEAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image',
extent: [4000, 3500, 6000, 6500],
},
},
);
const polygonData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
testOpacity: 0.4,
},
geometry: {
type: 'MultiPolygon',
coordinates: [
[
[
[6000, 6000],
[6000, 7000],
[7000, 7000],
[7000, 6000],
[6000, 6000],
],
[
[6300, 6300],
[6300, 6700],
[6700, 6700],
[6700, 6300],
[6300, 6300],
],
],
[
[
[5000, 5000],
[5000, 6000],
[6000, 6000],
[6000, 5000],
[5000, 5000],
],
],
],
},
},
],
};
const polygonLayer = new PolygonLayer()
.source(polygonData)
.shape('fill')
.color('#f00')
.style({
opacity: 0.6,
})
.active(true);
scene.on('loaded', () => {
scene.addLayer(layer);
scene.addLayer(imagelayer);
scene.addLayer(polygonLayer);
});
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
></div>
);
}
}

View File

@ -0,0 +1,15 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import PointGrid from './components/pointGrid';
import Image from './components/image';
import Polygon from './components/polygon';
import Line from './components/line';
import ParkDemo from './components/parkdemo';
storiesOf('平面坐标地图', module)
.add('Point', () => <PointGrid />)
.add('Image', () => <Image />)
.add('Polygon', () => <Polygon/>)
.add('Line', () => <Line/>)
.add('ParkDemo', () => <ParkDemo/>)