mirror of https://gitee.com/antv-l7/antv-l7
Shihui dev (#784)
* feat: add getModelMatrix into viewport * feat: 新增地球模式 (初步构建) * feat: 完善地球交互 * style: lint style * feat: 调整地球图层缩放的方向 * style: lint style * feat: 增加地球模式的 pointLayer/fill 图层 * style: lint style * feat: 增加地球、太阳的简单运动系统,优化部分代码结构
This commit is contained in:
parent
a0bf0ebaab
commit
0bcc822cdd
|
@ -10,7 +10,7 @@
|
|||
"@antv/gatsby-theme-antv": "^1.1.1",
|
||||
"@antv/l7-district": "^2.3.9",
|
||||
"@antv/l7-draw": "^2.3.40",
|
||||
"@antv/l7-react": "^2.3.2",
|
||||
"@antv/l7-react": "^2.3.3",
|
||||
"@babel/cli": "^7.6.4",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.6.0",
|
||||
|
@ -196,5 +196,6 @@
|
|||
},
|
||||
"tnpm": {
|
||||
"mode": "yarn"
|
||||
}
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ export default class CameraService implements ICameraService {
|
|||
return this.jitteredProjectionMatrix || this.viewport.getProjectionMatrix();
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return this.viewport.getModelMatrix();
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
return this.viewport.getViewMatrix();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export const CameraUniform = {
|
|||
export interface IViewport {
|
||||
syncWithMapCamera(mapCamera: Partial<IMapCamera>): void;
|
||||
getProjectionMatrix(): number[];
|
||||
getModelMatrix(): number[];
|
||||
getViewMatrix(): number[];
|
||||
getViewMatrixUncentered(): number[];
|
||||
getViewProjectionMatrixUncentered(): number[];
|
||||
|
|
|
@ -71,6 +71,9 @@ export interface ILayerModel {
|
|||
initModels(): IModel[];
|
||||
needUpdate(): boolean;
|
||||
clearModels(): void;
|
||||
|
||||
// earth mode
|
||||
setEarthTime?(time: number): void;
|
||||
}
|
||||
export interface IModelUniform {
|
||||
[key: string]: IUniform;
|
||||
|
@ -261,6 +264,13 @@ export interface ILayer {
|
|||
|
||||
// 增加加载模型的动画混合器
|
||||
addAnimateMixer?(mixer: AnimationMixer): void;
|
||||
|
||||
/**
|
||||
* 地球模式相关的方法
|
||||
*/
|
||||
|
||||
// 设置当前地球时间 控制太阳角度
|
||||
setEarthTime(time: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,7 +346,16 @@ export interface ILayerConfig {
|
|||
* 开启光照
|
||||
*/
|
||||
enableLighting: boolean;
|
||||
|
||||
/**
|
||||
* 动画参数
|
||||
*/
|
||||
animateOption: Partial<IAnimateOption>;
|
||||
|
||||
/**
|
||||
* 地球模式参数
|
||||
*/
|
||||
globelOtions: any;
|
||||
/**
|
||||
* layer point text 是否是 iconfont 模式
|
||||
*/
|
||||
|
|
|
@ -94,6 +94,16 @@ export interface IMapService<RawMap = {}> {
|
|||
// lngLatToCoords?(lnglatArray: any): any;
|
||||
getCustomCoordCenter?(): [number, number];
|
||||
exportMap(type: 'jpg' | 'png'): string;
|
||||
|
||||
// 地球模式下的地图方法/属性
|
||||
rotateY?(
|
||||
option:
|
||||
| {
|
||||
force?: boolean;
|
||||
reg?: number;
|
||||
}
|
||||
| undefined,
|
||||
): void;
|
||||
}
|
||||
|
||||
export const MapServiceEvent = ['mapload'];
|
||||
|
|
|
@ -989,6 +989,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 继承空方法
|
||||
* @param time
|
||||
*/
|
||||
public setEarthTime(time: number) {
|
||||
console.warn('empty fn');
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { IEncodeFeature } from '@antv/l7-core';
|
||||
import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
|
||||
import earcut from 'earcut';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
// @ts-ignore
|
||||
import { mat4, vec3 } from 'gl-matrix';
|
||||
import ExtrudePolyline from '../utils/extrude_polyline';
|
||||
import { calculateCentroid } from '../utils/geo';
|
||||
import extrudePolygon, {
|
||||
|
@ -20,6 +21,10 @@ interface IGeometryCache {
|
|||
[key: string]: IExtrudeGeomety;
|
||||
}
|
||||
const GeometryCache: IGeometryCache = {};
|
||||
|
||||
// 地球网格半径
|
||||
const EARTH_RADIUS = 100;
|
||||
const EARTH_SEGMENTS = 36;
|
||||
/**
|
||||
* 计算2D 填充点图顶点
|
||||
* @param feature 映射feature
|
||||
|
@ -33,6 +38,39 @@ export function PointFillTriangulation(feature: IEncodeFeature) {
|
|||
size: coordinates.length,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* 计算2D 填充点图顶点 (地球模式)
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function GlobelPointFillTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = calculateCentroid(feature.coordinates);
|
||||
const xyz = lglt2xyz(coordinates as [number, number]);
|
||||
return {
|
||||
vertices: [...xyz, ...xyz, ...xyz, ...xyz],
|
||||
indices: [0, 1, 2, 2, 3, 0],
|
||||
size: xyz.length,
|
||||
};
|
||||
}
|
||||
|
||||
function torad(deg: number) {
|
||||
return (deg / 180) * Math.acos(-1);
|
||||
}
|
||||
/**
|
||||
* 经纬度转xyz
|
||||
* @param longitude 经度
|
||||
* @param latitude 纬度
|
||||
* @param radius 半径
|
||||
*/
|
||||
function lglt2xyz(lnglat: [number, number]) {
|
||||
// TODO: + Math.PI/2 是为了对齐坐标
|
||||
const lng = torad(lnglat[0]) + Math.PI / 2;
|
||||
const lat = torad(lnglat[1]);
|
||||
|
||||
const z = EARTH_RADIUS * Math.cos(lat) * Math.cos(lng);
|
||||
const x = EARTH_RADIUS * Math.cos(lat) * Math.sin(lng);
|
||||
const y = EARTH_RADIUS * Math.sin(lat);
|
||||
return [x, y, z];
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3D 拉伸点图
|
||||
|
@ -123,7 +161,6 @@ export function polygonTriangulation(feature: IEncodeFeature) {
|
|||
const { coordinates } = feature;
|
||||
const flattengeo = earcut.flatten(coordinates as number[][][]);
|
||||
const { vertices, dimensions, holes } = flattengeo;
|
||||
|
||||
return {
|
||||
indices: earcut(vertices, holes, dimensions),
|
||||
vertices,
|
||||
|
@ -137,7 +174,6 @@ export function PolygonExtrudeTriangulation(feature: IEncodeFeature) {
|
|||
coordinates,
|
||||
true,
|
||||
);
|
||||
|
||||
return {
|
||||
vertices: positions, // [ x, y, z, uv.x,uv.y ]
|
||||
indices: index,
|
||||
|
@ -383,3 +419,134 @@ function addDir(dirX: number, dirY: number) {
|
|||
const y = (dirY + 1) / 2;
|
||||
return [x, y];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建地球三角网格
|
||||
* @returns
|
||||
*/
|
||||
export function earthTriangulation() {
|
||||
const mesh = primitiveSphere(EARTH_RADIUS, { segments: EARTH_SEGMENTS });
|
||||
const { positionsArr, indicesArr, normalArr } = mesh;
|
||||
return {
|
||||
vertices: positionsArr,
|
||||
indices: indicesArr,
|
||||
size: 5,
|
||||
normals: normalArr,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建地球球体网格
|
||||
* @param radius
|
||||
* @param opt
|
||||
* @returns
|
||||
*/
|
||||
function primitiveSphere(
|
||||
radius: number,
|
||||
opt: {
|
||||
segments: number;
|
||||
},
|
||||
) {
|
||||
const matRotY = mat4.create();
|
||||
const matRotZ = mat4.create();
|
||||
const up = vec3.fromValues(0, 1, 0);
|
||||
const tmpVec3 = vec3.fromValues(0, 0, 0);
|
||||
|
||||
opt = opt || {};
|
||||
radius = typeof radius !== 'undefined' ? radius : 1;
|
||||
const segments = typeof opt.segments !== 'undefined' ? opt.segments : 32;
|
||||
|
||||
const totalZRotationSteps = 2 + segments;
|
||||
const totalYRotationSteps = 2 * totalZRotationSteps;
|
||||
|
||||
const indices = [];
|
||||
const indicesArr = [];
|
||||
const positions = [];
|
||||
const positionsArr = [];
|
||||
const normals = [];
|
||||
const normalArr = [];
|
||||
const uvs = [];
|
||||
|
||||
for (
|
||||
let zRotationStep = 0;
|
||||
zRotationStep <= totalZRotationSteps;
|
||||
zRotationStep++
|
||||
) {
|
||||
const normalizedZ = zRotationStep / totalZRotationSteps;
|
||||
const angleZ = normalizedZ * Math.PI;
|
||||
|
||||
for (
|
||||
let yRotationStep = 0;
|
||||
yRotationStep <= totalYRotationSteps;
|
||||
yRotationStep++
|
||||
) {
|
||||
const normalizedY = yRotationStep / totalYRotationSteps;
|
||||
const angleY = normalizedY * Math.PI * 2;
|
||||
|
||||
mat4.identity(matRotZ);
|
||||
mat4.rotateZ(matRotZ, matRotZ, -angleZ);
|
||||
|
||||
mat4.identity(matRotY);
|
||||
mat4.rotateY(matRotY, matRotY, angleY);
|
||||
|
||||
vec3.transformMat4(tmpVec3, up, matRotZ);
|
||||
vec3.transformMat4(tmpVec3, tmpVec3, matRotY);
|
||||
|
||||
vec3.scale(tmpVec3, tmpVec3, -radius);
|
||||
|
||||
positions.push(tmpVec3.slice());
|
||||
positionsArr.push(...tmpVec3.slice());
|
||||
|
||||
vec3.normalize(tmpVec3, tmpVec3);
|
||||
normals.push(tmpVec3.slice());
|
||||
normalArr.push(...tmpVec3.slice());
|
||||
|
||||
uvs.push([normalizedY, 1 - normalizedZ]);
|
||||
|
||||
// position 和 uv 一起存储
|
||||
positionsArr.push(normalizedY, 1 - normalizedZ);
|
||||
}
|
||||
|
||||
if (zRotationStep > 0) {
|
||||
const verticesCount = positions.length;
|
||||
let firstIndex = verticesCount - 2 * (totalYRotationSteps + 1);
|
||||
for (
|
||||
;
|
||||
firstIndex + totalYRotationSteps + 2 < verticesCount;
|
||||
firstIndex++
|
||||
) {
|
||||
indices.push([
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
]);
|
||||
|
||||
indicesArr.push(
|
||||
firstIndex,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
);
|
||||
indices.push([
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
]);
|
||||
indicesArr.push(
|
||||
firstIndex + totalYRotationSteps + 1,
|
||||
firstIndex + 1,
|
||||
firstIndex + totalYRotationSteps + 2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
cells: indices,
|
||||
positions,
|
||||
normals,
|
||||
uvs,
|
||||
positionsArr,
|
||||
indicesArr,
|
||||
normalArr,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import BaseLayer from '../core/BaseLayer';
|
||||
import BaseEarthModel from './models/base';
|
||||
|
||||
export type EarthType = 'base';
|
||||
interface IEarthLayerStyleOptions {
|
||||
setEarthTime(time: number): void;
|
||||
}
|
||||
|
||||
const EarthModels: { [key in EarthType]: any } = {
|
||||
base: BaseEarthModel,
|
||||
};
|
||||
|
||||
export default class EarthLayer extends BaseLayer<IEarthLayerStyleOptions> {
|
||||
public type: string = 'EarthLayer';
|
||||
|
||||
public buildModels() {
|
||||
const shape = 'base';
|
||||
this.layerModel = new EarthModels[shape](this);
|
||||
this.models = this.layerModel.initModels();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前地球时间
|
||||
* @param time
|
||||
*/
|
||||
public setEarthTime(time: number) {
|
||||
if (this.layerModel && this.layerModel.setEarthTime) {
|
||||
this.layerModel.setEarthTime(time);
|
||||
} else {
|
||||
console.error('请在 scene loaded 之后执行该方法!');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
import {
|
||||
AttributeType,
|
||||
BlendType,
|
||||
gl,
|
||||
IEncodeFeature,
|
||||
ILayerConfig,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
ITexture2D,
|
||||
} from '@antv/l7-core';
|
||||
|
||||
import BaseModel, { styleOffset, styleSingle } from '../../core/BaseModel';
|
||||
import { earthTriangulation } from '../../core/triangulation';
|
||||
|
||||
import baseFrag from '../shaders/base_frag.glsl';
|
||||
import baseVert from '../shaders/base_vert.glsl';
|
||||
|
||||
export default class BaseEarthModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
// T: 当前的地球时间 - 控制太阳的方位
|
||||
private earthTime: number = 3.4;
|
||||
private sunX = 1000;
|
||||
private sunY = 1000;
|
||||
private sunZ = 1000;
|
||||
private sunRadius = Math.sqrt(
|
||||
this.sunX * this.sunX + this.sunY * this.sunY + this.sunZ * this.sunZ,
|
||||
);
|
||||
|
||||
public getUninforms(): IModelUniform {
|
||||
const { animateOption, globelOtions } = this.layer.getLayerConfig();
|
||||
if (animateOption?.enable) {
|
||||
// @ts-ignore
|
||||
// T: rotateY 方法只有在地球模式下存在
|
||||
this.mapService.rotateY({
|
||||
reg: 0.002,
|
||||
});
|
||||
this.earthTime += 0.02;
|
||||
|
||||
this.sunY = 10;
|
||||
this.sunX = Math.cos(this.earthTime) * (this.sunRadius - this.sunY);
|
||||
this.sunZ = Math.sin(this.earthTime) * (this.sunRadius - this.sunY);
|
||||
}
|
||||
|
||||
return {
|
||||
u_ambientRatio: globelOtions?.ambientRatio || 0.6, // 环境光
|
||||
u_diffuseRatio: globelOtions?.diffuseRatio || 0.4, // 漫反射
|
||||
u_specularRatio: globelOtions?.specularRatio || 0.1, // 高光反射
|
||||
// u_sunLight: [120, 120, 120],
|
||||
u_sunLight: [this.sunX, this.sunY, this.sunZ],
|
||||
|
||||
u_texture: this.texture,
|
||||
};
|
||||
}
|
||||
|
||||
public setEarthTime(time: number) {
|
||||
this.earthTime = time;
|
||||
|
||||
this.sunY = 10;
|
||||
this.sunX = Math.cos(this.earthTime) * (this.sunRadius - this.sunY);
|
||||
this.sunZ = Math.sin(this.earthTime) * (this.sunRadius - this.sunY);
|
||||
|
||||
this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
public initModels(): IModel[] {
|
||||
const { globelOtions } = this.layer.getLayerConfig();
|
||||
if (globelOtions?.earthTime !== undefined) {
|
||||
this.setEarthTime(globelOtions.earthTime);
|
||||
}
|
||||
|
||||
const source = this.layer.getSource();
|
||||
const { createTexture2D } = this.rendererService;
|
||||
this.texture = createTexture2D({
|
||||
height: 0,
|
||||
width: 0,
|
||||
});
|
||||
source.data.images.then((imageData: HTMLImageElement[]) => {
|
||||
this.texture = createTexture2D({
|
||||
data: imageData[0],
|
||||
width: imageData[0].width,
|
||||
height: imageData[0].height,
|
||||
});
|
||||
this.layerService.renderLayers();
|
||||
});
|
||||
|
||||
return this.buildModels();
|
||||
}
|
||||
|
||||
public clearModels() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public buildModels(): IModel[] {
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'baseEarth',
|
||||
vertexShader: baseVert,
|
||||
fragmentShader: baseFrag,
|
||||
triangulation: earthTriangulation,
|
||||
depth: { enable: true },
|
||||
blend: this.getBlend(),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Size',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const { size = 1 } = feature;
|
||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'normal',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Normal',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.STATIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 3,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
normal: number[],
|
||||
) => {
|
||||
return normal;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'uv',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Uv',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 2,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
return [vertex[3], vertex[4]];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
uniform sampler2D u_texture;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying float v_lightWeight;
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
vec4 color = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y));
|
||||
color.xyz = color.xyz * v_lightWeight;
|
||||
gl_FragColor = color;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec3 a_Normal;
|
||||
attribute vec2 a_Uv;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
// attribute vec2 a_Extrude;
|
||||
// attribute float a_Size;
|
||||
// attribute float a_Shape;
|
||||
|
||||
uniform vec3 u_CameraPosition;
|
||||
uniform mat4 u_ViewProjectionMatrix;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float u_ambientRatio : 0.5;
|
||||
uniform float u_diffuseRatio : 0.3;
|
||||
uniform float u_specularRatio : 0.2;
|
||||
uniform vec3 u_sunLight: [1.0, -10.5, 12.0];
|
||||
|
||||
|
||||
|
||||
float calc_lighting(vec4 pos) {
|
||||
|
||||
vec3 worldPos = vec3(pos * u_ModelMatrix);
|
||||
|
||||
vec3 worldNormal = a_Normal;
|
||||
|
||||
// cal light weight
|
||||
vec3 viewDir = normalize(u_CameraPosition - worldPos);
|
||||
|
||||
vec3 lightDir = normalize(u_sunLight);
|
||||
|
||||
vec3 halfDir = normalize(viewDir+lightDir);
|
||||
// lambert
|
||||
float lambert = dot(worldNormal, lightDir);
|
||||
// specular
|
||||
float specular = pow(max(0.0, dot(worldNormal, halfDir)), 32.0);
|
||||
//sum to light weight
|
||||
float lightWeight = u_ambientRatio + u_diffuseRatio * lambert + u_specularRatio * specular;
|
||||
|
||||
return lightWeight;
|
||||
}
|
||||
|
||||
varying float v_lightWeight;
|
||||
void main() {
|
||||
|
||||
v_texCoord = a_Uv;
|
||||
|
||||
float lightWeight = calc_lighting(vec4(a_Position, 1.0));
|
||||
v_lightWeight = lightWeight;
|
||||
|
||||
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
||||
}
|
|
@ -9,6 +9,8 @@ import PointLayer from './point';
|
|||
import PolygonLayer from './polygon';
|
||||
import RasterLayer from './raster';
|
||||
|
||||
import EarthLayer from './earth';
|
||||
|
||||
// import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
|
||||
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
||||
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
||||
|
@ -137,4 +139,5 @@ export {
|
|||
ImageLayer,
|
||||
RasterLayer,
|
||||
HeatmapLayer,
|
||||
EarthLayer,
|
||||
};
|
||||
|
|
|
@ -75,7 +75,8 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
|
|||
// 其他参数,例如视口大小、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_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
||||
u_ModelMatrix: this.cameraService.getModelMatrix(),
|
||||
u_PickingBuffer: layer.getLayerConfig().pickingBuffer || 0,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -15,17 +15,24 @@ import BaseModel, {
|
|||
styleOffset,
|
||||
styleSingle,
|
||||
} from '../../core/BaseModel';
|
||||
import { PointFillTriangulation } from '../../core/triangulation';
|
||||
import {
|
||||
GlobelPointFillTriangulation,
|
||||
PointFillTriangulation,
|
||||
} from '../../core/triangulation';
|
||||
import pointFillFrag from '../shaders/fill_frag.glsl';
|
||||
import pointFillVert from '../shaders/fill_vert.glsl';
|
||||
|
||||
import { isNumber, isString } from 'lodash';
|
||||
|
||||
import { mat4, vec3 } from 'gl-matrix';
|
||||
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: styleSingle;
|
||||
strokeWidth: styleSingle;
|
||||
stroke: styleColor;
|
||||
strokeOpacity: styleSingle;
|
||||
offsets: styleOffset;
|
||||
isGlobel?: boolean;
|
||||
}
|
||||
// 判断当前使用的 style 中的变量属性是否需要进行数据映射
|
||||
export default class FillModel extends BaseModel {
|
||||
|
@ -36,6 +43,8 @@ export default class FillModel extends BaseModel {
|
|||
strokeWidth = 0,
|
||||
stroke = 'rgba(0,0,0,0)',
|
||||
offsets = [0, 0],
|
||||
// TODO: 判断当前图层是否为地球模式
|
||||
isGlobel = false,
|
||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
|
||||
if (
|
||||
|
@ -85,6 +94,7 @@ export default class FillModel extends BaseModel {
|
|||
});
|
||||
}
|
||||
return {
|
||||
u_globel: this.mapService.version === 'GLOBEL' ? 1 : 0,
|
||||
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
|
||||
u_cellTypeLayout: this.getCellTypeLayout(),
|
||||
|
||||
|
@ -122,13 +132,18 @@ export default class FillModel extends BaseModel {
|
|||
}
|
||||
|
||||
public buildModels(): IModel[] {
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
const isGlobel = this.mapService.version === 'GLOBEL';
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'pointfill',
|
||||
vertexShader: pointFillVert,
|
||||
fragmentShader: pointFillFrag,
|
||||
triangulation: PointFillTriangulation,
|
||||
depth: { enable: false },
|
||||
triangulation: isGlobel
|
||||
? GlobelPointFillTriangulation
|
||||
: PointFillTriangulation,
|
||||
// depth: { enable: false },
|
||||
depth: { enable: isGlobel },
|
||||
blend: this.getBlend(),
|
||||
}),
|
||||
];
|
||||
|
@ -142,6 +157,9 @@ export default class FillModel extends BaseModel {
|
|||
return [option.enable ? 0 : 1.0, option.speed || 1, option.rings || 3, 0];
|
||||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
const isGlobel = this.mapService.version === 'GLOBEL';
|
||||
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'extrude',
|
||||
type: AttributeType.Attribute,
|
||||
|
@ -153,16 +171,57 @@ export default class FillModel extends BaseModel {
|
|||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 2,
|
||||
size: 3,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const extrude = [1, 1, -1, 1, -1, -1, 1, -1];
|
||||
const extrudeIndex = (attributeIdx % 4) * 2;
|
||||
return [extrude[extrudeIndex], extrude[extrudeIndex + 1]];
|
||||
let extrude;
|
||||
// 地球模式
|
||||
if (isGlobel) {
|
||||
const [x, y, z] = vertex;
|
||||
const n1 = vec3.fromValues(0, 0, 1);
|
||||
const n2 = vec3.fromValues(x, 0, z);
|
||||
|
||||
const xzReg =
|
||||
x >= 0 ? vec3.angle(n1, n2) : Math.PI * 2 - vec3.angle(n1, n2);
|
||||
|
||||
const yReg = Math.PI * 2 - Math.asin(y / 100);
|
||||
|
||||
const m = mat4.create();
|
||||
mat4.rotateY(m, m, xzReg);
|
||||
mat4.rotateX(m, m, yReg);
|
||||
|
||||
const v1 = vec3.fromValues(1, 1, 0);
|
||||
vec3.transformMat4(v1, v1, m);
|
||||
vec3.normalize(v1, v1);
|
||||
|
||||
const v2 = vec3.fromValues(-1, 1, 0);
|
||||
vec3.transformMat4(v2, v2, m);
|
||||
vec3.normalize(v2, v2);
|
||||
|
||||
const v3 = vec3.fromValues(-1, -1, 0);
|
||||
vec3.transformMat4(v3, v3, m);
|
||||
vec3.normalize(v3, v3);
|
||||
|
||||
const v4 = vec3.fromValues(1, -1, 0);
|
||||
vec3.transformMat4(v4, v4, m);
|
||||
vec3.normalize(v4, v4);
|
||||
|
||||
extrude = [...v1, ...v2, ...v3, ...v4];
|
||||
} else {
|
||||
// 平面模式
|
||||
extrude = [1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0];
|
||||
}
|
||||
|
||||
const extrudeIndex = (attributeIdx % 4) * 3;
|
||||
return [
|
||||
extrude[extrudeIndex],
|
||||
extrude[extrudeIndex + 1],
|
||||
extrude[extrudeIndex + 2],
|
||||
];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec2 a_Extrude;
|
||||
attribute vec3 a_Extrude;
|
||||
attribute float a_Size;
|
||||
attribute float a_Shape;
|
||||
|
||||
varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样式值传递给片元
|
||||
|
||||
uniform float u_globel;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
|
@ -29,7 +30,7 @@ uniform vec2 u_offsets;
|
|||
|
||||
|
||||
void main() {
|
||||
vec2 extrude = a_Extrude;
|
||||
vec3 extrude = a_Extrude;
|
||||
float shape_type = a_Shape;
|
||||
float newSize = setPickingSize(a_Size);
|
||||
|
||||
|
@ -123,10 +124,11 @@ void main() {
|
|||
float antialiasblur = 1.0 / u_DevicePixelRatio / (newSize + u_stroke_width);
|
||||
|
||||
// construct point coords
|
||||
v_data = vec4(extrude, antialiasblur,shape_type);
|
||||
// TODP: /abs(extrude.x) 是为了兼容地球模式
|
||||
v_data = vec4(extrude.x/abs(extrude.x), extrude.y/abs(extrude.y), antialiasblur,shape_type);
|
||||
|
||||
// vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
|
||||
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + textrueOffsets);
|
||||
vec2 offset = project_pixel(extrude.xy * (newSize + u_stroke_width) + textrueOffsets);
|
||||
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));
|
||||
|
||||
|
@ -136,6 +138,10 @@ void main() {
|
|||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));
|
||||
}
|
||||
|
||||
if(u_globel > 0.0) {
|
||||
gl_Position = u_ViewProjectionMatrix * vec4(a_Position + extrude * newSize * 0.1, 1.0);
|
||||
}
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
|
|
@ -0,0 +1,375 @@
|
|||
import { DOM } from '@antv/l7-utils';
|
||||
import { merge } from 'lodash';
|
||||
import Camera from './camera';
|
||||
import './css/l7.css';
|
||||
import LngLat, { LngLatLike } from './geo/lng_lat';
|
||||
import LngLatBounds, { LngLatBoundsLike } from './geo/lng_lat_bounds';
|
||||
// @ts-ignore
|
||||
import Point, { PointLike } from './geo/point';
|
||||
import BoxZoomHandler from './handler/box_zoom';
|
||||
import HandlerManager from './handler/handler_manager';
|
||||
import KeyboardHandler from './handler/keyboard';
|
||||
|
||||
import ScrollZoomHandler from './handler/scroll_zoom';
|
||||
import DoubleClickZoomHandler from './handler/shim/dblclick_zoom';
|
||||
import DragPanHandler from './handler/shim/drag_pan';
|
||||
import DragRotateHandler from './handler/shim/drag_rotate';
|
||||
import TouchZoomRotateHandler from './handler/shim/touch_zoom_rotate';
|
||||
import { TouchPitchHandler } from './handler/touch';
|
||||
import Hash from './hash';
|
||||
import { IMapOptions } from './interface';
|
||||
import { renderframe } from './util';
|
||||
import { PerformanceUtils } from './utils/performance';
|
||||
import TaskQueue, { TaskID } from './utils/task_queue';
|
||||
type CallBack = (_: number) => void;
|
||||
const defaultMinZoom = -2;
|
||||
const defaultMaxZoom = 22;
|
||||
|
||||
// the default values, but also the valid range
|
||||
const defaultMinPitch = 0;
|
||||
const defaultMaxPitch = 60;
|
||||
|
||||
const DefaultOptions: IMapOptions = {
|
||||
hash: false,
|
||||
zoom: -1,
|
||||
center: [112, 32],
|
||||
pitch: 0,
|
||||
bearing: 0,
|
||||
interactive: true,
|
||||
minZoom: defaultMinZoom,
|
||||
maxZoom: defaultMaxZoom,
|
||||
minPitch: defaultMinPitch,
|
||||
maxPitch: defaultMaxPitch,
|
||||
scrollZoom: true,
|
||||
boxZoom: true,
|
||||
dragRotate: true,
|
||||
dragPan: true,
|
||||
keyboard: true,
|
||||
doubleClickZoom: true,
|
||||
touchZoomRotate: true,
|
||||
touchPitch: true,
|
||||
bearingSnap: 7,
|
||||
clickTolerance: 3,
|
||||
pitchWithRotate: true,
|
||||
trackResize: true,
|
||||
renderWorldCopies: true,
|
||||
};
|
||||
export class EarthMap extends Camera {
|
||||
public doubleClickZoom: DoubleClickZoomHandler;
|
||||
public dragRotate: DragRotateHandler;
|
||||
public dragPan: DragPanHandler;
|
||||
public touchZoomRotate: TouchZoomRotateHandler;
|
||||
public scrollZoom: ScrollZoomHandler;
|
||||
public keyboard: KeyboardHandler;
|
||||
public touchPitch: TouchPitchHandler;
|
||||
public boxZoom: BoxZoomHandler;
|
||||
public handlers: HandlerManager;
|
||||
|
||||
private container: HTMLElement;
|
||||
private canvas: HTMLCanvasElement;
|
||||
private canvasContainer: HTMLElement;
|
||||
private renderTaskQueue: TaskQueue = new TaskQueue();
|
||||
private frame: { cancel: () => void } | null;
|
||||
private trackResize: boolean = true;
|
||||
private hash: Hash | undefined;
|
||||
constructor(options: Partial<IMapOptions>) {
|
||||
super(merge({}, DefaultOptions, options));
|
||||
this.initContainer();
|
||||
this.resize();
|
||||
this.handlers = new HandlerManager(this, this.options);
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.addEventListener('online', this.onWindowOnline, false);
|
||||
window.addEventListener('resize', this.onWindowResize, false);
|
||||
window.addEventListener('orientationchange', this.onWindowResize, false);
|
||||
}
|
||||
|
||||
const hashName =
|
||||
(typeof options.hash === 'string' && options.hash) || undefined;
|
||||
if (options.hash) {
|
||||
this.hash = new Hash(hashName).addTo(this) as Hash;
|
||||
}
|
||||
|
||||
// don't set position from options if set through hash
|
||||
if (!this.hash || !this.hash.onHashChange()) {
|
||||
this.jumpTo({
|
||||
center: options.center,
|
||||
zoom: options.zoom,
|
||||
bearing: options.bearing,
|
||||
pitch: options.pitch,
|
||||
});
|
||||
|
||||
if (options.bounds) {
|
||||
this.resize();
|
||||
this.fitBounds(
|
||||
options.bounds,
|
||||
merge({}, options.fitBoundsOptions, { duration: 0 }),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public resize(eventData?: any) {
|
||||
const dimensions = this.containerDimensions();
|
||||
const width = dimensions[0];
|
||||
const height = dimensions[1];
|
||||
|
||||
// this.resizeCanvas(width, height);
|
||||
this.transform.resize(width, height);
|
||||
const fireMoving = !this.moving;
|
||||
if (fireMoving) {
|
||||
this.stop();
|
||||
this.emit('movestart', new Event('movestart', eventData));
|
||||
this.emit('move', new Event('move', eventData));
|
||||
}
|
||||
|
||||
this.emit('resize', new Event('resize', eventData));
|
||||
|
||||
if (fireMoving) {
|
||||
this.emit('moveend', new Event('moveend', eventData));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public getContainer() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
public getCanvas() {
|
||||
return this.canvas;
|
||||
}
|
||||
|
||||
public getCanvasContainer() {
|
||||
return this.canvasContainer;
|
||||
}
|
||||
|
||||
public project(lngLat: LngLatLike) {
|
||||
return this.transform.locationPoint(LngLat.convert(lngLat));
|
||||
}
|
||||
|
||||
public unproject(point: PointLike) {
|
||||
return this.transform.pointLocation(Point.convert(point));
|
||||
}
|
||||
|
||||
public getBounds(): LngLatBounds {
|
||||
return this.transform.getBounds();
|
||||
}
|
||||
|
||||
public getMaxBounds(): LngLatBounds | null {
|
||||
return this.transform.getMaxBounds();
|
||||
}
|
||||
|
||||
public setMaxBounds(bounds: LngLatBoundsLike) {
|
||||
this.transform.setMaxBounds(LngLatBounds.convert(bounds));
|
||||
}
|
||||
|
||||
public setStyle(style: any) {
|
||||
return;
|
||||
}
|
||||
public setMinZoom(minZoom?: number) {
|
||||
minZoom =
|
||||
minZoom === null || minZoom === undefined ? defaultMinZoom : minZoom;
|
||||
if (minZoom >= defaultMinZoom && minZoom <= this.transform.maxZoom) {
|
||||
this.transform.minZoom = minZoom;
|
||||
if (this.getZoom() < minZoom) {
|
||||
this.setZoom(minZoom);
|
||||
}
|
||||
|
||||
return this;
|
||||
} else {
|
||||
throw new Error(
|
||||
`minZoom must be between ${defaultMinZoom} and the current maxZoom, inclusive`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getMinZoom() {
|
||||
return this.transform.minZoom;
|
||||
}
|
||||
|
||||
public setMaxZoom(maxZoom?: number) {
|
||||
maxZoom =
|
||||
maxZoom === null || maxZoom === undefined ? defaultMaxZoom : maxZoom;
|
||||
|
||||
if (maxZoom >= this.transform.minZoom) {
|
||||
this.transform.maxZoom = maxZoom;
|
||||
if (this.getZoom() > maxZoom) {
|
||||
this.setZoom(maxZoom);
|
||||
}
|
||||
|
||||
return this;
|
||||
} else {
|
||||
throw new Error('maxZoom must be greater than the current minZoom');
|
||||
}
|
||||
}
|
||||
public getMaxZoom() {
|
||||
return this.transform.maxZoom;
|
||||
}
|
||||
|
||||
public setMinPitch(minPitch?: number) {
|
||||
minPitch =
|
||||
minPitch === null || minPitch === undefined ? defaultMinPitch : minPitch;
|
||||
|
||||
if (minPitch < defaultMinPitch) {
|
||||
throw new Error(
|
||||
`minPitch must be greater than or equal to ${defaultMinPitch}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (minPitch >= defaultMinPitch && minPitch <= this.transform.maxPitch) {
|
||||
this.transform.minPitch = minPitch;
|
||||
if (this.getPitch() < minPitch) {
|
||||
this.setPitch(minPitch);
|
||||
}
|
||||
|
||||
return this;
|
||||
} else {
|
||||
throw new Error(
|
||||
`minPitch must be between ${defaultMinPitch} and the current maxPitch, inclusive`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getMinPitch() {
|
||||
return this.transform.minPitch;
|
||||
}
|
||||
|
||||
public setMaxPitch(maxPitch?: number) {
|
||||
maxPitch =
|
||||
maxPitch === null || maxPitch === undefined ? defaultMaxPitch : maxPitch;
|
||||
|
||||
if (maxPitch > defaultMaxPitch) {
|
||||
throw new Error(
|
||||
`maxPitch must be less than or equal to ${defaultMaxPitch}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (maxPitch >= this.transform.minPitch) {
|
||||
this.transform.maxPitch = maxPitch;
|
||||
if (this.getPitch() > maxPitch) {
|
||||
this.setPitch(maxPitch);
|
||||
}
|
||||
|
||||
return this;
|
||||
} else {
|
||||
throw new Error('maxPitch must be greater than the current minPitch');
|
||||
}
|
||||
}
|
||||
|
||||
public getMaxPitch() {
|
||||
return this.transform.maxPitch;
|
||||
}
|
||||
|
||||
public getRenderWorldCopies() {
|
||||
return this.transform.renderWorldCopies;
|
||||
}
|
||||
|
||||
public setRenderWorldCopies(renderWorldCopies?: boolean) {
|
||||
this.transform.renderWorldCopies = !!renderWorldCopies;
|
||||
}
|
||||
|
||||
public remove() {
|
||||
if (this.frame) {
|
||||
this.frame.cancel();
|
||||
this.frame = null;
|
||||
}
|
||||
this.renderTaskQueue.clear();
|
||||
}
|
||||
|
||||
public requestRenderFrame(cb: CallBack): TaskID {
|
||||
this.update();
|
||||
return this.renderTaskQueue.add(cb);
|
||||
}
|
||||
|
||||
public cancelRenderFrame(id: TaskID) {
|
||||
return this.renderTaskQueue.remove(id);
|
||||
}
|
||||
|
||||
public triggerRepaint() {
|
||||
if (!this.frame) {
|
||||
this.frame = renderframe((paintStartTimeStamp: number) => {
|
||||
PerformanceUtils.frame(paintStartTimeStamp);
|
||||
this.frame = null;
|
||||
this.update(paintStartTimeStamp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public update(time?: number) {
|
||||
if (!this.frame) {
|
||||
this.frame = renderframe((paintStartTimeStamp: number) => {
|
||||
PerformanceUtils.frame(paintStartTimeStamp);
|
||||
this.frame = null;
|
||||
this.renderTaskQueue.run(time);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private initContainer() {
|
||||
if (typeof this.options.container === 'string') {
|
||||
this.container = window.document.getElementById(
|
||||
this.options.container,
|
||||
) as HTMLElement;
|
||||
if (!this.container) {
|
||||
throw new Error(`Container '${this.options.container}' not found.`);
|
||||
}
|
||||
} else if (this.options.container instanceof HTMLElement) {
|
||||
this.container = this.options.container;
|
||||
} else {
|
||||
throw new Error(
|
||||
"Invalid type: 'container' must be a String or HTMLElement.",
|
||||
);
|
||||
}
|
||||
|
||||
const container = this.container;
|
||||
container.classList.add('l7-map');
|
||||
|
||||
const canvasContainer = (this.canvasContainer = DOM.create(
|
||||
'div',
|
||||
'l7-canvas-container',
|
||||
container,
|
||||
));
|
||||
if (this.options.interactive) {
|
||||
canvasContainer.classList.add('l7-interactive');
|
||||
}
|
||||
|
||||
// this.canvas = DOM.create(
|
||||
// 'canvas',
|
||||
// 'l7-canvas',
|
||||
// canvasContainer,
|
||||
// ) as HTMLCanvasElement;
|
||||
// this.canvas.setAttribute('tabindex', '-');
|
||||
// this.canvas.setAttribute('aria-label', 'Map');
|
||||
}
|
||||
|
||||
private containerDimensions(): [number, number] {
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
if (this.container) {
|
||||
width = this.container.clientWidth || 400;
|
||||
height = this.container.clientHeight || 300;
|
||||
}
|
||||
return [width, height];
|
||||
}
|
||||
|
||||
private resizeCanvas(width: number, height: number) {
|
||||
const pixelRatio = DOM.DPR || 1;
|
||||
this.canvas.width = pixelRatio * width;
|
||||
this.canvas.height = pixelRatio * height;
|
||||
|
||||
// Maintain the same canvas size, potentially downscaling it for HiDPI displays
|
||||
this.canvas.style.width = `${width}px`;
|
||||
this.canvas.style.height = `${height}px`;
|
||||
}
|
||||
|
||||
private onWindowOnline = () => {
|
||||
this.update();
|
||||
};
|
||||
|
||||
private onWindowResize = (event: Event) => {
|
||||
if (this.trackResize) {
|
||||
this.resize({ originalEvent: event }).update();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
export interface IHandlerResult {
|
||||
|
@ -8,7 +9,7 @@ export interface IHandlerResult {
|
|||
pitchDelta?: number;
|
||||
around?: Point | null;
|
||||
pinchAround?: Point | null;
|
||||
cameraAnimation?: (map: Map) => any;
|
||||
cameraAnimation?: (map: Map | EarthMap) => any;
|
||||
originalEvent?: any;
|
||||
// Makes the manager trigger a frame; allowing the handler to return multiple results over time (see scrollzoom).
|
||||
needsRenderFrame?: boolean;
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
import { MapMouseEvent, MapTouchEvent, MapWheelEvent } from './events';
|
||||
export default class BlockableMapEventHandler {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private delayContextMenu: boolean;
|
||||
private contextMenuEvent: MouseEvent;
|
||||
|
||||
constructor(map: Map) {
|
||||
constructor(map: Map | EarthMap) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.delayContextMenu = false;
|
||||
// @ts-ignore
|
||||
delete this.contextMenuEvent;
|
||||
}
|
||||
|
||||
|
@ -32,6 +34,7 @@ export default class BlockableMapEventHandler {
|
|||
'contextmenu',
|
||||
new MapMouseEvent('contextmenu', this.map, this.contextMenuEvent),
|
||||
);
|
||||
// @ts-ignore
|
||||
delete this.contextMenuEvent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
import DOM from '../utils/dom';
|
||||
|
@ -9,7 +10,7 @@ import { Event } from './events/event';
|
|||
* The bounding box is defined by clicking and holding `shift` while dragging the cursor.
|
||||
*/
|
||||
class BoxZoomHandler {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private el: HTMLElement;
|
||||
private container: HTMLElement;
|
||||
private enabled: boolean;
|
||||
|
@ -23,7 +24,7 @@ class BoxZoomHandler {
|
|||
* @private
|
||||
*/
|
||||
constructor(
|
||||
map: Map,
|
||||
map: Map | EarthMap,
|
||||
options: {
|
||||
clickTolerance: number;
|
||||
},
|
||||
|
@ -179,8 +180,9 @@ class BoxZoomHandler {
|
|||
}
|
||||
|
||||
DOM.enableDrag();
|
||||
|
||||
// @ts-ignore
|
||||
delete this.startPos;
|
||||
// @ts-ignore
|
||||
delete this.lastPos;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
|
||||
|
@ -17,7 +18,7 @@ export default class ClickZoomHandler {
|
|||
public dblclick(e: MouseEvent, point: Point) {
|
||||
e.preventDefault();
|
||||
return {
|
||||
cameraAnimation: (map: Map) => {
|
||||
cameraAnimation: (map: Map | EarthMap) => {
|
||||
map.easeTo(
|
||||
{
|
||||
duration: 300,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @ts-ignore
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import merge from 'lodash/merge';
|
||||
import { EarthMap } from '../../earthmap';
|
||||
import LngLat from '../../geo/lng_lat';
|
||||
import Point from '../../geo/point';
|
||||
import { Map } from '../../map';
|
||||
|
@ -27,7 +28,7 @@ export default class MapMouseEvent extends Event {
|
|||
/**
|
||||
* The `Map` object that fired the event.
|
||||
*/
|
||||
public target: Map;
|
||||
public target: Map | EarthMap;
|
||||
|
||||
/**
|
||||
* The DOM event which caused the map event.
|
||||
|
@ -51,7 +52,7 @@ export default class MapMouseEvent extends Event {
|
|||
*/
|
||||
constructor(
|
||||
type: string,
|
||||
map: Map,
|
||||
map: Map | EarthMap,
|
||||
originalEvent: MouseEvent,
|
||||
data: any = {},
|
||||
) {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../../earthmap';
|
||||
import LngLat from '../../geo/lng_lat';
|
||||
import Point from '../../geo/point';
|
||||
import { Map } from '../../map';
|
||||
|
@ -13,7 +14,7 @@ export default class MapTouchEvent extends Event {
|
|||
/**
|
||||
* The `Map` object that fired the event.
|
||||
*/
|
||||
public target: Map;
|
||||
public target: Map | EarthMap;
|
||||
|
||||
/**
|
||||
* The DOM event which caused the map event.
|
||||
|
@ -53,7 +54,7 @@ export default class MapTouchEvent extends Event {
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor(type: string, map: Map, originalEvent: TouchEvent) {
|
||||
constructor(type: string, map: Map | EarthMap, originalEvent: TouchEvent) {
|
||||
const touches =
|
||||
type === 'touchend'
|
||||
? originalEvent.changedTouches
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { EarthMap } from '../../earthmap';
|
||||
import { Map } from '../../map';
|
||||
import { Event } from './event';
|
||||
|
||||
export interface IMapBoxZoomEvent {
|
||||
type: 'boxzoomstart' | 'boxzoomend' | 'boxzoomcancel';
|
||||
target: Map;
|
||||
target: Map | EarthMap;
|
||||
originalEvent: MouseEvent;
|
||||
}
|
||||
export default class MapWheelEvent extends Event {
|
||||
|
@ -22,12 +23,12 @@ export default class MapWheelEvent extends Event {
|
|||
/**
|
||||
* The `Map` object that fired the event.
|
||||
*/
|
||||
public target: Map;
|
||||
public target: Map | EarthMap;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor(type: string, map: Map, originalEvent: WheelEvent) {
|
||||
constructor(type: string, map: Map | EarthMap, originalEvent: WheelEvent) {
|
||||
super(type, { originalEvent });
|
||||
this.defaultPrevented = false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import Point from '../geo/point';
|
|||
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import merge from 'lodash/merge';
|
||||
import { EarthMap } from '../earthmap';
|
||||
import { Map } from '../map';
|
||||
import { bezier, clamp, now } from '../util';
|
||||
import { IDragPanOptions } from './shim/drag_pan';
|
||||
|
@ -54,13 +55,13 @@ export interface IInertiaOptions {
|
|||
export type InputEvent = MouseEvent | TouchEvent | KeyboardEvent | WheelEvent;
|
||||
|
||||
export default class HandlerInertia {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private inertiaBuffer: Array<{
|
||||
time: number;
|
||||
settings: { [key: string]: any };
|
||||
}>;
|
||||
|
||||
constructor(map: Map) {
|
||||
constructor(map: Map | EarthMap) {
|
||||
this.map = map;
|
||||
this.clear();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @ts-ignore
|
||||
// tslint:disable-next-line: no-submodule-imports
|
||||
import merge from 'lodash/merge';
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
import DOM from '../utils/dom';
|
||||
|
@ -62,7 +63,7 @@ export interface IHandlerOptions {
|
|||
}
|
||||
|
||||
class HandlerManager {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private el: HTMLElement;
|
||||
private handlers: Array<{
|
||||
handlerName: string;
|
||||
|
@ -82,7 +83,7 @@ class HandlerManager {
|
|||
[HTMLElement, string, void | { passive?: boolean; capture?: boolean }]
|
||||
>;
|
||||
|
||||
constructor(map: Map, options: IHandlerOptions) {
|
||||
constructor(map: Map | EarthMap, options: IHandlerOptions) {
|
||||
this.map = map;
|
||||
this.el = this.map.getCanvasContainer();
|
||||
this.handlers = [];
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { EarthMap } from '../earthmap';
|
||||
import { Map } from '../map';
|
||||
|
||||
const defaultOptions = {
|
||||
|
@ -106,7 +107,7 @@ class KeyboardHandler {
|
|||
}
|
||||
|
||||
return {
|
||||
cameraAnimation: (map: Map) => {
|
||||
cameraAnimation: (map: Map | EarthMap) => {
|
||||
const zoom = map.getZoom();
|
||||
map.easeTo(
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
import { MapMouseEvent, MapTouchEvent, MapWheelEvent } from './events';
|
||||
|
@ -6,14 +7,15 @@ import { MapMouseEvent, MapTouchEvent, MapWheelEvent } from './events';
|
|||
export default class MapEventHandler {
|
||||
private mousedownPos: Point;
|
||||
private clickTolerance: number;
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
|
||||
constructor(map: Map, options: { clickTolerance: number }) {
|
||||
constructor(map: Map | EarthMap, options: { clickTolerance: number }) {
|
||||
this.map = map;
|
||||
this.clickTolerance = options.clickTolerance;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
// @ts-ignore
|
||||
delete this.mousedownPos;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../earthmap';
|
||||
import LngLat from '../geo/lng_lat';
|
||||
import Point from '../geo/point';
|
||||
import { Map } from '../map';
|
||||
|
@ -22,7 +23,7 @@ const maxScalePerFrame = 2;
|
|||
* The `ScrollZoomHandler` allows the user to zoom the map by scrolling.
|
||||
*/
|
||||
class ScrollZoomHandler {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private el: HTMLElement;
|
||||
private enabled: boolean;
|
||||
private active: boolean;
|
||||
|
@ -57,7 +58,7 @@ class ScrollZoomHandler {
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
constructor(map: Map, handler: HandlerManager) {
|
||||
constructor(map: Map | EarthMap, handler: HandlerManager) {
|
||||
this.map = map;
|
||||
this.el = map.getCanvasContainer();
|
||||
this.handler = handler;
|
||||
|
@ -287,7 +288,9 @@ class ScrollZoomHandler {
|
|||
this.finishTimeout = setTimeout(() => {
|
||||
this.zooming = false;
|
||||
this.handler.triggerRenderFrame();
|
||||
// @ts-ignore
|
||||
delete this.targetZoom;
|
||||
// @ts-ignore
|
||||
delete this.finishTimeout;
|
||||
}, 200);
|
||||
}
|
||||
|
@ -325,6 +328,7 @@ class ScrollZoomHandler {
|
|||
|
||||
if (this.finishTimeout) {
|
||||
clearTimeout(this.finishTimeout);
|
||||
// @ts-ignore
|
||||
delete this.finishTimeout;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// @ts-ignore
|
||||
import { EarthMap } from '../../earthmap';
|
||||
import Point from '../../geo/point';
|
||||
import { Map } from '../../map';
|
||||
import TapRecognizer from './tap_recognizer';
|
||||
|
@ -48,7 +49,7 @@ export default class TapZoomHandler {
|
|||
e.preventDefault();
|
||||
setTimeout(() => this.reset(), 0);
|
||||
return {
|
||||
cameraAnimation: (map: Map) =>
|
||||
cameraAnimation: (map: Map | EarthMap) =>
|
||||
map.easeTo(
|
||||
{
|
||||
duration: 300,
|
||||
|
@ -63,7 +64,7 @@ export default class TapZoomHandler {
|
|||
e.preventDefault();
|
||||
setTimeout(() => this.reset(), 0);
|
||||
return {
|
||||
cameraAnimation: (map: Map) =>
|
||||
cameraAnimation: (map: Map | EarthMap) =>
|
||||
map.easeTo(
|
||||
{
|
||||
duration: 300,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @ts-ignore
|
||||
// tslint:disable-next-line:no-submodule-imports
|
||||
import throttle from 'lodash/throttle';
|
||||
import { EarthMap } from './earthmap';
|
||||
import { Map } from './map';
|
||||
|
||||
/*
|
||||
|
@ -10,7 +11,7 @@ import { Map } from './map';
|
|||
* @returns {Hash} `this`
|
||||
*/
|
||||
class Hash {
|
||||
private map: Map;
|
||||
private map: Map | EarthMap;
|
||||
private updateHash: () => number | void;
|
||||
private hashName?: string;
|
||||
|
||||
|
@ -20,17 +21,19 @@ class Hash {
|
|||
// Mobile Safari doesn't allow updating the hash more than 100 times per 30 seconds.
|
||||
this.updateHash = throttle(this.updateHashUnthrottled, (30 * 1000) / 100);
|
||||
}
|
||||
public addTo(map: Map) {
|
||||
public addTo(map: Map | EarthMap) {
|
||||
this.map = map;
|
||||
window.addEventListener('hashchange', this.onHashChange, false);
|
||||
// @ts-ignore
|
||||
this.map.on('moveend', this.updateHash);
|
||||
return this;
|
||||
}
|
||||
public remove() {
|
||||
window.removeEventListener('hashchange', this.onHashChange, false);
|
||||
// @ts-ignore
|
||||
this.map.off('moveend', this.updateHash);
|
||||
// clearTimeout(this.updateHash());
|
||||
|
||||
// @ts-ignore
|
||||
delete this.map;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export * from './map';
|
||||
export * from './earthmap';
|
||||
|
|
|
@ -85,6 +85,10 @@ export default class Viewport implements IViewport {
|
|||
return this.projectionMatrix;
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
// @ts-ignore
|
||||
return this.viewMatrix;
|
||||
|
|
|
@ -97,6 +97,10 @@ export default class Viewport implements IViewport {
|
|||
return this.projectionMatrix;
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
// @ts-ignore
|
||||
return this.viewMatrix;
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
import { IMapCamera, IViewport } from '@antv/l7-core';
|
||||
import { mat4, vec3 } from 'gl-matrix';
|
||||
import WebMercatorViewport from 'viewport-mercator-project';
|
||||
|
||||
export default class Viewport implements IViewport {
|
||||
// TODO: 初始化相机的姿态 看向地球
|
||||
private xzReg: number = -Math.PI * 0.6;
|
||||
private yReg: number = Math.PI * 0.2;
|
||||
// 默认的地球相机半径、地球相机缩放层级
|
||||
private earthCameraRadius: number = 200;
|
||||
private earthCameraZoom: number = 1;
|
||||
|
||||
private cameraPosition: vec3 = vec3.create();
|
||||
|
||||
private viewport: WebMercatorViewport;
|
||||
|
||||
private projectionMatrix: mat4 = mat4.create();
|
||||
private modelMatrix: mat4 = mat4.create();
|
||||
private viewMatrix: mat4 = mat4.create();
|
||||
private viewProjectionMatrix: mat4 = mat4.create();
|
||||
private ViewProjectionMatrixUncentered: mat4 = mat4.create();
|
||||
private viewUncenteredMatrix: mat4 = mat4.create();
|
||||
|
||||
public syncWithMapCamera(mapCamera: Partial<IMapCamera>) {
|
||||
const { viewportHeight = 1, viewportWidth = 1 } = mapCamera;
|
||||
const aspect = viewportWidth / viewportHeight;
|
||||
const near = 0.1;
|
||||
const far = 10000;
|
||||
const fov = 20;
|
||||
|
||||
// 计算透视投影矩阵 projectionMatrix
|
||||
mat4.perspective(this.projectionMatrix, fov, aspect, near, far);
|
||||
// 计算相机矩阵 viewMatrix
|
||||
const x = this.earthCameraRadius * Math.cos(this.xzReg);
|
||||
const z = this.earthCameraRadius * Math.sin(this.xzReg);
|
||||
const y = this.earthCameraRadius * Math.sin(this.yReg);
|
||||
|
||||
this.cameraPosition = vec3.fromValues(x, y, z);
|
||||
vec3.normalize(this.cameraPosition, this.cameraPosition);
|
||||
vec3.multiply(
|
||||
this.cameraPosition,
|
||||
this.cameraPosition,
|
||||
vec3.fromValues(
|
||||
this.earthCameraRadius,
|
||||
this.earthCameraRadius,
|
||||
this.earthCameraRadius,
|
||||
),
|
||||
);
|
||||
|
||||
vec3.scale(this.cameraPosition, this.cameraPosition, this.earthCameraZoom);
|
||||
|
||||
const crossY = vec3.create();
|
||||
vec3.cross(crossY, this.cameraPosition, vec3.fromValues(0, 1, 0));
|
||||
|
||||
const up = vec3.fromValues(0, 1, 0);
|
||||
vec3.cross(up, crossY, this.cameraPosition);
|
||||
|
||||
const target = vec3.fromValues(0, 0, 0);
|
||||
mat4.lookAt(this.viewMatrix, this.cameraPosition, target, up);
|
||||
this.viewUncenteredMatrix = mat4.clone(this.viewMatrix);
|
||||
|
||||
mat4.multiply(
|
||||
this.viewProjectionMatrix,
|
||||
this.projectionMatrix,
|
||||
this.viewMatrix,
|
||||
);
|
||||
mat4.multiply(
|
||||
this.ViewProjectionMatrixUncentered,
|
||||
this.projectionMatrix,
|
||||
this.viewMatrix,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转方法 Y 轴
|
||||
* @param r
|
||||
*/
|
||||
public rotateY(r: number) {
|
||||
this.xzReg += r * Math.min(this.earthCameraZoom * this.earthCameraZoom, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转方法 X 轴
|
||||
* @param r
|
||||
*/
|
||||
public rotateX(r: number) {
|
||||
this.yReg += r * Math.min(this.earthCameraZoom * this.earthCameraZoom, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放方法
|
||||
* @param z
|
||||
*/
|
||||
public scaleZoom(z: number) {
|
||||
this.earthCameraZoom += z;
|
||||
this.earthCameraZoom = Math.max(this.earthCameraZoom, 0.6);
|
||||
}
|
||||
|
||||
public getZoom(): number {
|
||||
return 4;
|
||||
}
|
||||
|
||||
public getZoomScale(): number {
|
||||
return Math.pow(2, this.getZoom());
|
||||
}
|
||||
|
||||
public getCenter(): [number, number] {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
public getProjectionMatrix(): number[] {
|
||||
return this.projectionMatrix as number[];
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return this.modelMatrix as number[];
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
return this.viewMatrix as number[];
|
||||
}
|
||||
|
||||
public getViewMatrixUncentered(): number[] {
|
||||
return this.viewMatrix as number[];
|
||||
}
|
||||
public getViewProjectionMatrix(): number[] {
|
||||
return this.viewProjectionMatrix as number[];
|
||||
}
|
||||
|
||||
public getViewProjectionMatrixUncentered(): number[] {
|
||||
return this.viewProjectionMatrix as number[];
|
||||
}
|
||||
public getFocalDistance() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public projectFlat(
|
||||
lngLat: [number, number],
|
||||
scale?: number | undefined,
|
||||
): [number, number] {
|
||||
return this.viewport.projectFlat(lngLat, scale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { Map } from '@antv/l7-map';
|
||||
import BaseMapWrapper from '../BaseMapWrapper';
|
||||
import MapService from './map';
|
||||
export default class MapboxWrapper extends BaseMapWrapper<Map> {
|
||||
protected getServiceConstructor() {
|
||||
return MapService;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,413 @@
|
|||
/**
|
||||
* MapboxService
|
||||
*/
|
||||
import {
|
||||
Bounds,
|
||||
CoordinateSystem,
|
||||
ICoordinateSystemService,
|
||||
IGlobalConfigService,
|
||||
ILngLat,
|
||||
IMapConfig,
|
||||
IMapService,
|
||||
IMercator,
|
||||
IPoint,
|
||||
IStatusOptions,
|
||||
IViewport,
|
||||
MapServiceEvent,
|
||||
MapStyle,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import { EarthMap, Map } from '@antv/l7-map';
|
||||
import { DOM } from '@antv/l7-utils';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import 'reflect-metadata';
|
||||
import { Version } from '../version';
|
||||
import Viewport from './Viewport';
|
||||
const EventMap: {
|
||||
[key: string]: any;
|
||||
} = {
|
||||
mapmove: 'move',
|
||||
camerachange: 'move',
|
||||
zoomchange: 'zoom',
|
||||
dragging: 'drag',
|
||||
};
|
||||
import { MapTheme } from './theme';
|
||||
|
||||
const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
|
||||
/**
|
||||
* AMapService
|
||||
*/
|
||||
@injectable()
|
||||
export default class L7MapService implements IMapService<Map> {
|
||||
public version: string = Version.GLOBEL;
|
||||
public map: Map;
|
||||
|
||||
@inject(TYPES.MapConfig)
|
||||
private readonly config: Partial<IMapConfig>;
|
||||
|
||||
@inject(TYPES.IGlobalConfigService)
|
||||
private readonly configService: IGlobalConfigService;
|
||||
|
||||
@inject(TYPES.ICoordinateSystemService)
|
||||
private readonly coordinateSystemService: ICoordinateSystemService;
|
||||
|
||||
@inject(TYPES.IEventEmitter)
|
||||
private eventEmitter: any;
|
||||
private viewport: Viewport;
|
||||
private markerContainer: HTMLElement;
|
||||
private cameraChangedCallback: (viewport: IViewport) => void;
|
||||
private $mapContainer: HTMLElement | null;
|
||||
// T: 用于记录鼠标对相机的控制
|
||||
private handleCameraChanging: boolean;
|
||||
private handleCameraTimer: any;
|
||||
|
||||
// init
|
||||
public addMarkerContainer(): void {
|
||||
const container = this.map.getCanvasContainer();
|
||||
this.markerContainer = DOM.create('div', 'l7-marker-container', container);
|
||||
this.markerContainer.setAttribute('tabindex', '-1');
|
||||
}
|
||||
|
||||
public getMarkerContainer(): HTMLElement {
|
||||
return this.markerContainer;
|
||||
}
|
||||
|
||||
// map event
|
||||
public on(type: string, handle: (...args: any[]) => void): void {
|
||||
if (MapServiceEvent.indexOf(type) !== -1) {
|
||||
this.eventEmitter.on(type, handle);
|
||||
} else {
|
||||
// 统一事件名称
|
||||
this.map.on(EventMap[type] || type, handle);
|
||||
}
|
||||
}
|
||||
public off(type: string, handle: (...args: any[]) => void): void {
|
||||
this.map.off(EventMap[type] || type, handle);
|
||||
}
|
||||
|
||||
public getContainer(): HTMLElement | null {
|
||||
return this.map.getContainer();
|
||||
}
|
||||
|
||||
public getMapCanvasContainer(): HTMLElement {
|
||||
return this.map.getCanvasContainer() as HTMLElement;
|
||||
}
|
||||
|
||||
public getSize(): [number, number] {
|
||||
const size = this.map.transform;
|
||||
return [size.width, size.height];
|
||||
}
|
||||
// get mapStatus method
|
||||
|
||||
public getType() {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
public getZoom(): number {
|
||||
return this.map.getZoom();
|
||||
}
|
||||
|
||||
public setZoom(zoom: number) {
|
||||
return this.map.setZoom(zoom);
|
||||
}
|
||||
|
||||
public getCenter(): ILngLat {
|
||||
return this.map.getCenter();
|
||||
}
|
||||
|
||||
public setCenter(lnglat: [number, number]): void {
|
||||
this.map.setCenter(lnglat);
|
||||
}
|
||||
|
||||
public getPitch(): number {
|
||||
return this.map.getPitch();
|
||||
}
|
||||
|
||||
public getRotation(): number {
|
||||
return this.map.getBearing();
|
||||
}
|
||||
|
||||
public getBounds(): Bounds {
|
||||
return this.map.getBounds().toArray() as Bounds;
|
||||
}
|
||||
|
||||
public getMinZoom(): number {
|
||||
return this.map.getMinZoom();
|
||||
}
|
||||
|
||||
public getMaxZoom(): number {
|
||||
return this.map.getMaxZoom();
|
||||
}
|
||||
|
||||
public setRotation(rotation: number): void {
|
||||
this.map.setBearing(rotation);
|
||||
}
|
||||
|
||||
public zoomIn(option?: any, eventData?: any): void {
|
||||
this.map.zoomIn(option, eventData);
|
||||
}
|
||||
public zoomOut(option?: any, eventData?: any): void {
|
||||
this.map.zoomOut(option, eventData);
|
||||
}
|
||||
public setPitch(pitch: number) {
|
||||
return this.map.setPitch(pitch);
|
||||
}
|
||||
|
||||
public panTo(p: [number, number]): void {
|
||||
this.map.panTo(p);
|
||||
}
|
||||
|
||||
public panBy(pixel: [number, number]): void {
|
||||
this.panTo(pixel);
|
||||
}
|
||||
|
||||
public fitBounds(bound: Bounds, fitBoundsOptions?: any): void {
|
||||
this.map.fitBounds(bound, fitBoundsOptions);
|
||||
}
|
||||
|
||||
public setMaxZoom(max: number): void {
|
||||
this.map.setMaxZoom(max);
|
||||
}
|
||||
|
||||
public setMinZoom(min: number): void {
|
||||
this.map.setMinZoom(min);
|
||||
}
|
||||
public setMapStatus(option: Partial<IStatusOptions>): void {
|
||||
if (option.doubleClickZoom === true) {
|
||||
this.map.doubleClickZoom.enable();
|
||||
}
|
||||
if (option.doubleClickZoom === false) {
|
||||
this.map.doubleClickZoom.disable();
|
||||
}
|
||||
if (option.dragEnable === false) {
|
||||
this.map.dragPan.disable();
|
||||
}
|
||||
if (option.dragEnable === true) {
|
||||
this.map.dragPan.enable();
|
||||
}
|
||||
if (option.rotateEnable === false) {
|
||||
this.map.dragRotate.disable();
|
||||
}
|
||||
if (option.dragEnable === true) {
|
||||
this.map.dragRotate.enable();
|
||||
}
|
||||
if (option.keyboardEnable === false) {
|
||||
this.map.keyboard.disable();
|
||||
}
|
||||
if (option.keyboardEnable === true) {
|
||||
this.map.keyboard.enable();
|
||||
}
|
||||
if (option.zoomEnable === false) {
|
||||
this.map.scrollZoom.disable();
|
||||
}
|
||||
if (option.zoomEnable === true) {
|
||||
this.map.scrollZoom.enable();
|
||||
}
|
||||
}
|
||||
|
||||
public setZoomAndCenter(zoom: number, center: [number, number]): void {
|
||||
this.map.flyTo({
|
||||
zoom,
|
||||
center,
|
||||
});
|
||||
}
|
||||
|
||||
public setMapStyle(style: any): void {
|
||||
this.map.setStyle(this.getMapStyle(style));
|
||||
}
|
||||
// TODO: 计算像素坐标
|
||||
public pixelToLngLat(pixel: [number, number]): ILngLat {
|
||||
return this.map.unproject(pixel);
|
||||
}
|
||||
|
||||
public lngLatToPixel(lnglat: [number, number]): IPoint {
|
||||
return this.map.project(lnglat);
|
||||
}
|
||||
|
||||
public containerToLngLat(pixel: [number, number]): ILngLat {
|
||||
return this.map.unproject(pixel);
|
||||
}
|
||||
|
||||
public lngLatToContainer(lnglat: [number, number]): IPoint {
|
||||
return this.map.project(lnglat);
|
||||
}
|
||||
public lngLatToMercator(
|
||||
lnglat: [number, number],
|
||||
altitude: number,
|
||||
): IMercator {
|
||||
throw new Error('not implement');
|
||||
}
|
||||
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[] {
|
||||
throw new Error('not implement');
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
const {
|
||||
id = 'map',
|
||||
attributionControl = false,
|
||||
style = 'light',
|
||||
rotation = 0,
|
||||
mapInstance,
|
||||
...rest
|
||||
} = this.config;
|
||||
|
||||
this.viewport = new Viewport();
|
||||
|
||||
this.$mapContainer = this.creatAmapContainer(id);
|
||||
// @ts-ignore
|
||||
this.map = new EarthMap({
|
||||
container: this.$mapContainer,
|
||||
style: this.getMapStyle(style),
|
||||
bearing: rotation,
|
||||
...rest,
|
||||
});
|
||||
|
||||
this.map.on('load', this.handleCameraChanged);
|
||||
this.map.on('move', this.handleCameraChanged);
|
||||
|
||||
// 不同于高德地图,需要手动触发首次渲染
|
||||
this.handleCameraChanged({});
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
// TODO: 销毁地图可视化层的容器
|
||||
this.$mapContainer?.parentNode?.removeChild(this.$mapContainer);
|
||||
|
||||
this.eventEmitter.removeAllListeners();
|
||||
if (this.map) {
|
||||
this.map.remove();
|
||||
this.$mapContainer = null;
|
||||
}
|
||||
}
|
||||
public emit(name: string, ...args: any[]) {
|
||||
this.eventEmitter.emit(name, ...args);
|
||||
}
|
||||
public once(name: string, ...args: any[]) {
|
||||
this.eventEmitter.once(name, ...args);
|
||||
}
|
||||
|
||||
public getMapContainer() {
|
||||
return this.$mapContainer;
|
||||
}
|
||||
|
||||
public exportMap(type: 'jpg' | 'png'): string {
|
||||
const renderCanvas = this.map.getCanvas();
|
||||
const layersPng =
|
||||
type === 'jpg'
|
||||
? (renderCanvas?.toDataURL('image/jpeg') as string)
|
||||
: (renderCanvas?.toDataURL('image/png') as string);
|
||||
return layersPng;
|
||||
}
|
||||
public onCameraChanged(callback: (viewport: IViewport) => void): void {
|
||||
this.cameraChangedCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 地球模式向外暴露的 Y 轴旋转方法
|
||||
* @returns
|
||||
*/
|
||||
public rotateY(option: { force: boolean; reg: number }) {
|
||||
const { force = false, reg = 0.01 } = option || {};
|
||||
// TODO: 让旋转方法与
|
||||
if (this.handleCameraChanging && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.viewport) {
|
||||
this.viewport.rotateY(reg);
|
||||
|
||||
this.viewport.syncWithMapCamera({
|
||||
bearing: this.map.getBearing(),
|
||||
viewportHeight: this.map.transform.height,
|
||||
pitch: this.map.getPitch(),
|
||||
viewportWidth: this.map.transform.width,
|
||||
zoom: this.map.getZoom(),
|
||||
// mapbox 中固定相机高度为 viewport 高度的 1.5 倍
|
||||
cameraHeight: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private handleCameraChanged = (e: any) => {
|
||||
const DELAY_TIME = 2000;
|
||||
this.handleCameraChanging = true;
|
||||
if (this.handleCameraTimer) {
|
||||
clearTimeout(this.handleCameraTimer);
|
||||
}
|
||||
this.handleCameraTimer = setTimeout(() => {
|
||||
this.handleCameraChanging = false;
|
||||
}, DELAY_TIME);
|
||||
// 定义鼠标相机控制
|
||||
const rotateStep = 0.02;
|
||||
if (e.type && e.originalEvent) {
|
||||
if (e.originalEvent.type === 'wheel') {
|
||||
this.viewport.scaleZoom(
|
||||
0.01 * Math.sign(e.originalEvent.wheelDelta) * -1,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
Math.abs(e.originalEvent.movementX) >
|
||||
Math.abs(e.originalEvent.movementY)
|
||||
) {
|
||||
if (e.originalEvent.movementX > 0) {
|
||||
this.viewport.rotateY(rotateStep);
|
||||
} else if (e.originalEvent.movementX < 0) {
|
||||
this.viewport.rotateY(-rotateStep);
|
||||
}
|
||||
} else {
|
||||
if (e.originalEvent.movementY > 0) {
|
||||
this.viewport.rotateX(rotateStep);
|
||||
} else if (e.originalEvent.movementY < 0) {
|
||||
this.viewport.rotateX(-rotateStep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { offsetCoordinate = true } = this.config;
|
||||
|
||||
// resync
|
||||
this.viewport.syncWithMapCamera({
|
||||
bearing: this.map.getBearing(),
|
||||
viewportHeight: this.map.transform.height,
|
||||
pitch: this.map.getPitch(),
|
||||
viewportWidth: this.map.transform.width,
|
||||
zoom: this.map.getZoom(),
|
||||
// mapbox 中固定相机高度为 viewport 高度的 1.5 倍
|
||||
cameraHeight: 0,
|
||||
});
|
||||
// set coordinate system
|
||||
if (
|
||||
this.viewport.getZoom() > LNGLAT_OFFSET_ZOOM_THRESHOLD &&
|
||||
offsetCoordinate
|
||||
) {
|
||||
this.coordinateSystemService.setCoordinateSystem(
|
||||
CoordinateSystem.LNGLAT_OFFSET,
|
||||
);
|
||||
} else {
|
||||
this.coordinateSystemService.setCoordinateSystem(CoordinateSystem.LNGLAT);
|
||||
}
|
||||
|
||||
this.cameraChangedCallback(this.viewport);
|
||||
};
|
||||
|
||||
private creatAmapContainer(id: string | HTMLDivElement) {
|
||||
let $wrapper = id as HTMLDivElement;
|
||||
if (typeof id === 'string') {
|
||||
$wrapper = document.getElementById(id) as HTMLDivElement;
|
||||
}
|
||||
return $wrapper;
|
||||
}
|
||||
private getMapStyle(name: MapStyle) {
|
||||
if (typeof name !== 'string') {
|
||||
return name;
|
||||
}
|
||||
return MapTheme[name] ? MapTheme[name] : name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
export const MapTheme: {
|
||||
[key: string]: any;
|
||||
} = {
|
||||
light: 'mapbox://styles/zcxduo/ck2ypyb1r3q9o1co1766dex29',
|
||||
dark: 'mapbox://styles/zcxduo/ck241p6413s0b1cpayzldv7x7',
|
||||
normal: 'mapbox://styles/mapbox/streets-v11',
|
||||
blank: {
|
||||
version: 8,
|
||||
// sprite: 'https://lzxue.github.io/font-glyphs/sprite/sprite',
|
||||
// glyphs:
|
||||
// 'https://gw.alipayobjects.com/os/antvdemo/assets/mapbox/glyphs/{fontstack}/{range}.pbf',
|
||||
sources: {},
|
||||
layers: [
|
||||
{
|
||||
id: 'background',
|
||||
type: 'background',
|
||||
layout: {
|
||||
visibility: 'none',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
|
@ -2,7 +2,8 @@
|
|||
import GaodeMap from './amap/';
|
||||
// import GaodeMapV1 from './amap/';
|
||||
import GaodeMapV2 from './amap2/';
|
||||
import Earth from './earth/';
|
||||
import Map from './map/';
|
||||
import Mapbox from './mapbox/';
|
||||
|
||||
export { GaodeMap, GaodeMapV2, Mapbox, Map };
|
||||
export { GaodeMap, GaodeMapV2, Mapbox, Map, Earth };
|
||||
|
|
|
@ -45,6 +45,10 @@ export default class Viewport implements IViewport {
|
|||
return this.viewport.projectionMatrix;
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
return this.viewport.viewMatrix;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,10 @@ export default class Viewport implements IViewport {
|
|||
return this.viewport.projectionMatrix;
|
||||
}
|
||||
|
||||
public getModelMatrix(): number[] {
|
||||
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
||||
}
|
||||
|
||||
public getViewMatrix(): number[] {
|
||||
return this.viewport.viewMatrix;
|
||||
}
|
||||
|
|
|
@ -6,4 +6,5 @@ export enum Version {
|
|||
'GAODE2.x' = 'GAODE2.x',
|
||||
'MAPBOX' = 'MAPBOX',
|
||||
'L7MAP' = 'L7MAP',
|
||||
'GLOBEL' = 'GLOBEL',
|
||||
}
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
// @ts-ignore
|
||||
import { Scene } from '@antv/l7';
|
||||
import { PointLayer, EarthLayer } from '@antv/l7-layers';
|
||||
import { Earth } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class ScaleComponent extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new Earth({
|
||||
center: [120, 30],
|
||||
pitch: 0,
|
||||
zoom: 3,
|
||||
}),
|
||||
});
|
||||
|
||||
var d = [
|
||||
{ lng: 127.657407, lat: 49.76027 },
|
||||
{ lng: 129.397818, lat: 49.4406 },
|
||||
{ lng: 130.582293, lat: 48.729687 },
|
||||
{ lng: 130.987282, lat: 47.790132 },
|
||||
{ lng: 132.506672, lat: 47.78897 },
|
||||
{ lng: 133.373596, lat: 48.183442 },
|
||||
{ lng: 135.026311, lat: 48.47823 },
|
||||
{ lng: 134.500814, lat: 47.57844 },
|
||||
{ lng: 134.112362, lat: 47.212467 },
|
||||
{ lng: 133.769644, lat: 46.116927 },
|
||||
{ lng: 133.097127, lat: 45.144066 },
|
||||
{ lng: 131.883454, lat: 45.321162 },
|
||||
{ lng: 131.025212, lat: 44.967953 },
|
||||
{ lng: 131.288555, lat: 44.11152 },
|
||||
{ lng: 131.144688, lat: 42.92999 },
|
||||
{ lng: 130.633866, lat: 42.903015 },
|
||||
{ lng: 130.640016, lat: 42.395009 },
|
||||
{ lng: 129.994267, lat: 42.985387 },
|
||||
{ lng: 129.596669, lat: 42.424982 },
|
||||
{ lng: 128.052215, lat: 41.994285 },
|
||||
{ lng: 128.208433, lat: 41.466772 },
|
||||
{ lng: 127.343783, lat: 41.503152 },
|
||||
{ lng: 126.869083, lat: 41.816569 },
|
||||
{ lng: 126.182045, lat: 41.107336 },
|
||||
{ lng: 125.079942, lat: 40.569824 },
|
||||
{ lng: 124.265625, lat: 39.928493 },
|
||||
{ lng: 122.86757, lat: 39.637788 },
|
||||
{ lng: 122.131388, lat: 39.170452 },
|
||||
{ lng: 121.054554, lat: 38.897471 },
|
||||
{ lng: 121.585995, lat: 39.360854 },
|
||||
{ lng: 121.376757, lat: 39.750261 },
|
||||
{ lng: 122.168595, lat: 40.422443 },
|
||||
{ lng: 121.640359, lat: 40.94639 },
|
||||
{ lng: 120.768629, lat: 40.593388 },
|
||||
{ lng: 119.639602, lat: 39.898056 },
|
||||
{ lng: 119.023464, lat: 39.252333 },
|
||||
{ lng: 118.042749, lat: 39.204274 },
|
||||
{ lng: 117.532702, lat: 38.737636 },
|
||||
{ lng: 118.059699, lat: 38.061476 },
|
||||
{ lng: 118.87815, lat: 37.897325 },
|
||||
{ lng: 118.911636, lat: 37.448464 },
|
||||
{ lng: 119.702802, lat: 37.156389 },
|
||||
{ lng: 120.823457, lat: 37.870428 },
|
||||
{ lng: 121.711259, lat: 37.481123 },
|
||||
{ lng: 122.357937, lat: 37.454484 },
|
||||
{ lng: 122.519995, lat: 36.930614 },
|
||||
{ lng: 121.104164, lat: 36.651329 },
|
||||
{ lng: 120.637009, lat: 36.11144 },
|
||||
{ lng: 119.664562, lat: 35.609791 },
|
||||
{ lng: 119.151208, lat: 34.909859 },
|
||||
{ lng: 120.227525, lat: 34.360332 },
|
||||
{ lng: 120.620369, lat: 33.376723 },
|
||||
{ lng: 121.229014, lat: 32.460319 },
|
||||
{ lng: 121.908146, lat: 31.692174 },
|
||||
{ lng: 121.891919, lat: 30.949352 },
|
||||
{ lng: 121.264257, lat: 30.676267 },
|
||||
{ lng: 121.503519, lat: 30.142915 },
|
||||
{ lng: 122.092114, lat: 29.83252 },
|
||||
{ lng: 121.938428, lat: 29.018022 },
|
||||
{ lng: 121.684439, lat: 28.225513 },
|
||||
{ lng: 121.125661, lat: 28.135673 },
|
||||
{ lng: 120.395473, lat: 27.053207 },
|
||||
{ lng: 119.585497, lat: 25.740781 },
|
||||
{ lng: 118.656871, lat: 24.547391 },
|
||||
{ lng: 117.281606, lat: 23.624501 },
|
||||
{ lng: 115.890735, lat: 22.782873 },
|
||||
{ lng: 114.763827, lat: 22.668074 },
|
||||
{ lng: 114.152547, lat: 22.22376 },
|
||||
{ lng: 113.80678, lat: 22.54834 },
|
||||
{ lng: 113.241078, lat: 22.051367 },
|
||||
{ lng: 111.843592, lat: 21.550494 },
|
||||
{ lng: 110.785466, lat: 21.397144 },
|
||||
{ lng: 110.444039, lat: 20.341033 },
|
||||
{ lng: 109.889861, lat: 20.282457 },
|
||||
{ lng: 109.627655, lat: 21.008227 },
|
||||
{ lng: 109.864488, lat: 21.395051 },
|
||||
{ lng: 108.522813, lat: 21.715212 },
|
||||
{ lng: 108.05018, lat: 21.55238 },
|
||||
{ lng: 107.04342, lat: 21.811899 },
|
||||
{ lng: 106.567273, lat: 22.218205 },
|
||||
{ lng: 106.725403, lat: 22.794268 },
|
||||
{ lng: 105.811247, lat: 22.976892 },
|
||||
{ lng: 105.329209, lat: 23.352063 },
|
||||
{ lng: 104.476858, lat: 22.81915 },
|
||||
{ lng: 103.504515, lat: 22.703757 },
|
||||
{ lng: 102.706992, lat: 22.708795 },
|
||||
{ lng: 102.170436, lat: 22.464753 },
|
||||
{ lng: 101.652018, lat: 22.318199 },
|
||||
{ lng: 101.80312, lat: 21.174367 },
|
||||
{ lng: 101.270026, lat: 21.201652 },
|
||||
{ lng: 101.180005, lat: 21.436573 },
|
||||
{ lng: 101.150033, lat: 21.849984 },
|
||||
{ lng: 100.416538, lat: 21.558839 },
|
||||
{ lng: 99.983489, lat: 21.742937 },
|
||||
{ lng: 99.240899, lat: 22.118314 },
|
||||
{ lng: 99.531992, lat: 22.949039 },
|
||||
{ lng: 98.898749, lat: 23.142722 },
|
||||
{ lng: 98.660262, lat: 24.063286 },
|
||||
{ lng: 97.60472, lat: 23.897405 },
|
||||
{ lng: 97.724609, lat: 25.083637 },
|
||||
{ lng: 98.671838, lat: 25.918703 },
|
||||
{ lng: 98.712094, lat: 26.743536 },
|
||||
{ lng: 98.68269, lat: 27.508812 },
|
||||
{ lng: 98.246231, lat: 27.747221 },
|
||||
{ lng: 97.911988, lat: 28.335945 },
|
||||
{ lng: 97.327114, lat: 28.261583 },
|
||||
{ lng: 96.248833, lat: 28.411031 },
|
||||
{ lng: 96.586591, lat: 28.83098 },
|
||||
{ lng: 96.117679, lat: 29.452802 },
|
||||
{ lng: 95.404802, lat: 29.031717 },
|
||||
{ lng: 94.56599, lat: 29.277438 },
|
||||
{ lng: 93.413348, lat: 28.640629 },
|
||||
{ lng: 92.503119, lat: 27.896876 },
|
||||
{ lng: 91.696657, lat: 27.771742 },
|
||||
{ lng: 91.258854, lat: 28.040614 },
|
||||
{ lng: 90.730514, lat: 28.064954 },
|
||||
{ lng: 90.015829, lat: 28.296439 },
|
||||
{ lng: 89.47581, lat: 28.042759 },
|
||||
{ lng: 88.814248, lat: 27.299316 },
|
||||
{ lng: 88.730326, lat: 28.086865 },
|
||||
{ lng: 88.120441, lat: 27.876542 },
|
||||
{ lng: 86.954517, lat: 27.974262 },
|
||||
{ lng: 85.82332, lat: 28.203576 },
|
||||
{ lng: 85.011638, lat: 28.642774 },
|
||||
{ lng: 84.23458, lat: 28.839894 },
|
||||
{ lng: 83.898993, lat: 29.320226 },
|
||||
{ lng: 83.337115, lat: 29.463732 },
|
||||
{ lng: 82.327513, lat: 30.115268 },
|
||||
{ lng: 81.525804, lat: 30.422717 },
|
||||
{ lng: 81.111256, lat: 30.183481 },
|
||||
{ lng: 79.721367, lat: 30.882715 },
|
||||
{ lng: 78.738894, lat: 31.515906 },
|
||||
{ lng: 78.458446, lat: 32.618164 },
|
||||
{ lng: 79.176129, lat: 32.48378 },
|
||||
{ lng: 79.208892, lat: 32.994395 },
|
||||
{ lng: 78.811086, lat: 33.506198 },
|
||||
{ lng: 78.912269, lat: 34.321936 },
|
||||
{ lng: 77.837451, lat: 35.49401 },
|
||||
{ lng: 76.192848, lat: 35.898403 },
|
||||
{ lng: 75.896897, lat: 36.666806 },
|
||||
{ lng: 75.158028, lat: 37.133031 },
|
||||
{ lng: 74.980002, lat: 37.41999 },
|
||||
{ lng: 74.829986, lat: 37.990007 },
|
||||
{ lng: 74.864816, lat: 38.378846 },
|
||||
{ lng: 74.257514, lat: 38.606507 },
|
||||
{ lng: 73.928852, lat: 38.505815 },
|
||||
{ lng: 73.675379, lat: 39.431237 },
|
||||
{ lng: 73.960013, lat: 39.660008 },
|
||||
{ lng: 73.822244, lat: 39.893973 },
|
||||
{ lng: 74.776862, lat: 40.366425 },
|
||||
{ lng: 75.467828, lat: 40.562072 },
|
||||
{ lng: 76.526368, lat: 40.427946 },
|
||||
{ lng: 76.904484, lat: 41.066486 },
|
||||
{ lng: 78.187197, lat: 41.185316 },
|
||||
{ lng: 78.543661, lat: 41.582243 },
|
||||
{ lng: 80.11943, lat: 42.123941 },
|
||||
{ lng: 80.25999, lat: 42.349999 },
|
||||
{ lng: 80.18015, lat: 42.920068 },
|
||||
{ lng: 80.866206, lat: 43.180362 },
|
||||
{ lng: 79.966106, lat: 44.917517 },
|
||||
{ lng: 81.947071, lat: 45.317027 },
|
||||
{ lng: 82.458926, lat: 45.53965 },
|
||||
{ lng: 83.180484, lat: 47.330031 },
|
||||
{ lng: 85.16429, lat: 47.000956 },
|
||||
{ lng: 85.720484, lat: 47.452969 },
|
||||
{ lng: 85.768233, lat: 48.455751 },
|
||||
{ lng: 86.598776, lat: 48.549182 },
|
||||
{ lng: 87.35997, lat: 49.214981 },
|
||||
{ lng: 87.751264, lat: 49.297198 },
|
||||
{ lng: 88.013832, lat: 48.599463 },
|
||||
{ lng: 88.854298, lat: 48.069082 },
|
||||
{ lng: 90.280826, lat: 47.693549 },
|
||||
{ lng: 90.970809, lat: 46.888146 },
|
||||
{ lng: 90.585768, lat: 45.719716 },
|
||||
{ lng: 90.94554, lat: 45.286073 },
|
||||
{ lng: 92.133891, lat: 45.115076 },
|
||||
{ lng: 93.480734, lat: 44.975472 },
|
||||
{ lng: 94.688929, lat: 44.352332 },
|
||||
{ lng: 95.306875, lat: 44.241331 },
|
||||
{ lng: 95.762455, lat: 43.319449 },
|
||||
{ lng: 96.349396, lat: 42.725635 },
|
||||
{ lng: 97.451757, lat: 42.74889 },
|
||||
{ lng: 99.515817, lat: 42.524691 },
|
||||
{ lng: 100.845866, lat: 42.663804 },
|
||||
{ lng: 101.83304, lat: 42.514873 },
|
||||
{ lng: 103.312278, lat: 41.907468 },
|
||||
{ lng: 104.522282, lat: 41.908347 },
|
||||
{ lng: 104.964994, lat: 41.59741 },
|
||||
{ lng: 106.129316, lat: 42.134328 },
|
||||
{ lng: 107.744773, lat: 42.481516 },
|
||||
{ lng: 109.243596, lat: 42.519446 },
|
||||
{ lng: 110.412103, lat: 42.871234 },
|
||||
{ lng: 111.129682, lat: 43.406834 },
|
||||
{ lng: 111.829588, lat: 43.743118 },
|
||||
{ lng: 111.667737, lat: 44.073176 },
|
||||
{ lng: 111.348377, lat: 44.457442 },
|
||||
{ lng: 111.873306, lat: 45.102079 },
|
||||
{ lng: 112.436062, lat: 45.011646 },
|
||||
{ lng: 113.463907, lat: 44.808893 },
|
||||
{ lng: 114.460332, lat: 45.339817 },
|
||||
{ lng: 115.985096, lat: 45.727235 },
|
||||
{ lng: 116.717868, lat: 46.388202 },
|
||||
{ lng: 117.421701, lat: 46.672733 },
|
||||
{ lng: 118.874326, lat: 46.805412 },
|
||||
{ lng: 119.66327, lat: 46.69268 },
|
||||
{ lng: 119.772824, lat: 47.048059 },
|
||||
{ lng: 118.866574, lat: 47.74706 },
|
||||
{ lng: 118.064143, lat: 48.06673 },
|
||||
{ lng: 117.295507, lat: 47.697709 },
|
||||
{ lng: 116.308953, lat: 47.85341 },
|
||||
{ lng: 115.742837, lat: 47.726545 },
|
||||
{ lng: 115.485282, lat: 48.135383 },
|
||||
{ lng: 116.191802, lat: 49.134598 },
|
||||
{ lng: 116.678801, lat: 49.888531 },
|
||||
{ lng: 117.879244, lat: 49.510983 },
|
||||
{ lng: 119.288461, lat: 50.142883 },
|
||||
{ lng: 119.279366, lat: 50.582908 },
|
||||
{ lng: 120.18205, lat: 51.643566 },
|
||||
{ lng: 120.738191, lat: 51.964115 },
|
||||
{ lng: 120.725789, lat: 52.516226 },
|
||||
{ lng: 120.177089, lat: 52.753886 },
|
||||
{ lng: 121.003085, lat: 53.251401 },
|
||||
{ lng: 122.245748, lat: 53.431726 },
|
||||
{ lng: 123.571507, lat: 53.458804 },
|
||||
{ lng: 125.068211, lat: 53.161045 },
|
||||
{ lng: 125.946349, lat: 52.792799 },
|
||||
{ lng: 126.564399, lat: 51.784255 },
|
||||
{ lng: 126.939157, lat: 51.353894 },
|
||||
{ lng: 127.287456, lat: 50.739797 },
|
||||
{ lng: 127.657407, lat: 49.76027 },
|
||||
];
|
||||
|
||||
let pointlayer = new PointLayer()
|
||||
.source(
|
||||
d,
|
||||
// [
|
||||
// {"lng":10,"lat":0},
|
||||
// {"lng":20,"lat":0},
|
||||
// {"lng":30,"lat":0},
|
||||
// {"lng":40,"lat":0},
|
||||
// {"lng":50,"lat":0},
|
||||
// {"lng":60,"lat":0},
|
||||
// {"lng":70,"lat":0},
|
||||
// {"lng":80,"lat":0},
|
||||
// {"lng":90,"lat":0},
|
||||
|
||||
// {"lng":100,"lat":0},
|
||||
// {"lng":110,"lat":0},
|
||||
// {"lng":120,"lat":0},
|
||||
// {"lng":130,"lat":0},
|
||||
// {"lng":140,"lat":0},
|
||||
// {"lng":150,"lat":0},
|
||||
// {"lng":160,"lat":0},
|
||||
// {"lng":170,"lat":0},
|
||||
// {"lng":180,"lat":0},
|
||||
|
||||
// {"lng":190,"lat":0},
|
||||
// {"lng":200,"lat":0},
|
||||
// {"lng":210,"lat":0},
|
||||
// {"lng":220,"lat":0},
|
||||
// {"lng":230,"lat":0},
|
||||
// {"lng":240,"lat":0},
|
||||
// {"lng":250,"lat":0},
|
||||
// {"lng":260,"lat":0},
|
||||
// {"lng":270,"lat":0},
|
||||
|
||||
// {"lng":280,"lat":0},
|
||||
// {"lng":290,"lat":0},
|
||||
// {"lng":300,"lat":0},
|
||||
// {"lng":310,"lat":0},
|
||||
// {"lng":320,"lat":0},
|
||||
// {"lng":330,"lat":0},
|
||||
// {"lng":340,"lat":0},
|
||||
// {"lng":350,"lat":0},
|
||||
// {"lng":360,"lat":0},
|
||||
|
||||
// {"lng":0,"lat":0},
|
||||
|
||||
// {"lng":0,"lat":10},
|
||||
// {"lng":0,"lat":20},
|
||||
// {"lng":0,"lat":30},
|
||||
// {"lng":0,"lat":40},
|
||||
// {"lng":0,"lat":50},
|
||||
// {"lng":0,"lat":60},
|
||||
// {"lng":0,"lat":70},
|
||||
// {"lng":0,"lat":80},
|
||||
// {"lng":0,"lat":90},
|
||||
|
||||
// {"lng":0,"lat":-10},
|
||||
// {"lng":0,"lat":-20},
|
||||
// {"lng":0,"lat":-30},
|
||||
// {"lng":0,"lat":-40},
|
||||
// {"lng":0,"lat":-50},
|
||||
// {"lng":0,"lat":-60},
|
||||
// {"lng":0,"lat":-70},
|
||||
// {"lng":0,"lat":-80},
|
||||
// {"lng":0,"lat":-90},
|
||||
// ],
|
||||
{
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
},
|
||||
},
|
||||
)
|
||||
.shape('circle')
|
||||
// .shape('cylinder')
|
||||
.color('#f00')
|
||||
.size(10)
|
||||
.style({
|
||||
opacity: 0.6,
|
||||
})
|
||||
.active(true);
|
||||
|
||||
// scene.addLayer(pointlayer);
|
||||
|
||||
// let pointlayer = new PointLayer()
|
||||
// .source(
|
||||
// [
|
||||
// {
|
||||
// lng: 120,
|
||||
// lat: 30,
|
||||
// },
|
||||
// ],
|
||||
// {
|
||||
// parser: {
|
||||
// type: 'json',
|
||||
// x: 'lng',
|
||||
// y: 'lat',
|
||||
// },
|
||||
// },
|
||||
// )
|
||||
// .shape('circle')
|
||||
// .color('rgba(255, 0, 0, 1.0)')
|
||||
// .size(200);
|
||||
|
||||
const earthlayer = new EarthLayer()
|
||||
.source(
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
|
||||
{
|
||||
parser: {
|
||||
type: 'image',
|
||||
extent: [121.168, 30.2828, 121.384, 30.4219],
|
||||
},
|
||||
},
|
||||
)
|
||||
.color('#2E8AE6')
|
||||
.shape('fill')
|
||||
.style({
|
||||
opacity: 1.0,
|
||||
radius: 40,
|
||||
globelOtions: {
|
||||
ambientRatio: 0.6, // 环境光
|
||||
diffuseRatio: 0.4, // 漫反射
|
||||
specularRatio: 0.1, // 高光反射
|
||||
// earthTime: 4.0
|
||||
earthTime: 0.1,
|
||||
},
|
||||
})
|
||||
.animate(true);
|
||||
// earthlayer.setEarthTime(4.0)
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(earthlayer);
|
||||
scene.addLayer(pointlayer);
|
||||
|
||||
earthlayer.setEarthTime(4.0);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,9 @@ import * as React from 'react';
|
|||
|
||||
import Map from './components/Map';
|
||||
import Map2 from './components/Map2';
|
||||
import Earth from './components/earth'
|
||||
// @ts-ignore
|
||||
storiesOf('自定义地图', module).add('地图', () => <Map />)
|
||||
storiesOf('自定义地图', module)
|
||||
.add('Earth', () => <Earth />)
|
||||
.add('地图', () => <Map />)
|
||||
.add('地图2', () => <Map2 />);
|
||||
|
|
Loading…
Reference in New Issue