mirror of https://gitee.com/antv-l7/antv-l7
Merge branch 'grid-heatMap' into 'master'
Grid heat map 增加mapbox 增加多边形热力图 See merge request !5
This commit is contained in:
commit
1094b106bb
|
@ -69,7 +69,6 @@ lib
|
|||
|
||||
*.sw*
|
||||
*.un~
|
||||
demos/mapbox.html
|
||||
demos/gd.html
|
||||
demos/data
|
||||
demos/image
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
<title>point_circle</title>
|
||||
<style>
|
||||
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||
.amap-maps {
|
||||
cursor: auto !important
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
@ -55,15 +58,15 @@ scene.on('loaded', () => {
|
|||
.shape('2d:circle')
|
||||
.size('value', [ 2, 80]) // default 1
|
||||
//.size('value', [ 10, 300]) // default 1
|
||||
.active(false)
|
||||
.active(true)
|
||||
.filter('value', field_8 => {
|
||||
return field_8 * 1 > 500;
|
||||
})
|
||||
.color('type', colorObj.red)
|
||||
.color('type', colorObj.blue)
|
||||
.style({
|
||||
stroke: 'rgb(255,255,255)',
|
||||
strokeWidth: 1,
|
||||
opacity: 0.9
|
||||
opacity: 1.
|
||||
})
|
||||
.render();
|
||||
|
||||
|
|
|
@ -34,9 +34,11 @@ scene.on('loaded', () => {
|
|||
zIndex: 2
|
||||
})
|
||||
.source(data.list, {
|
||||
type: 'array',
|
||||
parser:{
|
||||
type: 'json',
|
||||
x: 'j',
|
||||
y: 'w',
|
||||
}
|
||||
})
|
||||
.shape('cylinder')
|
||||
.size('t',(level)=> {
|
||||
|
|
|
@ -34,9 +34,11 @@ scene.on('loaded', () => {
|
|||
zIndex: 2
|
||||
})
|
||||
.source(data, {
|
||||
parser:{
|
||||
type: 'csv',
|
||||
y: 'lat',
|
||||
x: 'lng'
|
||||
}
|
||||
})
|
||||
.size(1.0)
|
||||
.color('#0D408C')
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="geometry" content="diagram">
|
||||
<link rel="stylesheet" href="./assets/common.css">
|
||||
<link rel="stylesheet" href="./assets/info.css">
|
||||
<title>point_circle</title>
|
||||
<style>
|
||||
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||
.amap-maps {
|
||||
cursor: auto !important
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
|
||||
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||
<script src="./assets/dat.gui.min.js"></script>
|
||||
<script src="../build/L7.js"></script>
|
||||
<script>
|
||||
const colorObj ={
|
||||
blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse(),
|
||||
red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
|
||||
orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
|
||||
green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
|
||||
yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
|
||||
purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
|
||||
}
|
||||
|
||||
|
||||
const scene = new L7.Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'light', // 样式URL
|
||||
center: [ 120.19382669582967, 30.258134 ],
|
||||
pitch: 0,
|
||||
zoom: 4,
|
||||
maxZoom:14,
|
||||
minZoom:4,
|
||||
});
|
||||
window.scene = scene;
|
||||
scene.on('loaded', () => {
|
||||
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
||||
|
||||
|
||||
const circleLayer = scene.PointLayer({
|
||||
zIndex: 2
|
||||
})
|
||||
.source(data,{
|
||||
type: 'csv',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
})
|
||||
.size(1.0)
|
||||
.color('#0D408C')
|
||||
.style({
|
||||
stroke: 'rgb(255,255,255)',
|
||||
strokeWidth: 1,
|
||||
opacity: 1.
|
||||
})
|
||||
.render();
|
||||
|
||||
circleLayer.on('click',(e)=>{
|
||||
console.log(e);
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -33,8 +33,11 @@ const scene = new L7.Scene({
|
|||
scene.on('loaded', () => {
|
||||
const imageLayer = scene.ImageLayer().
|
||||
source('https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',{
|
||||
|
||||
parser:{
|
||||
type:'image',
|
||||
extent: [ 121.1680, 30.2828, 121.3840, 30.4219 ]
|
||||
}
|
||||
|
||||
})
|
||||
.style({
|
||||
opacity:1.0,
|
||||
|
|
|
@ -48,13 +48,14 @@ scene.on('loaded', () => {
|
|||
|
||||
const layer = scene.RasterLayer({ zIndex: 2 }).
|
||||
source(values, {
|
||||
parser: {
|
||||
type: 'raster',
|
||||
width: n,
|
||||
height: m,
|
||||
min: 0,
|
||||
max: 8000,
|
||||
extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
|
||||
|
||||
}
|
||||
})
|
||||
.style({
|
||||
rampColors: {
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="geometry" content="diagram">
|
||||
<link rel="stylesheet" href="./assets/common.css">
|
||||
<title>point_circle</title>
|
||||
<style>
|
||||
#map { position:absolute; top:0; bottom:0; width:100%; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="https://webapi.amap.com/maps?v=1.4.8&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D"></script>
|
||||
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||
<script src="./assets/dat.gui.min.js"></script>
|
||||
<script src="../build/L7.js"></script>
|
||||
<script>
|
||||
|
||||
const scene = new L7.Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'dark', // 样式URL
|
||||
center: [120.132624,30.281774],
|
||||
pitch: 0,
|
||||
zoom: 3.88
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
$.get('https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv', data => {
|
||||
var layer = scene.HeatMapLayer({
|
||||
zIndex: 2
|
||||
})
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
},
|
||||
transforms:[
|
||||
{
|
||||
type: 'map',
|
||||
callback:function(item){
|
||||
const [x, y] = item.coordinates;
|
||||
item.lat = item.lat*1;
|
||||
item.lng = item.lng*1;
|
||||
item.v = item.v *1;
|
||||
item.coordinates = [x*1,y*1];
|
||||
return item;
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
type: 'grid',
|
||||
size: 15000,
|
||||
field:'v',
|
||||
method:'sum'
|
||||
}
|
||||
]
|
||||
})
|
||||
.shape('gird')
|
||||
.style({
|
||||
coverage: 0.8
|
||||
})
|
||||
.color('count', ["#002466","#105CB3","#2894E0","#CFF6FF","#FFF5B8","#FFAB5C","#F27049","#730D1C"])
|
||||
.render();
|
||||
console.log(layer);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="geometry" content="diagram">
|
||||
<link rel="stylesheet" href="./assets/common.css">
|
||||
<link rel="stylesheet" href="./assets/info.css">
|
||||
<title>point_circle</title>
|
||||
<style>
|
||||
body {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
#map { position:absolute; top:0; bottom:0; width:100%; margin:0; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.js'></script>
|
||||
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.34.0/mapbox-gl.css' rel='stylesheet' />
|
||||
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||
<script src="./assets/dat.gui.min.js"></script>
|
||||
<script src="../build/L7.js"></script>
|
||||
<script>
|
||||
const colorObj ={
|
||||
blue: ["#E8FCFF", "#CFF6FF", "#A1E9ff", "#65CEF7", "#3CB1F0", "#2894E0", "#1772c2", "#105CB3", "#0D408C", "#002466"].reverse(),
|
||||
red: ["#FFF4F2", "#FFDFDB", "#FAADAA", "#F77472", "#F04850", "#D63147", "#BD223E", "#A81642", "#820C37", "#5C0023"].reverse(),
|
||||
orange:["#FFF7EB", "#FFECD4", "#FAD09D", "#F7B16A", "#F08D41", "#DB6C2C", "#C2491D", "#AD2B11", "#871D0C", "#610800"].reverse(),
|
||||
green:["#FAFFF0", "#EBF7D2", "#C8E695", "#A5D660", "#7DC238", "#59A616", "#3F8C0B", "#237804", "#125200", "#082B00"].reverse(),
|
||||
yellow:["#FFFFE8", "#FFFECC", "#FAF896", "#F7E463", "#F0CE3A", "#DBB125", "#C29117", "#AD7410", "#87500C", "#613000"].reverse(),
|
||||
purple:["#FCF2FF", "#F5DEFF", "#DDB3F2", "#BE7BE3", "#9B4ECF", "#7737B3", "#5B2899", "#411C85", "#270F5E", "#100338"].reverse()
|
||||
}
|
||||
|
||||
|
||||
const scene = new L7.Scene({
|
||||
container: 'map',
|
||||
mapType:'mapbox',
|
||||
style: 'mapbox://styles/mapbox/streets-v9', // stylesheet location
|
||||
center: [ 120.19382669582967, 30.258134 ],
|
||||
pitch: 0,
|
||||
hash:true,
|
||||
zoom: 1,
|
||||
});
|
||||
window.scene = scene;
|
||||
scene.on('loaded', () => {
|
||||
var colors = ["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"];
|
||||
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/JToMOWvicvJOISZFCkEI.json', city => {
|
||||
const citylayer = scene.PolygonLayer()
|
||||
.source(city)
|
||||
//.color('pm2_5_24h',["#FFF5B8","#FFDC7D","#FFAB5C","#F27049","#D42F31","#730D1C"])
|
||||
.color('pm2_5_24h',(p)=>{
|
||||
if(p>120){
|
||||
return colors[5];
|
||||
} else if(p>65){
|
||||
return colors[4];
|
||||
} else if(p>30) {
|
||||
return colors[3];
|
||||
} else if(p>15){
|
||||
return colors[2];
|
||||
} else if(p>8){
|
||||
return colors[1];
|
||||
}else {
|
||||
return colors[0];
|
||||
}
|
||||
})
|
||||
.shape('fill')
|
||||
.active(true)
|
||||
.style({
|
||||
opacity: 1
|
||||
})
|
||||
.render();
|
||||
console.log('success');
|
||||
});
|
||||
$.get('https://gw.alipayobjects.com/os/rmsportal/ggFwDClGjjvpSMBIrcEx.json', data => {
|
||||
citylayer = scene.PolygonLayer({
|
||||
zIndex: 2
|
||||
})
|
||||
.source(data)
|
||||
.shape('extrude')
|
||||
.active({fill:'red'})
|
||||
.size('floor',[0.1,1])
|
||||
.color('#aaa')
|
||||
.render();
|
||||
})
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -101,12 +101,14 @@
|
|||
"@turf/invariant": "^6.1.2",
|
||||
"@turf/meta": "^6.0.2",
|
||||
"d3-dsv": "^1.0.10",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"earcut": "^2.1.3",
|
||||
"fecha": "^2.3.3",
|
||||
"gl-matrix": "^2.4.1",
|
||||
"lodash": "^4.17.5",
|
||||
"polyline-normals": "^2.0.2",
|
||||
"rbush": "^2.0.2",
|
||||
"simple-statistics": "^7.0.1",
|
||||
"three": "^0.96.0",
|
||||
"venn.js": "^0.2.20",
|
||||
"viewport-mercator-project": "^5.2.0",
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
import geom from '../../geom/geom';
|
||||
import { GeoBuffer, bufferGeometry, Material } from '../../geom/index';
|
||||
|
||||
|
||||
// geom shape buffer geometry material
|
||||
// shape name type()
|
||||
// buffer 1:n geometry
|
||||
// geometry
|
||||
//
|
||||
export default function polygonGeom(shape, coordinates, properties, layerid) {
|
||||
const polygongeom = geom.polygon;
|
||||
const { buffer, geometry, material } = polygongeom[shape];// polygon 映射表
|
||||
const bufferData = new GeoBuffer[buffer]({
|
||||
coordinates,
|
||||
properties,
|
||||
shape
|
||||
});
|
||||
bufferData.bufferStruct.name = layerid;
|
||||
const bg = new bufferGeometry[geometry](bufferData.bufferStruct);
|
||||
const mtl = Material[material]();
|
||||
return {
|
||||
geometry: bg,
|
||||
mtl
|
||||
};
|
||||
}
|
||||
|
||||
export function pointGeom(shape, bufferData) {
|
||||
const pointgeom = geom.point;
|
||||
const { geometry, material } = pointgeom[shape];
|
||||
const bg = new bufferGeometry[geometry](bufferData.bufferStruct);
|
||||
const mtl = Material[material]();
|
||||
return {
|
||||
geometry: bg,
|
||||
mtl
|
||||
};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
import { getMap } from '../../map';
|
||||
import Base from '../base';
|
||||
export default class MapContorller extends Base {
|
||||
constructor(cfg, engine, scene) {
|
||||
super(cfg);
|
||||
this._engine = engine;
|
||||
this.scene = scene;
|
||||
}
|
||||
_init() {
|
||||
const mapType = this.get('mapType');
|
||||
const mapCfg = this.get('mapCfg');
|
||||
this.map = new getMap(mapType)(mapCfg);
|
||||
this.map('mapLoad', this._mapload.bind(this));
|
||||
}
|
||||
_mapload() {
|
||||
this.map.asyncCamera(this._engine);
|
||||
this.emit('loaded');
|
||||
}
|
||||
_bindMapMethod() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,9 @@ export default class Engine extends EventEmitter {
|
|||
this._camera = new Camera(container).camera;
|
||||
this._renderer = new Renderer(container).renderer;
|
||||
this._world = world;
|
||||
// for MapBox
|
||||
this.world = new THREE.Group();
|
||||
this._scene.add(this.world);
|
||||
this._picking = Picking(this._world, this._renderer, this._camera, this._scene);
|
||||
this.clock = new THREE.Clock();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ class Picking {
|
|||
this.scene = scene;
|
||||
this._raycaster.linePrecision = 10;
|
||||
this._pickingScene = PickingScene;
|
||||
this.world = new THREE.Group();
|
||||
this._pickingScene.add(this.world);
|
||||
const size = this._renderer.getSize();
|
||||
this._width = size.width;
|
||||
this._height = size.height;
|
||||
|
@ -34,8 +36,7 @@ class Picking {
|
|||
window.addEventListener('resize', this._resizeHandler, false);
|
||||
}
|
||||
pickdata(event) {
|
||||
const point = { x: event.pixel.x, y: event.pixel.y, type: event.type };
|
||||
|
||||
const point = { x: event.offsetX, y: event.offsetY, type: event.type };
|
||||
const normalisedPoint = { x: 0, y: 0 };
|
||||
normalisedPoint.x = (point.x / this._width) * 2 - 1;
|
||||
normalisedPoint.y = -(point.y / this._height) * 2 + 1;
|
||||
|
@ -61,12 +62,12 @@ class Picking {
|
|||
|
||||
}
|
||||
_filterObject(id) {
|
||||
this._pickingScene.children.forEach((object, index) => {
|
||||
this.world.children.forEach((object, index) => {
|
||||
index === id ? object.visible = true : object.visible = false;
|
||||
});
|
||||
}
|
||||
_pickAllObject(point, normalisedPoint) {
|
||||
this._pickingScene.children.forEach((object, index) => {
|
||||
this.world.children.forEach((object, index) => {
|
||||
this._filterObject(index);
|
||||
const item = this._pick(point, normalisedPoint, object.name);
|
||||
item.type = point.type;
|
||||
|
@ -86,7 +87,6 @@ class Picking {
|
|||
id = -999;
|
||||
// return;
|
||||
}
|
||||
|
||||
this._raycaster.setFromCamera(normalisedPoint, this._camera);
|
||||
|
||||
const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true);
|
||||
|
@ -111,13 +111,14 @@ class Picking {
|
|||
//
|
||||
// Picking ID should already be added as an attribute
|
||||
add(mesh) {
|
||||
this._pickingScene.add(mesh);
|
||||
this.world.add(mesh);
|
||||
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
// Remove mesh from picking scene
|
||||
remove(mesh) {
|
||||
this._pickingScene.remove(mesh);
|
||||
this.world.remove(mesh);
|
||||
this._needUpdate = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import Base from './base';
|
||||
import * as THREE from './three';
|
||||
import ColorUtil from '../attr/color-util';
|
||||
import * as source from '../source/index';
|
||||
import source from './source';
|
||||
import PickingMaterial from '../core/engine/picking/pickingMaterial';
|
||||
import Attr from '../attr/index';
|
||||
import Util from '../util';
|
||||
|
@ -63,7 +63,8 @@ export default class Layer extends Base {
|
|||
const layerId = this._getUniqueId();
|
||||
this.layerId = layerId;
|
||||
this._activeIds = null;
|
||||
scene._engine._scene.add(this._object3D);
|
||||
const world = scene._engine.world;
|
||||
world.add(this._object3D);
|
||||
this.layerMesh = null;
|
||||
this.layerLineMesh = null;
|
||||
this._initEvents();
|
||||
|
@ -106,12 +107,9 @@ export default class Layer extends Base {
|
|||
this._object3D.visible = this.get('visible');
|
||||
}
|
||||
source(data, cfg = {}) {
|
||||
const dataType = this._getDataType(data);
|
||||
const { type = dataType } = cfg;
|
||||
cfg.data = data;
|
||||
cfg.mapType = this.get('mapType');
|
||||
|
||||
this.layerSource = new source[type](cfg);
|
||||
cfg.mapType = this.scene.mapType;
|
||||
this.layerSource = new source(cfg);
|
||||
// this.scene.workerPool.runTask({
|
||||
// command: 'geojson',
|
||||
// data: cfg
|
||||
|
@ -279,10 +277,10 @@ export default class Layer extends Base {
|
|||
const { featureId } = e;
|
||||
if (featureId < 0) return;
|
||||
const activeStyle = this.get('activedOptions');
|
||||
const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
|
||||
// const selectFeatureIds = this.layerSource.getSelectFeatureId(featureId);
|
||||
// 如果数据不显示状态则不进行高亮
|
||||
if (this.StyleData[selectFeatureIds[0]].hasOwnProperty('filter') && this.StyleData[selectFeatureIds[0]].filter === false) { return; }
|
||||
const style = Util.assign({}, this.StyleData[featureId]);
|
||||
if (this.layerData[featureId].hasOwnProperty('filter') && this.layerData[featureId].filter === false) { return; }
|
||||
const style = Util.assign({}, this.layerData[featureId]);
|
||||
style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
|
||||
this.updateStyle([ featureId ], style);
|
||||
}
|
||||
|
@ -321,7 +319,7 @@ export default class Layer extends Base {
|
|||
_updateSize(zoom) {
|
||||
const sizeOption = this.get('attrOptions').size;
|
||||
const fields = parseFields(sizeOption.field);
|
||||
const data = this.layerSource.propertiesData;
|
||||
const data = this.layerSource.data.dataArray;
|
||||
if (!this.zoomSizeCache) this.zoomSizeCache = {};
|
||||
if (!this.zoomSizeCache[zoom]) {
|
||||
this.zoomSizeCache[zoom] = [];
|
||||
|
@ -339,7 +337,8 @@ export default class Layer extends Base {
|
|||
const self = this;
|
||||
const attrs = self.get('attrs');
|
||||
const mappedData = [];
|
||||
const data = this.layerSource.propertiesData;
|
||||
// const data = this.layerSource.propertiesData;
|
||||
const data = this.layerSource.data.dataArray;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const record = data[i];
|
||||
const newRecord = {};
|
||||
|
@ -362,18 +361,17 @@ export default class Layer extends Base {
|
|||
}
|
||||
}
|
||||
}
|
||||
newRecord.coordinates = record.coordinates;
|
||||
mappedData.push(newRecord);
|
||||
}
|
||||
|
||||
this.StyleData = mappedData;
|
||||
return mappedData;
|
||||
this.layerData = mappedData;
|
||||
}
|
||||
// 更新地图映射
|
||||
_updateMaping() {
|
||||
const self = this;
|
||||
const attrs = self.get('attrs');
|
||||
|
||||
const data = this.layerSource.propertiesData;
|
||||
const data = this.layerSource.data.dataArray;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const record = data[i];
|
||||
for (const attrName in attrs) {
|
||||
|
@ -385,10 +383,10 @@ export default class Layer extends Base {
|
|||
for (let j = 0; j < values.length; j++) {
|
||||
const val = values[j];
|
||||
const name = names[j];
|
||||
this.StyleData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||
this.layerData[i][name] = (Util.isArray(val) && val.length === 1) ? val[0] : val; // 只有一个值时返回第一个属性值
|
||||
}
|
||||
} else {
|
||||
this.StyleData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||
this.layerData[i][names[0]] = values.length === 1 ? values[0] : values;
|
||||
|
||||
}
|
||||
attr.neadUpdate = true;
|
||||
|
@ -468,6 +466,7 @@ export default class Layer extends Base {
|
|||
pickingMesh.material.setUniformsValue('u_zoom', zoom);
|
||||
};
|
||||
this._pickingMesh.add(pickingMesh);
|
||||
|
||||
}
|
||||
_setPickingId() {
|
||||
this._pickingId = this.getPickingId();
|
||||
|
@ -532,13 +531,13 @@ export default class Layer extends Base {
|
|||
*/
|
||||
_updateFilter(object) {
|
||||
this._updateMaping();
|
||||
const filterData = this.StyleData;
|
||||
const filterData = this.layerData;
|
||||
this._activeIds = null; // 清空选中元素
|
||||
const colorAttr = object.geometry.attributes.a_color;
|
||||
const pickAttr = object.geometry.attributes.pickingId;
|
||||
pickAttr.array.forEach((id, index) => {
|
||||
id = Math.abs(id);
|
||||
const color = [ ...this.StyleData[id - 1].color ];
|
||||
const color = [ ...this.layerData[id - 1].color ];
|
||||
id = Math.abs(id);
|
||||
const item = filterData[id - 1];
|
||||
if (item.hasOwnProperty('filter') && item.filter === false) {
|
||||
|
@ -584,7 +583,7 @@ export default class Layer extends Base {
|
|||
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
|
||||
const colorAttr = this.layerMesh.geometry.attributes.a_color;
|
||||
this._activeIds.forEach(index => {
|
||||
const color = this.StyleData[index].color;
|
||||
const color = this.layerData[index].color;
|
||||
const firstId = pickingId.indexOf(index + 1);
|
||||
for (let i = firstId; i < pickingId.length; i++) {
|
||||
if (pickingId[i] === index + 1) {
|
||||
|
|
|
@ -3,8 +3,8 @@ import { LAYER_MAP } from '../layer';
|
|||
import Base from './base';
|
||||
import LoadImage from './image';
|
||||
import WorkerPool from './worker';
|
||||
import { MapProvider } from '../map/provider';
|
||||
import GaodeMap from '../map/gaodeMap';
|
||||
// import { MapProvider } from '../map/AMap';
|
||||
import { getMap } from '../map/index';
|
||||
import Global from '../global';
|
||||
import { compileBuiltinModules } from '../geom/shader';
|
||||
export default class Scene extends Base {
|
||||
|
@ -31,16 +31,14 @@ export default class Scene extends Base {
|
|||
}
|
||||
_initMap() {
|
||||
this.mapContainer = this.get('id');
|
||||
this._container = document.getElementById(this.mapContainer);
|
||||
const Map = new MapProvider(this.mapContainer, this._attrs);
|
||||
this.mapType = this.get('mapType') || 'amap';
|
||||
const MapProvider = getMap(this.mapType);
|
||||
const Map = new MapProvider(this._attrs);
|
||||
Map.mixMap(this);
|
||||
this._container = document.getElementById(Map.container);
|
||||
// const Map = new MapProvider(this.mapContainer, this._attrs);
|
||||
Map.on('mapLoad', () => {
|
||||
this._initEngine(Map.renderDom);
|
||||
const sceneMap = new GaodeMap(Map.map);
|
||||
// eslint-disable-next-line
|
||||
Object.getOwnPropertyNames(sceneMap.__proto__).forEach((key)=>{
|
||||
// eslint-disable-next-line
|
||||
if ('key' !== 'constructor') { this.__proto__[key] = sceneMap.__proto__[key]; }
|
||||
});
|
||||
this.map = Map.map;
|
||||
Map.asyncCamera(this._engine);
|
||||
this.initLayer();
|
||||
|
@ -101,8 +99,10 @@ export default class Scene extends Base {
|
|||
'dblclick'
|
||||
];
|
||||
events.forEach(event => {
|
||||
this.map.on(event, e => {
|
||||
|
||||
this._container.addEventListener(event, e => {
|
||||
// 要素拾取
|
||||
e.pixel || (e.pixel = e.point);
|
||||
this._engine._picking.pickdata(e);
|
||||
}, false);
|
||||
});
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
/*
|
||||
* @Author: ThinkGIS
|
||||
* @Date: 2018-06-08 11:19:06
|
||||
* @Last Modified by: mikey.zhaopeng
|
||||
* @Last Modified time: 2018-11-01 11:50:43
|
||||
*/
|
||||
|
||||
import Base from './base';
|
||||
const Controller = require('./controller/index');
|
||||
import { aProjectFlat } from '../geo/project';
|
||||
import { getTransform, getParser } from '../source';
|
||||
import { getMap } from '../map/index';
|
||||
export default class Source extends Base {
|
||||
getDefaultCfg() {
|
||||
return {
|
||||
data: null,
|
||||
defs: {},
|
||||
parser: {},
|
||||
transforms: [],
|
||||
scales: {
|
||||
},
|
||||
options: {}
|
||||
|
@ -19,26 +17,40 @@ export default class Source extends Base {
|
|||
}
|
||||
constructor(cfg) {
|
||||
super(cfg);
|
||||
|
||||
const transform = this.get('transforms');
|
||||
this._transforms = transform || [];
|
||||
this._initControllers();
|
||||
this.prepareData();
|
||||
// 数据解析
|
||||
this._excuteParser();
|
||||
// 数据转换 统计,聚合,分类
|
||||
this._executeTrans();
|
||||
// 坐标转换
|
||||
this._projectCoords();
|
||||
}
|
||||
|
||||
// 标准化数据
|
||||
prepareData() {
|
||||
_excuteParser() {
|
||||
const parser = this.get('parser');
|
||||
const { type = 'geojson' } = parser;
|
||||
const data = this.get('data');
|
||||
this.propertiesData = [];// 临时使用
|
||||
this.geoData = [];
|
||||
|
||||
data.coordinates.forEach(geo => {
|
||||
const coord = this._coordProject(geo);
|
||||
this.geoData.push(coord);
|
||||
this.propertiesData.push([]);
|
||||
this.data = getParser(type)(data, parser);
|
||||
}
|
||||
/**
|
||||
* 数据统计
|
||||
*/
|
||||
_executeTrans() {
|
||||
const trans = this._transforms;
|
||||
trans.forEach(tran => {
|
||||
const { type } = tran;
|
||||
this.data = getTransform(type)(this.data, tran);
|
||||
});
|
||||
this._transforms = trans;
|
||||
}
|
||||
_projectCoords() {
|
||||
this.data.dataArray.forEach(data => {
|
||||
data.coordinates = this._coordProject(data.coordinates);
|
||||
});
|
||||
}
|
||||
|
||||
createScale(field) {
|
||||
const data = this.propertiesData;
|
||||
const data = this.data.dataArray;
|
||||
const scales = this.get('scales');
|
||||
let scale = scales[field];
|
||||
const scaleController = this.get('scaleController');
|
||||
|
@ -50,6 +62,8 @@ export default class Source extends Base {
|
|||
}
|
||||
_initControllers() {
|
||||
const defs = this.get('defs');
|
||||
const mapType = this.get('mapType');
|
||||
this.projectFlat = getMap(mapType).project;
|
||||
const scaleController = new Controller.Scale({
|
||||
defs
|
||||
});
|
||||
|
@ -83,9 +97,14 @@ export default class Source extends Base {
|
|||
}
|
||||
_coorConvert(geo) {
|
||||
|
||||
const ll = aProjectFlat(geo);
|
||||
return [ ll.x, -ll.y, geo[2] || 0 ];
|
||||
const ll = this.projectFlat(geo);
|
||||
return [ ll.x, ll.y, geo[2] || 0 ];
|
||||
|
||||
}
|
||||
getSelectFeature(featureId) {
|
||||
const data = this.get('data');
|
||||
// 如果是GeoJSON 数据返回原数
|
||||
return data.features ? data.features[featureId] : this.data.dataArray[featureId];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ export { Scene } from 'three/src/scenes/Scene.js';
|
|||
export { WebGLRenderer } from 'three/src/renderers/WebGLRenderer.js';
|
||||
export { CanvasTexture } from 'three/src/textures/CanvasTexture.js';
|
||||
export { Object3D } from 'three/src/core/Object3D.js';
|
||||
export { Group } from 'three/src/objects/Group';
|
||||
export { Clock } from 'three/src/core/Clock';
|
||||
export { Points } from 'three/src/objects/Points.js';
|
||||
export { LineSegments } from 'three/src/objects/LineSegments.js';
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -13,5 +13,20 @@ export function aProjectFlat(lnglat) {
|
|||
d = 0.5;
|
||||
x = scale * (a * x + b) - 215440491;
|
||||
y = scale * (c * y + d) - 106744817;
|
||||
return { x, y };
|
||||
return { x: parseInt(x), y: parseInt(y) };
|
||||
}
|
||||
export function unProjectFlat(px) {
|
||||
const a = 0.5 / Math.PI,
|
||||
b = 0.5,
|
||||
c = -0.5 / Math.PI;
|
||||
let d = 0.5;
|
||||
const scale = 256 << 20;
|
||||
let [ x, y ] = px;
|
||||
x = ((x + 215440491) / scale - b) / a;
|
||||
y = ((y + 106744817) / scale - d) / c;
|
||||
y = (Math.atan(Math.pow(Math.E, y)) - (Math.PI / 4)) * 2;
|
||||
d = Math.PI / 180;
|
||||
const lat = y / d;
|
||||
const lng = x / d;
|
||||
return [ lng, lat ];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
export default function gridBuffer(layerData) {
|
||||
const attribute = {
|
||||
vertices: [],
|
||||
miter: [],
|
||||
colors: [],
|
||||
pickingIds: []
|
||||
};
|
||||
layerData.forEach(element => {
|
||||
const { color, id } = element;
|
||||
const [ x, y, z ] = element.coordinates;
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(-1, -1);
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(1, 1);
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(-1, 1);
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(-1, -1);
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(1, -1);
|
||||
attribute.vertices.push(x, y, z);
|
||||
attribute.miter.push(1, 1);
|
||||
attribute.colors.push(...color);
|
||||
attribute.colors.push(...color);
|
||||
attribute.colors.push(...color);
|
||||
attribute.colors.push(...color);
|
||||
attribute.colors.push(...color);
|
||||
attribute.colors.push(...color);
|
||||
attribute.pickingIds.push(id, id, id, id, id, id);
|
||||
});
|
||||
return attribute;
|
||||
}
|
|
@ -4,8 +4,9 @@ import * as THREE from '../../core/three';
|
|||
|
||||
export default class ImageBuffer extends BufferBase {
|
||||
geometryBuffer() {
|
||||
const coordinates = this.get('coordinates');
|
||||
const images = this.get('image');
|
||||
const layerData = this.get('layerData');
|
||||
const coordinates = layerData[0].coordinates;
|
||||
const images = layerData[0].images;
|
||||
const positions = [ ...coordinates[0],
|
||||
coordinates[1][0], coordinates[0][1], 0,
|
||||
...coordinates[1],
|
||||
|
|
|
@ -3,8 +3,7 @@ import { lineShape } from '../shape';
|
|||
|
||||
export default class LineBuffer extends BufferBase {
|
||||
geometryBuffer() {
|
||||
const coordinates = this.get('coordinates');
|
||||
const properties = this.get('properties');
|
||||
const layerData = this.get('layerData');
|
||||
const shapeType = this.shapeType = this.get('shapeType');
|
||||
const positions = [];
|
||||
const positionsIndex = [];
|
||||
|
@ -16,16 +15,16 @@ export default class LineBuffer extends BufferBase {
|
|||
this.attributes = this._getArcLineAttributes();
|
||||
return;
|
||||
}
|
||||
coordinates.forEach((geo, index) => {
|
||||
const props = properties[index];
|
||||
const attrData = this._getShape(geo, props, index);
|
||||
layerData.forEach((item, index) => {
|
||||
const props = item;
|
||||
const attrData = this._getShape(item.coordinates, props, index);
|
||||
positions.push(...attrData.positions);
|
||||
positionsIndex.push(...attrData.indexes);
|
||||
if (attrData.hasOwnProperty('instances')) {
|
||||
instances.push(...attrData.instances);
|
||||
}
|
||||
});
|
||||
this.bufferStruct.style = properties;
|
||||
this.bufferStruct.style = layerData;
|
||||
this.bufferStruct.verts = positions;
|
||||
this.bufferStruct.indexs = positionsIndex;
|
||||
if (instances.length > 0) {
|
||||
|
@ -50,17 +49,16 @@ export default class LineBuffer extends BufferBase {
|
|||
|
||||
}
|
||||
_getArcLineAttributes() {
|
||||
const coordinates = this.get('coordinates');
|
||||
const properties = this.get('properties');
|
||||
const layerData = this.get('layerData');
|
||||
const positions = [];
|
||||
const colors = [];
|
||||
const indexArray = [];
|
||||
const sizes = [];
|
||||
const instances = [];
|
||||
coordinates.forEach((geo, index) => {
|
||||
const props = properties[index];
|
||||
layerData.forEach(item => {
|
||||
const props = item;
|
||||
const positionCount = positions.length / 3;
|
||||
const attrData = this._getShape(geo, props, positionCount);
|
||||
const attrData = this._getShape(item.coordinates, props, positionCount);
|
||||
positions.push(...attrData.positions);
|
||||
colors.push(...attrData.colors);
|
||||
indexArray.push(...attrData.indexArray);
|
||||
|
@ -76,8 +74,7 @@ export default class LineBuffer extends BufferBase {
|
|||
};
|
||||
}
|
||||
_getMeshLineAttributes() {
|
||||
const coordinates = this.get('coordinates');
|
||||
const properties = this.get('properties');
|
||||
const layerData = this.get('layerData');
|
||||
const { lineType } = this.get('style');
|
||||
const positions = [];
|
||||
const pickingIds = [];
|
||||
|
@ -87,10 +84,10 @@ export default class LineBuffer extends BufferBase {
|
|||
const indexArray = [];
|
||||
const sizes = [];
|
||||
const attrDistance = [];
|
||||
coordinates.forEach((geo, index) => {
|
||||
const props = properties[index];
|
||||
layerData.forEach(item => {
|
||||
const props = item;
|
||||
const positionCount = positions.length / 3;
|
||||
const attr = lineShape.Line(geo, props, positionCount, (lineType !== 'soild'));
|
||||
const attr = lineShape.Line(item.coordinates, props, positionCount, (lineType !== 'soild'));
|
||||
positions.push(...attr.positions);
|
||||
normal.push(...attr.normal);
|
||||
miter.push(...attr.miter);
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as THREE from '../../../core/three';
|
|||
import * as polygonShape from '../../shape/polygon';
|
||||
import * as polygonPath from '../../shape/path';
|
||||
import Util from '../../../util';
|
||||
export default function fillBuffer(coordinates, properties) {
|
||||
export default function fillBuffer(layerData) {
|
||||
const attribute = {
|
||||
vertices: [],
|
||||
normals: [],
|
||||
|
@ -14,8 +14,8 @@ export default function fillBuffer(coordinates, properties) {
|
|||
faceUv: []
|
||||
|
||||
};
|
||||
coordinates.forEach((geo, index) => {
|
||||
let { size, shape, color, id } = properties[index];
|
||||
layerData.forEach(item => {
|
||||
let { size, shape, color, id, coordinates } = item;
|
||||
let polygon = null;
|
||||
const path = polygonPath[shape]();
|
||||
if (pointShape['2d'].indexOf(shape) !== -1) {
|
||||
|
@ -27,7 +27,7 @@ export default function fillBuffer(coordinates, properties) {
|
|||
} else {
|
||||
throw new Error('Invalid shape type: ' + shape);
|
||||
}
|
||||
toPointShapeAttributes(polygon, geo, { size, shape, color, id }, attribute);
|
||||
toPointShapeAttributes(polygon, coordinates, { size, shape, color, id }, attribute);
|
||||
|
||||
});
|
||||
return attribute;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default function ImageBuffer(coordinates, properties, opt) {
|
||||
export default function ImageBuffer(layerData, opt) {
|
||||
const attributes = {
|
||||
vertices: [],
|
||||
colors: [],
|
||||
|
@ -7,10 +7,10 @@ export default function ImageBuffer(coordinates, properties, opt) {
|
|||
pickingIds: [],
|
||||
uv: []
|
||||
};
|
||||
coordinates.forEach((pos, index) => {
|
||||
const { color, size, id, shape } = properties[index];
|
||||
layerData.forEach(item => {
|
||||
const { color, size, id, shape, coordinates } = item;
|
||||
const { x, y } = opt.imagePos[shape];
|
||||
attributes.vertices.push(...pos);
|
||||
attributes.vertices.push(...coordinates);
|
||||
attributes.colors.push(...color);
|
||||
attributes.pickingIds.push(id);
|
||||
attributes.sizes.push(size * window.devicePixelRatio); //
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
export default function NormalBuffer(coordinates, properties) {
|
||||
export default function NormalBuffer(layerData) {
|
||||
const attributes = {
|
||||
vertices: [],
|
||||
colors: [],
|
||||
sizes: [],
|
||||
pickingIds: []
|
||||
};
|
||||
coordinates.forEach((pos, index) => {
|
||||
const { color, size, id } = properties[index];
|
||||
attributes.vertices.push(...pos);
|
||||
layerData.forEach(item => {
|
||||
const { color, size, id, coordinates} = item;
|
||||
attributes.vertices.push(...coordinates);
|
||||
attributes.colors.push(...color);
|
||||
attributes.pickingIds.push(id);
|
||||
attributes.sizes.push(size);
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as polygonShape from '../../shape/polygon';
|
|||
import * as lineShape from '../../shape/line';
|
||||
import { pointShape } from '../../../global';
|
||||
import Util from '../../../util';
|
||||
export default function StrokeBuffer(coordinates, properties, style) {
|
||||
export default function StrokeBuffer(layerData, style) {
|
||||
const attribute = {
|
||||
shapes: [],
|
||||
normal: [],
|
||||
|
@ -15,8 +15,8 @@ export default function StrokeBuffer(coordinates, properties, style) {
|
|||
colors: []
|
||||
};
|
||||
const { stroke, strokeWidth } = style;
|
||||
coordinates.forEach((geo, index) => {
|
||||
let { size, shape, id } = properties[index];
|
||||
layerData.forEach(item => {
|
||||
let { size, shape, id, coordinates } = item;
|
||||
const path = polygonPath[shape]();
|
||||
const positionsIndex = attribute.miter.length;
|
||||
let polygon = null;
|
||||
|
@ -33,7 +33,7 @@ export default function StrokeBuffer(coordinates, properties, style) {
|
|||
} else {
|
||||
throw new Error('Invalid shape type: ' + shape);
|
||||
}
|
||||
polygonLineBuffer(polygon, geo, size, attribute);
|
||||
polygonLineBuffer(polygon, coordinates, size, attribute);
|
||||
|
||||
});
|
||||
return attribute;
|
||||
|
|
|
@ -9,7 +9,7 @@ const metrics = {
|
|||
family: 'ios9',
|
||||
size: 24
|
||||
};
|
||||
export default function TextBuffer(coordinates, properties, style) {
|
||||
export default function TextBuffer(layerData, style) {
|
||||
EventEmitter.call(this);
|
||||
const attributes = {
|
||||
originPoints: [],
|
||||
|
@ -21,7 +21,7 @@ export default function TextBuffer(coordinates, properties, style) {
|
|||
const { textOffset = [ 0, 0 ] } = style;
|
||||
const chars = [];
|
||||
const textChars = {};
|
||||
properties.forEach(element => {
|
||||
layerData.forEach(element => {
|
||||
let text = element.shape || '';
|
||||
text = text.toString();
|
||||
for (let j = 0; j < text.length; j++) {
|
||||
|
@ -33,9 +33,9 @@ export default function TextBuffer(coordinates, properties, style) {
|
|||
}
|
||||
});
|
||||
loadTextInfo(chars, (chars, texture) => {
|
||||
properties.forEach((element, index) => {
|
||||
layerData.forEach(element => {
|
||||
const size = element.size;
|
||||
const pos = coordinates[index];
|
||||
const pos = layerData.coordinates;
|
||||
const pen = { x: textOffset[0], y: textOffset[1] };
|
||||
let text = element.shape || '';
|
||||
text = text.toString();
|
||||
|
|
|
@ -3,22 +3,21 @@ import BufferBase from './bufferBase';
|
|||
export default class PolygonBuffer extends BufferBase {
|
||||
|
||||
geometryBuffer() {
|
||||
const coordinates = this.get('coordinates');
|
||||
const properties = this.get('properties');
|
||||
const layerData = this.get('layerData');
|
||||
const shape = this.get('shape');
|
||||
const positions = [];
|
||||
const faceUv = [];
|
||||
const sizes = [];
|
||||
const positionsIndex = [];
|
||||
let indexCount = 0;
|
||||
this.bufferStruct.style = properties;
|
||||
const isExtrude = properties[0].hasOwnProperty('size');
|
||||
this.bufferStruct.style = layerData;
|
||||
const isExtrude = layerData[0].hasOwnProperty('size');
|
||||
// indices, normals, colors, UVs
|
||||
coordinates.forEach((geo, index) => {
|
||||
const heightValue = properties[index].size;
|
||||
let extrudeData = polygonShape[shape](geo);
|
||||
layerData.forEach(item => {
|
||||
const heightValue = item.size;
|
||||
let extrudeData = polygonShape[shape](item.coordinates);
|
||||
if (isExtrude && shape === 'extrude') {
|
||||
extrudeData = polygonShape.extrude(geo);
|
||||
extrudeData = polygonShape.extrude(item.coordinates);
|
||||
extrudeData.positions = extrudeData.positions.map(pos => {
|
||||
pos[2] *= heightValue;
|
||||
return pos;
|
||||
|
@ -48,7 +47,7 @@ export default class PolygonBuffer extends BufferBase {
|
|||
this.bufferStruct.indices = positionsIndex;
|
||||
this.bufferStruct.position = positions;
|
||||
this.bufferStruct.indexCount = indexCount;
|
||||
this.bufferStruct.style = properties;
|
||||
this.bufferStruct.style = layerData;
|
||||
this.bufferStruct.faceUv = faceUv;
|
||||
this.bufferStruct.sizes = sizes;
|
||||
if (shape !== 'line') {
|
||||
|
|
|
@ -3,8 +3,8 @@ import { colorScales } from '../../attr/colorscales';
|
|||
import * as THREE from '../../core/three';
|
||||
export class RasterBuffer extends BufferBase {
|
||||
geometryBuffer() {
|
||||
const coordinates = this.get('coordinates');
|
||||
|
||||
const layerData = this.get('layerData');
|
||||
const { coordinates, width, data, height } = layerData.dataArray[0];
|
||||
const positions = [
|
||||
...coordinates[0],
|
||||
coordinates[1][0], coordinates[0][1], 0,
|
||||
|
@ -14,9 +14,8 @@ export class RasterBuffer extends BufferBase {
|
|||
coordinates[0][0], coordinates[1][1], 0
|
||||
];
|
||||
const imgPosUv = [ 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 ];
|
||||
const raster = this.get('raster');
|
||||
const size = this.get('size');
|
||||
const texture = new THREE.DataTexture(new Float32Array(raster.data), raster.width, raster.height, THREE.LuminanceFormat, THREE.FloatType);
|
||||
const texture = new THREE.DataTexture(new Float32Array(data), width, height, THREE.LuminanceFormat, THREE.FloatType);
|
||||
texture.generateMipmaps = true;
|
||||
texture.needsUpdate = true;
|
||||
const colors = this.get('rampColors');
|
||||
|
@ -28,7 +27,7 @@ export class RasterBuffer extends BufferBase {
|
|||
this.bufferStruct.u_extent = [ coordinates[0][0], coordinates[0][1], coordinates[1][0], coordinates[1][1] ];
|
||||
|
||||
this.bufferStruct.u_colorTexture = colorTexture; // 颜色表‘=
|
||||
const triangles = this._buildTriangles(raster, size, this.bufferStruct.u_extent);
|
||||
const triangles = this._buildTriangles(width, height, size, this.bufferStruct.u_extent);
|
||||
const attributes = {
|
||||
vertices: new Float32Array(triangles.vertices),
|
||||
uvs: new Float32Array(triangles.uvs),
|
||||
|
@ -78,9 +77,8 @@ export class RasterBuffer extends BufferBase {
|
|||
texture1.needsUpdate = true;
|
||||
return texture1;
|
||||
}
|
||||
_buildTriangles(raster, size = 1, extent) {
|
||||
_buildTriangles(width, height, size = 1, extent) {
|
||||
// const extent = [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ]
|
||||
const { width, height } = raster;
|
||||
const indices = [];
|
||||
const vertices = [];
|
||||
const uvs = [];
|
||||
|
|
|
@ -13,12 +13,11 @@ export default class TextBuffer extends BufferBase {
|
|||
family: 'ios9',
|
||||
size: 24
|
||||
};
|
||||
const coordinates = this.get('coordinates');
|
||||
const properties = this.get('properties');
|
||||
const layerData = this.get('layerData');
|
||||
const { textOffset = [ 0, 0 ] } = this.get('style');
|
||||
const chars = [];
|
||||
const textChars = {};
|
||||
properties.forEach(element => {
|
||||
layerData.forEach(element => {
|
||||
let text = element.shape || '';
|
||||
text = text.toString();
|
||||
for (let j = 0; j < text.length; j++) {
|
||||
|
@ -39,9 +38,9 @@ export default class TextBuffer extends BufferBase {
|
|||
const originPoints = [];
|
||||
const textSizes = [];
|
||||
const textOffsets = [];
|
||||
properties.forEach((element, index) => {
|
||||
layerData.forEach(element => {
|
||||
const size = element.size;
|
||||
const pos = coordinates[index];
|
||||
const pos = element.coordinates;
|
||||
// const pen = { x: pos[0] - dimensions.advance / 2, y: pos[1] };
|
||||
const pen = { x: textOffset[0], y: textOffset[1] };
|
||||
let text = element.shape || '';
|
||||
|
@ -53,7 +52,7 @@ export default class TextBuffer extends BufferBase {
|
|||
this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
|
||||
}
|
||||
});
|
||||
this.bufferStruct.style = properties;
|
||||
this.bufferStruct.style = layerData;
|
||||
this.attributes = {
|
||||
originPoints,
|
||||
textSizes,
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import grid_frag from '../shader/grid_frag.glsl';
|
||||
import grid_vert from '../shader/grid_vert.glsl';
|
||||
import Material from './material';
|
||||
|
||||
|
||||
export default class GridMaterial extends Material {
|
||||
getDefaultParameters() {
|
||||
return {
|
||||
uniforms: {
|
||||
u_opacity: { value: 1.0 },
|
||||
u_time: { value: 0 },
|
||||
u_xOffset: { value: 0.01 },
|
||||
u_yOffset: { value: 0.01 },
|
||||
u_coverage: { value: 0.8 }
|
||||
},
|
||||
defines: {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
constructor(_uniforms, _defines, parameters) {
|
||||
super(parameters);
|
||||
const { uniforms, defines } = this.getDefaultParameters();
|
||||
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
|
||||
this.type = 'GridMaterial';
|
||||
this.defines = Object.assign(defines, _defines);
|
||||
this.vertexShader = grid_vert;
|
||||
this.fragmentShader = grid_frag;
|
||||
this.transparent = true;
|
||||
}
|
||||
}
|
|
@ -1,28 +1,5 @@
|
|||
import Material from './material';
|
||||
import { getModule } from '../../util/shaderModule';
|
||||
// export default function PolygonMaterial(options) {
|
||||
// const material = new Material({
|
||||
// uniforms: {
|
||||
// u_opacity: { value: options.u_opacity || 1.0 },
|
||||
// u_texture: { value: options.u_texture },
|
||||
// u_time: { value: options.u_time || 0 },
|
||||
// u_zoom: { value: options.u_zoom || 0 },
|
||||
// u_baseColor: { value: options.u_baseColor || [ 1.0, 0, 0, 1.0 ] },
|
||||
// u_brightColor: { value: options.u_brightColor || [ 1.0, 0, 0, 1.0 ] },
|
||||
// u_windowColor: { value: options.u_windowColor || [ 1.0, 0, 0, 1.0 ] },
|
||||
// u_near: { value: options.u_near || 0.0 },
|
||||
// u_far: { value: options.u_far || 1.0 }
|
||||
// },
|
||||
// vertexShader: polygon_vert,
|
||||
// fragmentShader: polygon_frag,
|
||||
// transparent: true,
|
||||
// defines: {
|
||||
// TEXCOORD_0: !!options.u_texture
|
||||
// }
|
||||
// });
|
||||
// return material;
|
||||
// }
|
||||
|
||||
export default class PolygonMaterial extends Material {
|
||||
getDefaultParameters() {
|
||||
return {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
precision highp float;
|
||||
uniform float u_opacity;
|
||||
varying vec4 v_color;
|
||||
void main() {
|
||||
vec4 color = v_color;
|
||||
gl_FragColor = color;
|
||||
gl_FragColor.a =color.a*u_opacity;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
precision highp float;
|
||||
attribute vec2 miter;
|
||||
attribute vec4 a_color;
|
||||
uniform float u_xOffset;
|
||||
uniform float u_yOffset;
|
||||
uniform float u_coverage;
|
||||
varying vec4 v_color;
|
||||
|
||||
void main() {
|
||||
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
||||
v_color = a_color;
|
||||
float x = position.x + miter.x * u_xOffset * u_coverage;
|
||||
float y = position.y + miter.y * u_yOffset * u_coverage;
|
||||
gl_Position = matModelViewProjection * vec4(x, y, position.z, 1.0);
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
|
||||
precision highp float;
|
||||
|
||||
#pragma import "common"
|
||||
#define PI 3.14159265359
|
||||
#define TWO_PI 6.28318530718
|
||||
|
||||
uniform float u_strokeWidth;
|
||||
uniform vec4 u_stroke;
|
||||
|
|
|
@ -15,7 +15,7 @@ varying float v_size;
|
|||
|
||||
void main() {
|
||||
float scale = pow(2.0,(20.0 - u_zoom));
|
||||
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
|
||||
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix * 100.;
|
||||
vec3 newposition = position;
|
||||
// newposition.x -= 128.0;
|
||||
#ifdef SHAPE
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import Layer from '../core/layer';
|
||||
import gridBuffer from '../geom/buffer/heatmap/grid';
|
||||
import DrawGrid from './render/heatmap/gird';
|
||||
|
||||
export default class HeatMapLayer extends Layer {
|
||||
shape(type) {
|
||||
this.shapeType = type;
|
||||
return this;
|
||||
}
|
||||
render() {
|
||||
this._prepareRender();
|
||||
return this;
|
||||
}
|
||||
_prepareRender() {
|
||||
this.init();
|
||||
this.type = 'heatmap';
|
||||
const style = this.get('styleOptions');
|
||||
const { xOffset, yOffset } = this.layerSource.data;
|
||||
this._buffer = new gridBuffer(this.layerData);
|
||||
const config = {
|
||||
...style,
|
||||
xOffset,
|
||||
yOffset
|
||||
};
|
||||
const girdMesh = new DrawGrid(this._buffer, config);
|
||||
this.add(girdMesh);
|
||||
}
|
||||
}
|
|
@ -1,26 +1,19 @@
|
|||
import Layer from '../core/layer';
|
||||
import * as THREE from '../core/three';
|
||||
import imageSource from '../source/imageSource';
|
||||
import ImageBuffer from '../geom/buffer/image';
|
||||
// import ImageGeometry from '../geom/bufferGeometry/image';
|
||||
import ImageMaterial from '../geom/material/imageMaterial';
|
||||
export default class imageLayer extends Layer {
|
||||
source(data, cfg = {}) {
|
||||
cfg.mapType = this.get('mapType');
|
||||
cfg.data = data;
|
||||
this.layerSource = new imageSource(cfg);
|
||||
return this;
|
||||
}
|
||||
render() {
|
||||
this.init();
|
||||
this.type = 'image';
|
||||
const source = this.layerSource;
|
||||
const { opacity } = this.get('styleOptions');
|
||||
// 加载 完成事件
|
||||
source.on('imageLoaded', () => {
|
||||
source.data.images.then(images => {
|
||||
this.layerData[0].images = images;
|
||||
const buffer = new ImageBuffer({
|
||||
coordinates: source.geoData,
|
||||
image: source.image
|
||||
layerData: this.layerData
|
||||
});
|
||||
this.initGeometry(buffer.attributes);
|
||||
const material = new ImageMaterial({
|
||||
|
|
|
@ -4,17 +4,14 @@ import PointLayer from './pointLayer';
|
|||
import LineLayer from './lineLayer';
|
||||
import ImageLayer from './imageLayer';
|
||||
import RasterLayer from './rasterLayer';
|
||||
import HeatMapLayer from './heatmap';
|
||||
|
||||
registerLayer('PolygonLayer', PolygonLayer);
|
||||
registerLayer('PointLayer', PointLayer);
|
||||
registerLayer('LineLayer', LineLayer);
|
||||
registerLayer('ImageLayer', ImageLayer);
|
||||
registerLayer('RasterLayer', RasterLayer);
|
||||
registerLayer('HeatMapLayer', HeatMapLayer);
|
||||
|
||||
export { LAYER_MAP } from './factory';
|
||||
export { default as PolygonLayer } from './polygonLayer';
|
||||
export { default as PointLayer } from './pointLayer';
|
||||
export { default as LineLayer } from './lineLayer';
|
||||
export { default as ImageLayer } from './imageLayer';
|
||||
export { default as RasterLayer } from './rasterLayer';
|
||||
|
||||
|
|
|
@ -12,11 +12,10 @@ export default class LineLayer extends Layer {
|
|||
this.type = 'polyline';
|
||||
this.init();
|
||||
const source = this.layerSource;
|
||||
const StyleData = this.StyleData;
|
||||
const layerData = this.layerData;
|
||||
const style = this.get('styleOptions');
|
||||
const buffer = this._buffer = new LineBuffer({
|
||||
coordinates: source.geoData,
|
||||
properties: StyleData,
|
||||
layerData,
|
||||
shapeType: this.shapeType,
|
||||
style
|
||||
});
|
||||
|
|
|
@ -45,12 +45,12 @@ export default class PointLayer extends Layer {
|
|||
case 'fill' :// 填充图形
|
||||
{
|
||||
if (fill !== 'none') { // 是否填充
|
||||
const attributes = PointBuffer.FillBuffer(source.geoData, this.StyleData, style);
|
||||
const attributes = PointBuffer.FillBuffer(this.layerData, style);
|
||||
const meshfill = drawPoint.DrawFill(attributes, this.get('styleOptions'));
|
||||
this.add(meshfill);
|
||||
}
|
||||
if (stroke !== 'none') { // 是否绘制边界
|
||||
const lineAttribute = PointBuffer.StrokeBuffer(source.geoData, this.StyleData, style);
|
||||
const lineAttribute = PointBuffer.StrokeBuffer(this.layerData, style);
|
||||
const meshStroke = drawPoint.DrawStroke(lineAttribute, this.get('styleOptions'));
|
||||
this.add(meshStroke, 'line');
|
||||
}
|
||||
|
@ -58,14 +58,14 @@ export default class PointLayer extends Layer {
|
|||
}
|
||||
case 'image':// 绘制图片标注
|
||||
{
|
||||
const imageAttribute = PointBuffer.ImageBuffer(source.geoData, this.StyleData, { imagePos: this.scene.image.imagePos });
|
||||
const imageAttribute = PointBuffer.ImageBuffer(this.layerData, { imagePos: this.scene.image.imagePos });
|
||||
const imageMesh = drawPoint.DrawImage(imageAttribute, { ...style, texture: this.scene.image.texture });
|
||||
this.add(imageMesh);
|
||||
break;
|
||||
}
|
||||
case 'normal' : // 原生点
|
||||
{
|
||||
const normalAttribute = PointBuffer.NormalBuffer(source.geoData, this.StyleData, style);
|
||||
const normalAttribute = PointBuffer.NormalBuffer(this.layerData, style);
|
||||
const normalPointMesh = drawPoint.DrawNormal(normalAttribute, style);
|
||||
this.add(normalPointMesh);
|
||||
break;
|
||||
|
@ -77,11 +77,11 @@ export default class PointLayer extends Layer {
|
|||
|
||||
_getShape() {
|
||||
let shape = null;
|
||||
if (!this.StyleData[0].hasOwnProperty('shape')) {
|
||||
if (!this.layerData[0].hasOwnProperty('shape')) {
|
||||
return 'normal';
|
||||
}
|
||||
for (let i = 0; i < this.StyleData.length; i++) {
|
||||
shape = this.StyleData[i].shape;
|
||||
for (let i = 0; i < this.layerData.length; i++) {
|
||||
shape = this.layerData[i].shape;
|
||||
if (shape !== undefined) {
|
||||
break;
|
||||
}
|
||||
|
@ -102,8 +102,7 @@ export default class PointLayer extends Layer {
|
|||
const styleOptions = this.get('styleOptions');
|
||||
const buffer = new TextBuffer({
|
||||
type: this.shapeType,
|
||||
coordinates: source.geoData,
|
||||
properties: this.StyleData,
|
||||
layerData: this.layerData,
|
||||
style: this.get('styleOptions')
|
||||
});
|
||||
|
||||
|
|
|
@ -21,11 +21,9 @@ export default class PolygonLayer extends Layer {
|
|||
_prepareRender() {
|
||||
this.init();
|
||||
this.type = 'polygon';
|
||||
const source = this.layerSource;
|
||||
this._buffer = new PolygonBuffer({
|
||||
shape: this.shape,
|
||||
coordinates: source.geoData,
|
||||
properties: this.StyleData
|
||||
layerData: this.layerData
|
||||
});
|
||||
this.add(this._getLayerRender());
|
||||
}
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
import Layer from '../core/layer';
|
||||
import * as THREE from '../core/three';
|
||||
import RasterSource from '../source/rasterSource';
|
||||
import RasterMaterial from '../geom/material/rasterMaterial';
|
||||
import { RasterBuffer } from '../geom/buffer/raster';
|
||||
|
||||
export default class RasterLayer extends Layer {
|
||||
source(data, cfg = {}) {
|
||||
cfg.mapType = this.get('mapType');
|
||||
cfg.data = data;
|
||||
this.layerSource = new RasterSource(cfg);
|
||||
return this;
|
||||
}
|
||||
|
||||
render() {
|
||||
this.type = 'raster';
|
||||
this.init();
|
||||
|
@ -18,18 +12,18 @@ export default class RasterLayer extends Layer {
|
|||
// 加载 完成事件
|
||||
const styleOptions = this.get('styleOptions');
|
||||
const buffer = new RasterBuffer({
|
||||
coordinates: source.geoData,
|
||||
raster: source.rasterData,
|
||||
layerData: source.data,
|
||||
rampColors: styleOptions.rampColors
|
||||
});
|
||||
this.initGeometry(buffer.attributes);
|
||||
const rasterConfig = source.data.dataArray[0];
|
||||
const material = new RasterMaterial({
|
||||
u_texture: buffer.bufferStruct.u_raster,
|
||||
u_colorTexture: buffer.bufferStruct.u_colorTexture,
|
||||
u_opacity: 1.0,
|
||||
u_extent: buffer.bufferStruct.u_extent,
|
||||
u_min: source.rasterData.min,
|
||||
u_max: source.rasterData.max,
|
||||
u_min: rasterConfig.min,
|
||||
u_max: rasterConfig.max,
|
||||
u_dimension: buffer.attributes.dimension
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import * as THREE from '../../../core/three';
|
||||
import GridMaterial from '../../../geom/material/grid';
|
||||
export default function DrawGrid(attributes, style) {
|
||||
const { opacity, xOffset, yOffset, coverage } = style;
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
|
||||
geometry.addAttribute('miter', new THREE.Float32BufferAttribute(attributes.miter, 2));
|
||||
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
|
||||
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
|
||||
const material = new GridMaterial({
|
||||
u_opacity: opacity,
|
||||
u_xOffset: xOffset,
|
||||
u_yOffset: yOffset,
|
||||
u_coverage: coverage
|
||||
}, {
|
||||
SHAPE: false
|
||||
});
|
||||
const gridMesh = new THREE.Mesh(geometry, material);
|
||||
return gridMesh;
|
||||
}
|
||||
|
|
@ -1,18 +1,34 @@
|
|||
import Base from '../core/base';
|
||||
import { scene } from '../global';
|
||||
import * as Theme from '../theme/index';
|
||||
import Util from '../util';
|
||||
import { scene } from '../global';
|
||||
const DEG2RAD = Math.PI / 180;
|
||||
export class MapProvider extends Base {
|
||||
export default class GaodeMap extends Base {
|
||||
getDefaultCfg() {
|
||||
return Util.assign(scene, {
|
||||
resizeEnable: true,
|
||||
viewMode: '3D'
|
||||
});
|
||||
}
|
||||
constructor(container, cfg) {
|
||||
static project(lnglat) {
|
||||
const maxs = 85.0511287798;
|
||||
const lat = Math.max(Math.min(maxs, lnglat[1]), -maxs);
|
||||
const scale = 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,
|
||||
b = 0.5,
|
||||
c = -0.5 / Math.PI;
|
||||
d = 0.5;
|
||||
x = scale * (a * x + b) - 215440491;
|
||||
y = -(scale * (c * y + d) - 106744817);
|
||||
return { x, y };
|
||||
}
|
||||
constructor(cfg) {
|
||||
super(cfg);
|
||||
this.container = container;
|
||||
this.container = this.get('id');
|
||||
this.initMap();
|
||||
this.addOverLayer();
|
||||
setTimeout(() => {
|
||||
|
@ -85,4 +101,31 @@ export class MapProvider extends Base {
|
|||
this.renderDom.id = 'l7_canvaslayer';
|
||||
canvasContainer.appendChild(this.renderDom);
|
||||
}
|
||||
mixMap(scene) {
|
||||
const map = this.map;
|
||||
scene.getZoom = () => { return map.getZoom(); };
|
||||
scene.getCenter = () => { return map.getCenter(); };
|
||||
scene.getSize = () => { return map.getSize(); };
|
||||
scene.getPitch = () => { return map.getPitch(); };
|
||||
scene.getRotation = () => { return map.getRotation(); };
|
||||
scene.getStatus = () => { return map.getStatus(); };
|
||||
scene.getScale = () => { return map.getScale(); };
|
||||
scene.getZoom = () => { return map.getZoom(); };
|
||||
scene.setZoom = () => { return map.setZoom(); };
|
||||
scene.setBounds = () => { return map.setBounds(); };
|
||||
scene.setRotation = () => { return map.setRotation(); };
|
||||
scene.zoomIn = () => { return map.zoomIn(); };
|
||||
scene.setRotation = () => { return map.setRotation(); };
|
||||
scene.zoomOut = () => { return map.zoomOut(); };
|
||||
scene.panTo = () => { return map.panTo(); };
|
||||
scene.panBy = () => { return map.panBy(); };
|
||||
scene.setPitch = () => { return map.setPitch(); };
|
||||
scene.pixelToLngLat = () => { return map.pixelToLngLat(); };
|
||||
scene.lngLatToPixel = () => { return map.lngLatToPixel(); };
|
||||
scene.setMapStyle = () => { return map.setMapStyle(); };
|
||||
scene.containerToLngLat = pixel => {
|
||||
const ll = new AMap.Pixel(pixel.x, pixel.y);
|
||||
return map.containerToLngLat(ll);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ export default class GaodeMap {
|
|||
return this.map.getStatus();
|
||||
}
|
||||
getScale() {
|
||||
return this.getScale();
|
||||
return this.map.getScale();
|
||||
}
|
||||
setZoom(zoom) {
|
||||
return this.map.setZoom(zoom);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import MapBox from './mapbox';
|
||||
import { default as AMap } from './AMap';
|
||||
export {
|
||||
AMap,
|
||||
MapBox
|
||||
};
|
||||
const MapType = {
|
||||
amap: AMap,
|
||||
mapbox: MapBox
|
||||
};
|
||||
export const getMap = type => {
|
||||
return MapType[type.toLowerCase()];
|
||||
};
|
||||
|
||||
export const registerMap = (type, map) => {
|
||||
if (getMap(type)) {
|
||||
throw new Error(`Map type '${type}' existed.`);
|
||||
}
|
||||
map.type = type;
|
||||
// 存储到 map 中
|
||||
MapType[type.toLowerCase()] = map;
|
||||
};
|
|
@ -0,0 +1,154 @@
|
|||
import Base from '../core/base';
|
||||
import Util from '../util';
|
||||
import { scene } from '../global';
|
||||
import * as THREE from '../core/three';
|
||||
const WORLD_SIZE = 512;
|
||||
const MERCATOR_A = 6378137.0;
|
||||
const WORLD_SCALE = 1 / 100;
|
||||
const PROJECTION_WORLD_SIZE = WORLD_SIZE / (MERCATOR_A * Math.PI) / 2;
|
||||
export default class MapBox extends Base {
|
||||
getDefaultCfg() {
|
||||
return Util.assign(scene, {
|
||||
resizeEnable: true,
|
||||
viewMode: '3D'
|
||||
});
|
||||
}
|
||||
static project(lnglat) {
|
||||
const d = Math.PI / 180;
|
||||
const x = -MERCATOR_A * lnglat[0] * d * PROJECTION_WORLD_SIZE;
|
||||
const y = -MERCATOR_A * Math.log(Math.tan((Math.PI * 0.25) + (0.5 * lnglat[1] * d))) * PROJECTION_WORLD_SIZE;
|
||||
return { x, y };
|
||||
}
|
||||
constructor(cfg) {
|
||||
super(cfg);
|
||||
this.container = this.get('container');
|
||||
this.initMap();
|
||||
this.addOverLayer();
|
||||
setTimeout(() => {
|
||||
this.emit('mapLoad');
|
||||
}, 100);
|
||||
|
||||
}
|
||||
|
||||
initMap() {
|
||||
mapboxgl.accessToken = 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ';
|
||||
this.map = new mapboxgl.Map(this._attrs);
|
||||
}
|
||||
asyncCamera(engine) {
|
||||
this.engine = engine;
|
||||
const camera = engine._camera;
|
||||
const scene = engine.world;
|
||||
const pickScene = engine._picking.world;
|
||||
camera.matrixAutoUpdate = false;
|
||||
scene.position.x = scene.position.y = WORLD_SIZE / 2;
|
||||
scene.matrixAutoUpdate = false;
|
||||
pickScene.position.x = pickScene.position.y = WORLD_SIZE / 2;
|
||||
pickScene.matrixAutoUpdate = false;
|
||||
this.updateCamera();
|
||||
this.map.on('move', () => {
|
||||
this.updateCamera();
|
||||
});
|
||||
}
|
||||
updateCamera() {
|
||||
const engine = this.engine;
|
||||
const scene = engine.world;
|
||||
const pickScene = engine._picking.world;
|
||||
const camera = engine._camera;
|
||||
// Build a projection matrix, paralleling the code found in Mapbox GL JS
|
||||
const fov = 0.6435011087932844;
|
||||
const cameraToCenterDistance = 0.5 / Math.tan(fov / 2) * this.map.transform.height * WORLD_SCALE;
|
||||
const halfFov = fov / 2;
|
||||
const groundAngle = Math.PI / 2 + this.map.transform._pitch;
|
||||
const topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov);
|
||||
|
||||
// Calculate z distance of the farthest fragment that should be rendered.
|
||||
const furthestDistance = Math.cos(Math.PI / 2 - this.map.transform._pitch) * topHalfSurfaceDistance + cameraToCenterDistance;
|
||||
|
||||
// Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
|
||||
let farZ = furthestDistance * 1.1;
|
||||
if (this.pitch > 50) {
|
||||
farZ = 1000;
|
||||
}
|
||||
const { x, y } = this.map.transform.point;
|
||||
camera.projectionMatrix = this.makePerspectiveMatrix(fov, this.map.transform.width / this.map.transform.height, 1, farZ);
|
||||
const cameraWorldMatrix = new THREE.Matrix4();
|
||||
const cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
|
||||
const cameraRotateX = new THREE.Matrix4().makeRotationX(this.map.transform._pitch);
|
||||
const cameraRotateZ = new THREE.Matrix4().makeRotationZ(this.map.transform.angle);
|
||||
const cameraTranslateXY = new THREE.Matrix4().makeTranslation(x * WORLD_SCALE, -y * WORLD_SCALE, 0);
|
||||
// const cameraTranslateCenter = new THREE.Matrix4().makeTranslation(0, 0, cameraToCenterDistance);
|
||||
// Unlike the Mapbox GL JS camera, separate camera translation and rotation out into its world matrix
|
||||
// If this is applied directly to the projection matrix, it will work OK but break raycasting
|
||||
cameraWorldMatrix
|
||||
.premultiply(cameraTranslateZ)
|
||||
.premultiply(cameraRotateX)
|
||||
.premultiply(cameraRotateZ)
|
||||
.premultiply(cameraTranslateXY);
|
||||
|
||||
camera.matrixWorld.copy(cameraWorldMatrix);
|
||||
|
||||
const zoomPow = this.map.transform.scale * WORLD_SCALE;
|
||||
// Handle scaling and translation of objects in the map in the world's matrix transform, not the camera
|
||||
const scale = new THREE.Matrix4();
|
||||
const translateCenter = new THREE.Matrix4();
|
||||
const translateMap = new THREE.Matrix4();
|
||||
const rotateMap = new THREE.Matrix4();
|
||||
scale
|
||||
.makeScale(zoomPow, zoomPow, 1.0);
|
||||
translateCenter
|
||||
.makeTranslation(WORLD_SIZE / 2, -WORLD_SIZE / 2, 0);
|
||||
translateMap
|
||||
.makeTranslation(-this.map.transform.x, this.map.transform.y, 0);
|
||||
rotateMap
|
||||
.makeRotationZ(Math.PI);
|
||||
scene.matrix = new THREE.Matrix4();
|
||||
scene.matrix
|
||||
.premultiply(rotateMap)
|
||||
.premultiply(translateCenter)
|
||||
.premultiply(scale);
|
||||
pickScene.matrix = new THREE.Matrix4();
|
||||
pickScene.matrix
|
||||
.premultiply(rotateMap)
|
||||
.premultiply(translateCenter)
|
||||
.premultiply(scale);
|
||||
}
|
||||
makePerspectiveMatrix(fovy, aspect, near, far) {
|
||||
const out = new THREE.Matrix4();
|
||||
const f = 1.0 / Math.tan(fovy / 2),
|
||||
nf = 1 / (near - far);
|
||||
const newMatrix = [
|
||||
f / aspect, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, (far + near) * nf, -1,
|
||||
0, 0, (2 * far * near) * nf, 0
|
||||
];
|
||||
out.elements = newMatrix;
|
||||
return out;
|
||||
}
|
||||
|
||||
projectFlat(lnglat) {
|
||||
return this.map.lngLatToGeodeticCoord(lnglat);
|
||||
}
|
||||
getCenter() {
|
||||
return this.map.getCenter();
|
||||
}
|
||||
getCenterFlat() {
|
||||
return this.projectFlat(this.getCenter());
|
||||
}
|
||||
addOverLayer() {
|
||||
const canvasContainer = document.getElementById(this.container);
|
||||
this.canvasContainer = canvasContainer;
|
||||
this.renderDom = document.createElement('div');
|
||||
this.renderDom.style.cssText += 'position: absolute;top: 0; z-index:10;height: 100%;width: 100%;pointer-events: none;';
|
||||
this.renderDom.id = 'l7_canvaslayer';
|
||||
canvasContainer.appendChild(this.renderDom);
|
||||
}
|
||||
mixMap(scene) {
|
||||
const map = this.map;
|
||||
scene.getZoom = () => { return map.getZoom(); };
|
||||
scene.getCenter = () => { return map.getCenter(); };
|
||||
scene.getPitch = () => { return map.getPitch(); };
|
||||
scene.containerToLngLat = point => { return map.unproject(point); };
|
||||
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import Source from '../core/source';
|
||||
import FeatureIndex from '../geo/featureIndex';
|
||||
import { csvParse } from 'd3-dsv';
|
||||
export default class CSVSource extends Source {
|
||||
prepareData() {
|
||||
this.type = 'csv';
|
||||
const data = this.get('data');
|
||||
const x = this.get('x');
|
||||
const y = this.get('y');
|
||||
const x1 = this.get('x1');
|
||||
const y1 = this.get('y1');
|
||||
const coords = this.get('coordinates');
|
||||
this.propertiesData = [];// 临时使用
|
||||
this.geoData = [];
|
||||
let csvdata = data;
|
||||
Array.isArray(csvdata) || (csvdata = csvParse(data));
|
||||
this.propertiesData = csvdata;
|
||||
csvdata.forEach((col, featureIndex) => {
|
||||
let coordinates = [];
|
||||
if (col.coordinates) {
|
||||
coordinates = col.coordinates;
|
||||
}
|
||||
if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
|
||||
if (x1 && y1) { // 弧线 或者线段
|
||||
coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
|
||||
}
|
||||
if (coords && col.coords) { coordinates = col.coords; }
|
||||
col._id = featureIndex + 1;
|
||||
this._coordProject(coordinates);
|
||||
this.geoData.push(this._coordProject(coordinates));
|
||||
});
|
||||
}
|
||||
|
||||
featureIndex() {
|
||||
const data = this.get('data');
|
||||
this.featureIndex = new FeatureIndex(data);
|
||||
}
|
||||
getSelectFeatureId(featureId) {
|
||||
return [ featureId ];
|
||||
}
|
||||
getSelectFeature(featureId) {
|
||||
return this.propertiesData[featureId];
|
||||
|
||||
}
|
||||
_getCoord(geo) {
|
||||
if (geo.geometry) {
|
||||
// GeoJSON feature
|
||||
geo = geo.geometry.coordinates;
|
||||
} else if (geo.coordinates) {
|
||||
// GeoJSON geometry
|
||||
geo = geo.coordinates;
|
||||
}
|
||||
return geo;
|
||||
}
|
||||
_coordProject(geo) {
|
||||
if (Array.isArray(geo[0][0])) {
|
||||
return geo.map(coor => {
|
||||
return this._coordProject(coor);
|
||||
});
|
||||
}
|
||||
if (!Array.isArray(geo[0])) {
|
||||
return this._coorConvert(geo);
|
||||
}
|
||||
return geo.map(coor => {
|
||||
return this._coorConvert(coor);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
const TRANSFORMS = {};
|
||||
const PARSERS = {};
|
||||
export const getParser = type => PARSERS[type];
|
||||
export const registerParser = (type, parserFunction) => {
|
||||
PARSERS[type] = parserFunction;
|
||||
};
|
||||
export const getTransform = type => TRANSFORMS[type];
|
||||
export const registerTransform = (type, transFunction) => {
|
||||
TRANSFORMS[type] = transFunction;
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
import Source from '../core/source';
|
||||
import * as turfMeta from '@turf/meta';
|
||||
import { default as cleanCoords } from '@turf/clean-coords';
|
||||
import { getCoords } from '@turf/invariant';
|
||||
import FeatureIndex from '../geo/featureIndex';
|
||||
|
||||
export default class GeojsonSource extends Source {
|
||||
prepareData() {
|
||||
this.type = 'geojson';
|
||||
const data = this.get('data');
|
||||
this.propertiesData = [];
|
||||
this.geoData = [];
|
||||
turfMeta.flattenEach(data, (currentFeature, featureIndex) => {
|
||||
const coord = getCoords(cleanCoords(currentFeature));
|
||||
this.geoData.push(this._coordProject(coord));
|
||||
currentFeature.properties._id = featureIndex + 1;
|
||||
this.propertiesData.push(currentFeature.properties);
|
||||
});
|
||||
}
|
||||
featureIndex() {
|
||||
const data = this.get('data');
|
||||
this.featureIndex = new FeatureIndex(data);
|
||||
}
|
||||
getSelectFeatureId(featureId) {
|
||||
const data = this.get('data');
|
||||
const selectFeatureIds = [];
|
||||
let featureStyleId = 0;
|
||||
turfMeta.flattenEach(data, (currentFeature, featureIndex/* , multiFeatureIndex*/) => {
|
||||
if (featureIndex === (featureId)) {
|
||||
selectFeatureIds.push(featureStyleId);
|
||||
}
|
||||
featureStyleId++;
|
||||
if (featureIndex > featureId) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
return selectFeatureIds;
|
||||
|
||||
}
|
||||
getSelectFeature(featureId) {
|
||||
const data = this.get('data');
|
||||
return data.features[featureId];
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
import Source from '../core/source';
|
||||
import { getImage } from '../util/ajax';
|
||||
export default class ImageSource extends Source {
|
||||
prepareData() {
|
||||
this.type = 'image';
|
||||
const extent = this.get('extent');
|
||||
const lb = this._coorConvert(extent.slice(0, 2));
|
||||
const tr = this._coorConvert(extent.slice(2, 4));
|
||||
this.geoData = [ lb, tr ];
|
||||
this.propertiesData = [];
|
||||
this._loadData();
|
||||
}
|
||||
_loadData() {
|
||||
const url = this.get('data');
|
||||
this.image = [];
|
||||
if (typeof (url) === 'string') {
|
||||
getImage({ url }, (err, img) => {
|
||||
this.image = img;
|
||||
this.emit('imageLoaded');
|
||||
});
|
||||
} else {
|
||||
const imageCount = url.length;
|
||||
let imageindex = 0;
|
||||
url.forEach(item => {
|
||||
getImage({ url: item }, (err, img) => {
|
||||
imageindex++;
|
||||
this.image.push(img);
|
||||
if (imageindex === imageCount) {
|
||||
this.emit('imageLoaded');
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,23 @@
|
|||
export { default as geojson } from './geojsonSource';
|
||||
export { default as csv } from './csvSource';
|
||||
export { default as array } from './csvSource';
|
||||
export { default as basic } from '../core/source';
|
||||
export { default as imageSource } from './imageSource';
|
||||
// source parser
|
||||
|
||||
import geojson from './parser/geojson';
|
||||
import image from './parser/image';
|
||||
import csv from './parser/csv';
|
||||
import json from './parser/json';
|
||||
import raster from './parser/raster';
|
||||
|
||||
import { registerTransform, registerParser } from './factory';
|
||||
import { aggregatorToGrid } from './transform/grid';
|
||||
import { map } from './transform/map';
|
||||
|
||||
registerParser('geojson', geojson);
|
||||
registerParser('image', image);
|
||||
registerParser('csv', csv);
|
||||
registerParser('json', json);
|
||||
registerParser('raster', raster);
|
||||
// 注册transform
|
||||
|
||||
registerTransform('grid', aggregatorToGrid);
|
||||
registerTransform('map', map);
|
||||
|
||||
export { getTransform, registerTransform, getParser, registerParser } from './factory';
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { csvParse } from 'd3-dsv';
|
||||
export default function csv(data, cfg) {
|
||||
const { x, y, x1, y1 } = cfg;
|
||||
const csvdata = csvParse(data);
|
||||
const resultdata = [];
|
||||
csvdata.forEach((col, featureIndex) => {
|
||||
let coordinates = [];
|
||||
if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
|
||||
if (x1 && y1) { // 弧线 或者线段
|
||||
coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
|
||||
}
|
||||
col._id = featureIndex + 1;
|
||||
const dataItem = {
|
||||
...col,
|
||||
coordinates
|
||||
|
||||
};
|
||||
resultdata.push(dataItem);
|
||||
});
|
||||
return {
|
||||
dataArray: resultdata
|
||||
};
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import * as turfMeta from '@turf/meta';
|
||||
import { default as cleanCoords } from '@turf/clean-coords';
|
||||
import { getCoords } from '@turf/invariant';
|
||||
|
||||
export default function geoJSON(data) {
|
||||
const resultData = [];
|
||||
turfMeta.flattenEach(data, (currentFeature, featureIndex) => { // 多个polygon 拆成一个
|
||||
const coord = getCoords(cleanCoords(currentFeature));
|
||||
const dataItem = {
|
||||
...currentFeature.properties,
|
||||
coordinates: coord,
|
||||
_id: featureIndex + 1
|
||||
};
|
||||
resultData.push(dataItem);
|
||||
});
|
||||
return {
|
||||
dataArray: resultData
|
||||
};
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import { getImage } from '../../util/ajax';
|
||||
export default function image(data, cfg) {
|
||||
const { extent } = cfg;
|
||||
|
||||
const images = new Promise(resolve => {
|
||||
loadData(data, res => {
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
const resultData = {
|
||||
images,
|
||||
_id: 1,
|
||||
dataArray: [{ coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
|
||||
};
|
||||
return resultData;
|
||||
}
|
||||
function loadData(data, done) {
|
||||
const url = data;
|
||||
let image = [];
|
||||
if (typeof (url) === 'string') {
|
||||
getImage({ url }, (err, img) => {
|
||||
image = img;
|
||||
done(image);
|
||||
});
|
||||
} else {
|
||||
const imageCount = url.length;
|
||||
let imageindex = 0;
|
||||
url.forEach(item => {
|
||||
getImage({ url: item }, (err, img) => {
|
||||
imageindex++;
|
||||
image.push(img);
|
||||
if (imageindex === imageCount) {
|
||||
done(image);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
return image;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
export default function json(data, cfg) {
|
||||
const { x, y, x1, y1 } = cfg;
|
||||
const resultdata = [];
|
||||
data.forEach((col, featureIndex) => {
|
||||
let coordinates = [];
|
||||
if (x && y) { coordinates = [ col[x], col[y] ]; } // 点数据
|
||||
if (x1 && y1) { // 弧线 或者线段
|
||||
coordinates = [[ col[x], col[y] ], [ col[x1], col[y1] ]];
|
||||
}
|
||||
col._id = featureIndex + 1;
|
||||
const dataItem = {
|
||||
...col,
|
||||
coordinates
|
||||
|
||||
};
|
||||
resultdata.push(dataItem);
|
||||
});
|
||||
return {
|
||||
dataArray: resultdata
|
||||
};
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
export default function raster(data, cfg) {
|
||||
const { extent, width, height, min, max } = cfg;
|
||||
const resultData = {
|
||||
_id: 1,
|
||||
dataArray: [
|
||||
{
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
min,
|
||||
max,
|
||||
coordinates: [[ extent[0], extent[1] ], [ extent[2], extent[3] ]] }]
|
||||
};
|
||||
return resultData;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import imageSource from './imageSource';
|
||||
export class RainSource extends imageSource {
|
||||
prepareData() {
|
||||
const extent = this.get('extent');
|
||||
const lb = this._coorConvert(extent.slice(0, 2));
|
||||
const tr = this._coorConvert(extent.slice(2, 4));
|
||||
this.extent = [ lb, tr ];
|
||||
this.propertiesData = [];
|
||||
this._genaratePoints();
|
||||
this._loadData();
|
||||
}
|
||||
_genaratePoints() {
|
||||
const numParticles = 512 * 512;
|
||||
|
||||
const particleRes = this.particleRes = Math.ceil(Math.sqrt(numParticles));
|
||||
const numPoints = particleRes * particleRes;
|
||||
const particleState = [];
|
||||
const particleState0 = new Uint8ClampedArray(numPoints * 4);
|
||||
const particleState1 = new Uint8ClampedArray(numPoints * 4);
|
||||
const emptyPixels = new Uint8ClampedArray(numPoints * 4);
|
||||
for (let i = 0; i < particleState0.length; i++) {
|
||||
particleState0[i] = Math.floor(Math.random() * 256); // randomize the initial particle positions
|
||||
}
|
||||
this.particleIndices = new Float32Array(numPoints);
|
||||
for (let i = 0; i < numPoints; i++) this.particleIndices[i] = i;
|
||||
this.particleImage0 = new ImageData(particleState0, particleRes, particleRes);
|
||||
this.particleImage1 = new ImageData(particleState1, particleRes, particleRes);
|
||||
this.backgroundImage = new ImageData(emptyPixels, particleRes, particleRes);
|
||||
this.geoData = particleState;
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import Source from '../core/source';
|
||||
export default class RasterSource extends Source {
|
||||
prepareData() {
|
||||
this.type = 'raster';
|
||||
const extent = this.get('extent');
|
||||
const lb = this._coorConvert(extent.slice(0, 2));
|
||||
const tr = this._coorConvert(extent.slice(2, 4));
|
||||
this.geoData = [ lb, tr ];
|
||||
this.propertiesData = [];
|
||||
this.rasterData = {
|
||||
data: this.get('data'),
|
||||
width: this.get('width'),
|
||||
height: this.get('height'),
|
||||
min: this.get('min'),
|
||||
max: this.get('max')
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* 生成四边形热力图
|
||||
*/
|
||||
import * as statistics from './statistics';
|
||||
|
||||
const R_EARTH = 6378000;
|
||||
|
||||
/**
|
||||
* 计算方格密度图
|
||||
* @param {*} data 经纬度数据 和属性数据
|
||||
* @param {*} size 半径大小 单位 km
|
||||
* @return
|
||||
*/
|
||||
export function aggregatorToGrid(data, option) {
|
||||
const dataArray = data.dataArray;
|
||||
const { size = 10 } = option;
|
||||
const { gridHash, gridOffset } = _pointsGridHash(dataArray, size);
|
||||
const layerData = _getGridLayerDataFromGridHash(gridHash, gridOffset, option);
|
||||
return {
|
||||
xOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
|
||||
yOffset: gridOffset.xOffset / 360 * (256 << 20) / 2,
|
||||
dataArray: layerData
|
||||
};
|
||||
}
|
||||
|
||||
function _pointsGridHash(dataArray, size) {
|
||||
let latMin = Infinity;
|
||||
let latMax = -Infinity;
|
||||
let pLat;
|
||||
for (let index = 0; index < dataArray.length; index++) {
|
||||
const point = dataArray[index];
|
||||
pLat = point.coordinates[1];
|
||||
if (Number.isFinite(pLat)) {
|
||||
latMin = pLat < latMin ? pLat : latMin;
|
||||
latMax = pLat > latMax ? pLat : latMax;
|
||||
}
|
||||
|
||||
}
|
||||
// const centerLat = (latMin + latMax) / 2;
|
||||
const centerLat = 34.54083;
|
||||
const gridOffset = _calculateGridLatLonOffset(size, centerLat);
|
||||
if (gridOffset.xOffset <= 0 || gridOffset.yOffset <= 0) {
|
||||
return { gridHash: {}, gridOffset };
|
||||
}
|
||||
const gridHash = {};
|
||||
for (let index = 0; index < dataArray.length; index++) {
|
||||
const point = dataArray[index];
|
||||
const lat = point.coordinates[1];
|
||||
const lng = point.coordinates[0];
|
||||
|
||||
if (Number.isFinite(lat) && Number.isFinite(lng)) {
|
||||
const latIdx = Math.floor((lat + 90) / gridOffset.yOffset);
|
||||
const lonIdx = Math.floor((lng + 180) / gridOffset.xOffset);
|
||||
const key = `${latIdx}-${lonIdx}`;
|
||||
|
||||
gridHash[key] = gridHash[key] || { count: 0, points: [] };
|
||||
gridHash[key].count += 1;
|
||||
gridHash[key].points.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
return { gridHash, gridOffset };
|
||||
}
|
||||
// 计算网格偏移量
|
||||
function _calculateGridLatLonOffset(cellSize, latitude) {
|
||||
const yOffset = _calculateLatOffset(cellSize);
|
||||
const xOffset = _calculateLonOffset(latitude, cellSize);
|
||||
return { yOffset, xOffset };
|
||||
}
|
||||
|
||||
function _calculateLatOffset(dy) {
|
||||
return (dy / R_EARTH) * (180 / Math.PI);
|
||||
}
|
||||
|
||||
function _calculateLonOffset(lat, dx) {
|
||||
return ((dx / R_EARTH) * (180 / Math.PI)) / Math.cos((lat * Math.PI) / 180);
|
||||
}
|
||||
function _getGridLayerDataFromGridHash(gridHash, gridOffset, option) {
|
||||
return Object.keys(gridHash).reduce((accu, key, i) => {
|
||||
const idxs = key.split('-');
|
||||
const latIdx = parseInt(idxs[0], 10);
|
||||
const lonIdx = parseInt(idxs[1], 10);
|
||||
const item = {};
|
||||
if (option.field && option.method) {
|
||||
const columns = getColumn(gridHash[key].points, option.field);
|
||||
item[option.method] = statistics[option.method](columns);
|
||||
}
|
||||
Object.assign(item, {
|
||||
_id: i + 1,
|
||||
coordinates: [ -180 + gridOffset.xOffset * lonIdx, -90 + gridOffset.yOffset * latIdx ],
|
||||
count: gridHash[key].count
|
||||
});
|
||||
accu.push(item);
|
||||
return accu;
|
||||
}, []);
|
||||
}
|
||||
function getColumn(data, columnName) {
|
||||
return data.map(item => {
|
||||
return item[columnName];
|
||||
});
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import { hexbin } from 'd3-hexbin';
|
||||
import { aProjectFlat, unProjectFlat } from '../../geo/project';
|
||||
import * as statistics from './statistics';
|
||||
const R_EARTH = 6378000;
|
||||
export function pointToHexbin(data, option) {
|
||||
const dataArray = data.dataArray;
|
||||
const { size = 10 } = option;
|
||||
const pixlSize = size / (2 * Math.PI * R_EARTH) * (256 << 20) / 2;
|
||||
const screenPoints = dataArray.map(point => {
|
||||
const { x, y } = aProjectFlat(point.coordinates);
|
||||
return {
|
||||
...point,
|
||||
coordinates: [ x, y ]
|
||||
};
|
||||
});
|
||||
|
||||
const newHexbin = hexbin()
|
||||
.radius(pixlSize)
|
||||
.x(d => d.coordinates[0])
|
||||
.y(d => d.coordinates[1]);
|
||||
const hexbinBins = newHexbin(screenPoints);
|
||||
const result = {
|
||||
size: pixlSize
|
||||
};
|
||||
result.dataArray = hexbinBins.map((hex, index) => {
|
||||
if (option.field && option.method) {
|
||||
const columns = getColumn(hex, option.field);
|
||||
hex[option.method] = statistics[option.method](columns);
|
||||
}
|
||||
return {
|
||||
coordinates: unProjectFlat([ hex.x, hex.y ]),
|
||||
id: index + 1
|
||||
};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function getColumn(data, columnName) {
|
||||
return data.map(item => {
|
||||
return item[columnName];
|
||||
});
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export function map(data, options) {
|
||||
const { callback } = options;
|
||||
if (callback) {
|
||||
data.dataArray = data.dataArray.map(callback);
|
||||
}
|
||||
return data;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/* 支持 'max', 'mean', 'median', 'min', 'mode', 'product', 'standardDeviation',
|
||||
* 'sum', 'sumSimple', 'variance', 'count', 'distinct'
|
||||
*/
|
||||
export { default as min } from 'simple-statistics/src/min';
|
||||
export { default as max } from 'simple-statistics/src/max';
|
||||
export { default as mean } from 'simple-statistics/src/mean';
|
||||
export { default as sum } from 'simple-statistics/src/sum';
|
||||
export { default as median } from 'simple-statistics/src/median';
|
||||
export { default as standardDeviation } from 'simple-statistics/src/standard_deviation';
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
import { expect } from 'chai';
|
||||
import { pointData } from '../../../asset/data/point';
|
||||
import { pointToHexbin } from '../../../../src/source/transform/hexagon';
|
||||
describe('hexagon Test', function() {
|
||||
|
||||
it('pointToHexbin', function() {
|
||||
const dataArray = pointData.map(item => {
|
||||
const lng = 1e-6 * (250 * item.grid_x + 125),
|
||||
lat = 1e-6 * (250 * item.grid_y + 125);
|
||||
return {
|
||||
v: item.count * 1,
|
||||
coordinates: [ lng, lat ]
|
||||
};
|
||||
});
|
||||
|
||||
const data = {
|
||||
dataArray
|
||||
};
|
||||
const hexgonGrid = pointToHexbin(data, { size: 100, field: 'count', method: 'sum' });
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue