mirror of https://gitee.com/antv-l7/antv-l7
fix(meshline):修复动画流动方向颠倒的问题
This commit is contained in:
parent
bb342b5094
commit
c968530976
|
@ -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);
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -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)];
|
||||
})
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -86,6 +86,7 @@ scene.on('loaded', () => {
|
|||
opacity: 1
|
||||
})
|
||||
.render();
|
||||
/**
|
||||
const citylayer2 = scene.PolygonLayer()
|
||||
.source(city)
|
||||
.shape('line')
|
||||
|
@ -93,7 +94,8 @@ scene.on('loaded', () => {
|
|||
.style({
|
||||
opacity: 0.1
|
||||
})
|
||||
.render();
|
||||
// .render();
|
||||
**/
|
||||
|
||||
citylayer.on('click',(e)=>{
|
||||
$("#info").css({'left': e.pixel.x,'top':e.pixel.y, display:'block'});
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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>`);
|
||||
})
|
||||
**/
|
||||
});
|
||||
});
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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>
|
||||
|
|
@ -41,7 +41,7 @@ scene.on('loaded', () => {
|
|||
.animate({enable:true})
|
||||
.render();
|
||||
});
|
||||
$.get('./data/2.geojson', data => {
|
||||
$.get('https://gw.alipayobjects.com/os/rmsportal/vmvAxgsEwbpoSWbSYvix.json', data => {
|
||||
buildLayer = scene.PolygonLayer({
|
||||
zIndex: 2
|
||||
})
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -48,12 +48,12 @@ class Picking {
|
|||
// 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() {
|
||||
|
@ -76,10 +76,10 @@ class Picking {
|
|||
_update(point) {
|
||||
|
||||
const texture = this._pickingTexture;
|
||||
if (this._needUpdate) {
|
||||
// if (this._needUpdate) {
|
||||
this._renderer.render(this._pickingScene, this._camera, this._pickingTexture);
|
||||
this._needUpdate = false;
|
||||
}
|
||||
// this._needUpdate = false;
|
||||
// }
|
||||
this.pixelBuffer = new Uint8Array(4);
|
||||
this._renderer.readRenderTargetPixels(texture, point.x, this._height - point.y, 1, 1, this.pixelBuffer);
|
||||
|
||||
|
@ -99,17 +99,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 +134,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 +146,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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -36,9 +36,10 @@ 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
|
||||
},
|
||||
// 选中时的配置项
|
||||
|
@ -63,31 +64,35 @@ export default class Layer extends Base {
|
|||
this._activeIds = null;
|
||||
scene._engine._scene.add(this._object3D);
|
||||
this.layerMesh = null;
|
||||
this.layerLineMesh = null;
|
||||
|
||||
}
|
||||
/**
|
||||
* 将图层添加加到 Object
|
||||
* @param {*} object three 物体
|
||||
* @param {*} type mesh类型是区别是填充还是边线
|
||||
*/
|
||||
add(object) {
|
||||
this.layerMesh = object;
|
||||
add(object, type = 'fill') {
|
||||
type === 'fill' ? this.layerMesh = object : this.layerLineMesh = object;
|
||||
|
||||
this._visibleWithZoom();
|
||||
this.scene.on('zoomchange', () => {
|
||||
this._visibleWithZoom();
|
||||
});
|
||||
|
||||
this.layerMesh.onBeforeRender = () => {
|
||||
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);
|
||||
|
@ -131,7 +136,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 +176,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 +257,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('active', activeHander);
|
||||
this.on('mouseleave', resetHander);
|
||||
|
||||
} else {
|
||||
this.scene.off('pick', activeHander);
|
||||
this.off('active', 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);
|
||||
|
@ -434,6 +443,7 @@ export default class Layer extends Base {
|
|||
}
|
||||
_addPickMesh(mesh) {
|
||||
this._pickingMesh = new THREE.Object3D();
|
||||
this._pickingMesh.name = this.layerId;
|
||||
this._visibleWithZoom();
|
||||
this.scene.on('zoomchange', () => {
|
||||
this._visibleWithZoom();
|
||||
|
@ -445,6 +455,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();
|
||||
|
@ -457,20 +468,40 @@ export default class Layer extends Base {
|
|||
}
|
||||
_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];
|
||||
this.scene.on('pick-' + this.layerId, e => {
|
||||
const { featureId, point2d,type} = e;
|
||||
|
||||
if (featureId < -100 && this._activeIds !== null) {
|
||||
this.emit('mouseleave');
|
||||
return;
|
||||
}
|
||||
// if (intersects.length === 0) { 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 }
|
||||
};
|
||||
if(featureId>=0) {
|
||||
|
||||
switch(type) {
|
||||
case 'mouseup':
|
||||
this.emit('click', target);
|
||||
// this.emit('move', target);
|
||||
break;
|
||||
case 'mousemove':
|
||||
this.emit('mousemove', target);
|
||||
this.emit('active', target);
|
||||
break;
|
||||
default:
|
||||
//this.emit('click', target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
@ -480,7 +511,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;
|
||||
|
@ -508,14 +539,14 @@ 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 +557,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 +568,8 @@ export default class Layer extends Base {
|
|||
});
|
||||
colorAttr.needsUpdate = true;
|
||||
pickAttr.needsUpdate = true;
|
||||
this._needUpdateFilter = false;
|
||||
this._needUpdateColor = false;
|
||||
// this._needUpdateFilter = false;
|
||||
// this._needUpdateColor = false;
|
||||
}
|
||||
_visibleWithZoom() {
|
||||
const zoom = this.scene.getZoom();
|
||||
|
@ -561,7 +592,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,6 +609,7 @@ export default class Layer extends Base {
|
|||
}
|
||||
});
|
||||
colorAttr.needsUpdate = true;
|
||||
this._activeIds = null;
|
||||
}
|
||||
/**
|
||||
* 销毁Layer对象
|
||||
|
@ -609,5 +642,8 @@ export default class Layer extends Base {
|
|||
this._object3D = null;
|
||||
this.scene = null;
|
||||
}
|
||||
_preRender(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Engine from './engine';
|
||||
import * as THREE from './three';
|
||||
import * as layers from '../layer';
|
||||
import Base from './base';
|
||||
import LoadImage from './image';
|
||||
|
@ -19,6 +18,7 @@ export default class Scene extends Base {
|
|||
}
|
||||
|
||||
_initEngine(mapContainer) {
|
||||
this._el = mapContainer;
|
||||
this._engine = new Engine(mapContainer, this);
|
||||
this._engine.run();
|
||||
}
|
||||
|
@ -77,16 +77,34 @@ 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._el.addEventListener(event, e => {
|
||||
|
||||
}, false);
|
||||
})
|
||||
}
|
||||
// 代理map事件
|
||||
removeLayer(layer) {
|
||||
const layerIndex = this._layers.indexOf(layer);
|
||||
if (layerIndex > -1) {
|
||||
|
|
|
@ -9,8 +9,8 @@ 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 { 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 +18,15 @@ 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 { 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 { 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 { 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,
|
||||
|
|
|
@ -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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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,7 +68,7 @@ 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';
|
||||
|
@ -67,7 +80,20 @@ 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);
|
||||
// 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 +107,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 ];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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';
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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); // 多边形大小
|
||||
});
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
|
||||
import { getJSON } from '../../../util/ajax';
|
||||
import * as THREE from '../../../core/three';
|
||||
import Global from '../../../global';
|
||||
const Space = 1;
|
||||
export default function TextBuffer(coordinates, properties, style) {
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
@ -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 horiBearingY = metric[3];
|
||||
|
||||
const horiAdvance = metric[4];
|
||||
const posX = metric[5];
|
||||
const posY = metric[6];
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
#ifdef ANIMATE
|
||||
gl_FragColor.a *= vTime;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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 ;
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -13,17 +13,16 @@ void main() {
|
|||
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;
|
||||
|
|
|
@ -14,7 +14,13 @@ 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);
|
||||
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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
}
|
||||
|
|
13
src/index.js
13
src/index.js
|
@ -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
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -33,83 +32,64 @@ export default class PointLayer extends Layer {
|
|||
return this;
|
||||
}
|
||||
_prepareRender() {
|
||||
const { opacity, strokeWidth, stroke, strokeOpacity, shape, 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();
|
||||
|
||||
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 (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')
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
if (stroke !== 'none') { // 是否绘制边界
|
||||
const lineAttribute = PointBuffer.StrokeBuffer(source.geoData, this.StyleData, style);
|
||||
const meshStroke = drawPoint.DrawStroke(lineAttribute, this.get('styleOptions'));
|
||||
this.add(meshStroke, 'line');
|
||||
}
|
||||
}
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
this.add(mesh);
|
||||
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';
|
||||
|
||||
|
||||
}
|
||||
_textPoint() {
|
||||
const source = this.layerSource;
|
||||
|
@ -133,11 +113,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 ]
|
||||
});
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* @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);
|
||||
const fillMesh = new THREE.Mesh(geometry, material);
|
||||
return fillMesh;
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
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
|
||||
});
|
||||
const strokeMesh = new THREE.Points(geometry, material);
|
||||
return strokeMesh;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import * as THREE from '../../../core/three';
|
||||
import TextMaterial from '../../../geom/material/textMaterial';
|
||||
export default function DawText(attributes, 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: buffer.bufferStruct.textTexture,
|
||||
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);
|
||||
}
|
|
@ -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';
|
|
@ -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);
|
||||
|
|
|
@ -39,6 +39,10 @@ export default class CSVSource extends Source {
|
|||
getSelectFeatureId(featureId) {
|
||||
return [ featureId ];
|
||||
}
|
||||
getSelectFeature(featureId) {
|
||||
return this.propertiesData[featureId];
|
||||
|
||||
}
|
||||
_getCoord(geo) {
|
||||
if (geo.geometry) {
|
||||
// GeoJSON feature
|
||||
|
|
|
@ -39,5 +39,9 @@ export default class GeojsonSource extends Source {
|
|||
return selectFeatureIds;
|
||||
|
||||
}
|
||||
getSelectFeature(featureId){
|
||||
const data = this.get('data');
|
||||
return data.features[featureId];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue