可以动态监控某个数据的变化,并实时显示到模型当中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sprite 粒子(精灵)创建文字</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 溢出隐藏 */
}
</style>
<!-- <script src="../../libs/build/three-r93.js"></script>
<script src="../../libs/examples/js/Detector.js"></script>
<script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
<script src="../../libs/examples/js/libs/stats.min.js"></script>
<script src="../../libs/examples/js/controls/OrbitControls.js"></script> -->
<script src="../js/three.js"></script>
<script src="../js/controls/OrbitControls.js"></script>
<script src="../js/stats.js"></script>
<script src=""></script>
<script src=""></script>
</head>
<body>
<script>
var num = 1;
var scene, camera, renderer, controls, points;
var stats = initStats();
/* 场景 */
function initScene() {
scene = new THREE.Scene();
var axes = new THREE.AxisHelper(15);
scene.add(axes)
}
/* 相机 */
function initCamera() {
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(20, 10, 50);
camera.lookAt(new THREE.Vector3(0, 0, 0));
}
/* 渲染器 */
function initRender() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
/* 灯光 */
function initLight() {
}
/* 控制器 */
function initControls() {
controls = new THREE.OrbitControls(camera, renderer.domElement);
/* 属性参数默认 */
}
/* 场景中的内容 */
function initContent() {
var dirX = new THREE.Vector3(1, 0, 0);
var dirY = new THREE.Vector3(0, 1, 0);
var dirZ = new THREE.Vector3(0, 0, 1);
var origin = new THREE.Vector3(0, 0, 0);
var length = 10;
var arrowHelperX = new THREE.ArrowHelper(dirX, origin, length, 0xff0000);
var arrowHelperY = new THREE.ArrowHelper(dirY, origin, length, 0x00ff00);
var arrowHelperZ = new THREE.ArrowHelper(dirZ, origin, length, 0x0000ff);
scene.add(arrowHelperX);
scene.add(arrowHelperY);
scene.add(arrowHelperZ);
/* 原点 */
var spriteOrigin = makeTextSprite(" vector3(0, 0, 0) ",
{
fontsize: 20,
borderColor: { r: 255, g: 0, b: 0, a: 0.4 },/* 边框黑色 */
backgroundColor: { r: 255, g: 255, b: 255, a: 0.9 }/* 背景颜色 */
});
spriteOrigin.center = new THREE.Vector2(0, 0);
scene.add(spriteOrigin);
spriteOrigin.position.set(0, -5, 0);
var spriteY = makeTextSprite(num,
{
fontsize: 20,
borderColor: { r: 255, g: 0, b: 0, a: 0.4 },/* 边框黑色 */
backgroundColor: { r: 255, g: 255, b: 255, a: 0.9 }/* 背景颜色 */
});
spriteY.center = new THREE.Vector2(0, 0);
scene.add(spriteY);
spriteY.position.set(0, 6, 0);
var spriteX = makeTextSprite("10, -5, 0",
{
fontsize: 20,
borderColor: { r: 255, g: 0, b: 0, a: 0.4 },/* 边框黑色 */
backgroundColor: { r: 255, g: 255, b: 255, a: 0.9 }/* 背景颜色 */
});
spriteX.center = new THREE.Vector2(0, 0);
scene.add(spriteX);
spriteX.position.set(10, -5, 0);
var spriteZ = makeTextSprite("0, -5, 10",
{
fontsize: 20,
borderColor: { r: 255, g: 0, b: 0, a: 0.4 },/* 边框黑色 */
backgroundColor: { r: 255, g: 255, b: 255, a: 0.9 }/* 背景颜色 */
});
spriteZ.center = new THREE.Vector2(0, 0);
scene.add(spriteZ);
spriteZ.position.set(0, -5, 10);
}
/* 创建字体精灵 */
function makeTextSprite(message, parameters) {
if (parameters === undefined) parameters = {};
var fontface = parameters.hasOwnProperty("fontface") ?
parameters["fontface"] : "Arial";
/* 字体大小 */
var fontsize = parameters.hasOwnProperty("fontsize") ?
parameters["fontsize"] : 18;
/* 边框厚度 */
var borderThickness = parameters.hasOwnProperty("borderThickness") ?
parameters["borderThickness"] : 4;
/* 边框颜色 */
var borderColor = parameters.hasOwnProperty("borderColor") ?
parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 };
/* 背景颜色 */
var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 };
/* 创建画布 */
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
/* 字体加粗 */
context.font = "Bold " + fontsize + "px " + fontface;
/* 获取文字的大小数据,高度取决于文字的大小 */
var metrics = context.measureText(message);
var textWidth = metrics.width;
/* 背景颜色 */
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
+ backgroundColor.b + "," + backgroundColor.a + ")";
/* 边框的颜色 */
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
+ borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
/* 绘制圆角矩形 */
roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
/* 字体颜色 */
context.fillStyle = "rgba(0, 0, 0, 1.0)";
context.fillText(message, borderThickness, fontsize + borderThickness);
/* 画布内容用于纹理贴图 */
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture });
var sprite = new THREE.Sprite(spriteMaterial);
// console.log(sprite.spriteMaterial);
/* 缩放比例 */
sprite.scale.set(10, 5, 1);
return sprite;
}
/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
/* 性能插件 */
function initStats() {
var stats = new Stats();
document.body.appendChild(stats.domElement);
return stats;
}
/* 窗口变动触发 */
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
/* 数据更新 */
function update() {
stats.update();
}
// 动态数据更新
function upnum() {
setInterval(() => {
num += 1;
console.log(num)
}, 50)
}
/* 初始化 */
function init() {
upnum();
initScene();
initCamera();
initRender();
initLight();
initControls();
initContent();
/* 监听事件 */
window.addEventListener('resize', onWindowResize, false);
}
/* 循环渲染 */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
update();
initContent();
}
/* 初始加载 */
(function () {
console.log("three init start...");
init();
animate();
console.log("three init send...");
})();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02-1:中国城市PM2.5可视化案例-点精灵实现</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="../../js/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="../../js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
var axes = new THREE.AxisHelper(1000);
scene.add(axes)
// 保存产过来的json数据值
var jsonData
/**
* 一个精灵模型对象表示一个城市的位置和数据
*/
// 加载一个背景透明的圆形贴图,矩形精灵显示为圆形效果
var texture = new THREE.TextureLoader().load("sprite2.png");
// 创建组对象,包含所有精灵对象
var group = new THREE.Group();
// 文件加载对象
var loader = new THREE.FileLoader().setResponseType('json');
// 加载PM2.5数据
loader.load('data.json', function (data) {
console.log(data);
jsonData = data
//遍历数据
data.forEach(elem => {
// 精灵材质
var spriteMaterial = new THREE.SpriteMaterial({
map: texture, //设置精灵纹理贴图
transparent: true,
opacity: 0.5,
rotation: Math.PI / 4,
// color: 0x00ff00
});
// 创建精灵模型对象
var sprite = new THREE.Sprite(spriteMaterial);
group.add(sprite);
// 控制精灵大小 使用PM2.5大小设置精灵模型的大小
// 注意适当缩放pm2.5大小,以便得到更好的显示效果
var k = elem.value / 200
sprite.scale.set(k, k, 1);
// sprite.scale.set(elem.value,elem.value, 1);
//获得城市坐标设置精灵模型对象的位置
sprite.position.set(elem.coordinate[0], elem.coordinate[1], 0)
});
// 中国城市坐标整体的几何中心不在坐标原点,需要适当的平移
group.position.set(-110, -30, 0);
scene.add(group);//把精灵群组插入场景中
})
console.log(group.children.length)
// *********坐标点有误差,定位不准确,适用于3维模型的交互*********
// document.addEventListener('mousemove', onDocumentMouseMove, false);
// function onDocumentMouseMove(event) {
// // console.log(event)2
// // 点击屏幕创建一个向量
// var vector = new THREE.Vector3((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5);
// vector = vector.unproject(camera); // 将屏幕的坐标转换成三维场景中的坐标
// // console.log(vector)
// var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
// // console.log(raycaster)
// // 计算射线和参数[meth]中的模型对象是否相交,参数数组中可以设置多个模型模型对象
// var intersects = raycaster.intersectObjects([group], true);
// console.log(intersects)
// if (intersects.length > 0) {// 判断参数[boxMesh]中模型对象是否与射线相交
// document.body.style.cursor = "pointer";
// // intersects.forEach(function (e) {
// // var obj = e.object;
// // // 判断相交的是否是精灵对象并且是对应标签的名称,如果是鼠标变小手
// // if (obj instanceof THREE.Sprite && obj.name.indexOf("shexiangtou") > -1) {
// // document.body.style.cursor = "pointer";
// // }
// // })
// }
// else {
// document.body.style.cursor = "default";
// }
// }
// 适用于通过json得到的sprite精灵绘制的
//点击射线
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
// document.getElementById("container").addEventListener('mousedown', onDocumentMouseDown, false);
document.body.addEventListener('mousemove', onDocumentMouseMove, false);
function onDocumentMouseMove(event){
event.preventDefault();
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects([group], true);
if (intersects.length > 0) {
document.body.style.cursor = "pointer";
}else{
document.body.style.cursor = "default";
}
}
document.body.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
// console.log(event)
event.preventDefault();
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
// 总结一下,这里必须装网格,mesh,装入组是没有效果的
// 所以我们将所有的盒子的网格放入对象就可以了
// 需要被监听的对象要存储在clickObjects中。
// 返回射线选中的对象 第二个参数如果不填 默认是false
var intersects = raycaster.intersectObjects([group], true);
if (intersects.length > 0) {
console.log(intersects)
console.log([intersects[0].point.x, intersects[0].point.y]);
var val = {
lng: intersects[0].point.x,
lat: intersects[0].point.y
}
addSpread(val)
}
}
// 场景添加字体精灵
/* 原点 */
var spriteOrigin
function addSpread(val) {
// console.log(data[0].coordinate[0])
// console.log(val.lng)
// console.log(val.lat)
jsonData.forEach((e) => {
// console.log(e.coordinate[0])
// if(e.coordinate[0] == val.lng ){
// console.log(e)
// }else{
// console.log('找不到')
// }
})
console.log(scene)
// 如果存在上一个字体精灵,先删除后再重新渲染视图
if (spriteOrigin) {
scene.remove(spriteOrigin)
render()
}
spriteOrigin = makeTextSprite(val.lng,
{
fontsize: 20,
borderColor: { r: 255, g: 0, b: 0, a: 0.4 },/* 边框黑色 */
backgroundColor: { r: 255, g: 255, b: 255, a: 0.9 }/* 背景颜色 */
});
spriteOrigin.center = new THREE.Vector2(0, 0);
scene.add(spriteOrigin);
spriteOrigin.position.set(val.lng, val.lat - 3, 0);
}
// 坐标系辅助显示
// var axesHelper = new THREE.AxesHelper(200);
// scene.add(axesHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x888888);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 25; //控制所有sprite的分布范围
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
// camera.position.set(200, 200, 200); //设置相机位置
camera.position.set(0, 0, 200); //数据平面可视化,沿着z轴观察
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
// renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
// if(spriteOrigin){
// scene.remove(spriteOrigin)
// }
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera);
// 禁止旋转操作
controls.enableRotate = true;
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
window.addEventListener('resize', onWindowResize, false);
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
/* 创建字体精灵 */
function makeTextSprite(message, parameters) {
if (parameters === undefined) parameters = {};
var fontface = parameters.hasOwnProperty("fontface") ?
parameters["fontface"] : "Arial";
/* 字体大小 */
var fontsize = parameters.hasOwnProperty("fontsize") ?
parameters["fontsize"] : 18;
/* 边框厚度 */
var borderThickness = parameters.hasOwnProperty("borderThickness") ?
parameters["borderThickness"] : 4;
/* 边框颜色 */
var borderColor = parameters.hasOwnProperty("borderColor") ?
parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 };
/* 背景颜色 */
var backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
parameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 };
/* 创建画布 */
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
/* 字体加粗 */
context.font = "Bold " + fontsize + "px " + fontface;
/* 获取文字的大小数据,高度取决于文字的大小 */
var metrics = context.measureText(message);
var textWidth = metrics.width;
/* 背景颜色 */
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
+ backgroundColor.b + "," + backgroundColor.a + ")";
/* 边框的颜色 */
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
+ borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
/* 绘制圆角矩形 */
roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);
/* 字体颜色 */
context.fillStyle = "rgba(0, 0, 0, 1.0)";
context.fillText(message, borderThickness, fontsize + borderThickness);
/* 画布内容用于纹理贴图 */
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({ map: texture });
var sprite = new THREE.Sprite(spriteMaterial);
// console.log(sprite.spriteMaterial);
/* 缩放比例 */
sprite.scale.set(10, 5, 1);
return sprite;
}
/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>02-2:中国城市PM2.5可视化案例-Points模型实现</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="../../js/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="../../js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 一个精灵模型对象表示一个城市的位置和数据
*/
// 加载一个背景透明的圆形贴图,矩形精灵显示为圆形效果
//var texture = new THREE.TextureLoader().load("sprite.png");
// 文件加载对象
var loader = new THREE.FileLoader().setResponseType('json');
var geometry
// 加载PM2.5数据
loader.load('data.json', function (data) {
//遍历数据
data.forEach(elem => {
geometry = new THREE.Geometry();
let material = new THREE.PointsMaterial({
// map:texture,
color: 0xff00ff,
size: 10
});
// vector3表示一个城市坐标
geometry.vertices.push(new THREE.Vector3(elem.coordinate[0], elem.coordinate[1], 0));
let points = new THREE.Points(geometry, material);
scene.add(points);
// 中国城市坐标整体的几何中心不在坐标原点,需要适当的平移
points.position.set(-110, -30, 0);
});
})
// 坐标系辅助显示
var axesHelper = new THREE.AxesHelper(200);
// scene.add(axesHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x888888);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 25; //控制所有sprite的分布范围
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
// camera.position.set(200, 300, 200); //设置相机位置
camera.position.set(0, 0, 200); //数据平面可视化,沿着z轴观察
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
// renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera);
</script>
</body>
</html>
// 加载PM2.5数据
loader.load('data.json', function(data) {
//遍历数据
data.forEach(elem => {
var material = new THREE.MeshBasicMaterial({
color: 0xffff00,
transparent: true,
opacity: 0.5
});
// material.color.setRGB(elem.value/300,0.4,0.3)
// var geometry = new THREE.CircleGeometry(elem.value / 400, 30)
var geometry = new THREE.CircleGeometry(0.5, 30)
var mesh = new THREE.Mesh(geometry, material)
group.add(mesh);
// 控制精灵大小 使用PM2.5大小设置精灵模型的大小
// 注意适当缩放pm2.5大小,以便得到更好的显示效果
var k = elem.value / 200
mesh.scale.set(k, k, 1);
//获得城市坐标设置精灵模型对象的位置
mesh.position.set(elem.coordinate[0], elem.coordinate[1], 0)
});
// 中国城市坐标整体的几何中心不在坐标原点,需要适当的平移
group.position.set(-110, -30, 0);
scene.add(group); //把精灵群组插入场景中
})
// 加载PM2.5数据
loader.load('data.json', function(data) {
//遍历数据
data.forEach(elem => {
var material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
opacity: 0.5,
})
// 矩形平面几何体
var geometry = new THREE.PlaneGeometry(1, 1)
var mesh = new THREE.Mesh(geometry, material)
group.add(mesh);
// 控制精灵大小 使用PM2.5大小设置精灵模型的大小
// 注意适当缩放pm2.5大小,以便得到更好的显示效果
var k = elem.value / 200
mesh.scale.set(k, k, 1);
//获得城市坐标设置精灵模型对象的位置
mesh.position.set(elem.coordinate[0], elem.coordinate[1], 0)
});
// 中国城市坐标整体的几何中心不在坐标原点,需要适当的平移
group.position.set(-110, -30, 0);
scene.add(group); //把精灵群组插入场景中
})