/*``
* @Author: tjc
* @Date: 2017-04-20 17:03:05
* @Last Modified by: hydata
* @Last Modified time: 2018-05-10 17:12:02
* @Email: 304861063@qq.com
* @File Path: F:\work\hyMap\src\components\layer\buildingLayer.js
* @File Name: clustersLayer.js
* @Descript:雷达图,利用three进行绘制
*/
import * as THREE from 'three';
import mapboxgl from 'mapbox-gl';
import baseLayer from './baseLayer';
/**
* 雷达层
* @extends baseLayer
*/
class RadarLayer extends baseLayer {
/**
* 初始化
* @param {*} options
*/
constructor(options) {
super(options);
this.options = options;
this.threebox = options.threebox;
this.play = false;
this.init();
}
/**
* 添加雷达图
*/
init() {
if (!this.play) {
this.addRadarToMap(this.options);
this.play = true;
}
}
/**
* 添加雷达图
* @param center 中心点坐标
* @param radius 半径
* @param color 渲染颜色
*/
addRadarToMap({center, radius, color} = {}) {
this.radius = radius;
radius = radius * 1000;
// //创建组
// this.group = new THREE.Group();
//创建圆形区域并添加至地图
let circleGeometry = new THREE.CircleBufferGeometry(radius, 72);
circleGeometry.addAttribute('position', circleGeometry.attributes.position);
let cMat = this.createCircleMaterial({
color: color,
radius: radius
});
this.circleMesh = new THREE.Mesh(circleGeometry, cMat);
this.threebox.addAtCoordinate(this.circleMesh, center, {
scaleToLatitude: true,
preScale: 1
});
//创建扇形区域并添加至地图
let sectorGeometry = new THREE.CircleBufferGeometry(radius, 72, 2 * Math.PI / 3, Math.PI / 3);
sectorGeometry.addAttribute('position', sectorGeometry.attributes.position);
let sMat = this.createSectorMaterial({
color: color,
radius: radius
});
this.sectorMesh = new THREE.Mesh(sectorGeometry, sMat);
this.threebox.addAtCoordinate(this.sectorMesh, [center[0], center[1], 5], {
scaleToLatitude: true,
preScale: 1
});
//循环转动扇形
const run = () => {
this.sectorMesh.rotateZ(-Math.PI / 60);
this.threebox.update();
this.animation = window.requestAnimationFrame(run);
};
run();
// this.addSliderSymbol(raderAttr);
}
/**
* 生成圆形材质
* @param opt
* @returns {RawShaderMaterial}
*/
createCircleMaterial = opt => {
opt = opt || {};
let ret = {
uniforms: {
color: {type: 'c', value: new THREE.Color(opt.color !== null ? opt.color : '#ff0000')},
radius: {type: 'f', value: (typeof opt.radius === 'number' ? opt.radius : 3000.000)}
},
vertexShader: [
'precision mediump float;',
'precision mediump int;',
'uniform mat4 modelViewMatrix;',
'uniform mat4 projectionMatrix;',
'attribute vec3 position;',
'varying vec3 vPosition;',
'void main() {',
//'vPosition = position.xyz + vec3(1000, 0,0);',
'vPosition = position;',
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
'}'
].join('\n'),
fragmentShader: [
'precision mediump float;',
'precision mediump int;',
'uniform vec3 color;',
'uniform float radius;',
'varying vec3 vPosition;',
'void main(){',
'vec4 vcolor = vec4( color,1);',
'float opacity=sqrt(vPosition.x*vPosition.x+vPosition.y*vPosition.y)/radius/1.5;',//透明度沿半径方向衰减
'vcolor.a = opacity*opacity*opacity ;',
'gl_FragColor = vcolor;',
'}'
].join('\n'),
transparent: true,
side: THREE.DoubleSide
};
return new THREE.RawShaderMaterial(ret);
};
/**
* 生成扇形材质
* @param opt
* @returns {RawShaderMaterial}
*/
createSectorMaterial = opt => {
opt = opt || {};
let ret = {
uniforms: {
color: {type: 'c', value: new THREE.Color(opt.color !== null ? opt.color : '#ff0000')},
radius: {type: 'f', value: (typeof opt.radius === 'number' ? parseFloat(opt.radius) : 3000.000)}
},
vertexShader: [
'precision mediump float;',
'precision mediump int;',
'uniform mat4 modelViewMatrix;',
'uniform mat4 projectionMatrix;',
'attribute vec3 position;',
'varying vec3 vPosition;',
'void main() {',
'vPosition = position;',
'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
'}'
].join('\n'),
fragmentShader: [
'precision mediump float;',
'precision mediump int;',
'uniform vec3 color;',
'uniform float radius;',
'varying vec3 vPosition;',
'void main(){',
'vec4 vcolor = vec4( color,1);',
'float angel=atan(abs(vPosition.y)/(2.00000*radius-abs(vPosition.x)));',
'float opacity= angel/(3.1415/4.00000);',//透明度随角度递增而增加
'vcolor.a =opacity ;',
'gl_FragColor = vcolor;',
'}'
].join('\n'),
transparent: true,
side: THREE.DoubleSide
};
return new THREE.RawShaderMaterial(ret);
};
/**
* 改变雷达半径
* @param position
* @param newRadius
*/
setRadarOptions(position, newRadius) {
this.threebox.moveToCoordinate(this.circleMesh, position, {
preScale: newRadius / this.radius
});
let sectorCoordinate = [position[0], position[1], 5];
this.threebox.moveToCoordinate(this.sectorMesh, sectorCoordinate,
{
preScale: newRadius / this.radius
});
}
/**
*@在雷达图上添加滑动和关闭按钮
*@author lc
*@date 2018-04-13 10:28:58
*/
addSliderSymbol({position, radius} = {}) {
//图标信息
let marker =
{
'properties': {
'message': 'Foo',
'iconSize': [50, 80]
},
'geometry': {
'type': 'Point',
'coordinates': position
}
};
//获取图标容器
let el = document.createElement('mapbox-gl-slider');
el.style.width = marker.properties.iconSize[0] + 'px';
el.style.height = marker.properties.iconSize[1] + 'px';
el.style.fontSize = 18 + 'px';
el.style.color = '#ffffff';
//显示雷达半径
let html = '';
html += '<div style="width:100%;height:30%;">' + radius + 'm</div>';
el.innerHTML = html;
//对图标添加拖拽监听,放大缩小雷达
el.addEventListener('mousedown', (event) => {
let mouseMove = true;
let distance = radius;
event.stopPropagation();
this.map.on('mousemove', (ev) => {
if (mouseMove) {
distance = 6378137 * 2 * Math.PI * Math.cos(position[1] / 180 * Math.PI) * (ev.lngLat.lng - position[0]) / 360;
if (distance > radius[0] && distance < radius[1]) {
//设置图标位置
slider.setLngLat([ev.lngLat.lng, position[1]]);
//更新显示雷达半径
html = '';
if (distance > 3000) {
html += '<div>' + (distance / 1000).toFixed(2) + 'km</div>';
}
else {
html += '<div>' + distance.toFixed(0) + 'm</div>';
}
el.innerHTML = html;
//缩放雷达覆盖范围
// this.threebox.moveToCoordinate(this.circleGroup, position, {preScale: distance / radius});
// let sectorCoordinate = [position[0], position[1], 5];
// this.threebox.moveToCoordinate(this.sectorMesh, sectorCoordinate, {preScale: distance / radius});
}
}
});
/* el.onmouseup = () => {
updateMarkerLayer(doQuerys(raderAttr.position, distance / 1000, this.layerGeojson), "testPolice");
mouseMove = false;
};*/
this.map.on('mouseup', () => {
mouseMove = false;
});
});
// 将图标放置至地图上
let markerPosition = [marker.geometry.coordinates[0] + radius / (111000 * Math.cos(marker.geometry.coordinates[1] / 180 * Math.PI)), marker.geometry.coordinates[1]];
let slider = new mapboxgl.Marker(el)
.setLngLat(markerPosition)
.addTo(this.map);
}
/**
* 清空
*/
clear() {
cancelAnimationFrame(this.animation);
this.threebox.remove(this.circleMesh.parent);
this.threebox.remove(this.sectorMesh.parent);
this.threebox.update();
this.play = false;
}
/**
* 显示雷达层
*/
showRadarLayer() {
this.init(this.options);
}
}
export default RadarLayer;