feat(many): gaode1.x -> gaode2.0 not finished

This commit is contained in:
伊钱耀 2021-04-22 15:08:41 +08:00
parent bee72723d4
commit 0fdb6d1b0d
44 changed files with 2253 additions and 86 deletions

View File

@ -3,6 +3,7 @@ import { inject, injectable } from 'inversify';
import { TYPES } from '../../types';
import { getDistanceScales } from '../../utils/project';
import { ICameraService } from '../camera/ICameraService';
// import { IMapService } from '../map/IMapService'
import {
CoordinateSystem,
ICoordinateSystemService,
@ -17,6 +18,10 @@ export default class CoordinateSystemService
@inject(TYPES.ICameraService)
private readonly cameraService: ICameraService;
// map.getCenter
// @inject(TYPES.IMapService)
// private readonly mapService: IMapService
/**
* 1. Web
* 2.

View File

@ -17,6 +17,7 @@ export enum CoordinateSystem {
P20 = 5.0,
P20_OFFSET = 6.0,
METER_OFFSET = 7.0,
P20_2 = 8.0,
}
// 后续传入 Shader 的变量
@ -27,6 +28,8 @@ export const CoordinateUniform = {
PixelsPerDegree: 'u_PixelsPerDegree',
PixelsPerDegree2: 'u_PixelsPerDegree2',
PixelsPerMeter: 'u_PixelsPerMeter',
Mvp: 'u_Mvp',
};
export interface ICoordinateSystemService {

View File

@ -30,8 +30,10 @@ export interface IMapWrapper {
}
export interface IMapService<RawMap = {}> {
version: string;
map: RawMap;
init(): void;
initViewPort?(): void;
destroy(): void;
onCameraChanged(callback: (viewport: IViewport) => void): void;
// init map
@ -85,6 +87,12 @@ export interface IMapService<RawMap = {}> {
scale: [number, number, number],
origin: IMercator,
): number[];
lngLatToCoord?(lnglat: [number, number]): [number, number];
lngLatToCoords?(
lnglatArray: number[][][] | number[][],
): number[][][] | number[][] | number[][][] | number[][];
// lngLatToCoords?(lnglatArray: any): any;
getCustomCoordCenter?(): [number, number];
exportMap(type: 'jpg' | 'png'): string;
}
@ -178,6 +186,9 @@ export interface IMapCamera {
center: [number, number];
// 相机高度
cameraHeight: number;
cameraPosition?: [number, number, number];
up?: [number, number, number];
lookAt?: [number, number, number];
// 偏移原点,例如 P20 坐标系下
offsetOrigin: [number, number];
}

View File

@ -139,15 +139,32 @@ export default class Scene extends EventEmitter implements ISceneService {
*/
this.hooks.init.tapPromise('initMap', async () => {
// 等待首次相机同步
await new Promise((resolve) => {
await new Promise<void>((resolve) => {
this.map.onCameraChanged((viewport: IViewport) => {
this.cameraService.init();
this.cameraService.update(viewport);
resolve();
if (this.map.version !== 'GAODE2.x') {
// not amap2
resolve();
}
});
this.map.init();
if (this.map.version !== 'GAODE2.x') {
// not amap2
this.map.init();
} else {
// amap2
resolve();
}
});
if (this.map.version === 'GAODE2.x' && this.map.initViewPort) {
// amap2
await this.map.init();
this.map.initViewPort();
}
// this.controlService.addControls();
// 重新绑定非首次相机更新事件
this.map.onCameraChanged(this.handleMapCameraChanged);
this.map.addMarkerContainer();
@ -208,7 +225,6 @@ export default class Scene extends EventEmitter implements ISceneService {
// 执行异步并行初始化任务
// @ts-ignore
this.initPromise = this.hooks.init.promise();
this.render();
}
@ -222,11 +238,11 @@ export default class Scene extends EventEmitter implements ISceneService {
if (this.rendering || this.destroyed) {
return;
}
this.rendering = true;
// 首次初始化,或者地图的容器被强制销毁的需要重新初始化
if (!this.inited) {
// 还未初始化完成需要等待
await this.initPromise;
if (this.destroyed) {
this.destroy();
@ -243,9 +259,7 @@ export default class Scene extends EventEmitter implements ISceneService {
// 尝试初始化未初始化的图层
this.layerService.renderLayers();
// 组件需要等待layer 初始化完成之后添加
this.logger.debug(`scene ${this.id} render`);
this.rendering = false;
}

View File

@ -10,6 +10,8 @@
#define COORDINATE_SYSTEM_P20_OFFSET 6.0
#define COORDINATE_SYSTEM_METER_OFFSET 7.0
#define COORDINATE_SYSTEM_P20_2 8.0
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectionMatrix;
uniform mat4 u_ViewProjectionMatrix;
@ -28,6 +30,8 @@ uniform float u_DevicePixelRatio;
uniform float u_FocalDistance;
uniform vec3 u_CameraPosition;
// uniform mat4 u_Mvp;
// web mercator coords -> world coords
vec2 project_mercator(vec2 lnglat) {
float x = lnglat.x;
@ -38,7 +42,13 @@ vec2 project_mercator(vec2 lnglat) {
}
float project_scale(float meters) {
return meters * u_PixelsPerMeter.z;
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
// 因为高德2.0和1.x的相机控制方向相反而u_PixelsPerMeter的计算与此相关计算结果也相反
// 可通过 shaderUniformPlugin -> CoordinateSystemService -> project 的顺序查看区别
return meters * u_PixelsPerMeter.z * -1.0;
} else {
return meters * u_PixelsPerMeter.z;
}
}
@ -69,6 +79,10 @@ vec3 reverse_offset_normal(vec3 vector) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 ||u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET ) {
return vector * vec3(1.0, -1.0, 1.0);
}
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.0
return vector * vec3(1.0, -1.0, 1.0);
}
return vector;
}
@ -97,6 +111,17 @@ vec4 project_position(vec4 position) {
position.w
);
}
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
// return vec4(
// (position.xy * WORLD_SCALE * u_ZoomScale) * vec2(1., -1.),
// project_scale(position.z),
// position.w);
return vec4(
position.xy,
project_scale(position.z),
position.w);
}
return position;
// TODO: 瓦片坐标系 & 常规世界坐标系
@ -111,6 +136,10 @@ float project_pixel(float pixel) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom));
}
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
// P20_2 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减3
return pixel * pow(2.0, (19.0 - 3.0 - u_Zoom));
}
return pixel;
}
vec2 project_pixel(vec2 pixel) {
@ -118,6 +147,10 @@ vec2 project_pixel(vec2 pixel) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom));
}
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
// P20_2 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减3
return pixel * pow(2.0, (19.0 - 3.0 - u_Zoom));
}
return pixel * -1.;
}
@ -127,6 +160,7 @@ vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatr
// Needs to be divided with project_uCommonUnitsPerMeter
position.w *= u_PixelsPerMeter.z;
}
return viewProjectionMatrix * position + center;
}
@ -153,5 +187,4 @@ vec4 unproject_clipspace_to_position(vec4 clipspacePos, mat4 u_InverseViewProjec
bool isEqual( float a, float b) {
return a< b + 0.001 && a > b - 0.001;
}
}

View File

@ -69,19 +69,48 @@ export function PointImageTriangulation(feature: IEncodeFeature) {
* @param feature feature
*/
export function LineTriangulation(feature: IEncodeFeature) {
const { coordinates } = feature;
let path = coordinates as number[][][] | number[][];
if (!Array.isArray(path[0][0])) {
path = [coordinates] as number[][][];
}
const { coordinates, originCoordinates, version } = feature;
// let path = coordinates as number[][][] | number[][];
// if (!Array.isArray(path[0][0])) {
// path = [coordinates] as number[][][];
// }
const line = new ExtrudePolyline({
dash: true,
join: 'bevel', //
});
path.forEach((item: any) => {
// 处理带洞的多边形
line.extrude(item as number[][]);
join: 'bevel',
});
if (version === 'GAODE2.x') {
// 处理高德2.0几何体构建
let path1 = coordinates as number[][][] | number[][];
if (!Array.isArray(path1[0][0])) {
path1 = [coordinates] as number[][][];
}
let path2 = originCoordinates as number[][][] | number[][];
if (!Array.isArray(path2[0][0])) {
path2 = [originCoordinates] as number[][][];
}
path1.forEach((item: any) => {
// 处理带洞的多边形
line.extrude1(item as number[][]);
});
path2.forEach((item: any) => {
// 处理带洞的多边形
line.extrude2(item as number[][]);
});
} else {
// 处理非高德2.0的几何体构建
let path = coordinates as number[][][] | number[][];
if (!Array.isArray(path[0][0])) {
path = [coordinates] as number[][][];
}
path.forEach((item: any) => {
line.extrude(item as number[][]);
});
}
const linebuffer = line.complex;
return {
vertices: linebuffer.positions, // [ x,y,z, distance, miter,total ]
@ -207,6 +236,7 @@ export function LineArcTriangulation(feature: IEncodeFeature) {
);
}
}
// console.log('positions', positions)
return {
vertices: positions,
indices: indexArray,

View File

@ -6,6 +6,7 @@ attribute vec3 a_Position;
attribute vec4 a_Instance;
attribute float a_Size;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform float segmentNumber;
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
varying vec4 v_color;
@ -78,8 +79,14 @@ void main() {
vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0));
vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0));
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * (vec4(curr.xy + offset, 0, 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
}
setPickingColor(a_PickingColor);
}

