Merge branch 'dev' into 'master'

Dev



See merge request !3
This commit is contained in:
象数 2019-01-24 16:29:15 +08:00
commit 944d50697a
90 changed files with 1817 additions and 414 deletions

View File

@ -35,7 +35,9 @@ const scene = new L7.Scene({
mapStyle: 'light', // 样式URL
center: [ 120.19382669582967, 30.258134 ],
pitch: 0,
zoom: 12
zoom: 12,
maxZoom:14,
minZoom:11,
});
window.scene = scene;
scene.on('loaded', () => {
@ -53,7 +55,7 @@ scene.on('loaded', () => {
.shape('2d:circle')
.size('value', [ 2, 80]) // default 1
//.size('value', [ 10, 300]) // default 1
.active(true)
.active(false)
.filter('value', field_8 => {
return field_8 * 1 > 500;
})
@ -65,7 +67,9 @@ scene.on('loaded', () => {
})
.render();
circleLayer.on('click',(e)=>{
console.log(e);
})
});
});

View File

@ -38,7 +38,7 @@ scene.on('loaded', () => {
x: 'j',
y: 'w',
})
.shape('3d:circle')
.shape('cylinder')
.size('t',(level)=> {
return [2,2,(level*3+20)];
})

View File

@ -127,6 +127,10 @@ scene.on('loaded', () => {
.render();
});
scene.on('zoomchange',(e)=>{
console.log(e);
})
});

View File

@ -29,8 +29,6 @@ const scene = new L7.Scene({
scene.on('loaded', () => {
scene.image.addImage('local', 'https://gw.alipayobjects.com/zos/rmsportal/xZXhTxbglnuTmZEwqQrE.png');
$.getJSON('https://gw.alipayobjects.com/os/rmsportal/UpapMomPYUeiBjbHNAma.json', region => {
const color = [ 'rgb(22,32,101)', 'rgb(28,43,127)', 'rgb(36,68,142)', 'rgb(45,94,158)', 'rgb(53,119,174)', 'rgb(61,145,190)', 'rgb(70,170,206)', 'rgb(98,190,210)', 'rgb(138,205,206)', 'rgb(179,221,204)', 'rgb(220,236,201)' ];
var points = region.features.map((feature)=>{
@ -70,7 +68,7 @@ $.getJSON('https://gw.alipayobjects.com/os/rmsportal/dzpMOiLYBKxpdmsgBLoE.json',
.size([ 1.5, 0 ])
.shape('line')
.style({
// 'lineType':'solid'
'lineType':'dash'
})
.render();
});

View File

@ -17,8 +17,25 @@
<body>
<div id="map"></div>
<div id ="info" class ="tooltip" style="display:none">
</div>
<div id ="info" class ="tooltip" style="display:none"></div>
<div class='info-panel top-right'>
<p>
<label>min</label><input name="minaqi" type="range" step="1" min="0" max="200" value=0> <label>0</label>
</p>
<p>
<label>max</label><input name="maxaqi" type="range" step="1" min="0" max="300" value=300><label>300</label>
</p>
<p><label>color</label><select>
<option value ="default">default</option>
<option value ="blue">blue</option>
<option value ="red">red</option>
<option value="orange">orange</option>
<option value="green">green</option>
<option value="yellow">yellow</option>
<option value="purple">purple</option>
</select> </p>
<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>
@ -35,7 +52,7 @@ const colorObj ={
const scene = new L7.Scene({
id: 'map',
mapStyle: 'light', // 样式URL
mapStyle: 'dark', // 样式URL
center: [104.838088,34.075889 ],
pitch: 0,
zoom: 4.5,
@ -69,19 +86,34 @@ scene.on('loaded', () => {
opacity: 1
})
.render();
const citylayer2 = scene.PolygonLayer()
.source(city)
.shape('line')
.color('#fff')
.style({
opacity: 0.1
opacity: 1.0
})
.render();
citylayer.on('click',(e)=>{
$("#info").css({'left': e.pixel.x,'top':e.pixel.y, display:'block'});
$("#info").html(`<p>${e.feature.properties.area || e.feature.properties.name }<span">${e.feature.properties.pm2_5_24h || 0}</span></p>`);
})
$('.info-panel input').change(function(){
$(this).next().text($(this).val());
const min = $('.info-panel input').val();
const max = $($('.info-panel input')[1]).val();
citylayer.filter('pm2_5_24h',(value)=>{
return (value>=min && value<=max)
}).render();
})
$('.info-panel select').change(function(){
const color = $(this).val();
citylayer.color('pm2_5_24h',colorObj[color]).render();
console.timeEnd('color')
})
});
});

View File

@ -63,6 +63,12 @@ scene.on('loaded', () => {
}
})
.render();
setTimeout(()=>{
layer.style({
rampColors: 'viridis',
}).render();
},3000)
}
};
xhr.send();

View File

@ -35,7 +35,7 @@ scene.on('loaded', () => {
})
.source(data)
.shape('name', 'text')
.size(10) // default 1
.size(12) // default 1
.color('#fff')
.style({
stroke: '#999',

View File

@ -38,6 +38,7 @@ scene.on('loaded', () => {
})
.source(data)
.shape('fill')
.active({fill:'blue'})
.color('rgb(79,174,234)')
.render();
});
@ -71,10 +72,12 @@ scene.on('loaded', () => {
.size('floor',[10,2000])
.color('rgba(242,246,250,0.96)')
.render();
/**
citylayer.on('click',(e)=>{
$("#info").css({'left': e.pixel.x,'top':e.pixel.y, display:'block'});
$("#info").html(`<p>楼高<span">${e.feature.properties.floor || 0}</span></p>`);
})
**/
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1016 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

63
demos/line.html Normal file

File diff suppressed because one or more lines are too long

57
demos/point.html Normal file
View File

@ -0,0 +1,57 @@
<!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: [104.838088,34.075889 ],
pitch: 0,
zoom: 9,
minZoom: 8,
rotation:0
});
scene.on('loaded', () => {
scene.image.addImage('local', 'https://gw.alipayobjects.com/zos/rmsportal/xZXhTxbglnuTmZEwqQrE.png');
$.get('https://gw.alipayobjects.com/os/rmsportal/oVTMqfzuuRFKiDwhPSFL.json', data => {
scene.PointLayer({
zIndex: 2
})
.source(data.list, {
type: 'array',
x: 'j',
y: 'w',
})
.shape('m','text')
.size(20)
.color('#fff')
.style({
stroke:'#fff',
strokeWidth:1.0,
opacity:1.0,
})
.render();
});
});
</script>
</body>
</html>

View File

@ -20,23 +20,6 @@
<script src="./assets/dat.gui.min.js"></script>
<script src="../build/L7.js"></script>
<script>
const gui = new dat.GUI({ autoPlace: false });
const customContainer = document.getElementById('gui');
customContainer.appendChild(gui.domElement);
var palette = {
baseColor: '#3CB4F0', // CSS string
windowColor: '#65CEF7', // RGB array
brightColor: '#98E3FA', // RGB with alpha
};
gui.addColor(palette, 'baseColor').onChange(()=>{
changeStyle();
});
gui.addColor(palette, 'windowColor').onChange(()=>{
changeStyle();
});
gui.addColor(palette, 'brightColor').onChange(()=>{
changeStyle();
});
var buildLayer =null;
const scene = new L7.Scene({
id: 'map',
@ -48,16 +31,17 @@ const scene = new L7.Scene({
maxZoom: 18
});
scene.on('loaded', () => {
$.get('./data/road.json', data => {
$.get('https://gw.alipayobjects.com/os/rmsportal/kNDVHmyUWAKhWmWXmjxM.json', data => {
scene.LineLayer({
zIndex: 2
})
.source(data)
.color('#F08D41')
//.color('#F08D41')
.color('#ff893a')
.animate({enable:true})
.render();
});
$.get('./data/2.geojson', data => {
$.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => {
buildLayer = scene.PolygonLayer({
zIndex: 2
})
@ -70,8 +54,8 @@ scene.on('loaded', () => {
opacity:1.0,
baseColor:'rgb(16,16,16)',
windowColor:'rgb(30,60,89)',
brightColor:'rgb(155,217,255)',
//brightColor:'rgb(155,217,255)'
brightColor:'rgb(255,176,38)'
})
.render();

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7",
"version": "1.0.0",
"version": "1.0.1",
"description": "Large-scale WebGL-powered Geospatial Data Visualization",
"main": "build/l7.js",
"browser": "build/l7.js",
@ -53,7 +53,8 @@
"string-replace-loader": "~1.3.0",
"torchjs": "~2.1.0",
"uglify-js": "~3.1.10",
"webpack": "~3.10.0"
"webpack": "~3.10.0",
"worker-loader": "^2.0.0"
},
"scripts": {
"build": "webpack",
@ -109,6 +110,7 @@
"three": "^0.96.0",
"venn.js": "^0.2.20",
"viewport-mercator-project": "^5.2.0",
"webworkify-webpack": "^2.1.3",
"wolfy87-eventemitter": "~5.2.4"
}
}

View File

@ -4,7 +4,7 @@
*/
import EventEmitter from 'wolfy87-eventemitter';
import Util from '../util';
import { assign } from '../util';
class Base extends EventEmitter {
@ -19,7 +19,7 @@ class Base extends EventEmitter {
};
const defaultCfg = this.getDefaultCfg();
this._attrs = attrs;
Util.assign(attrs, defaultCfg, cfg);
assign(attrs, defaultCfg, cfg);
}
get(name) {

View File

@ -36,26 +36,31 @@ class Picking {
this._resizeHandler = this._resizeTexture.bind(this);
window.addEventListener('resize', this._resizeHandler, false);
this._mouseUpHandler = this._onMouseUp.bind(this);
this._world._container.addEventListener('mouseup', this._mouseUpHandler, false);
this._world._container.addEventListener('mousemove', this._mouseUpHandler, false);
this._world._container.addEventListener('mousemove', this._onWorldMove.bind(this), false);
// this._mouseUpHandler = this._onMouseUp.bind(this);
// this._world._container.addEventListener('mouseup', this._mouseUpHandler, false);
// this._world._container.addEventListener('mousemove', this._mouseUpHandler, false);
// this._world._container.addEventListener('mousemove', this._onWorldMove.bind(this), false);
}
pickdata(event) {
const point = { x: event.clientX, y: event.clientY, 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;
this._pickAllObject(point, normalisedPoint);
}
_onMouseUp(event) {
// Only react to main button click
// if (event.button !== 0) {
// return;
// }
const point = { x: event.clientX, y: event.clientY };
const point = { x: event.clientX, y: event.clientY, 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;
this._pick(point, normalisedPoint);
this._pickAllObject(point, normalisedPoint);
// this._pick(point, normalisedPoint);
}
_onWorldMove() {
this._needUpdate = true;
@ -67,7 +72,6 @@ class Picking {
this._width = size.width;
this._height = size.height;
this._pickingTexture.setSize(this._width, this._height);
this._pixelBuffer = new Uint8Array(4 * this._width * this._height);
@ -76,10 +80,10 @@ class Picking {
_update(point) {
const texture = this._pickingTexture;
if (this._needUpdate) {
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
this._needUpdate = false;
}
// if (this._needUpdate) {
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
// this._needUpdate = false;
// }
this.pixelBuffer = new Uint8Array(4);
this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer);
@ -99,17 +103,33 @@ class Picking {
});
}
_filterObject(id) {
this._pickingScene.children.forEach((object, index) => {
index === id ? object.visible = true : object.visible = false;
});
}
_pickAllObject(point, normalisedPoint) {
this._pickingScene.children.forEach((object, index) => {
this._filterObject(index);
const item = this._pick(point, normalisedPoint, object.name);
item.type = point.type;
this._world.emit('pick', item);
this._world.emit('pick-' + object.name, item);
});
}
_updateRender() {
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
}
_pick(point, normalisedPoint) {
_pick(point, normalisedPoint, layerId) {
this._update(point);
// Interpret the pixel as an ID
const id = (this.pixelBuffer[2] * 255 * 255) + (this.pixelBuffer[1] * 255) + (this.pixelBuffer[0]);
let id = (this.pixelBuffer[2] * 255 * 255) + (this.pixelBuffer[1] * 255) + (this.pixelBuffer[0]);
// Skip if ID is 16646655 (white) as the background returns this
if (id === 16646655 || this.pixelBuffer[3] === 0) {
return;
id = -999;
// return;
}
this._raycaster.setFromCamera(normalisedPoint, this._camera);
@ -118,7 +138,6 @@ class Picking {
//
// TODO: Only perform intersection test on the relevant picking mesh
const intersects = this._raycaster.intersectObjects(this._pickingScene.children, true);
const _point2d = { x: point.x, y: point.y };
let _point3d;
@ -131,13 +150,14 @@ class Picking {
//
// TODO: Look into the leak potential for passing so much by reference here
const item = {
layerId,
featureId: id - 1,
point2d: _point2d,
point3d: _point3d,
intersects
};
this._world.emit('pick', item);
// this._world.emit('pick-' + id, _point2d, _point3d, intersects);
return item;
}
// Add mesh to picking scene
@ -180,15 +200,6 @@ class Picking {
}
this._pickingScene.remove(child);
// Probably not a good idea to dispose of geometry due to it being
// shared with the non-picking scene
// if (child.geometry) {
// // Dispose of mesh and materials
// child.geometry.dispose();
// child.geometry = null;
// }
if (child.material) {
if (child.material.map) {
child.material.map.dispose();

View File

@ -5,30 +5,32 @@ import { getImage } from '../util/ajax';
export default class LoadImage extends EventEmitter {
constructor() {
super();
this.imageWidth = 64;
const pixelRatio = window.devicePixelRatio || 1;
this.imageWidth = 64 * pixelRatio;
this.canvas = document.createElement('canvas');
this.canvas.style.cssText += 'height: 512px;width: 512px;';
this.canvas.width = this.imageWidth * 8;
this.canvas.height = this.imageWidth * 8;
this.ctx = this.canvas.getContext('2d');
this.images = [];
this.imagesCount = 0;
this.imagePos = {};
this.imagesIds = [];
}
addImage(id, opt) {
this.imagesCount ++;
this.imagesIds.push(id);
const imageCount = this.imagesCount;
const x = imageCount % 8 * 64;
const y = parseInt(imageCount / 8) * 64;
this.imagePos[id] = { x: x / 512, y: y / 512 };
const x = imageCount % 8 * this.imageWidth;
const y = parseInt(imageCount / 8) * this.imageWidth;
this.imagePos[id] = { x: x / this.canvas.width, y: y / this.canvas.height };
this.texture = new THREE.Texture(this.canvas);
if (typeof opt === 'string') {
getImage({ url: opt }, (err, img) => {
img.id = id;
this.images.push(img);
this.ctx.drawImage(img, x, y, 64, 64);
this.ctx.drawImage(img, x, y, this.imageWidth, this.imageWidth);
this.texture.magFilter = THREE.LinearFilter;
this.texture.minFilter = THREE.LinearFilter;
@ -47,7 +49,7 @@ export default class LoadImage extends EventEmitter {
image.data = data;
image.id = id;
this.images.push(image);
this.ctx.drawImage(image, x, y, 64, 64);
this.ctx.drawImage(image, x, y, this.imageWidth, this.imageWidth);
this.texture = new THREE.CanvasTexture(this.canvas);
this.imagePos[id] = { x: x >> 9, y: y >> 9 };
if (this.images.length === this.imagesCount) {

View File

@ -36,11 +36,13 @@ export default class Layer extends Base {
attrs: {},
// 样式配置项
styleOptions: {
stroke: [ 1.0, 1.0, 1.0, 1.0 ],
stroke: 'none',
strokeWidth: 1.0,
opacity: 1.0,
strokeOpacity: 1.0,
texture: false
},
destroyed: false,
// 选中时的配置项
selectedOptions: null,
// active 时的配置项
@ -63,35 +65,38 @@ export default class Layer extends Base {
this._activeIds = null;
scene._engine._scene.add(this._object3D);
this.layerMesh = null;
this.layerLineMesh = null;
this._initEvents();
}
/**
* 将图层添加加到 Object
* @param {*} object three 物体
* @param {*} type mesh类型是区别是填充还是边线
*/
add(object) {
this.layerMesh = object;
this._visibleWithZoom();
this.scene.on('zoomchange', () => {
this._visibleWithZoom();
});
add(object, type = 'fill') {
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
this.layerMesh.onBeforeRender = () => {
this._visibleWithZoom();
this._zoomchangeHander = this._visibleWithZoom.bind(this);
this.scene.on('zoomchange', this._zoomchangeHander);
object.onBeforeRender = () => {
const zoom = this.scene.getZoom();
this.layerMesh.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
this.layerMesh.material.setUniformsValue('u_zoom', zoom);
object.material.setUniformsValue('u_time', this.scene._engine.clock.getElapsedTime());
object.material.setUniformsValue('u_zoom', zoom);
this._preRender();
};
// 更新
if (this._needUpdateFilter) {
this._updateFilter();
this._updateFilter(object);
}
this._object3D.add(object);
this._addPickMesh(object);
if (type === 'fill') { this._addPickMesh(object); }
}
remove(object) {
this._object3D.remove(object);
}
_getUniqueId() {
return id++;
@ -107,6 +112,12 @@ export default class Layer extends Base {
cfg.mapType = this.get('mapType');
this.layerSource = new source[type](cfg);
// this.scene.workerPool.runTask({
// command: 'geojson',
// data: cfg
// }).then(data => {
// console.log(data);
// });
return this;
}
@ -131,7 +142,7 @@ export default class Layer extends Base {
}
values === 'text' ? this.shapeType = values : null;
this._createAttrOption('shape', field, values, Global.sizes);
this._createAttrOption('shape', field, values, Global.shape);
return this;
}
/**
@ -171,7 +182,7 @@ export default class Layer extends Base {
styleOptions.fields = fields;
Util.assign(styleOptions, cfg);
for (const item in cfg) {
if (colorItem.indexOf(item) !== -1) {
if (colorItem.indexOf(item) !== -1 && styleOptions[item] !== 'none') {
styleOptions[item] = ColorUtil.color2RGBA(styleOptions[item]);
}
styleOptions[item] = styleOptions[item];
@ -252,20 +263,24 @@ export default class Layer extends Base {
this._mapping();
const activeHander = this._addActiveFeature.bind(this);
const resetHander = this._resetStyle.bind(this);
if (this.get('allowActive')) {
this.scene.on('pick', activeHander);
this.on('mousemove', activeHander);
this.on('mouseleave', resetHander);
} else {
this.scene.off('pick', activeHander);
this.off('mousemove', activeHander);
this.off('mouseleave', resetHander);
}
}
_addActiveFeature(e) {
const { featureId } = e;
if (featureId < 0) return;
const activeStyle = this.get('activedOptions');
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]);
style.color = ColorUtil.toRGB(activeStyle.fill).map(e => e / 255);
@ -418,11 +433,11 @@ export default class Layer extends Base {
});
}
}
on(type, callback) {
// on(type, callback) {
this._addPickingEvents();
super.on(type, callback);
}
// this._addPickingEvents();
// super.on(type, callback);
// }
getPickingId() {
return this.scene._engine._picking.getNextId();
}
@ -434,10 +449,11 @@ export default class Layer extends Base {
}
_addPickMesh(mesh) {
this._pickingMesh = new THREE.Object3D();
this._visibleWithZoom();
this.scene.on('zoomchange', () => {
this._visibleWithZoom();
});
this._pickingMesh.name = this.layerId;
// this._visibleWithZoom();
// this.scene.on('zoomchange', () => {
// this._visibleWithZoom();
// });
this.addToPicking(this._pickingMesh);
const pickmaterial = new PickingMaterial({
@ -445,6 +461,7 @@ export default class Layer extends Base {
});
const pickingMesh = new THREE[mesh.type](mesh.geometry, pickmaterial);
pickingMesh.name = this.layerId;
pickmaterial.setDefinesvalue(this.type, true);
pickingMesh.onBeforeRender = () => {
const zoom = this.scene.getZoom();
@ -455,22 +472,25 @@ export default class Layer extends Base {
_setPickingId() {
this._pickingId = this.getPickingId();
}
_addPickingEvents() {
// TODO: Find a way to properly remove this listener on destroy
this.scene.on('pick', e => {
// Re-emit click event from the layer
const { featureId, point2d, intersects } = e;
if (intersects.length === 0) { return; }
const source = this.layerSource.get('data');
const feature = source.features[featureId];
_initEvents() {
this.scene.on('pick-' + this.layerId, e => {
const { featureId, point2d, type } = e;
if (featureId < -100 && this._activeIds !== null) {
this.emit('mouseleave');
return;
}
const feature = this.layerSource.getSelectFeature(featureId);
const lnglat = this.scene.containerToLngLat(point2d);
const target = {
featureId,
feature,
pixel: point2d,
lnglat: { lng: lnglat.lng, lat: lnglat.lat }
};
this.emit('click', target);
// this.emit('move', target);
if (featureId >= 0) {
this.emit(type, target);
}
});
}
/**
@ -480,7 +500,7 @@ export default class Layer extends Base {
*/
updateStyle(featureStyleId, style) {
if (this._activeIds) {
this.resetStyle();
this._resetStyle();
}
this._activeIds = featureStyleId;
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
@ -507,15 +527,15 @@ export default class Layer extends Base {
}
/**
* 用于过滤数据
* @param {*} filterData 数据过滤标识符
* 用于过滤数据
* @param {*} object 需要过滤的mesh
*/
_updateFilter() {
_updateFilter(object) {
this._updateMaping();
const filterData = this.StyleData;
this._activeIds = null; // 清空选中元素
const colorAttr = this.layerMesh.geometry.attributes.a_color;
const pickAttr = this.layerMesh.geometry.attributes.pickingId;
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 ];
@ -526,7 +546,7 @@ export default class Layer extends Base {
colorAttr.array[index * 4 + 1] = 0;
colorAttr.array[index * 4 + 2] = 0;
colorAttr.array[index * 4 + 3] = 0;
pickAttr.array[index] = -id;
pickAttr.array[index] = -id; // 通过Id数据过滤 id<0 不显示
} else {
colorAttr.array[index * 4 + 0] = color[0];
colorAttr.array[index * 4 + 1] = color[1];
@ -537,8 +557,6 @@ export default class Layer extends Base {
});
colorAttr.needsUpdate = true;
pickAttr.needsUpdate = true;
this._needUpdateFilter = false;
this._needUpdateColor = false;
}
_visibleWithZoom() {
const zoom = this.scene.getZoom();
@ -561,7 +579,8 @@ export default class Layer extends Base {
/**
* 重置高亮要素
*/
resetStyle() {
_resetStyle() {
const pickingId = this.layerMesh.geometry.attributes.pickingId.array;
const colorAttr = this.layerMesh.geometry.attributes.a_color;
this._activeIds.forEach(index => {
@ -577,12 +596,13 @@ export default class Layer extends Base {
}
});
colorAttr.needsUpdate = true;
this._activeIds = null;
}
/**
* 销毁Layer对象
*/
despose() {
this.destroy();
destroy() {
this.removeAllListeners();
if (this._object3D && this._object3D.children) {
let child;
for (let i = 0; i < this._object3D.children.length; i++) {
@ -592,7 +612,7 @@ export default class Layer extends Base {
}
this.remove(child);
if (child.geometry) {
child.geometry.dispose();
// child.geometry.dispose();
child.geometry = null;
}
if (child.material) {
@ -604,10 +624,17 @@ export default class Layer extends Base {
child.material.dispose();
child.material = null;
}
child = null;
}
}
this._object3D = null;
this.scene = null;
this.scene._engine._scene.remove(this._object3D);
this.scene._engine._picking.remove(this._pickingMesh);
this.scene.off('zoomchange', this._zoomchangeHander);
this.destroyed = true;
}
_preRender() {
}
}

View File

@ -1,8 +1,8 @@
import Engine from './engine';
import * as THREE from './three';
import * as layers 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 Global from '../global';
@ -21,6 +21,7 @@ export default class Scene extends Base {
_initEngine(mapContainer) {
this._engine = new Engine(mapContainer, this);
this._engine.run();
this.workerPool = new WorkerPool();
}
// 为pickup场景添加 object 对象
addPickMesh(object) {
@ -41,6 +42,7 @@ export default class Scene extends Base {
this.map = Map.map;
Map.asyncCamera(this._engine);
this.initLayer();
this._registEvents();
this.emit('loaded');
});
@ -59,6 +61,11 @@ export default class Scene extends Base {
if (this.map) { this.map.on(type, hander); }
super.on(type, hander);
}
off(type, hander) {
if (this.map) { this.map.off(type, hander); }
super.off(type, hander);
}
_initAttribution() {
const message = '<a href="http://antv.alipay.com/zh-cn/index.html title="Large-scale WebGL-powered Geospatial Data Visualization">AntV | L7 </a>';
const element = document.createElement('div');
@ -77,15 +84,33 @@ export default class Scene extends Base {
return this._layers;
}
_addLight() {
const scene = this._engine._scene;
const ambientLight = new THREE.AmbientLight(0xaaaaaa);
scene.add(ambientLight);
// const scene = this._engine._scene;
// //const ambientLight = new THREE.AmbientLight(0xaaaaaa);
// scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
scene.add(directionalLight);
// const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// scene.add(directionalLight);
}
_addLayer() {
}
_registEvents() {
const events = [
'mouseout',
'mouseover',
'mousemove',
'mousedown',
'mouseleave',
'mouseup',
'click',
'dblclick'
];
events.forEach(event => {
this._container.addEventListener(event, e => {
// 要素拾取
this._engine._picking.pickdata(e);
}, false);
});
}
removeLayer(layer) {
const layerIndex = this._layers.indexOf(layer);
@ -93,6 +118,7 @@ export default class Scene extends Base {
this._layers.splice(layerIndex, 1);
}
layer.destroy();
layer = null;
}
}

View File

@ -9,8 +9,6 @@ export { Points } from 'three/src/objects/Points.js';
export { LineSegments } from 'three/src/objects/LineSegments.js';
export { Mesh } from 'three/src/objects/Mesh.js';
export { Texture } from 'three/src/textures/Texture.js';
export { DirectionalLight } from 'three/src/lights/DirectionalLight.js';
export { AmbientLight } from 'three/src/lights/AmbientLight.js';
export { WebGLRenderTarget } from 'three/src/renderers/WebGLRenderTarget.js';
export { PerspectiveCamera } from 'three/src/cameras/PerspectiveCamera.js';
export { BufferGeometry } from 'three/src/core/BufferGeometry.js';
@ -18,15 +16,10 @@ export { Raycaster } from 'three/src/core/Raycaster.js';
export { Matrix4 } from 'three/src/math/Matrix4.js';
export { Matrix3 } from 'three/src/math/Matrix3.js';
export { Line } from 'three/src/objects/Line.js';
export { LineLoop } from 'three/src/objects/LineLoop.js';
export { Vector4 } from 'three/src/math/Vector4.js';
export { Vector3 } from 'three/src/math/Vector3.js';
export { Vector2 } from 'three/src/math/Vector2.js';
export { TextureLoader } from 'three/src/loaders/TextureLoader.js';
export { LineDashedMaterial } from 'three/src/materials/LineDashedMaterial.js';
export { ShaderMaterial } from 'three/src/materials/ShaderMaterial.js';
export { PointsMaterial } from 'three/src/materials/PointsMaterial.js';
export { VideoTexture } from 'three/src/textures/VideoTexture.js';
export { DataTexture } from 'three/src/textures/DataTexture.js';
export {
Float64BufferAttribute,

View File

@ -1,4 +1,4 @@
import Worker from './main.worker.js';
import Worker from '../worker/main.worker.js';
class WorkerPool {
constructor(workerCount) {
this.workerCount = workerCount || Math.max(Math.floor(window.navigator.hardwareConcurrency / 2), 1);

0
src/geo/bound.js Normal file
View File

20
src/geo/lngLat.js Normal file
View File

@ -0,0 +1,20 @@
export class LatLng {
constructor(lat, lng, alt) {
if (isNaN(lat) || isNaN(lng)) {
throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
}
this.lat = +lat;
this.lng = +lng;
if (alt !== undefined) {
this.alt = +alt;
}
}
equal() {
}
distanceTo() {
}
}

View File

@ -1,5 +1,9 @@
import BufferBase from './bufferBase';
import { regularShape } from '../shape/index';
import * as polygonPath from '../shape/path';
import * as polygonShape from '../shape/polygon';
import * as lineShape from '../shape/line';
import { pointShape } from '../../global';
import Util from '../../util';
export default class PointBuffer extends BufferBase {
geometryBuffer() {
@ -43,8 +47,17 @@ export default class PointBuffer extends BufferBase {
this.attributes = this._toPointsAttributes(this.bufferStruct);
}
_3dRegularBuffer() {
const lineAttribute = {
shapes: [],
normal: [],
miter: [],
indexArray: [],
sizes: [],
positions: []
};
const coordinates = this.get('coordinates');
const properties = this.get('properties');
const style = this.get('style');
const type = this.get('type');
const positions = [];
const shapes = [];
@ -55,10 +68,10 @@ export default class PointBuffer extends BufferBase {
this.bufferStruct.style = properties;
coordinates.forEach((geo, index) => {
let { size, shape } = properties[index];
let shapeType = 'extrude';
// let shapeType = '';
if (type === '2d' || (type === '3d' && size[2] === 0)) {
shapeType = 'fill';
// let shapeType = 'fill';
Util.isArray(size) || (size = [ size, size, 0 ]);
} else {
Util.isArray(size) || (size = [ size, size, size ]);
@ -67,7 +80,19 @@ export default class PointBuffer extends BufferBase {
uvs.push(0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0);
shape = 'square';
}
const vert = regularShape[shape](shapeType);
properties[index].size = size;
const [ vert, polygonLine ] = this._getShape(properties[index], style, lineAttribute.miter.length);
polygonLine.miter.forEach(() => {
lineAttribute.positions.push(...geo);
lineAttribute.sizes.push(...size);
});
lineAttribute.shapes.push(...polygonLine.positions);
lineAttribute.normal.push(...polygonLine.normal);
lineAttribute.miter.push(...polygonLine.miter);
lineAttribute.indexArray.push(...polygonLine.indexArray);
shapes.push(vert.positions);
positions.push(geo);
sizes.push(size);
@ -81,6 +106,21 @@ export default class PointBuffer extends BufferBase {
this.bufferStruct.sizes = sizes;
this.bufferStruct.faceUv = uvs;
this.attributes = this._toPointShapeAttributes(this.bufferStruct);
this.lineAttribute = lineAttribute;
}
_getShape(props, style, positionsIndex) {
const { shape } = props;
const { stroke, strokeWidth } = style;
const path = polygonPath[shape]();
let polygon = null;
let polygonLine = null;
if (pointShape['3d'].indexOf(shape) === -1) {
polygon = polygonShape.fill([ path ]);
polygonLine = lineShape.Line(path, { size: [ strokeWidth, 0 ], color: stroke }, positionsIndex);
} else {
polygon = polygonShape.extrude([ path ]);
}
return [ polygon, polygonLine ];
}
}

View File

@ -0,0 +1,81 @@
import { pointShape } from '../../../global';
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) {
const attribute = {
vertices: [],
normals: [],
colors: [],
pickingIds: [],
shapePositions: [],
a_size: [],
faceUv: []
};
coordinates.forEach((geo, index) => {
let { size, shape, color, id } = properties[index];
let polygon = null;
const path = polygonPath[shape]();
if (pointShape['2d'].indexOf(shape) !== -1) {
Util.isArray(size) || (size = [ size, size, 0 ]);
polygon = polygonShape.fill([ path ]);
} else if (pointShape['3d'].indexOf(shape) !== -1) {
Util.isArray(size) || (size = [ size, size, size ]);
polygon = polygonShape.extrude([ path ]);
} else {
throw new Error('Invalid shape type: ' + shape);
}
toPointShapeAttributes(polygon, geo, { size, shape, color, id }, attribute);
});
return attribute;
}
function toPointShapeAttributes(polygon, geo, style, attribute) {
const { positionsIndex, positions } = polygon;
const pA = new THREE.Vector3();
const pB = new THREE.Vector3();
const pC = new THREE.Vector3();
const cb = new THREE.Vector3();
const ab = new THREE.Vector3();
for (let i = 0; i < positionsIndex.length / 3; i++) {
let index = positionsIndex[i * 3];
const { color, size, id } = style;
const ax = positions[index][0];
const ay = positions[index][1];
const az = positions[index][2];
index = positionsIndex[i * 3 + 1];
const bx = positions[index][0];
const by = positions[index][1];
const bz = positions[index][2];
index = positionsIndex[i * 3 + 2];
const cx = positions[index][0];
const cy = positions[index][1];
const cz = positions[index][2];
pA.set(ax, ay, az);
pB.set(bx, by, bz);
pC.set(cx, cy, cz);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
cb.normalize();
const nx = cb.x;
const ny = cb.y;
const nz = cb.z;
attribute.vertices.push(...geo, ...geo, ...geo);
attribute.shapePositions.push(ax, ay, az, bx, by, bz, cx, cy, cz);
attribute.a_size.push(...size, ...size, ...size);
attribute.normals.push(nx, ny, nz, nx, ny, nz, nx, ny, nz);
attribute.colors.push(...color, ...color, ...color);
attribute.pickingIds.push(id, id, id);
}
}

View File

@ -0,0 +1,23 @@
export default function ImageBuffer(coordinates, properties, opt) {
const attributes = {
vertices: [],
colors: [],
sizes: [],
shapes: [],
pickingIds: [],
uv: []
};
coordinates.forEach((pos, index) => {
const { color, size, id, shape } = properties[index];
const { x, y } = opt.imagePos[shape];
attributes.vertices.push(...pos);
attributes.colors.push(...color);
attributes.pickingIds.push(id);
attributes.sizes.push(size * window.devicePixelRatio); //
attributes.uv.push(x, y);
attributes.shapes.push(shape);
});
return attributes;
}

View File

@ -0,0 +1,4 @@
export { default as FillBuffer } from './fillBuffer';
export { default as StrokeBuffer } from './strokeBuffer';
export { default as ImageBuffer } from './imageBuffer';
export { default as NormalBuffer } from './normalBuffer';

View File

@ -0,0 +1,19 @@
export default function NormalBuffer(coordinates, properties) {
const attributes = {
vertices: [],
colors: [],
sizes: [],
pickingIds: []
};
coordinates.forEach((pos, index) => {
const { color, size, id } = properties[index];
attributes.vertices.push(...pos);
attributes.colors.push(...color);
attributes.pickingIds.push(id);
attributes.sizes.push(size);
});
return attributes;
}

View File

@ -0,0 +1,246 @@
// const SDFCommonWordsKey = '_AMap_sdf_com_words';
// /**
// * SDF 常用字获取/存储/check
// *
// */
// const SDFCommonWords = {
// store() {
// },
// /**
// * 检查一个字符是否在常用字中
// * @param {*} charcode 汉字
// */
// check(charcode) {
// const range = this.range || [];
// const info = this.info || {};
// if (typeof charcode !== 'number') {
// charcode = charcode.substr(0).charCodeAt(0);
// }
// for (let i = 0; i < range.length; i++) {
// const curRange = range[i];
// const [ rangeStart, rangeEnd ] = curRange.split('-');
// if (charcode >= rangeStart && charcode <= rangeEnd) {
// const curInfo = info[curRange] && info[curRange].info || {};
// if (curInfo[charcode]) {
// return true;
// }
// }
// }
// return false;
// },
// /**
// * 获取纹理和位置信息
// * @param list
// * @param cb
// */
// getImagesAndInfo(list, cb) {
// const range = this.range;
// },
// loadCanvas(url, range, done) {
// try {
// const xhr = new XMLHttpRequest();
// xhr.open('GET', url);
// // 直接用 blob 格式 load 图片文件,方便直接转换成 base64
// // 转成 base64 便于存储
// // 使用 canvas 转换 base64 容易有损
// xhr.responseType = 'blob';
// xhr.onerror = function() {
// done({ code: 0 });
// };
// xhr.onload = function() {
// if (xhr.status === 200) {
// const reader = new FileReader();
// reader.onload = () => {
// done(reader.result, range);
// };
// reader.readAsDataURL(xhr.response);
// } else {
// done({ code: 0 });
// }
// };
// xhr.send();
// } catch (err) {
// done({ code: 0 });
// }
// },
// loadImages(urls = []) {
// const deferred = $.Deferred();
// const totalNumbers = urls.length;
// const localInfo = this.info;
// let loadPicNum = 0;
// for (let i = 0; i < urls.length; i++) {
// const { url, range } = urls[i];
// this.loadCanvas(url, range, (base64, range) => {
// // image to base64
// loadPicNum++;
// !localInfo[range] && (localInfo[range] = {});
// localInfo[range].pic = base64;
// this.info = localInfo;
// // todo: temp 暂时用 localstorage 存储,因为数据比较大,最好使用 indexDB
// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
// if (loadPicNum === totalNumbers) {
// deferred.resolve();
// }
// });
// }
// return deferred;
// },
// loadInfo(urls) {
// const deferred = $.Deferred();
// const totalNumbers = urls.length;
// const localInfo = this.info;
// let loadInfoNum = 0;
// for (let i = 0; i < urls.length; i++) {
// const { url, range } = urls[i];
// $.ajax({
// url,
// dataType: 'json',
// success: data => {
// loadInfoNum++;
// !localInfo[range] && (localInfo[range] = {});
// localInfo[range].info = data;
// this.info = localInfo;
// localStorage.setItem(SDFCommonWordsKey, JSON.stringify(localInfo));
// if (loadInfoNum === totalNumbers) {
// deferred.resolve();
// }
// },
// error: () => {
// }
// });
// }
// return deferred;
// },
// getTotalAssets(info, cb) {
// const { range = [], urlPrefix } = info;
// const picUrls = [];
// const infoUrls = [];
// this.range = range;
// for (let i = 0; i < range.length; i++) {
// const curRange = range[i];
// const baseUrl = urlPrefix + curRange;
// const picUrl = baseUrl + '.png';
// const infoUrl = baseUrl + '.json';
// picUrls.push({ range: curRange, url: picUrl });
// infoUrls.push({ range: curRange, url: infoUrl });
// }
// const imageDeferred = this.loadImages(picUrls);
// const infoDeferred = this.loadInfo(infoUrls);
// $.when(imageDeferred, infoDeferred)
// .then(() => {
// // all info load complete
// // console.log("all info load complete", " -- ", 1);
// cb && cb(this.info);
// }, () => {
// // fail
// });
// },
// // 获取数据
// getData(cb) {
// if (!_.isEmpty(this.info)) {
// cb && cb(this.info);
// } else {
// this.getRemoteData(cb);
// }
// },
// /**
// * 从服务获取数据,什么时候强制去取一回数据?过期?
// * @param cb
// */
// getRemoteData(cb) {
// const self = this;
// $.ajax({
// url: '/getcommonwords',
// dataType: 'json',
// success: data => {
// if (data.code == 1) {
// const info = data.data;
// self.getTotalAssets(info, cb);
// }
// }
// });
// },
// destroy() {
// },
// init() {
// let info = localStorage.getItem(SDFCommonWordsKey);
// this.range = [];
// this.info = {};
// if (info) {
// info = JSON.parse(info);
// this.range = Object.keys(info);
// this.info = info;
// }
// this.info = info || {};
// }
// };
// export default SDFCommonWords;

View File

@ -0,0 +1,53 @@
import * as polygonPath from '../../shape/path';
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) {
const attribute = {
shapes: [],
normal: [],
miter: [],
indexArray: [],
sizes: [],
positions: [],
pickingIds: [],
colors: []
};
const { stroke, strokeWidth } = style;
coordinates.forEach((geo, index) => {
let { size, shape, id } = properties[index];
const path = polygonPath[shape]();
const positionsIndex = attribute.miter.length;
let polygon = null;
if (pointShape['2d'].indexOf(shape) !== -1) {
Util.isArray(size) || (size = [ size, size, 0 ]);
polygon = lineShape.Line([ path ], { size: [ strokeWidth, 0 ], color: stroke, id }, positionsIndex);
} else if (pointShape['3d'].indexOf(shape) !== -1) {
Util.isArray(size) || (size = [ size, size, size ]);
const polygonExtrudePath = polygonShape.extrudeline([ path ]);
// TODO 3d line
polygon = lineShape.Line([ polygonExtrudePath ], { size: [ strokeWidth, 0 ], color: stroke, id }, positionsIndex);
} else {
throw new Error('Invalid shape type: ' + shape);
}
polygonLineBuffer(polygon, geo, size, attribute);
});
return attribute;
}
function polygonLineBuffer(polygon, geo, size, attribute) {
attribute.shapes.push(...polygon.positions);
attribute.normal.push(...polygon.normal);
attribute.miter.push(...polygon.miter);
attribute.pickingIds.push(...polygon.pickingIds);
attribute.indexArray.push(...polygon.indexArray);
attribute.colors.push(...polygon.colors);
polygon.miter.forEach(() => {
attribute.positions.push(...geo); // 多边形位置
attribute.sizes.push(...size); // 多边形大小
});
}

View File

@ -0,0 +1,181 @@
import { getJSON } from '../../../util/ajax';
import EventEmitter from 'wolfy87-eventemitter';
import Global from '../../../global';
// const Space = 1;
const metrics = {
buffer: 3,
family: 'ios9',
size: 24
};
export default function TextBuffer(coordinates, properties, style) {
EventEmitter.call(this);
const attributes = {
originPoints: [],
textSizes: [],
textOffsets: [],
colors: [],
textureElements: []
};
const { textOffset = [ 0, 0 ] } = style;
const chars = [];
const textChars = {};
properties.forEach(element => {
let text = element.shape || '';
text = text.toString();
for (let j = 0; j < text.length; j++) {
const code = text.charCodeAt(j);
textChars[text] = 0;
if (chars.indexOf(code) === -1) {
chars.push(text.charCodeAt(j));
}
}
});
loadTextInfo(chars, (chars, texture) => {
properties.forEach((element, index) => {
const size = element.size;
const pos = coordinates[index];
const pen = { x: textOffset[0], y: textOffset[1] };
let text = element.shape || '';
text = text.toString();
for (let i = 0; i < text.length; i++) {
const color = element.color;
drawGlyph(chars, pos, text[i], pen, size, attributes.colors, attributes.textureElements, attributes.originPoints, attributes.textSizes, attributes.textOffsets, color);
}
this.emit('completed', { attributes, texture });
});
});
}
function loadTextInfo(chars, done) {
getJSON({
url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
}, (e, info) => {
loadTextTexture(info.url, texture => {
done(info.info, texture);
});
});
}
function loadTextTexture(url, cb) {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
const textTexture = this._creatTexture(img);
cb(textTexture);
};
img.src = url;
}
/**
* 计算每个标注词语的位置
* @param {*} chars 文本信息
* @param {*} pos 文字三维空间坐标
* @param {*} text 字符
* @param {*} pen 字符在词语的偏移量
* @param {*} size 字体大小
* @param {*} colors 颜色
* @param {*} textureElements 纹理坐标
* @param {*} originPoints 初始位置数据
* @param {*} textSizes 文字大小数组
* @param {*} textOffsets 字体偏移量数据
* @param {*} color 文字颜色
*/
function drawGlyph(chars, pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
const chr = text.charCodeAt(0);
const metric = chars[chr];
if (!metric) return;
const scale = size / metrics.size;
let width = metric[0];
let height = metric[1];
const posX = metric[5];
const posY = metric[6];
const buffer = metrics.buffer;
if (width > 0 && height > 0) {
width += buffer * 2;
height += buffer * 2;
const originX = 0;
const originY = 0;
const offsetX = pen.x;
const offsetY = pen.y;
originPoints.push(
pos[0] + originX, pos[1] + originY, 0,
pos[0] + originX, pos[1] + originY, 0,
pos[0] + originX, pos[1] + originY, 0,
pos[0] + originX, pos[1] + originY, 0,
pos[0] + originX, pos[1] + originY, 0,
pos[0] + originX, pos[1] + originY, 0,
);
const bx = 0;
const by = metrics.size / 2 + buffer;
textSizes.push(
((bx - buffer + width) * scale), (height - by) * scale,
((bx - buffer) * scale), (height - by) * scale,
((bx - buffer) * scale), -by * scale,
((bx - buffer + width) * scale), (height - by) * scale,
((bx - buffer) * scale), -by * scale,
((bx - buffer + width) * scale), -by * scale,
);
textOffsets.push(
offsetX, offsetY,
offsetX, offsetY,
offsetX, offsetY,
offsetX, offsetY,
offsetX, offsetY,
offsetX, offsetY,
);
colors.push(
...color,
...color,
...color,
...color,
...color,
...color,
);
textureElements.push(
posX + width, posY,
posX, posY,
posX, posY + height,
posX + width, posY,
posX, posY + height,
posX + width, posY + height
);
}
pen.x = pen.x + size * 1.8;
}
// function measureText(text, size) {
// const dimensions = {
// advance: 0
// };
// const metrics = this.metrics;
// const scale = size / metrics.size;
// for (let i = 0; i < text.length; i++) {
// const code = text.charCodeAt(i);
// const horiAdvance = metrics.chars[code][4];
// dimensions.advance += (horiAdvance + Space) * scale;
// }
// return dimensions;
// }
// function creatTexture(image) {
// this.bufferStruct.textSize = [ image.width, image.height ];
// const texture = new THREE.Texture(image);
// texture.minFilter = THREE.LinearFilter;
// texture.magFilter = THREE.ClampToEdgeWrapping;
// texture.needsUpdate = true;
// return texture;
// }

View File

@ -1,6 +1,8 @@
import BufferBase from './bufferBase';
import { getJSON } from '../../util/ajax';
import * as THREE from '../../core/three';
import TinySDF from '@mapbox/tiny-sdf';
import Global from '../../global';
const Space = 1;
export default class TextBuffer extends BufferBase {
@ -15,16 +17,21 @@ export default class TextBuffer extends BufferBase {
const properties = this.get('properties');
const { textOffset = [ 0, 0 ] } = this.get('style');
const chars = [];
const textChars = {};
properties.forEach(element => {
let text = element.shape || '';
text = text.toString();
for (let j = 0; j < text.length; j++) {
const code = text.charCodeAt(j);
textChars[text] = 0;
if (chars.indexOf(code) === -1) {
chars.push(text.charCodeAt(j));
}
}
});
const sdfTexture = this._updateSdf(Object.keys(textChars).join(''));
this.sdfTexture = sdfTexture;
this._loadTextInfo(chars);
this.on('SourceLoaded', () => {
const textureElements = [];
@ -40,10 +47,10 @@ export default class TextBuffer extends BufferBase {
let text = element.shape || '';
text = text.toString();
for (let i = 0; i < text.length; i++) {
const chr = text.charCodeAt(i);
const color = element.color;
this._drawGlyph(pos, chr, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
this._drawGlyph(pos, text[i], pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color);
}
});
this.bufferStruct.style = properties;
@ -64,6 +71,7 @@ export default class TextBuffer extends BufferBase {
url: `${Global.sdfHomeUrl}/getsdfdata?chars=${chars.join('|')}`
}, (e, info) => {
this.metrics.chars = info.info;
this._loadTextTexture(info.url);
});
}
@ -73,8 +81,9 @@ export default class TextBuffer extends BufferBase {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => {
this.bufferStruct.textTexture = this._creatTexture(img);
this.bufferStruct.textTexture = this._creatTexture(this.sdfTexture.texure);
this.emit('SourceLoaded');
};
img.src = url;
@ -83,7 +92,7 @@ export default class TextBuffer extends BufferBase {
/**
* 计算每个标注词语的位置
* @param {*} pos 文字三维空间坐标
* @param {*} chr 字符
* @param {*} text 字符
* @param {*} pen 字符在词语的偏移量
* @param {*} size 字体大小
* @param {*} colors 颜色
@ -93,22 +102,26 @@ export default class TextBuffer extends BufferBase {
* @param {*} textOffsets 字体偏移量数据
* @param {*} color 文字颜色
*/
_drawGlyph(pos, chr, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
_drawGlyph(pos, text, pen, size, colors, textureElements, originPoints, textSizes, textOffsets, color) {
const metrics = this.metrics;
const chr = text.charCodeAt(0);
const metric = metrics.chars[chr];
if (!metric) return;
const info = this.sdfTexture.info;
const { x, y } = info[text];
const scale = size / metrics.size;
let width = metric[0];
let height = metric[1];
let width = 24; // metric[0];
let height = 24;// metric[1];
const horiBearingX = metric[2];
const horiBearingY = metric[3];
// const horiBearingX = metric[2];
// const horiBearingY = metric[3];
const horiAdvance = metric[4];
const posX = metric[5];
const posY = metric[6];
// const horiAdvance = metric[4];
// const posX = metric[5];
// const posY = metric[6];
const posX = x;
const posY = y;
const buffer = metrics.buffer;
@ -117,12 +130,17 @@ export default class TextBuffer extends BufferBase {
height += buffer * 2;
// Add a quad (= two triangles) per glyph.
const originX = (horiBearingX - buffer + width / 2) * scale;
const originY = -(height / 2 - horiBearingY) * scale;
// const originY = (height / 2 - horiBearingY) * scale;
// const originY = 0;
const offsetWidth = width / 2 * scale / (1.0 - horiBearingX * 1.5 / horiAdvance);
const offsetHeight = (horiAdvance / 2) * scale;
// const originX = (horiBearingX - buffer + width / 2) * scale;
// const originY = -(height - horiBearingY) * scale;
const originX = 0;
const originY = 0;
// const offsetWidth = width / 2 * scale / (1.0 - horiBearingX * 1.5 / horiAdvance);
// const offsetHeight = (horiAdvance / 2) * scale;
// const offsetWidth = width/2 * scale;
// const offsetHeight = height / 2 * scale;
// const offsetHeight = height * scale;
const offsetX = pen.x;
const offsetY = pen.y;
@ -135,14 +153,31 @@ export default class TextBuffer extends BufferBase {
pos[0] + originX, pos[1] + originY, 0,
);
// textSizes.push(
// offsetWidth, offsetHeight,
// -offsetWidth, offsetHeight,
// -offsetWidth, -offsetHeight,
// offsetWidth, offsetHeight,
// -offsetWidth, -offsetHeight,
// offsetWidth, -offsetHeight,
// );
const bx = 0;
const by = metrics.size / 2 + buffer;
textSizes.push(
offsetWidth, offsetHeight,
-offsetWidth, offsetHeight,
-offsetWidth, -offsetHeight,
offsetWidth, offsetHeight,
-offsetWidth, -offsetHeight,
offsetWidth, -offsetHeight,
((bx - buffer + width) * scale), (height - by) * scale,
((bx - buffer) * scale), (height - by) * scale,
((bx - buffer) * scale), -by * scale,
((bx - buffer + width) * scale), (height - by) * scale,
((bx - buffer) * scale), -by * scale,
((bx - buffer + width) * scale), -by * scale,
);
textOffsets.push(
offsetX, offsetY,
offsetX, offsetY,
@ -172,7 +207,8 @@ export default class TextBuffer extends BufferBase {
);
}
pen.x = pen.x + (horiAdvance + Space) * scale;
// pen.x = pen.x + (horiAdvance + Space) * scale;
pen.x = pen.x + size * 1.8;
}
@ -196,8 +232,46 @@ export default class TextBuffer extends BufferBase {
this.bufferStruct.textSize = [ image.width, image.height ];
const texture = new THREE.Texture(image);
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.magFilter = THREE.ClampToEdgeWrapping;
texture.needsUpdate = true;
return texture;
}
_updateSdf(chars) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const sdfs = {};
const fontSize = 24;
const fontWeight = 100;
const buffer = fontSize / 8;
const radius = fontSize / 3;
const canvasSize = Math.floor(Math.pow(chars.length, 0.5)) * (fontSize + buffer + radius);
canvas.width = canvasSize;
canvas.height = canvasSize;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const sdf = new TinySDF(fontSize, buffer, radius, null, null, fontWeight);
for (let y = 0, i = 0; y + sdf.size <= canvas.height && i < chars.length; y += sdf.size) {
for (let x = 0; x + sdf.size <= canvas.width && i < chars.length; x += sdf.size) {
ctx.putImageData(this._makeRGBAImageData(ctx, sdf.draw(chars[i]), sdf.size), x, y);
sdfs[chars[i]] = { x, y };
i++;
}
}
return {
info: sdfs,
texure: canvas
};
}
_makeRGBAImageData(ctx, alphaChannel, size) {
const imageData = ctx.createImageData(size, size);
const data = imageData.data;
for (let i = 0; i < alphaChannel.length; i++) {
data[4 * i + 0] = alphaChannel[i];
data[4 * i + 1] = alphaChannel[i];
data[4 * i + 2] = alphaChannel[i];
data[4 * i + 3] = 255;
}
return imageData;
}
}

View File

@ -45,7 +45,10 @@ export function MeshLineMaterial(options) {
uniforms: {
u_opacity: { value: options.u_opacity || 1.0 },
u_time: { value: options.u_time || 0 },
u_zoom: { value: options.u_zoom }
u_zoom: { value: options.u_zoom },
u_duration: { value: options.u_duration || 2.0 },
u_interval: { value: options.u_interval || 1.0 },
u_trailLength: { value: options.u_trailLength || 0.2 }
},
vertexShader: meshline_vert,
fragmentShader: meshline_frag,

View File

@ -0,0 +1,29 @@
import Material from './material';
import point_frag from '../shader/point_meshLine_frag.glsl';
import point_vert from '../shader/point_meshLine_vert.glsl';
export default class PointLineMaterial extends Material {
getDefaultParameters() {
return {
uniforms: {
u_strokeOpacity: { value: 1 },
u_stroke: { value: [ 1.0, 1.0, 1.0, 1.0 ] },
u_strokeWidth: { value: 1.0 },
u_zoom: { value: 10 }
}
};
}
constructor(_uniforms, _defines, parameters) {
super(parameters);
const { uniforms } = this.getDefaultParameters();
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
this.type = 'PointLineMaterial';
this.vertexShader = point_vert;
this.fragmentShader = point_frag;
this.transparent = true;
}
}

View File

@ -1,25 +1,55 @@
import polygon_frag from '../shader/polygon_frag.glsl';
import polygon_vert from '../shader/polygon_vert.glsl';
import Material from './material';
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 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 {
uniforms: {
u_opacity: { value: 1.0 },
u_time: { value: 0 },
u_zoom: { value: 0 },
u_baseColor: { value: [ 1.0, 0, 0, 1.0 ] },
u_brightColor: { value: [ 1.0, 0, 0, 1.0 ] },
u_windowColor: { value: [ 1.0, 0, 0, 1.0 ] },
u_near: { value: 0.0 },
u_far: { value: 1.0 }
},
defines: {
}
};
}
constructor(_uniforms, _defines, parameters) {
super(parameters);
const { uniforms, defines } = this.getDefaultParameters();
this.uniforms = Object.assign(uniforms, this.setUniform(_uniforms));
this.type = 'PolygonMaterial';
this.defines = Object.assign(defines, _defines);
this.vertexShader = polygon_vert;
this.fragmentShader = polygon_frag;
this.transparent = true;
}
}

View File

@ -5,7 +5,7 @@ uniform float u_dashSmooth;
uniform float u_dashDistance;
varying vec4 v_color;
void main() {
float lineUMod = mod(v_lineU, 1.0/u_dashSteps) * u_dashSteps;
float lineUMod = mod(v_lineU, 1.0/ u_dashSteps) * u_dashSteps;
float dash = smoothstep(u_dashDistance, u_dashDistance+u_dashSmooth, length(lineUMod-0.5));
gl_FragColor = vec4(v_color.xyz * vec3(dash), v_color.a*u_opacity * dash);
}

View File

@ -1,7 +1,11 @@
precision highp float;
uniform float u_opacity;
varying vec4 v_color;
varying float vTime;
void main() {
gl_FragColor = v_color;
gl_FragColor.a = v_color.a * u_opacity ;
gl_FragColor.a = v_color.a * u_opacity;
#ifdef ANIMATE
gl_FragColor.a *= vTime;
#endif
}

View File

@ -2,12 +2,30 @@ precision highp float;
attribute float a_miter;
attribute vec4 a_color;
attribute float a_size;
attribute float a_distance;
uniform float u_zoom;
varying vec4 v_color;
uniform float u_time;
varying float vTime;
// animate
#ifdef ANIMATE
uniform float u_duration; // 动画持续时间
uniform float u_interval;
uniform float u_repeat;
uniform float u_trailLength;
#endif
void main() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
vec3 pointPos = position.xyz + vec3(normal * a_size * pow(2.0,20.0-u_zoom) / 2.0 * a_miter);
v_color = a_color;
#ifdef ANIMATE
//mod(a_distance,0.2) * 5.
float alpa =1.0 - fract( mod(1.0- a_distance,u_interval)* (1.0/u_interval) + u_time / u_duration);
alpa = (alpa + u_trailLength -1.0) / u_trailLength;
vTime = clamp(alpa,0.,1.);
#endif
gl_Position = matModelViewProjection * vec4(pointPos, 1.0);
}

View File

@ -0,0 +1,17 @@
precision highp float;
uniform float u_strokeOpacity;
uniform vec4 u_stroke;
varying float v_pickingId;
void main() {
if(v_pickingId < -0.1) {
discard;
}
#ifdef ANIMATE
if (vTime > 1.0 || vTime < 0.0) {
discard;
}
#endif
gl_FragColor = u_stroke;
gl_FragColor.a = u_stroke.a * u_strokeOpacity ;
}

View File

@ -0,0 +1,23 @@
precision highp float;
attribute float a_miter;
attribute vec3 a_size;
attribute vec3 a_shape;
attribute float pickingId;
uniform float u_strokeWidth;
uniform float u_zoom;
varying float v_pickingId;
uniform float u_time;
varying float vTime;
void main() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
float scale = pow(2.0,(20.0 - u_zoom));
vec3 newposition = position + (a_size + vec3(u_strokeWidth/2.,u_strokeWidth/2.,0)) * scale* a_shape;
v_pickingId = pickingId;
#ifdef ANIMATE
vTime = 1.0- (mod(u_time*50.,3600.)- position.z) / 100.;
#endif
//vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * pow(2.0,20.0-u_zoom) / 2.0 * a_miter);
vec3 pointPos = newposition.xyz + vec3(normal * u_strokeWidth * scale / 2.0 * a_miter);
gl_Position = matModelViewProjection * vec4(pointPos, 1.0);
}

View File

@ -15,8 +15,8 @@ varying float v_size;
vec3 getWindowColor(float n, float hot, vec3 brightColor, vec3 darkColor) {
float s = step(hot, n);
//vec3 color = mix(brightColor,brightColor - vec3(0.4,0.4,0.4),n);
vec3 color = mix(brightColor,vec3(1.0,1.0,1.0),n);
vec3 color = mix(brightColor,vec3(0.9,0.9,1.0),n);
return mix(darkColor, color, s);
}
float random (vec2 st) {
@ -87,7 +87,7 @@ void main() {
if(ux == targetColId){
n =0.;
}
float timeP = min(0.95, abs ( sin(u_time/6.0) ) );
float timeP = min(0.75, abs ( sin(u_time/6.0) ) );
float hot = smoothstep(1.0,0.0,timeP);
vec3 color = mix(baseColor, getWindowColor(n,hot,brightColor,windowColor), s);
//vec3 color = mix(baseColor, getWindowColor(n,hot,brightColor,windowColor), 1.0);

View File

View File

@ -0,0 +1,48 @@
precision highp float;
#define ambientRatio 0.5
#define diffuseRatio 0.4
#define specularRatio 0.1
attribute vec4 a_color;
attribute vec4 a_idColor;
attribute vec2 faceUv;
attribute vec3 a_shape;
attribute vec3 a_size;
uniform float u_zoom;
varying vec2 v_texCoord;
varying vec4 v_color;
varying float v_lightWeight;
varying float v_size;
void main() {
float scale = pow(2.0,(20.0 - u_zoom));
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
vec3 newposition = position;
#ifdef SHAPE
newposition =position + a_size * scale* a_shape;
#endif
v_texCoord = faceUv;
if(normal == vec3(0.,0.,1.)){
v_color = a_color;
gl_Position = matModelViewProjection * vec4(newposition, 1.0);
return;
}
vec3 worldPos = vec3(vec4(newposition,1.0) * modelMatrix);
vec3 worldNormal = vec3(vec4(normal,1.0) * modelMatrix);
// //cal light weight
vec3 viewDir = normalize(cameraPosition - worldPos);
//vec3 lightDir = normalize(vec3(1, -10.5, 12));
vec3 lightDir = normalize(vec3(0.,-10.,1.));
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 = ambientRatio + diffuseRatio * lambert + specularRatio * specular;
v_texCoord = faceUv;
v_lightWeight = lightWeight;
// v_size = a_size;
v_color =vec4(a_color.rgb*lightWeight, a_color.w);
gl_Position = matModelViewProjection * vec4(newposition, 1.0);
}

View File

@ -10,20 +10,19 @@ varying vec2 v_texcoord;
void main() {
float dist = texture2D(u_texture, vec2(v_texcoord.x,1.0-v_texcoord.y)).r;
float dist =texture2D(u_texture, vec2(v_texcoord.x,1.0-v_texcoord.y)).r;
float alpha;
if(u_strokeWidth == 0.0){
alpha = smoothstep(u_buffer - u_gamma, u_buffer, dist);
alpha = smoothstep(u_buffer - u_gamma, u_buffer + u_gamma, dist);
gl_FragColor = vec4(v_color.rgb, alpha * v_color.a);
}else{
if(dist <= u_buffer - u_gamma){
alpha = smoothstep(u_strokeWidth - u_gamma, u_strokeWidth, dist);
alpha = smoothstep(u_strokeWidth - u_gamma, u_strokeWidth+ u_gamma, dist);
gl_FragColor = vec4(u_stroke.rgb, alpha * u_stroke.a);
}else if(dist < u_buffer){
alpha = smoothstep(u_buffer - u_gamma, u_buffer, dist);
alpha = smoothstep(u_buffer - u_gamma, u_buffer+u_gamma, dist);
gl_FragColor = vec4(alpha * v_color.rgb + (1.0 - alpha) * u_stroke.rgb, 1.0 * v_color.a * alpha + (1.0 - alpha) * u_stroke.a);
}else{
alpha = 1.0;

View File

@ -13,8 +13,14 @@ varying vec4 v_color;
void main() {
mat4 matModelViewProjection = projectionMatrix * modelViewMatrix;
vec4 cur_position = matModelViewProjection * vec4(position.xy, 0, 1);
gl_Position = cur_position / cur_position.w + vec4((a_txtOffsets + a_txtsize)/ u_glSize * 2.0,0.0, 0.0) +vec4(abs(a_txtsize.x)/u_glSize.x *2.0, -abs(a_txtsize.y)/u_glSize.y* 2.0, 0.0, 0.0);
gl_Position = cur_position / cur_position.w + vec4((a_txtOffsets + a_txtsize)/ u_glSize * 2.0,0.0, 0.0) +vec4(abs(a_txtsize.x)/u_glSize.x *2.0, -abs(a_txtsize.y)/u_glSize.y* 2.0, 0.0, 0.0);
highp float camera_to_anchor_distance = gl_Position.w;
// highp float perspective_ratio = clamp(
// 0.5 + 0.5 * distance_ratio,
// 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles
// 4.0);
v_color = a_color;
v_color.a = v_color.a * camera_to_anchor_distance;
v_texcoord = uv / u_textSize;
}

View File

@ -120,7 +120,7 @@ export function defaultLine(geo, index) {
return { positions, indexes: indexArray };
}
// mesh line
export function Line(path, props, positionsIndex, dash = false) {
export function Line(path, props, positionsIndex) {
if (path.length === 1) path = path[0];// 面坐标转线坐标
const positions = [];
const pickingIds = [];
@ -129,7 +129,7 @@ export function Line(path, props, positionsIndex, dash = false) {
const colors = [];
const indexArray = [];
const normals = getNormal(path);
const attrDistance = [];
let attrDistance = [];
const sizes = [];
let c = 0;
let index = positionsIndex;
@ -153,10 +153,14 @@ export function Line(path, props, positionsIndex, dash = false) {
point[2] = size[1];
positions.push(...point);
positions.push(...point);
if (dash) {
const d = pointIndex / (list.length - 1);
if (pointIndex === 0) {
attrDistance.push(0, 0);
} else {
const d = attrDistance[pointIndex * 2 - 1] + lineSegmentDistance(path[pointIndex - 1], path[pointIndex]);
attrDistance.push(d, d);
}
index += 2;
});
normals.forEach(n => {
@ -167,6 +171,9 @@ export function Line(path, props, positionsIndex, dash = false) {
miter.push(-m);
miter.push(m);
});
attrDistance = attrDistance.map(d => {
return d / attrDistance[attrDistance.length - 1];
});
return {
positions,
normal,
@ -179,3 +186,9 @@ export function Line(path, props, positionsIndex, dash = false) {
};
}
function lineSegmentDistance(end, start) {
const dx = start[0] - end[0];
const dy = start[1] - end[1];
const dz = start[2] - end[2];
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}

45
src/geom/shape/path.js Normal file
View File

@ -0,0 +1,45 @@
/**
* @author lzxue
* @email lzx199065@gmail.com
* @create date 2018-11-28 11:01:33
* @modify date 2018-11-28 11:01:33
* @desc ,线, coordinates
*/
function circle() {
return polygonPath(30);
}
function square() {
return polygonPath(4);
}
function triangle() {
return polygonPath(3);
}
function hexagon() {
return polygonPath(6);
}
export {
circle,
square,
triangle,
hexagon,
circle as cylinder,
triangle as triangleColumn,
hexagon as hexagonColumn,
square as squareColumn
};
export function polygonPath(pointCount) {
const step = Math.PI * 2 / pointCount;
const line = [];
for (let i = 0; i < pointCount; i++) {
line.push(step * i);
}
const path = line.map(t => {
const x = Math.sin(t + Math.PI / 4),
y = Math.cos(t + Math.PI / 4);
return [ x, y, 0 ];
});
path.push(path[0]);
return path;
}

View File

@ -1,12 +1,12 @@
import * as polygonShape from './polygon';
import { polygonPath } from './path';
/**
* shape circle
* @param {enum} type 渲染类型
* @return {object} 顶点坐标和索引坐标
*/
export function circle(type) {
const points = polygonPoint(30);
const points = polygonPath(30);
return polygonShape[type]([ points ]);
}
/**
@ -15,7 +15,7 @@ export function circle(type) {
* @return {object} 顶点坐标和索引坐标
*/
export function triangle(type) {
const points = polygonPoint(3);
const points = polygonPath(3);
return polygonShape[type]([ points ]);
}
@ -25,7 +25,7 @@ export function triangle(type) {
* @return {object} 顶点坐标和索引坐标
*/
export function diamond(type) {
const points = polygonPoint(4);
const points = polygonPath(4);
return polygonShape[type]([ points ]);
}
@ -39,26 +39,6 @@ export function square(type) {
* @return {object} 顶点坐标和索引坐标
*/
export function hexagon(type) {
const points = polygonPoint(6);
const points = polygonPath(6);
return polygonShape[type]([ points ]);
}
/**
* 规则多边形
* @param {*} pointCount 顶点个数
* @param {*} extrude 是否拔高
* @return {Array} 顶点坐标
*/
function polygonPoint(pointCount) {
const step = Math.PI * 2 / pointCount;
const line = [];
for (let i = 0; i < pointCount; i++) {
line.push(step * i);
}
// debugger
const points = line.map(t => {
const x = Math.sin(t + Math.PI / 4),
y = Math.cos(t + Math.PI / 4);
return [ x, y, 0 ];
});
return points;
}

View File

@ -55,8 +55,9 @@ export function extrudeline(points) {
vertIndex.push(vertCount, 0);
vertIndex.push(vertCount, vertCount + pointCount);
vertIndex.push(vertCount + pointCount, pointCount);
return {
positions,
positionsIndex: vertIndex
};
const newPositions = [];
vertIndex.forEach(index => {
newPositions.push(positions[index]);
});
return newPositions;
}

View File

@ -4,7 +4,7 @@
*/
// const Global = {};
const Global = {
version: '____L7_VERSION____',
version: '1.0.0',
scene: {
mapType: 'AMAP',
zoom: 5,
@ -22,6 +22,11 @@ const Global = {
// 指定固定 tick 数的逼近值
snapCountArray: [ 0, 1, 1.2, 1.5, 1.6, 2, 2.2, 2.4, 2.5, 3, 4, 5, 6, 7.5, 8, 10 ],
size: 10000,
shape: 'circle',
pointShape: {
'2d': [ 'circle', 'square', 'hexagon', 'triangle' ],
'3d': [ 'cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn' ]
},
sdfHomeUrl: 'https://sdf.amap.com',
scales: {
}

View File

@ -1,8 +1,17 @@
// import Util from './util';
import Scene from './core/scene';
const version = '0.0.1';
import Global from './global';
const version = Global.version;
const track = function(enable) {
Global.trackable = enable;
};
require('./track');
export {
version,
Scene
Scene,
track
};

View File

@ -46,6 +46,7 @@ export default class LineLayer extends Layer {
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
const lineType = style.lineType;
let material;
@ -55,6 +56,20 @@ export default class LineLayer extends Layer {
u_opacity: opacity,
u_zoom: this.scene.getZoom()
});
if (animateOptions.enable) {
material.setDefinesvalue('ANIMATE', true);
const { duration, interval, trailLength, repeat = Infinity } = animateOptions;
this.animateDuration = this.scene._engine.clock.getElapsedTime() + duration * repeat;
material.upDateUninform({
u_duration: duration,
u_interval: interval,
u_trailLength: trailLength
});
}
} else {
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
material = new DashLineMaterial({
@ -80,4 +95,11 @@ export default class LineLayer extends Layer {
}
return this;
}
_preRender() {
if (this.animateDuration > 0 && this.animateDuration < this.scene._engine.clock.getElapsedTime()) {
this.layerMesh.material.setDefinesvalue('ANIMATE', false);
this.emit('animateEnd');
this.animateDuration = Infinity;
}
}
}

View File

@ -1,12 +1,11 @@
import Layer from '../core/layer';
import * as THREE from '../core/three';
import PointBuffer from '../geom/buffer/point';
import PointMaterial from '../geom/material/pointMaterial';
import PolygonMaterial from '../geom/material/polygonMaterial';
import * as drawPoint from '../layer/render/point';
import { pointShape } from '../global';
// import PointBuffer from '../geom/buffer/point';
import TextBuffer from '../geom/buffer/text';
import TextMaterial from '../geom/material/textMaterial';
import radar from '../geom/shader/radar_frag.glsl';
import warn from '../geom/shader/warn_frag.glsl';
import * as PointBuffer from '../geom/buffer/point/index';
/**
* point shape 2d circle, traingle text,image
@ -32,83 +31,71 @@ export default class PointLayer extends Layer {
return this;
}
_prepareRender() {
const { stroke, fill } = this.get('styleOptions');
if (this.shapeType === 'text') { // 绘制文本图层
this._textPoint();
return;
}
const source = this.layerSource;
const { opacity, strokeWidth, stroke, shape } = this.get('styleOptions');
this._buffer = new PointBuffer({
type: this.shapeType,
imagePos: this.scene.image.imagePos,
coordinates: source.geoData,
properties: this.StyleData
});
const geometry = this.geometry = new THREE.BufferGeometry();
let mtl;
if (this.shapeType === '2d' || this.shapeType === '3d') {
mtl = new PolygonMaterial({
u_opacity: opacity,
u_zoom: this.scene.getZoom()
});
// mtl= new pickingMaterial({
// u_opacity: opacity,
// u_zoom: this.scene.getZoom()
// })
// mtl.setDefinesvalue('point', true);
mtl.setDefinesvalue('SHAPE', true);
if (shape === 'radar') {
mtl.fragmentShader = radar;
const style = this.get('styleOptions');
const pointShapeType = this._getShape();
}
if (shape === 'warn') {
mtl.fragmentShader = warn;
}
} else { // sdf 绘制点
mtl = new PointMaterial({
u_opacity: opacity,
u_strokeWidth: strokeWidth,
u_stroke: stroke,
shape: this.shapeType || false,
u_texture: this.scene.image.texture
}, {
SHAPE: (this.shapeType !== 'image'),
TEXCOORD_0: (this.shapeType === 'image')
});
switch (pointShapeType) {
case 'fill' :// 填充图形
{
if (fill !== 'none') { // 是否填充
const attributes = PointBuffer.FillBuffer(source.geoData, this.StyleData, 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 meshStroke = drawPoint.DrawStroke(lineAttribute, this.get('styleOptions'));
this.add(meshStroke, 'line');
}
break;
}
case 'image':// 绘制图片标注
{
const imageAttribute = PointBuffer.ImageBuffer(source.geoData, this.StyleData, { 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 normalPointMesh = drawPoint.DrawNormal(normalAttribute, style);
this.add(normalPointMesh);
break;
}
default:
return null;
}
}
const { attributes } = this._buffer;
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
if (this.shapeType === 'image') {
geometry.addAttribute('uv', new THREE.Float32BufferAttribute(attributes.uvs, 2));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
} else if (this.shapeType === undefined) {
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
} else { // 多边形面
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(attributes.shapePositions, 3));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3));
if (shape) {
geometry.addAttribute('faceUv', new THREE.Float32BufferAttribute(attributes.faceUv, 2));
_getShape() {
let shape = null;
if (!this.StyleData[0].hasOwnProperty('shape')) {
return 'normal';
}
for (let i = 0; i < this.StyleData.length; i++) {
shape = this.StyleData[i].shape;
if (shape !== undefined) {
break;
}
}
let mesh;
if (this.shapeType === 'image') {
mesh = new THREE.Points(geometry, mtl);
} else if (this.shapeType === undefined) { // 散点图
mesh = new THREE.Points(geometry, mtl);
} else {
mesh = new THREE.Mesh(geometry, mtl);
if (pointShape['2d'].indexOf(shape) !== -1 || pointShape['3d'].indexOf(shape) !== -1) {
return 'fill';
} else if (shape === 'text') {
return 'text';
} else if (this.scene.image.imagesIds.indexOf(shape) !== -1) {
return 'image';
}
return 'normal';
this.add(mesh);
}
_textPoint() {
const source = this.layerSource;
@ -132,11 +119,11 @@ export default class PointLayer extends Layer {
const material = new TextMaterial({
name: this.layerId,
u_texture: buffer.bufferStruct.textTexture,
u_strokeWidth: 1,
u_strokeWidth: styleOptions.strokeWidth,
u_stroke: stroke,
u_textSize: buffer.bufferStruct.textSize,
u_gamma: 0.11,
u_buffer: 0.8,
u_gamma: 2 * 1.4142 / 64,
u_buffer: 0.65,
u_color: color,
u_glSize: [ width, height ]
});

View File

@ -1,8 +1,6 @@
import * as THREE from '../core/three';
import Layer from '../core/layer';
import * as drawPolygon from './render/polygon';
import PolygonBuffer from '../geom/buffer/polygon';
import PolygonMaterial from '../geom/material/polygonMaterial';
import { LineMaterial } from '../geom/material/lineMaterial';
export default class PolygonLayer extends Layer {
shape(type) {
this.shape = type;
@ -15,80 +13,38 @@ export default class PolygonLayer extends Layer {
} else {
this._initAttrs();
(this._needUpdateFilter || this._needUpdateColor) ? this._updateFilter() : null;
const { opacity, baseColor, brightColor, windowColor } = this.get('styleOptions');
this.layerMesh.material.upDateUninform({
u_opacity: opacity,
u_baseColor: baseColor,
u_brightColor: brightColor,
u_windowColor: windowColor
});
(this._needUpdateFilter || this._needUpdateColor) ? this._updateFilter(this.layerMesh) : null;
// TODO update Style;
}
return this;
}
_prepareRender() {
this.init();
this.type = 'polygon';
const source = this.layerSource;
this._buffer = new PolygonBuffer({
shape: this.shape,
coordinates: source.geoData,
properties: this.StyleData
});
const { attributes } = this._buffer;
this.geometry = new THREE.BufferGeometry();
this.geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
this.geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
this.geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
if (this.shape === 'line') {
this._renderLine();
} else {
this._renderPolygon();
}
this.add(this._getLayerRender());
}
_renderLine() {
const { opacity } = this.get('styleOptions');
const lineMaterial = new LineMaterial({
u_opacity: opacity
});
const polygonLine = new THREE.LineSegments(this.geometry, lineMaterial);
this.add(polygonLine);
}
_renderPolygon() {
const animateOptions = this.get('animateOptions');
const { opacity, baseColor, brightColor, windowColor } = this.get('styleOptions');
const camera = this.map.getCameraState();
const material = new PolygonMaterial({
u_opacity: opacity,
u_baseColor: baseColor,
u_brightColor: brightColor,
u_windowColor: windowColor,
u_near: camera.near,
u_far: camera.far
});
const { attributes } = this._buffer;
this.geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
if (animateOptions.enable) {
material.setDefinesvalue('ANIMATE', true);
this.geometry.addAttribute('faceUv', new THREE.Float32BufferAttribute(attributes.faceUv, 2));
this.geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
}
// const pickmaterial = new PickingMaterial();
const polygonMesh = new THREE.Mesh(this.geometry, material);
this.add(polygonMesh);
}
update() {
this.updateFilter(this.StyleData);
this.updateFilter(this.layerMesh);
// 动态更新相关属性
}
_getLayerRender() {
const animateOptions = this.get('animateOptions');
const { attributes } = this._buffer;
const style = this.get('styleOptions');
if (this.shape === 'line') {
return drawPolygon.DrawLine(attributes, style);
} else if (animateOptions.enable) {
const { near, far } = this.map.getCameraState();
return drawPolygon.DrawAnimate(attributes, { ...style, near, far });
}
return drawPolygon.DrawFill(attributes, style);
}
}

View File

@ -0,0 +1,19 @@
import * as THREE from '../../../core/three';
import { ArcLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawArcLine(attributes, style) {
const { opacity, zoom } = style;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('a_instance', new THREE.Float32BufferAttribute(attributes.instances, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const lineMaterial = new ArcLineMaterial({
u_opacity: opacity,
u_zoom: zoom
}, {
SHAPE: false
});
const arcMesh = new THREE.Mesh(geometry, lineMaterial);
return arcMesh;
}

View File

View File

@ -0,0 +1,27 @@
import * as THREE from '../../../core/three';
import { MeshLineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawLine(attributes, style) {
const { opacity, zoom, animate, duration, interval, trailLength } = style;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('a_distance', new THREE.Float32BufferAttribute(attributes.attrDistance, 1));
const lineMaterial = new MeshLineMaterial({
u_opacity: opacity,
u_zoom: zoom,
u_duration: duration,
u_interval: interval,
u_trailLength: trailLength,
u_time: 0
}, {
SHAPE: false,
ANIMATE: animate
});
const arcMesh = new THREE.Mesh(geometry, lineMaterial);
return arcMesh;
}

View File

@ -0,0 +1,29 @@
/**
* @author lzxue
* @email lzx199065@gmail.com
* @create date 2018-11-29 16:07:24
* @modify date 2018-11-29 16:07:24
* @desc [description] 绘制点图层的面状填充三角形六边形
*/
import * as THREE from '../../../core/three';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
export default function DrawFill(attributes, style) {
const { opacity } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(attributes.shapePositions, 3));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.a_size, 3));
const material = new PolygonMaterial({
u_opacity: opacity
}, {
SHAPE: true
});
material.setDefinesvalue('SHAPE', true);
material.depthTest = false;
const fillMesh = new THREE.Mesh(geometry, material);
return fillMesh;
}

View File

@ -0,0 +1,24 @@
import * as THREE from '../../../core/three';
import PointMaterial from '../../../geom/material/pointMaterial';
export default function DrawImage(attributes, style) {
const geometry = new THREE.BufferGeometry();
const { strokeWidth, stroke, opacity, texture } = style;
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('uv', new THREE.Float32BufferAttribute(attributes.uv, 2));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const material = new PointMaterial({
u_opacity: opacity,
u_strokeWidth: strokeWidth,
u_stroke: stroke,
u_texture: texture
}, {
SHAPE: false,
TEXCOORD_0: true
});
material.depthTest = false;
const strokeMesh = new THREE.Points(geometry, material);
return strokeMesh;
}

View File

@ -0,0 +1,21 @@
/**
* 原生点绘制
*/
import * as THREE from '../../../core/three';
import PointMaterial from '../../../geom/material/pointMaterial';
export default function DrawNormal(attributes, style) {
const geometry = new THREE.BufferGeometry();
const { opacity } = style;
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const material = new PointMaterial({
u_opacity: opacity
}, {
SHAPE: false,
TEXCOORD_0: false
});
const strokeMesh = new THREE.Points(geometry, material);
return strokeMesh;
}

View File

@ -0,0 +1,29 @@
/**
* @author lzxue
* @email lzx199065@gmail.com
* @create date 2018-11-29 16:35:34
* @modify date 2018-11-29 16:35:34
* @desc [description] 绘制图形的边框
*/
import PointLineMaterial from '../../../geom/material/pointLineMaterial';
import * as THREE from '../../../core/three';
export default function DrawStroke(attributes, style) {
const { strokeWidth, stroke, strokeOpacity } = style;
const geometry = new THREE.BufferGeometry();
geometry.setIndex(attributes.indexArray);
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.positions, 3));
geometry.addAttribute('a_shape', new THREE.Float32BufferAttribute(attributes.shapes, 3));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 3));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normal, 3));
geometry.addAttribute('a_miter', new THREE.Float32BufferAttribute(attributes.miter, 1));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
const material = new PointLineMaterial({
u_strokeOpacity: strokeOpacity,
u_stroke: stroke,
u_strokeWidth: strokeWidth
});
const strokeMesh = new THREE.Mesh(geometry, material);
return strokeMesh;
}

View File

@ -0,0 +1,23 @@
// import * as THREE from '../../../core/three';
// import TextMaterial from '../../../geom/material/textMaterial';
// export default function DawText(attributes, texture, style) {
// const geometry = new THREE.BufferGeometry();
// const { strokeWidth, stroke, opacity } = style;
// geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.originPoints, 3));
// geometry.addAttribute('uv', new THREE.Float32BufferAttribute(attributes.textureElements, 2));
// geometry.addAttribute('a_txtsize', new THREE.Float32BufferAttribute(attributes.textSizes, 2));
// geometry.addAttribute('a_txtOffsets', new THREE.Float32BufferAttribute(attributes.textOffsets, 2));
// geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
// const material = new TextMaterial({
// name: this.layerId,
// u_texture: texture,
// u_strokeWidth: 1,
// u_stroke: stroke,
// u_textSize: buffer.bufferStruct.textSize,
// u_gamma: 0.11,
// u_buffer: 0.8,
// u_color: color,
// u_glSize: [ width, height ]
// });
// const mesh = new THREE.Mesh(geometry, material);
// }

View File

@ -0,0 +1,4 @@
export { default as DrawFill } from './drawFill';
export { default as DrawImage } from './drawImage';
export { default as DrawStroke } from './drawStroke';
export { default as DrawNormal } from './drawNormal';

View File

@ -0,0 +1,35 @@
import * as THREE from '../../../core/three';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
export default function DrawAnimate(attributes, style) {
const { opacity, baseColor, brightColor, windowColor, near, far } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
geometry.addAttribute('faceUv', new THREE.Float32BufferAttribute(attributes.faceUv, 2));
geometry.addAttribute('a_size', new THREE.Float32BufferAttribute(attributes.sizes, 1));
const material = new PolygonMaterial({
u_opacity: opacity,
u_baseColor: baseColor,
u_brightColor: brightColor,
u_windowColor: windowColor,
u_near: near,
u_far: far
}, {
SHAPE: false,
ANIMATE: true
});
const fillPolygonMesh = new THREE.Mesh(geometry, material);
this.fillPolygonMesh = fillPolygonMesh;
return fillPolygonMesh;
}
DrawAnimate.prototype.updateStyle = function(style) {
this.fillPolygonMesh.material.upDateUninform({
u_opacity: style.opacity,
u_baseColor: style.baseColor,
u_brightColor: style.brightColor,
u_windowColor: style.windowColor
});
};

View File

@ -0,0 +1,18 @@
import * as THREE from '../../../core/three';
import PolygonMaterial from '../../../geom/material/polygonMaterial';
export default function DrawPolygonFill(attributes, style) {
const { opacity } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
geometry.addAttribute('normal', new THREE.Float32BufferAttribute(attributes.normals, 3));
const material = new PolygonMaterial({
u_opacity: opacity
}, {
SHAPE: false
});
const fillPolygonMesh = new THREE.Mesh(geometry, material);
return fillPolygonMesh;
}

View File

@ -0,0 +1,16 @@
import * as THREE from '../../../core/three';
import { LineMaterial } from '../../../geom/material/lineMaterial';
export default function DrawPolygonLine(attributes, style) {
const { opacity } = style;
const geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.Float32BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('a_color', new THREE.Float32BufferAttribute(attributes.colors, 4));
geometry.addAttribute('pickingId', new THREE.Float32BufferAttribute(attributes.pickingIds, 1));
const lineMaterial = new LineMaterial({
u_opacity: opacity
}, {
SHAPE: false
});
const polygonLineMesh = new THREE.LineSegments(geometry, lineMaterial);
return polygonLineMesh;
}

View File

@ -0,0 +1,3 @@
export { default as DrawAnimate } from './drawAnimate';
export { default as DrawFill } from './drawFill';
export { default as DrawLine } from './drawLine';

View File

@ -23,6 +23,7 @@ export class MapProvider extends Base {
initMap() {
const mapStyle = this.get('mapStyle');
switch (mapStyle) {
case 'dark' :
this.set('mapStyle', Theme.DarkTheme.mapStyle);
@ -31,7 +32,7 @@ export class MapProvider extends Base {
this.set('mapStyle', Theme.LightTheme.mapStyle);
break;
default:
this.set('mapStyle', Theme.LightTheme.mapStyle);
this.set('mapStyle', mapStyle);
}
this.set('zooms', [ this.get('minZoom'), this.get('maxZoom') ]);
this.map = new AMap.Map(this.container, this._attrs);

View File

@ -1,6 +1,5 @@
import Source from '../core/source';
import FeatureIndex from '../geo/featureIndex';
import Util from '../util';
import { csvParse } from 'd3-dsv';
export default class CSVSource extends Source {
prepareData() {
@ -14,15 +13,15 @@ export default class CSVSource extends Source {
this.propertiesData = [];// 临时使用
this.geoData = [];
let csvdata = data;
Util.isArray(csvdata) || (csvdata = csvParse(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) {
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; }
@ -39,6 +38,10 @@ export default class CSVSource extends Source {
getSelectFeatureId(featureId) {
return [ featureId ];
}
getSelectFeature(featureId) {
return this.propertiesData[featureId];
}
_getCoord(geo) {
if (geo.geometry) {
// GeoJSON feature

View File

@ -37,5 +37,9 @@ export default class GeojsonSource extends Source {
return selectFeatureIds;
}
getSelectFeature(featureId){
const data = this.get('data');
return data.features[featureId];
}
}

22
src/track.js Normal file
View File

@ -0,0 +1,22 @@
/**
* @fileOverview track g2
* @author dxq613@gmail.com
*/
const Global = require('./global');
const SERVER_URL = 'https://kcart.alipay.com/web/bi.do';
// 延迟发送请求
setTimeout(function() {
if (Global.trackable) {
const image = new Image();
const newObj = {
pg: document.URL,
r: new Date().getTime(),
l7: true,
version: Global.version,
page_type: 'syslog'
};
const d = encodeURIComponent(JSON.stringify([ newObj ]));
image.src = `${SERVER_URL}?BIProfile=merge&d=${d}`;
}
}, 3000);

View File

@ -1,22 +1,2 @@
import { getJSON } from '../util/ajax';
import { GeojsonSource } from '../source/geojsonSource';
const EventEmitter = require('wolfy87-eventemitter');
export class geoJsonSourceWorker extends EventEmitter {
constructor(cfg) {
super();
this.source = new GeojsonSource(cfg);
}
_loadData(url) {
const data = this.source.get('data');
if (typeof (data) === 'string') {
this.emit('dataLoading');
getJSON(url, data => {
this.emit('dataLoaded', { data });
});
}
}
}

View File

@ -1,13 +1,4 @@
const extrude = require('geometry-extrude');
// import { geoJsonSourceWorker } from './geojsonSourceWorker';
/**
* workerOption
* {
* type:
* data:
*
* }
*/
self.addEventListener('message', e => {
const res = e.data;
// res = {
@ -17,12 +8,8 @@ self.addEventListener('message', e => {
let result;
switch (res.command) {
case 'geojson':
result = extrude.extrudeGeoJSON(res.data.data, res.data.options).polygon;
self.postMessage(result, [ result.indices.buffer, result.normal.buffer, result.position.buffer, result.uv.buffer ]);
break;
case 'POLYLINE-EXTRUDE':
result = extrude.extrudeGeoJSON(res.data.data, res.data.options).polyline;
self.postMessage(result, [ result.indices.buffer, result.normal.buffer, result.position.buffer, result.uv.buffer ]);
result = res;
self.postMessage(result);
break;
default:
self.postMessage(result);

View File

@ -4,7 +4,7 @@ const pkg = require('./package.json');
module.exports = {
devtool: 'cheap-source-map',
entry: {
L7: './src/index.js'
l7: './src/index.js'
},
output: {
filename: '[name].js',
@ -30,6 +30,16 @@ module.exports = {
loader: 'glsl-shaders-loader'
}
},
{
test: /\.worker\.js$/,
use: {
loader: 'worker-loader',
options: {
inline: true,
fallback: false
}
}
},
{
test: /global\.js$/,
use: {