View File

@ -13,6 +13,7 @@ attribute float a_Total_Distance;
attribute float a_Distance;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform float u_line_type: 0.0;
uniform vec4 u_dash_array: [10.0, 5.0, 0];
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
@ -42,7 +43,15 @@ void main() {
vec2 offset = project_pixel(size.xy);
v_side = a_Miter * a_Size.x;
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
// gl_Position = u_Mvp * (vec4(project_pos.xy + offset, a_Size.y, 1.0));
gl_Position = u_Mvp * (vec4(project_pos.xy + offset, a_Size.y, 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
}
setPickingColor(a_PickingColor);
}

View File

@ -3,7 +3,9 @@ import {
IGlobalConfigService,
ILayer,
ILayerPlugin,
ILngLat,
ILogService,
IMapService,
IParseDataItem,
IStyleAttribute,
IStyleAttributeService,
@ -11,6 +13,7 @@ import {
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
import { cloneDeep } from 'lodash';
@injectable()
export default class DataMappingPlugin implements ILayerPlugin {
@ -20,6 +23,9 @@ export default class DataMappingPlugin implements ILayerPlugin {
@inject(TYPES.ILogService)
private readonly logger: ILogService;
@inject(TYPES.IMapService)
private readonly mapService: IMapService;
public apply(
layer: ILayer,
{
@ -99,7 +105,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
data: IParseDataItem[],
predata?: IEncodeFeature[],
): IEncodeFeature[] {
return data.map((record: IParseDataItem, i) => {
const mappedData = data.map((record: IParseDataItem, i) => {
const preRecord = predata ? predata[i] : {};
const encodeRecord: IEncodeFeature = {
id: record._id,
@ -124,6 +130,35 @@ export default class DataMappingPlugin implements ILayerPlugin {
});
return encodeRecord;
}) as IEncodeFeature[];
// console.log('mappedData', mappedData)
// 根据地图的类型判断是否需要对点位数据进行处理
if (this.mapService.version === 'GAODE2.x') {
// 若是高德2.0则需要对坐标进行相对偏移
if (typeof mappedData[0].coordinates[0] === 'number') {
// 单个的点数据
// @ts-ignore
mappedData.map((d) => {
d.version = 'GAODE2.x';
// @ts-ignore
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
// @ts-ignore
d.coordinates = this.mapService.lngLatToCoord(d.coordinates);
});
} else {
// 连续的线、面数据
// @ts-ignore
mappedData.map((d) => {
d.version = 'GAODE2.x';
// @ts-ignore
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
// @ts-ignore
d.coordinates = this.mapService.lngLatToCoords(d.coordinates);
});
}
}
return mappedData;
}
private applyAttributeMapping(

View File

@ -1,6 +1,13 @@
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
import {
ILayer,
ILayerPlugin,
ILngLat,
IMapService,
TYPES,
} from '@antv/l7-core';
import Source from '@antv/l7-source';
import { injectable } from 'inversify';
import { cloneDeep } from 'lodash';
@injectable()
export default class DataSourcePlugin implements ILayerPlugin {

View File

@ -5,6 +5,7 @@ import {
ICoordinateSystemService,
ILayer,
ILayerPlugin,
IMapService,
IRendererService,
TYPES,
} from '@antv/l7-core';
@ -29,13 +30,28 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
@inject(TYPES.IRendererService)
private readonly rendererService: IRendererService;
@inject(TYPES.IMapService)
private readonly mapService: IMapService;
public apply(layer: ILayer) {
const version = this.mapService.version;
let mvp = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; // default matrix (for gaode2.x)
// let sceneCenterMKT = [0, 0]
layer.hooks.beforeRender.tap('ShaderUniformPlugin', () => {
// 重新计算坐标系参数
this.coordinateSystemService.refresh();
if (version === 'GAODE2.x') {
// @ts-ignore
mvp = this.mapService.map.customCoords.getMVPMatrix();
// mvp = amapCustomCoords.getMVPMatrix()
// @ts-ignore
// sceneCenterMKT = this.mapService.getCustomCoordCenter()
}
const { width, height } = this.rendererService.getViewportSize();
layer.models.forEach((model) =>
layer.models.forEach((model) => {
model.addUniforms({
// 相机参数,包含 VP 矩阵、缩放等级
[CameraUniform.ProjectionMatrix]: this.cameraService.getProjectionMatrix(),
@ -52,13 +68,16 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
[CoordinateUniform.PixelsPerDegree]: this.coordinateSystemService.getPixelsPerDegree(),
[CoordinateUniform.PixelsPerDegree2]: this.coordinateSystemService.getPixelsPerDegree2(),
[CoordinateUniform.PixelsPerMeter]: this.coordinateSystemService.getPixelsPerMeter(),
// 坐标系是高德2.0的时候单独计算
[CoordinateUniform.Mvp]: mvp,
// u_SceneCenterMKT: sceneCenterMKT,
// 其他参数例如视口大小、DPR 等
u_ViewportSize: [width, height],
u_DevicePixelRatio: window.devicePixelRatio,
u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
u_PickingBuffer: layer.getLayerConfig().pickingBuffer || 0,
}),
);
});
});
// TODO脏检查决定是否需要渲染
});

View File

@ -11,7 +11,6 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new PointModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {

View File

@ -67,7 +67,7 @@ export default class FillModel extends BaseModel {
vertexShader: pointFillVert,
fragmentShader: pointFillFrag,
triangulation: PointFillTriangulation,
depth: { enable: true },
depth: { enable: false },
blend: this.getBlend(),
}),
];

View File

@ -330,8 +330,7 @@ export default class TextModel extends BaseModel {
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
const data = this.layer.getEncodedData();
this.glyphInfo = data.map((feature: IEncodeFeature) => {
const { shape = '', coordinates, id, size = 1 } = feature;
const { shape = '', id, size = 1 } = feature;
const shaping = shapeText(
shape.toString(),
mapping,
@ -345,17 +344,28 @@ export default class TextModel extends BaseModel {
const glyphQuads = getGlyphQuads(shaping, textOffset, false);
feature.shaping = shaping;
feature.glyphQuads = glyphQuads;
feature.centroid = calculteCentroid(coordinates);
// feature.centroid = calculteCentroid(coordinates);
feature.centroid = calculteCentroid(feature.coordinates);
// if (feature.version === 'GAODE2.x') {
// // 此时地图为高德2.0
// feature.originCentroid = calculteCentroid(feature.originCoordinates);
// } else {
// // 此时地图不是高德2.0 originCentroid == centroid
// feature.originCentroid = feature.centroid;
// }
feature.originCentroid = feature.version === 'GAODE2.x'?calculteCentroid(feature.originCoordinates):feature.originCentroid = feature.centroid;
this.glyphInfoMap[id as number] = {
shaping,
glyphQuads,
centroid: calculteCentroid(coordinates),
centroid: calculteCentroid(feature.coordinates),
};
return feature;
});
}
/**
*
* depend on originCentorid
*/
private filterGlyphs() {
const {
@ -374,7 +384,9 @@ export default class TextModel extends BaseModel {
const collisionIndex = new CollisionIndex(width, height);
const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => {
const { shaping, id = 0 } = feature;
const centroid = feature.centroid as [number, number];
// const centroid = feature.centroid as [number, number];
// const centroid = feature.originCentroid as [number, number];
const centroid = (feature.version === 'GAODE2.x'?feature.originCentroid:feature.centroid) as [number, number];
const size = feature.size as number;
const fontScale: number = size / 24;
const pixels = this.mapService.lngLatToContainer(centroid);

View File

@ -11,6 +11,7 @@ attribute vec3 a_Size;
attribute vec3 a_Normal;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform vec2 u_offsets;
varying vec4 v_color;
@ -30,6 +31,12 @@ void main() {
float lightWeight = calc_lighting(pos);
v_color =vec4(a_Color.rgb * lightWeight, a_Color.w);
gl_Position = project_common_position_to_clipspace(pos);
// gl_Position = project_common_position_to_clipspace(pos);
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * pos;
} else {
gl_Position = project_common_position_to_clipspace(pos);
}
setPickingColor(a_PickingColor);
}

View File

@ -4,6 +4,7 @@ attribute vec2 a_Extrude;
attribute float a_Size;
attribute float a_Shape;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform float u_stroke_width : 2;
uniform vec2 u_offsets;
@ -16,24 +17,16 @@ varying float v_radius;
#pragma include "picking"
void main() {
vec2 extrude = a_Extrude;
float shape_type = a_Shape;
float newSize = setPickingSize(a_Size);
// unpack color(vec2)
v_color = a_Color;
vec2 extrude = a_Extrude;
float shape_type = a_Shape;
float newSize = setPickingSize(a_Size);
// radius(16-bit)
v_radius = newSize;
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
// TODO: billboard
// anti-alias
float antialiasblur = 1.0 / u_DevicePixelRatio / (newSize + u_stroke_width);
@ -41,8 +34,15 @@ void main() {
// construct point coords
v_data = vec4(extrude, antialiasblur,shape_type);
setPickingColor(a_PickingColor);
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
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, project_pixel(setPickingOrder(0.0)), 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * vec4(project_pos.xy + offset, 0.0, 1.0);
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));
}
setPickingColor(a_PickingColor);
}

View File

@ -6,6 +6,7 @@ attribute float a_Size;
varying vec4 v_color;
varying vec2 v_uv;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform float u_stroke_width : 1;
uniform vec2 u_offsets;
varying float v_size;
@ -19,7 +20,14 @@ void main() {
vec4 project_pos = project_position(vec4(a_Position, 1.0));
v_size = a_Size;
vec2 offset = project_pixel(u_offsets);
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0);
} else {
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0));
}
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
setPickingColor(a_PickingColor);

View File

@ -1,6 +1,7 @@
attribute vec3 a_Position;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
attribute float a_Size;
attribute vec4 a_Color;
varying vec4 v_color;
@ -11,9 +12,18 @@ uniform vec2 u_offsets;
#pragma include "picking"
void main() {
v_color = a_Color;
vec2 offset = project_pixel(u_offsets);
vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));
// vec2 offset = project_pixel(u_offsets);
// vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
// gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));\
//
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * vec4(a_Position, 1.0);
} else { // else
vec2 offset = project_pixel(u_offsets);
vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));
}
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
setPickingColor(a_PickingColor);
setPickingColor(a_PickingColor);
}

View File

@ -10,6 +10,7 @@ attribute float a_Rotate;
uniform vec2 u_sdf_map_size;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
varying vec2 v_uv;
varying float v_gamma_scale;
@ -25,15 +26,25 @@ void main() {
// 文本缩放比例
float fontScale = a_Size / FONT_SIZE;
v_fontScale = fontScale;
vec4 project_pos = project_position(vec4(a_Position, 1.0));
v_fontScale = fontScale;
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
highp float angle_sin = sin(a_Rotate);
highp float angle_cos = cos(a_Rotate);
mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
gl_Position = vec4(projected_position.xy / projected_position.w
+ rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
vec4 project_pos = project_position(vec4(a_Position, 1.0));
// vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
highp float angle_sin = sin(a_Rotate);
highp float angle_cos = cos(a_Rotate);
mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
// gl_Position = vec4(projected_position.xy / projected_position.w + rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
vec4 projected_position;
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
projected_position = u_Mvp * (vec4(a_Position.xyz, 1.0));
} else { // else
projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
}
gl_Position = vec4(projected_position.xy / projected_position.w + rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
v_gamma_scale = gl_Position.w;
setPickingColor(a_PickingColor);

View File

@ -9,6 +9,7 @@ attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute float a_Size;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
varying vec4 v_Color;
@ -20,7 +21,14 @@ void main() {
vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0);
vec4 project_pos = project_position(pos);
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
// gl_Position = u_Mvp * (vec4(project_pos.xyz * vec3(1.0, 1.0, -1.0), 1.0));
gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
}
float lightWeight = calc_lighting(pos);
// v_Color = a_Color;

View File

@ -3,6 +3,7 @@ attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute float a_Size;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
varying vec4 v_Color;
@ -12,7 +13,13 @@ varying vec4 v_Color;
void main() {
v_Color = a_Color;
vec4 project_pos = project_position(vec4(a_Position, 1.0));
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
}
setPickingColor(a_PickingColor);
}

View File

@ -115,6 +115,62 @@ export default class ExtrudePolyline {
complex.startIndex = complex.positions.length / 6;
return complex;
}
public extrude1(points: number[][]) {
const complex = this.complex;
if (points.length <= 1) {
return complex;
}
this.lastFlip = -1;
this.started = false;
this.normal = null;
this.totalDistance = 0;
// 去除数组里重复的点
// points = getArrayUnique(points);
const total = points.length;
let count = complex.startIndex;
for (let i = 1; i < total; i++) {
const last = points[i - 1] as vec2;
const cur = points[i] as vec2;
const next = i < points.length - 1 ? points[i + 1] : null;
const amt = this.segment1(complex, count, last, cur, next as vec2);
count += amt;
}
if (this.dash) {
for (let i = 0; i < complex.positions.length / 6; i++) {
complex.positions[i * 6 + 5] = this.totalDistance;
}
}
complex.startIndex = complex.positions.length / 6;
return complex;
}
public extrude2(points: number[][]) {
const complex = this.complex;
if (points.length <= 1) {
return complex;
}
this.lastFlip = -1;
this.started = false;
this.normal = null;
this.totalDistance = 0;
// 去除数组里重复的点
// points = getArrayUnique(points);
const total = points.length;
let count = complex.startIndex;
for (let i = 1; i < total; i++) {
const last = points[i - 1] as vec2;
const cur = points[i] as vec2;
const next = i < points.length - 1 ? points[i + 1] : null;
const amt = this.segment2(complex, count, last, cur, next as vec2);
count += amt;
}
if (this.dash) {
for (let i = 0; i < complex.positions.length / 6; i++) {
complex.positions[i * 6 + 5] = this.totalDistance;
}
}
complex.startIndex = complex.positions.length / 6;
return complex;
}
private segment(
complex: any,
index: number,
@ -329,6 +385,285 @@ export default class ExtrudePolyline {
}
return count;
}
private segment1(
complex: any,
index: number,
last: vec2,
cur: vec2,
next: vec2,
) {
let count = 0;
const indices = complex.indices;
const positions = complex.positions;
const capSquare = this.cap === 'square';
const joinBevel = this.join === 'bevel';
const flatCur = aProjectFlat([cur[0], cur[1]]) as [number, number];
const flatLast = aProjectFlat([last[0], last[1]]) as [number, number];
direction(lineA, flatCur, flatLast);
let segmentDistance = 0;
if (this.dash) {
segmentDistance = this.lineSegmentDistance(flatCur, flatLast);
this.totalDistance += segmentDistance;
}
if (!this.normal) {
this.normal = vec2.create();
computeNormal(this.normal, lineA);
}
if (!this.started) {
this.started = true;
// if the end cap is type square, we can just push the verts out a bit
if (capSquare) {
// vec2.scaleAndAdd(capEnd, last, lineA, -this.thickness);
const out1 = vec2.create();
const out2 = vec2.create();
vec2.add(out1, this.normal, lineA);
vec2.add(out2, this.normal, lineA);
positions.push(
last[0],
last[1],
0,
this.totalDistance - segmentDistance,
-this.thickness,
0,
);
positions.push(
last[0],
last[1],
0,
this.totalDistance - segmentDistance,
this.thickness,
0,
);
} else {
this.extrusionsPosition(
positions,
last,
this.thickness,
this.totalDistance - segmentDistance,
);
}
}
indices.push(index + 0, index + 1, index + 2);
if (!next) {
computeNormal(this.normal, lineA);
if (capSquare) {
const out1 = vec2.create();
const out2 = vec2.create();
vec2.sub(out2, lineA, this.normal);
vec2.add(out1, lineA, this.normal);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness,
0,
);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness,
0,
);
} else {
this.extrusionsPosition(
positions,
cur,
this.thickness,
this.totalDistance,
);
}
indices.push(
...(this.lastFlip === 1
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
count += 2;
} else {
const flatNext = aProjectFlat([next[0], next[1]]) as [number, number];
if (isPointEqual(flatCur, flatNext)) {
vec2.add(
flatNext,
flatCur,
vec2.normalize(flatNext, vec2.subtract(flatNext, flatCur, flatLast)),
);
}
direction(lineB, flatNext, flatCur);
const [miterLen, miter] = computeMiter(
tangent,
vec2.create(),
lineA,
lineB,
this.thickness,
);
let flip = vec2.dot(tangent, this.normal) < 0 ? -1 : 1;
let bevel = joinBevel;
if (!bevel && this.join === 'miter') {
const limit = miterLen;
if (limit > this.miterLimit) {
bevel = true;
}
}
if (bevel) {
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
-this.thickness * flip,
0,
);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness * flip,
0,
);
indices.push(
...(this.lastFlip !== -flip
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
indices.push(index + 2, index + 3, index + 4);
computeNormal(tmp, lineB);
vec2.copy(this.normal, tmp); // store normal for next round
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
-this.thickness * flip,
0,
);
count += 3;
} else {
this.extrusionsPosition(positions, cur, miterLen, this.totalDistance);
indices.push(
...(this.lastFlip === 1
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
flip = -1;
vec2.copy(this.normal, miter);
count += 2;
}
this.lastFlip = flip;
}
return count;
}
private segment2(
complex: any,
index: number,
last: vec2,
cur: vec2,
next: vec2,
) {
let count = 0;
const normals = complex.normals;
const capSquare = this.cap === 'square';
const joinBevel = this.join === 'bevel';
const flatCur = aProjectFlat([cur[0], cur[1]]) as [number, number];
const flatLast = aProjectFlat([last[0], last[1]]) as [number, number];
direction(lineA, flatCur, flatLast);
let segmentDistance = 0;
if (this.dash) {
segmentDistance = this.lineSegmentDistance(flatCur, flatLast);
this.totalDistance += segmentDistance;
}
if (!this.normal) {
this.normal = vec2.create();
computeNormal(this.normal, lineA);
}
if (!this.started) {
this.started = true;
if (capSquare) {
const out1 = vec2.create();
const out2 = vec2.create();
vec2.add(out1, this.normal, lineA);
vec2.add(out2, this.normal, lineA);
normals.push(out2[0], out2[1], 0);
normals.push(out1[0], out1[1], 0);
} else {
this.extrusionsNormal(normals, this.normal);
}
}
if (!next) {
computeNormal(this.normal, lineA);
if (capSquare) {
const out1 = vec2.create();
const out2 = vec2.create();
vec2.sub(out2, lineA, this.normal);
vec2.add(out1, lineA, this.normal);
normals.push(out2[0], out2[1], 0);
normals.push(out1[0], out1[1], 0);
} else {
this.extrusionsNormal(normals, this.normal);
}
count += 2;
} else {
const flatNext = aProjectFlat([next[0], next[1]]) as [number, number];
if (isPointEqual(flatCur, flatNext)) {
vec2.add(
flatNext,
flatCur,
vec2.normalize(flatNext, vec2.subtract(flatNext, flatCur, flatLast)),
);
}
direction(lineB, flatNext, flatCur);
const [miterLen, miter] = computeMiter(
tangent,
vec2.create(),
lineA,
lineB,
this.thickness,
);
let flip = vec2.dot(tangent, this.normal) < 0 ? -1 : 1;
let bevel = joinBevel;
if (!bevel && this.join === 'miter') {
const limit = miterLen;
if (limit > this.miterLimit) {
bevel = true;
}
}
if (bevel) {
normals.push(this.normal[0], this.normal[1], 0);
normals.push(miter[0], miter[1], 0);
computeNormal(tmp, lineB);
vec2.copy(this.normal, tmp); // store normal for next round
normals.push(this.normal[0], this.normal[1], 0);
count += 3;
} else {
this.extrusionsNormal(normals, miter);
flip = -1;
vec2.copy(this.normal, miter);
count += 2;
}
this.lastFlip = flip;
}
return count;
}
private extrusions(
positions: number[],
@ -343,6 +678,20 @@ export default class ExtrudePolyline {
positions.push(point[0], point[1], 0, distanceRadio, -thickness, 0);
positions.push(point[0], point[1], 0, distanceRadio, thickness, 0);
}
private extrusionsPosition(
positions: number[],
point: vec2, // 顶点
thickness: number, // 高度
distanceRadio: number,
) {
positions.push(point[0], point[1], 0, distanceRadio, -thickness, 0);
positions.push(point[0], point[1], 0, distanceRadio, thickness, 0);
}
private extrusionsNormal(normals: number[], normal: vec2) {
// 法向量
normals.push(normal[0], normal[1], 0);
normals.push(normal[0], normal[1], 0);
}
private lineSegmentDistance(b1: vec2, a1: vec2) {
const dx = a1[0] - b1[0];
const dy = a1[1] - b1[1];

View File

@ -25,6 +25,7 @@ import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import { IAMapEvent, IAMapInstance } from '../../typings/index';
import { toPaddingOptions } from '../utils';
import { Version } from '../version';
import './logo.css';
import { MapTheme } from './theme';
import Viewport from './Viewport';
@ -54,6 +55,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12; // 暂时关闭 fix 统一不同坐标
@injectable()
export default class AMapService
implements IMapService<AMap.Map & IAMapInstance> {
public version: string = Version['GAODE1.x'];
/**
*
*/
@ -328,7 +330,7 @@ export default class AMapService
} = this.config;
// 高德地图创建独立的container
// tslint:disable-next-line:typedef
await new Promise((resolve) => {
await new Promise<void>((resolve) => {
const resolveMap = () => {
if (mapInstance) {
this.map = mapInstance as AMap.Map & IAMapInstance;
@ -458,7 +460,6 @@ export default class AMapService
offsetOrigin: [position.x, position.y],
});
const { offsetZoom = LNGLAT_OFFSET_ZOOM_THRESHOLD } = this.config;
// set coordinate system
if (this.viewport.getZoom() > offsetZoom) {
this.coordinateSystemService.setCoordinateSystem(

View File

@ -0,0 +1,124 @@
import { IMapCamera, IViewport } from '@antv/l7-core';
import { mat4, vec3 } from 'gl-matrix';
export default class Viewport implements IViewport {
private projectionMatrix: mat4 = mat4.create();
private viewMatrix: mat4 = mat4.create();
private viewProjectionMatrix: mat4 = mat4.create();
private ViewProjectionMatrixUncentered: mat4 = mat4.create();
private viewUncenteredMatrix: mat4 = mat4.create();
private zoom: number;
private center: number[];
public syncWithMapCamera(mapCamera: Partial<IMapCamera>) {
const {
zoom = 1,
center = [0, 0],
offsetOrigin = [0, 0],
cameraPosition = [0, 0, 0],
up = [0, 1, 0],
lookAt = [0, 0, 0],
aspect = 1,
near = 0.1,
far = 1000,
fov = 0,
} = mapCamera;
this.zoom = zoom;
this.center = center;
// 计算透视投影矩阵 projectionMatrix
mat4.perspective(this.projectionMatrix, fov, aspect, near, far);
// 计算相机矩阵 viewMatrix
const eyePoint = vec3.fromValues(...cameraPosition);
const lookAtPoint = vec3.fromValues(...lookAt);
const upDirect = vec3.fromValues(...up);
mat4.lookAt(this.viewMatrix, eyePoint, lookAtPoint, upDirect);
this.viewUncenteredMatrix = mat4.clone(this.viewMatrix);
// 移动相机位置
mat4.translate(
this.viewMatrix,
this.viewMatrix,
vec3.fromValues(-offsetOrigin[0], offsetOrigin[1], 0),
);
mat4.multiply(
this.viewProjectionMatrix,
this.projectionMatrix,
this.viewMatrix,
);
mat4.multiply(
this.ViewProjectionMatrixUncentered,
this.projectionMatrix,
this.viewMatrix,
);
}
public getZoom(): number {
return this.zoom;
}
public getZoomScale(): number {
// 512 尺寸下的缩放2 ^ 19
return 524288;
}
public getCenter(): [number, number] {
const [lng, lat] = this.center;
return [lng, lat];
}
public getProjectionMatrix(): number[] {
// @ts-ignore
return this.projectionMatrix;
}
public getViewMatrix(): number[] {
// @ts-ignore
return this.viewMatrix;
}
public getViewMatrixUncentered(): number[] {
// @ts-ignore
return this.viewUncenteredMatrix;
}
public getViewProjectionMatrix(): number[] {
// @ts-ignore
return this.viewProjectionMatrix;
}
public getViewProjectionMatrixUncentered(): number[] {
// @ts-ignore
return this.ViewProjectionMatrixUncentered;
}
public getFocalDistance() {
return 1;
}
/**
* P20 scale
*/
public projectFlat(
lngLat: [number, number],
scale?: number | undefined,
): [number, number] {
const maxs = 85.0511287798;
const lat = Math.max(Math.min(maxs, lngLat[1]), -maxs);
// tslint:disable-next-line:no-bitwise
const zoomScale = 256 << 20;
let d = Math.PI / 180;
let x = lngLat[0] * d;
let y = lat * d;
y = Math.log(Math.tan(Math.PI / 4 + y / 2));
const a = 0.5 / Math.PI;
const b = 0.5;
const c = -0.5 / Math.PI;
d = 0.5;
x = zoomScale * (a * x + b) - 215440491;
y = -(zoomScale * (c * y + d) - 106744817);
return [x, y];
}
}

View File

@ -0,0 +1,11 @@
import { IAMapInstance } from '../../typings/index';
import BaseMapWrapper from '../BaseMapWrapper';
import AMapService from './map';
export default class AMapWrapper2 extends BaseMapWrapper<
AMap.Map & IAMapInstance
> {
protected getServiceConstructor() {
return AMapService;
}
}

View File

@ -0,0 +1,3 @@
.amap-logo{
display: none !important;
}

View File

@ -0,0 +1,625 @@
/**
* AMapService
*/
import AMapLoader from '@amap/amap-jsapi-loader';
import {
Bounds,
CoordinateSystem,
ICameraOptions,
ICoordinateSystemService,
IGlobalConfigService,
ILngLat,
ILogService,
IMapConfig,
IMapService,
IMercator,
IPoint,
IStatusOptions,
IViewport,
MapServiceEvent,
MapStyle,
Point,
TYPES,
} from '@antv/l7-core';
import { DOM } from '@antv/l7-utils';
import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import { IAMapEvent, IAMapInstance } from '../../typings/index';
import { toPaddingOptions } from '../utils';
import { Version } from '../version';
import './logo.css';
import { MapTheme } from './theme';
import Viewport from './Viewport';
let mapdivCount = 0;
// @ts-ignore
window.forceWebGL = true;
// const AMAP_API_KEY: string = '15cd8a57710d40c9b7c0e3cc120f1200';
const AMAP_API_KEY: string = 'ff533602d57df6f8ab3b0fea226ae52f';
// const AMAP_VERSION: string = '1.4.15';
const AMAP_VERSION: string = '2.0';
/**
*
*/
const AMAP_SCRIPT_ID: string = 'amap-script';
/**
*
*/
let amapLoaded = false;
/**
*
*/
let pendingResolveQueue: Array<() => void> = [];
/**
* AMapService
*/
@injectable()
export default class AMapService
implements IMapService<AMap.Map & IAMapInstance> {
public version: string = Version['GAODE2.x'];
/**
*
*/
public map: AMap.Map & IAMapInstance;
/**
* customCooords
*/
public sceneCenter!: [number, number]; // 一般使用用户数据的第一个
public sceneCenterMKT!: [number, number]; // 莫卡托
@inject(TYPES.IGlobalConfigService)
private readonly configService: IGlobalConfigService;
@inject(TYPES.ILogService)
private readonly logger: ILogService;
@inject(TYPES.MapConfig)
private readonly config: Partial<IMapConfig>;
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
@inject(TYPES.IEventEmitter)
private eventEmitter: any;
private markerContainer: HTMLElement;
private $mapContainer: HTMLElement | null;
private viewport: Viewport;
private cameraChangedCallback: (viewport: IViewport) => void;
/**
* 2.0
*/
public setCustomCoordCenter(center: [number, number]) {
this.sceneCenter = center;
// @ts-ignore
this.sceneCenterMKT = this.map.getProjection().project(...this.sceneCenter);
}
public getCustomCoordCenter(): [number, number] {
return this.sceneCenterMKT;
}
/**
* 2.0
*/
public lngLatToCoord(lnglat: [number, number]) {
// @ts-ignore
const proj = this.map.getProjection();
const project = proj.project;
// console.log('proj', proj.project)
// 单点
if (!this.sceneCenter) {
// @ts-ignore
this.map.customCoords.setCenter(lnglat);
this.setCustomCoordCenter(lnglat);
}
return this._sub(project(lnglat[0], lnglat[1]), this.sceneCenterMKT);
}
/**
* 线
*/
// public lngLatToCoords(lnglatArray: Array<Array<[number, number]>> | Array<[number, number]>): Array<Array<[number, number]>>|Array<[number, number]> {
public lngLatToCoords(
lnglatArray: number[][][] | number[][],
): number[][][] | number[][] {
// @ts-ignore
return lnglatArray.map((lnglats) => {
if (typeof lnglats[0] === 'number') {
return this.lngLatToCoord(lnglats);
} else {
// @ts-ignore
return lnglats.map((lnglat) => {
return this.lngLatToCoord(lnglat);
});
}
});
}
public addMarkerContainer(): void {
const mapContainer = this.map.getContainer();
if (mapContainer !== null) {
const amap = mapContainer.getElementsByClassName(
'amap-maps',
)[0] as HTMLElement;
this.markerContainer = DOM.create('div', 'l7-marker-container', amap);
}
}
public getMarkerContainer(): HTMLElement {
return this.markerContainer;
}
// map event
public on(type: string, handler: (...args: any[]) => void): void {
if (MapServiceEvent.indexOf(type) !== -1) {
this.eventEmitter.on(type, handler);
} else {
this.map.on(type, handler);
}
}
public off(type: string, handler: (...args: any[]) => void): void {
if (MapServiceEvent.indexOf(type) !== -1) {
this.eventEmitter.off(type, handler);
} else {
this.map.off(type, handler);
}
}
public getContainer(): HTMLElement | null {
return this.map.getContainer();
}
public getMapCanvasContainer(): HTMLElement {
return this.map
.getContainer()
?.getElementsByClassName('amap-maps')[0] as HTMLElement;
}
public getSize(): [number, number] {
const size = this.map.getSize();
return [size.getWidth(), size.getHeight()];
}
public getType() {
return 'amap';
}
public getZoom(): number {
// 统一返回 Mapbox 缩放等级
return this.map.getZoom() - 1;
}
public setZoom(zoom: number): void {
return this.map.setZoom(zoom);
}
public getCenter(options?: ICameraOptions): ILngLat {
if (options?.padding) {
const originCenter = this.getCenter();
const [w, h] = this.getSize();
const padding = toPaddingOptions(options.padding);
const px = this.lngLatToPixel([originCenter.lng, originCenter.lat]);
const offsetPx = [
(padding.right - padding.left) / 2,
(padding.bottom - padding.top) / 2,
];
const newCenter = this.pixelToLngLat([
px.x - offsetPx[0],
px.y - offsetPx[1],
]);
return newCenter;
}
const center = this.map.getCenter();
return {
lng: center.getLng(),
lat: center.getLat(),
};
}
public setCenter(lnglat: [number, number], options?: ICameraOptions): void {
if (options?.padding) {
const padding = toPaddingOptions(options.padding);
const px = this.lngLatToPixel(lnglat);
const offsetPx = [
(padding.right - padding.left) / 2,
(padding.bottom - padding.top) / 2,
];
const newCenter = this.pixelToLngLat([
px.x + offsetPx[0],
px.y + offsetPx[1],
]);
this.map.setCenter([newCenter.lng, newCenter.lat]);
} else {
this.map.setCenter(lnglat);
}
}
public getPitch(): number {
return this.map.getPitch();
}
public getRotation(): number {
// 统一返回逆时针旋转角度
return 360 - this.map.getRotation();
}
public getBounds(): Bounds {
// @ts-ignore
// const amapBound = this.map.getBounds().toBounds();
// const NE = amapBound.getNorthEast();
// const SW = amapBound.getSouthWest();
const bounds = this.map.getBounds();
// console.log('bounds', bounds)
// @ts-ignore
const NE = bounds.getNorthEast();
// @ts-ignore
const SW = bounds.getSouthWest();
const center = this.getCenter();
const maxlng =
center.lng > NE.getLng() || center.lng < SW.getLng()
? 180 - NE.getLng()
: NE.getLng();
const minlng = center.lng < SW.getLng() ? SW.getLng() - 180 : SW.getLng();
// 兼容 Mapbox统一返回西南、东北
return [
[minlng, SW.getLat()],
[maxlng, NE.getLat()],
];
}
public getMinZoom(): number {
const zooms = this.map.get('zooms') as [number, number];
return zooms[0] - 1;
}
public getMaxZoom(): number {
const zooms = this.map.get('zooms') as [number, number];
return zooms[1] - 1;
}
public setRotation(rotation: number): void {
return this.map.setRotation(rotation);
}
public setPitch(pitch: number) {
return this.map.setPitch(pitch);
}
public zoomIn(): void {
this.map.zoomIn();
}
public zoomOut(): void {
this.map.zoomOut();
}
public panTo(p: [number, number]): void {
this.map.panTo(p);
}
public panBy(pixel: [number, number]): void {
this.map.panTo(pixel);
}
public fitBounds(extent: Bounds): void {
this.map.setBounds(
new AMap.Bounds([extent[0][0], extent[0][1], extent[1][0], extent[1][1]]),
);
}
public setZoomAndCenter(zoom: number, center: [number, number]): void {
this.map.setZoomAndCenter(zoom, center);
}
public setMapStyle(style: string): void {
this.map.setMapStyle(this.getMapStyle(style));
}
public setMapStatus(option: Partial<IStatusOptions>): void {
this.map.setStatus(option);
}
public pixelToLngLat(pixel: [number, number]): ILngLat {
const lngLat = this.map.pixelToLngLat(new AMap.Pixel(pixel[0], pixel[1]));
return { lng: lngLat.getLng(), lat: lngLat.getLat() };
}
public lngLatToPixel(lnglat: [number, number]): IPoint {
const p = this.map.lnglatToPixel(new AMap.LngLat(lnglat[0], lnglat[1]));
return {
x: p.getX(),
y: p.getY(),
};
}
public containerToLngLat(pixel: [number, number]): ILngLat {
const ll = new AMap.Pixel(pixel[0], pixel[1]);
const lngLat = this.map.containerToLngLat(ll);
return {
lng: lngLat?.getLng(),
lat: lngLat?.getLat(),
};
}
public lngLatToContainer(lnglat: [number, number]): IPoint {
const ll = new AMap.LngLat(lnglat[0], lnglat[1]);
const pixel = this.map.lngLatToContainer(ll);
return {
x: pixel.getX(),
y: pixel.getY(),
};
}
public lngLatToMercator(
lnglat: [number, number],
altitude: number,
): IMercator {
return {
x: 0,
y: 0,
z: 0,
};
}
public getModelMatrix(
lnglat: [number, number],
altitude: number,
rotate: [number, number, number],
scale: [number, number, number] = [1, 1, 1],
origin: IMercator = { x: 0, y: 0, z: 0 },
): number[] {
const flat = this.viewport.projectFlat(lnglat);
// @ts-ignore
const modelMatrix = mat4.create();
mat4.translate(
modelMatrix,
modelMatrix,
vec3.fromValues(flat[0], flat[1], altitude),
);
mat4.scale(
modelMatrix,
modelMatrix,
vec3.fromValues(scale[0], scale[1], scale[2]),
);
mat4.rotateX(modelMatrix, modelMatrix, rotate[0]);
mat4.rotateY(modelMatrix, modelMatrix, rotate[1]);
mat4.rotateZ(modelMatrix, modelMatrix, rotate[2]);
return (modelMatrix as unknown) as number[];
}
public async init(): Promise<void> {
const {
id,
style = 'light',
minZoom = 0,
maxZoom = 18,
token = AMAP_API_KEY,
mapInstance,
plugin = [],
...rest
} = this.config;
// 高德地图创建独立的container
// tslint:disable-next-line:typedef
await new Promise<void>((resolve) => {
const resolveMap = () => {
if (mapInstance) {
this.map = mapInstance as AMap.Map & IAMapInstance;
this.$mapContainer = this.map.getContainer();
setTimeout(() => {
this.map.on('viewchange', this.handleViewChanged);
resolve();
}, 30);
} else {
this.$mapContainer = this.creatAmapContainer(
id as string | HTMLDivElement,
);
const map = new AMap.Map(this.$mapContainer, {
mapStyle: this.getMapStyle(style as string),
zooms: [minZoom, maxZoom],
viewMode: '3D',
...rest,
});
// @ts-ignore
this.map = map;
// 在使用 map.customCoords 的时候必须使用
const mapInitCenter = map.getCenter();
// @ts-ignore
map.customCoords.setCenter([mapInitCenter.lng, mapInitCenter.lat]);
// @ts-ignore
this.setCustomCoordCenter([mapInitCenter.lng, mapInitCenter.lat]);
// 监听地图相机事件
map.on('viewchange', this.handleViewChanged);
setTimeout(() => {
resolve();
}, 10);
}
};
this.viewport = new Viewport();
if (!amapLoaded && !mapInstance) {
if (token === AMAP_API_KEY) {
this.logger.warn(this.configService.getSceneWarninfo('MapToken'));
}
amapLoaded = true;
plugin.push('Map3D');
AMapLoader.load({
key: token, // 申请好的Web端开发者Key首次调用 load 时必填
version: AMAP_VERSION, // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: plugin, // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
resolveMap();
if (pendingResolveQueue.length) {
pendingResolveQueue.forEach((r) => r());
pendingResolveQueue = [];
}
})
.catch((e) => {
throw new Error(e);
});
} else {
if ((amapLoaded && window.AMap) || mapInstance) {
resolveMap();
} else {
pendingResolveQueue.push(resolveMap);
}
}
});
}
public exportMap(type: 'jpg' | 'png'): string {
const renderCanvas = this.getContainer()?.getElementsByClassName(
'amap-layer',
)[0] as HTMLCanvasElement;
const layersPng =
type === 'jpg'
? (renderCanvas?.toDataURL('image/jpeg') as string)
: (renderCanvas?.toDataURL('image/png') as string);
return layersPng;
}
public emit(name: string, ...args: any[]) {
this.eventEmitter.emit(name, ...args);
}
public once(name: string, ...args: any[]) {
this.eventEmitter.once(name, ...args);
}
public destroy() {
this.map.destroy();
// @ts-ignore
delete window.initAMap;
const $jsapi = document.getElementById(AMAP_SCRIPT_ID);
if ($jsapi) {
document.head.removeChild($jsapi);
}
}
public getMapContainer() {
return this.$mapContainer;
}
public onCameraChanged(callback: (viewport: IViewport) => void): void {
this.cameraChangedCallback = callback;
}
public initViewPort() {
// @ts-ignore
const {
// @ts-ignore
fov,
// @ts-ignore
near,
// @ts-ignore
far,
// @ts-ignore
aspect,
// @ts-ignore
position,
// @ts-ignore
lookAt,
// @ts-ignore
up,
// @ts-ignore
} = this.map.customCoords.getCameraParams();
const center = this.map.getCenter();
const zoom = this.map.getZoom();
if (this.cameraChangedCallback) {
this.viewport.syncWithMapCamera({
aspect,
far,
fov,
cameraPosition: position,
lookAt,
near,
up,
// AMap 定义的缩放等级 与 Mapbox 相差 1
zoom: zoom - 1, // 与amap1.x对比相差一个级别
center: [center.getLat(), center.getLng()],
offsetOrigin: [position[0], position[1]],
});
// set coordinate system
this.coordinateSystemService.setCoordinateSystem(CoordinateSystem.P20_2);
this.cameraChangedCallback(this.viewport);
}
}
private _sub(a: number[] | vec3 | vec2, b: number[]): [number, number] {
const r: [number, number] = [0, 0];
r[0] = a[0] - b[0];
r[1] = a[1] - b[1];
return r;
}
/**
*
* @param e
*/
private handleViewChanged = (e: any): void => {
// @ts-ignore
const {
// @ts-ignore
fov,
// @ts-ignore
near,
// @ts-ignore
far,
// @ts-ignore
aspect,
// @ts-ignore
position,
// @ts-ignore
lookAt,
// @ts-ignore
up,
// @ts-ignore
} = this.map.customCoords.getCameraParams();
const { zoom } = e;
// console.log('zoom', zoom, this.map.getZoom())
const center = this.map.getCenter();
if (this.cameraChangedCallback) {
// resync viewport
this.viewport.syncWithMapCamera({
aspect,
far,
fov,
cameraPosition: position,
lookAt,
up,
near,
// AMap 定义的缩放等级 与 Mapbox 相差 1
zoom: zoom - 1, // 与amap1.x对比相差一个级别
center: [center.getLat(), center.getLng()],
offsetOrigin: [position[0], position[1]],
});
// set coordinate system
this.coordinateSystemService.setCoordinateSystem(CoordinateSystem.P20_2);
this.cameraChangedCallback(this.viewport);
}
};
private getMapStyle(name: string): string {
return MapTheme[name] ? MapTheme[name] : name;
}
private creatAmapContainer(id: string | HTMLDivElement) {
let $wrapper = id as HTMLDivElement;
if (typeof id === 'string') {
$wrapper = document.getElementById(id) as HTMLDivElement;
}
const $amapdiv = document.createElement('div');
$amapdiv.style.cssText += `
position: absolute;
top: 0;
height: 100%;
width: 100%;
`;
$amapdiv.id = 'l7_amap_div' + mapdivCount++;
$wrapper.appendChild($amapdiv);
return $amapdiv;
}
}

View File

@ -0,0 +1,8 @@
export const MapTheme: {
[key: string]: any;
} = {
dark: 'amap://styles/2a09079c3daac9420ee53b67307a8006?isPublic=true',
light: 'amap://styles/1fd9f8ef9751298f11f5c56968312c70?isPublic=true',
normal: 'amap://styles/normal',
blank: 'amap://styles/07c17002b38775b32a7a76c66cf90e99?isPublic=true',
};

View File

@ -1,5 +1,6 @@
import GaodeMap from './amap/';
import GaodeMap2 from './amap2/';
import Map from './map/';
import Mapbox from './mapbox/';
export { GaodeMap, Mapbox, Map };
export { GaodeMap, GaodeMap2, Mapbox, Map };

View File

@ -22,7 +22,7 @@ import { Map } from '@antv/l7-map';
import { DOM } from '@antv/l7-utils';
import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import { Version } from '../version';
import Viewport from './Viewport';
const EventMap: {
[key: string]: any;
@ -40,6 +40,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
*/
@injectable()
export default class L7MapService implements IMapService<Map> {
public version: string = Version.L7MAP;
public map: Map;
@inject(TYPES.MapConfig)

View File

@ -22,10 +22,10 @@ import { DOM } from '@antv/l7-utils';
import { mat4, vec2, vec3 } from 'gl-matrix';
import { inject, injectable } from 'inversify';
import mapboxgl, { IControl, Map } from 'mapbox-gl';
// tslint:disable-next-line:no-submodule-imports
import 'mapbox-gl/dist/mapbox-gl.css';
import { IMapboxInstance } from '../../typings/index';
import { Version } from '../version';
import Viewport from './Viewport';
window.mapboxgl = mapboxgl;
const EventMap: {
@ -47,6 +47,7 @@ const MAPBOX_API_KEY =
@injectable()
export default class MapboxService
implements IMapService<Map & IMapboxInstance> {
public version: string = Version.MAPBOX;
public map: Map & IMapboxInstance;
@inject(TYPES.MapConfig)

View File

@ -0,0 +1,9 @@
/**
* L7
*/
export enum Version {
'GAODE1.x' = 'GAODE1.x',
'GAODE2.x' = 'GAODE2.x',
'MAPBOX' = 'MAPBOX',
'L7MAP' = 'L7MAP',
}

View File

@ -17,8 +17,15 @@ interface IAMapEvent {
};
}
interface CustomCoords {
getCameraParams(): void;
getCenter(): void;
getMVPMatrix(): void;
[other:string]:any
}
interface IAMapInstance {
get(key: string): unknown;
customCoords?: CustomCoords;
}
interface IMapboxInstance {

View File

@ -28,6 +28,7 @@ import { getParser, getTransform } from './';
import { cluster } from './transform/cluster';
import { statMap } from './utils/statistics';
import { getColumn } from './utils/util';
function mergeCustomizer(objValue: any, srcValue: any) {
if (Array.isArray(srcValue)) {
return srcValue;
@ -54,6 +55,7 @@ export default class Source extends EventEmitter {
zoom: -99,
method: 'count',
};
private readonly mapService: IMapService;
// 原始数据
private originData: any;
@ -66,7 +68,6 @@ export default class Source extends EventEmitter {
super();
// this.rawData = cloneDeep(data);
this.originData = data;
this.initCfg(cfg);
this.hooks.init.tap('parser', () => {
@ -204,6 +205,7 @@ export default class Source extends EventEmitter {
const trans = this.transforms;
trans.forEach((tran: ITransform) => {
const { type } = tran;
const data = getTransform(type)(this.data, tran);
Object.assign(this.data, data);
});

View File

@ -0,0 +1,88 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
export default class Amap2demo extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
center: [121.107846, 30.267069],
pitch: 0,
style: 'normal',
zoom: 13,
animateEnable: false,
}),
});
let originData = [
{
lng: 121.107846,
lat: 30.267069,
},
{
lng: 121.1,
lat: 30.267069,
},
{
lng: 120.107846,
lat: 30.267069,
},
{
lng: 38.54,
lat: 77.02,
},
];
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
const layer = new PointLayer()
.source(originData, {
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
})
.shape('circle')
// .shape('normal')
.color('rgba(255, 0, 0, 0.9)')
.size(10)
.style({
stroke: '#fff',
storkeWidth: 2,
})
.active(true);
scene.addLayer(layer);
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -0,0 +1,74 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, LineLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
export default class Amap2demo_arcLine extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
pitch: 0,
center: [107.77791556935472, 35.443286920228644],
zoom: 2.9142882493605033,
}),
});
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
fetch(
'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt',
)
.then((res) => res.text())
.then((data) => {
const layer = new LineLayer({})
.source(data, {
parser: {
type: 'csv',
x: 'lng1',
y: 'lat1',
x1: 'lng2',
y1: 'lat2',
},
})
.size(1)
.shape('arc')
.color('#8C1EB2')
.style({
opacity: 0.8,
blur: 0.99,
});
scene.addLayer(layer);
});
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -0,0 +1,84 @@
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
export default class Amapdemo_extrude extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
center: [121.107846, 30.267069],
pitch: 35.210526315789465,
style: 'normal',
zoom: 8,
animateEnable: false,
}),
});
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
fetch(
'https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json',
)
.then((res) => res.json())
.then((data) => {
const pointLayer = new PointLayer({})
.source(data.list, {
parser: {
type: 'json',
x: 'j',
y: 'w',
},
})
.shape('cylinder')
.size('t', function(level) {
return [1, 2, level * 2 + 20];
})
.active(true)
.color('t', [
'#094D4A',
'#146968',
'#1D7F7E',
'#289899',
'#34B6B7',
'#4AC5AF',
'#5FD3A6',
'#7BE39E',
'#A1EDB8',
'#CEF8D6',
])
.style({
opacity: 1.0,
});
scene.addLayer(pointLayer);
});
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -0,0 +1,80 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
export default class Amap2demo_image extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
pitch: 0,
style: 'light',
center: [121.434765, 31.256735],
zoom: 14.83,
}),
});
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
fetch(
'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json',
)
.then((res) => res.json())
.then((data) => {
scene.addImage(
'00',
'https://gw.alipayobjects.com/zos/basement_prod/604b5e7f-309e-40db-b95b-4fac746c5153.svg',
);
scene.addImage(
'01',
'https://gw.alipayobjects.com/zos/basement_prod/30580bc9-506f-4438-8c1a-744e082054ec.svg',
);
scene.addImage(
'02',
'https://gw.alipayobjects.com/zos/basement_prod/7aa1f460-9f9f-499f-afdf-13424aa26bbf.svg',
);
const imageLayer = new PointLayer()
.source(data, {
parser: {
type: 'json',
x: 'longitude',
y: 'latitude',
},
})
.shape('name', ['00', '01', '02'])
.size(20);
scene.addLayer(imageLayer);
});
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -0,0 +1,140 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { DrawPolygon } from '@antv/l7-draw';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
function convertRGB2Hex(rgb: number[]) {
return (
'#' + rgb.map((r) => ('0' + Math.floor(r).toString(16)).slice(-2)).join('')
);
}
export default class Amap2demo_polygon extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
// 'https://gw.alipayobjects.com/os/basement_prod/f79485d8-d86f-4bb3-856d-537b586be06e.json',
'https://gw.alipayobjects.com/os/basement_prod/619a6f16-ecb0-4fca-9f9a-b06b67f6f02b.json',
);
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
pitch: 0,
// style: 'dark',
center: [-44.40673828125, -18.375379094031825],
zoom: 13,
}),
});
this.scene = scene;
const data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'MultiPolygon',
coordinates: [
[
[
[110.5224609375, 32.731840896865684],
[113.0712890625, 32.731840896865684],
[113.0712890625, 34.56085936708384],
[110.5224609375, 34.56085936708384],
[110.5224609375, 32.731840896865684],
],
[
[111.26953125, 33.52307880890422],
[111.26953125, 34.03445260967645],
[112.03857421875, 34.03445260967645],
[112.03857421875, 33.52307880890422],
[111.26953125, 33.52307880890422],
],
],
[
[
[115.04882812499999, 34.379712580462204],
[114.9609375, 33.46810795527896],
[115.8837890625, 33.50475906922609],
[115.86181640625001, 34.379712580462204],
[115.04882812499999, 34.379712580462204],
],
],
],
},
},
{
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: [
[
[113.8623046875, 30.031055426540206],
[116.3232421875, 30.031055426540206],
[116.3232421875, 31.090574094954192],
[113.8623046875, 31.090574094954192],
[113.8623046875, 30.031055426540206],
],
[
[117.26806640625, 32.13840869677249],
[118.36669921875, 32.13840869677249],
[118.36669921875, 32.47269502206151],
[117.26806640625, 32.47269502206151],
[117.26806640625, 32.13840869677249],
],
],
},
},
],
};
const layer = new PolygonLayer({
autoFit: true,
})
.source(data)
.shape('fill')
.color('red')
.style({
opacity: 1.0,
});
scene.addLayer(layer);
const layer2 = new PolygonLayer({
autoFit: true,
})
.source(data)
.shape('line')
.color('#000')
.style({
opacity: 1.0,
});
scene.addLayer(layer2);
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,132 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { DrawPolygon } from '@antv/l7-draw';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
function convertRGB2Hex(rgb: number[]) {
return (
'#' + rgb.map((r) => ('0' + Math.floor(r).toString(16)).slice(-2)).join('')
);
}
export default class Amap2demo_polygon_extrude extends React.Component {
private gui: dat.GUI;
private $stats: Node;
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const response = await fetch(
// 'https://gw.alipayobjects.com/os/basement_prod/f79485d8-d86f-4bb3-856d-537b586be06e.json',
'https://gw.alipayobjects.com/os/basement_prod/619a6f16-ecb0-4fca-9f9a-b06b67f6f02b.json',
);
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
pitch: 0,
// style: 'dark',
center: [-44.40673828125, -18.375379094031825],
zoom: 13,
}),
});
this.scene = scene;
const data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'MultiPolygon',
coordinates: [
[
[
[110.5224609375, 32.731840896865684],
[113.0712890625, 32.731840896865684],
[113.0712890625, 34.56085936708384],
[110.5224609375, 34.56085936708384],
[110.5224609375, 32.731840896865684],
],
[
[111.26953125, 33.52307880890422],
[111.26953125, 34.03445260967645],
[112.03857421875, 34.03445260967645],
[112.03857421875, 33.52307880890422],
[111.26953125, 33.52307880890422],
],
],
[
[
[115.04882812499999, 34.379712580462204],
[114.9609375, 33.46810795527896],
[115.8837890625, 33.50475906922609],
[115.86181640625001, 34.379712580462204],
[115.04882812499999, 34.379712580462204],
],
],
],
},
},
{
type: 'Feature',
properties: {},
geometry: {
type: 'Polygon',
coordinates: [
[
[113.8623046875, 30.031055426540206],
[116.3232421875, 30.031055426540206],
[116.3232421875, 31.090574094954192],
[113.8623046875, 31.090574094954192],
[113.8623046875, 30.031055426540206],
],
[
[117.26806640625, 32.13840869677249],
[118.36669921875, 32.13840869677249],
[118.36669921875, 32.47269502206151],
[117.26806640625, 32.47269502206151],
[117.26806640625, 32.13840869677249],
],
],
},
},
],
};
const layer = new PolygonLayer({
autoFit: true,
})
.source(data)
// .shape('fill')
.shape('extrude')
.color('red')
.size(6000000)
.style({
opacity: 1.0,
})
.active(true);
scene.addLayer(layer);
}
public render() {
return (
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
);
}
}

View File

@ -0,0 +1,80 @@
import { vec2, vec3 } from 'gl-matrix';
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
import { mat4 } from 'gl-matrix';
export default class Amap2demo_text extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap2({
center: [120.19382669582967, 30.258134],
pitch: 0,
style: 'light',
zoom: 3,
}),
});
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
fetch(
'https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json',
)
.then((res) => res.json())
.then((data) => {
const pointLayer = new PointLayer({})
.source(data.list, {
parser: {
type: 'json',
x: 'j',
y: 'w',
},
})
.shape('m', 'text')
.size(12)
.color('w', ['#0e0030', '#0e0030', '#0e0030'])
.style({
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
spacing: 2, // 字符间距
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
stroke: '#ffffff', // 描边颜色
strokeWidth: 0.3, // 描边宽度
strokeOpacity: 1.0,
// textAllowOverlap: true
});
scene.addLayer(pointLayer);
});
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -0,0 +1,84 @@
// @ts-ignore
import { ILngLat, PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { GaodeMap, GaodeMap2 } from '@antv/l7-maps';
import * as React from 'react';
export default class Amapdemo_extrude extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [121.107846, 30.267069],
pitch: 35.210526315789465,
style: 'normal',
zoom: 8,
animateEnable: false,
}),
});
this.scene = scene;
scene.on('loaded', () => {
console.log('event test');
fetch(
'https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json',
)
.then((res) => res.json())
.then((data) => {
const pointLayer = new PointLayer({})
.source(data.list, {
parser: {
type: 'json',
x: 'j',
y: 'w',
},
})
.shape('cylinder')
.size('t', function(level) {
return [1, 2, level * 2 + 20];
})
.active(true)
.color('t', [
'#094D4A',
'#146968',
'#1D7F7E',
'#289899',
'#34B6B7',
'#4AC5AF',
'#5FD3A6',
'#7BE39E',
'#A1EDB8',
'#CEF8D6',
])
.style({
opacity: 1.0,
});
scene.addLayer(pointLayer);
});
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -18,7 +18,7 @@ export default class GaodeMapComponent extends React.Component {
center: [121.107846, 30.267069],
pitch: 0,
style: 'normal',
zoom: 11,
zoom: 13,
animateEnable: false,
}),
});
@ -30,6 +30,18 @@ export default class GaodeMapComponent extends React.Component {
lng: 121.107846,
lat: 30.267069,
},
{
lng: 121.1,
lat: 30.267069,
},
{
lng: 120.107846,
lat: 30.267069,
},
{
lng: 38.54,
lat: 77.02,
},
],
{
parser: {
@ -40,6 +52,7 @@ export default class GaodeMapComponent extends React.Component {
},
)
.shape('circle')
// .shape('normal')
.color('blue')
.size(10)
.style({
@ -51,27 +64,25 @@ export default class GaodeMapComponent extends React.Component {
this.scene = scene;
scene.on('loaded', () => {
const padding = {
top: 50,
right: 0,
bottom: 200,
left: 800,
};
// const padding = {
// top: 50,
// right: 0,
// bottom: 200,
// left: 800,
// };
// const px = scene.lngLatToPixel([center.lng, center.lat]);
// const offsetPx = [
// (padding.right - padding.left) / 2,
// (padding.bottom - padding.top) / 2,
// ];
scene.setCenter([121.107846, 30.267069], { padding });
// scene.setCenter([121.107846, 30.267069], { padding });
// const newCenter = scene.pixelToLngLat([
// px.x + offsetPx[0],
// px.y + offsetPx[1],
// ]);
// @ts-ignore
// scene.setCenter();
// get originCenter
// const originCenter = scene.getCenter();
// const originPx = scene.lngLatToPixel([
// originCenter.lng,
@ -85,7 +96,6 @@ export default class GaodeMapComponent extends React.Component {
// originPx.x - offsetPx[0],
// originPx.y - offsetPx[1],
// ]);
// lngLatToContainer
// 获取当前地图像素坐标
// console.log(originCenter, center, newCenter2);
@ -106,7 +116,7 @@ export default class GaodeMapComponent extends React.Component {
bottom: 0,
}}
/>
<div
{/* <div
style={{
position: 'absolute',
bottom: '0px',
@ -115,8 +125,8 @@ export default class GaodeMapComponent extends React.Component {
height: '200px',
width: '100%',
}}
/>
<div
/> */}
{/* <div
style={{
position: 'absolute',
top: '0px',
@ -135,7 +145,7 @@ export default class GaodeMapComponent extends React.Component {
height: '100%',
width: '800px',
}}
/>
/> */}
</>
);
}

View File

@ -1,6 +1,24 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import MapCenter from './components/mapCenter';
import Amap2demo from './components/amap2demo'
import Amap2demo_extrude from './components/amap2demo_extrude'
import Amapdemo_extrude from './components/amapdemo_extrude'
import Amap2demo_text from './components/amap2demo_text'
import Amap2demo_image from './components/amap2demo_image'
import Amap2demo_polygon from './components/amap2demo_polygon'
import Amap2demo_polygon_extrude from './components/amap2demo_polygon_extrude'
import Amap2demo_arcLine from "./components/amap2demo_arcLine"
// @ts-ignore
storiesOf('地图方法', module).add('地图中心点', () => <MapCenter />);
storiesOf('地图方法', module)
.add('高德地图 point/demo', () => <MapCenter />)
.add('高德地图2.0 point/demo', () => <Amap2demo />)
.add('高德地图 point/extrude', () => <Amapdemo_extrude />)
.add('高德地图2.0 point/extrude', () => <Amap2demo_extrude />)
.add('高德地图2.0 point/text', () => <Amap2demo_text />)
.add('高德地图2.0 point/image', () => <Amap2demo_image />)
.add('高德地图2.0 polygon', () => <Amap2demo_polygon />)
.add('高德地图2.0 polygon_extrude', () => <Amap2demo_polygon_extrude />)
.add('高德地图2.0 line_arc', () => <Amap2demo_arcLine />)