好看的3D地图搭建出来,一定是要能为开发者所用与业务系统开发中才能真正地体现价值。基因于此,CityBuilder建立了与ThingJS的通道——直转ThingJS代码,支持将配置完成的3D地图一键转为代码,不仅减少开发者的工作量,还能作为非GISer开发者的地图教学工具,使一般开发者也能码出专业、炫酷的3D地图。
上节说到如何使用GeoJSON、QGIS编辑地图数据,使用CItyBuilder搭建一键城市模型,并且转入到ThingJS开发,以免大家遗忘,我将步骤再次贴出来,然后告诉大家如何使用ThingJS的“在线开发”完成建筑的自定义顶牌、环绕飞行、沟边效果。
本教程使用GeoJSON绘制并且编写地图数据,使用QGIS微调,以优锘科技所在区域为地图数据,制作一个小范围的智慧城市模型一共分以下五个步骤:
1. 绘制地图资源:进入GeoJSON绘制优锘科技所在区域地图数据,根据项目所需为每个建筑添加必要的属性(name、height、type、district);
2. 编辑地图数据:将GeoJSON数据下载 ,使用QGIS编辑数据(没有数据偏移可以省略这一步,本次省略使用QGIS,感兴趣的人可以网上搜索如何使用QGIS编辑数据,超简单);
3. 上传地图数据:将处理好的GeoJSON上传至CityBuilder中,在CityBuilder中修改样式;
4. 调整地图样式:CityBuilder中调整好样式之后,保存并且退出CityBuilder编辑器,在CityBuilder页面中选择开发刚刚调整好的项目;
5. 开发相关功能:当完成第四步后,就进入到ThingJS在线开发中,为我们的智慧城市添加功能(视角自动轮巡、自动旋转等);
想知道前四个步骤的具体实现步骤,可以查看我写的《使用CityBuilder搭建智慧城市3D可视化模型之创建三维城市(上)》。
开发相关功能:
通过CityBuilder进入到ThingJS中,会生成相关代码引用我们刚才完成的地图场景,生成的相关代码如下:
var app = new THING.App();
// 设置app背景为黑色
app.background = [0, 0, 0];
// 引用地图组件脚本
THING.Utils.dynamicLoad(["https://www.thingjs.com/uearth/uearth.min.js"], function () {
app.create({
type: "Map",
url: "https://www.thingjs.com/citybuilder_console/mapProject/config/TVRnNE1EUT1DaXR5QnVpbGRlckAyMDE5",
complete: function (event) {
// 我们所有的代码都在complete函数中书写。
console.log(event.object.userLayers.length);
}
});
});
ThingJS在线开发中拥有着完善的官方示例,使用官方示例就能够完成我们的大部分需求,现在我们以图文结合代码的形式为大家讲解使用ThingJS制作的五个功能。
第一个小功能-获取建筑名字:
// aPP是ThingJS的全局对象,对全局对象绑定click事件,当点击到任意建筑,都会触发该事件。
app.on('click', function (ev) {
console.log(ev.object.userData.name) // 输出建筑的名字
}
第二个小功能-建筑自定义顶牌:
建筑自定义顶牌是官方示例中的代码,可以直接复制到你的项目中去,同时可以修改html文件,改成你所需要的顶牌样式。不过要记得调用test_create_ui()这个方法。

// 添加html
function create_html() {
var sign =
`<div class="sign" id="board" style="font-size: 12px;width: 120px;text-align: center;border: 3px solid #eeeeee;border-radius: 8px;color: #eee;position: absolute;top: 0;left: 0;z-index: 10;display: none;">
<div class="s1" style="margin: 5px 0px 5px 0px;line-height: 32px;overflow: hidden;">
<span class="span-l icon" style="float: left;width: 30px;height: 30px;background:url(https://www.thingjs.com/static/images/example/hydrant.png) no-repeat center;margin: 1px 1px 1px 5px;"></span>
<span class="span-l font" style="float: left;margin: 0px 0px 0px 3px;">物体</span>
<span class="span-r point" style="float: right;width: 12px;height: 12px;border-radius: 50%;margin: 10px 5px 10px 0px;"></span>
</div>
<div class="s2" style="margin: 5px 0px 10px 0px;line-height: 18px;font-size: 10px;overflow: hidden;">
<span class="span-l font1" style="float: left;margin: 0px 10px 0px 10px;">数值</span>
<span class="span-l font2" style="float: left;width: 70px;">0.14MPa</span>
</div>
<div class="point-top" style="position: absolute;top: -7px;right: -7px;width: 10px;height: 10px;border: 3px solid #eee;border-radius: 50%;"></div>
</div>`
$('#div3d').append($(sign));
}
create_html();
// 生成一个新面板
function create_element() {
var srcElem = document.getElementById('board');
var newElem = srcElem.cloneNode(true);
newElem.style.display = "block";
app.domElement.insertBefore(newElem, srcElem);
return newElem;
}
// 物体顶界面
var ui = null;
function test_create_ui() {
ui = app.create({
type: 'UIAnchor',
parent: app.query('car02')[0],
element: create_element(),
localPosition: [0, 2, 0],
pivot: [0.5, 1] // [0,0]即以界面左上角定位,[1,1]即以界面右下角进行定位
});
}
test_create_ui();
第三个小功能-物体环绕飞行:
物体环绕飞行同样也是是官方示例中的代码,但是需要修改几个位置,这是因为使用CityBuilder搭建的智慧城市可视化应用,所使用的摄像机与通过CamBuilder(模模搭)搭建的园区可视化或者是其他可视化行业应用不一样,需要修改摄像机环绕和停止的方法。将// 绕某看点位置 或者 某物体 环绕 注释对应的代码修改为app.camera.earthFlyRotateBySpeed({ ;将// 停止旋转注释对应的代码修改为app.camera.stopEarthFly();总的来说,就是切换camera对象所调用的方法。然后在环绕飞行的代码后面添加一个定时器,让其启动。
setTimeout(startRotate, 1000);

修改后的代码如下:
var timer;
// 设置停止操作的时间
var stopTime = 5 * 1000;
// 开始旋转
function startRotate() {
// 绕某看点位置 或者 某物体 环绕
app.camera.earthFlyRotateBySpeed({
target: app.camera.target, // 围绕摄像机当前目标点
speed: 3, // 环绕飞行的时间(3min)
});
clearTimer();
}
// 停止旋转
function stopRotate() {
app.camera.stopEarthFly();
resetTimer();
}
// 清除定时器
function clearTimer() {
if (timer) {
clearTimeout(timer);
timer = null;
}
}
// 重置定时器
function resetTimer() {
clearTimer();
timer = setTimeout(function () {
startRotate();
}, stopTime)
}
app.on(THING.EventType.MouseDown, function () {
stopRotate();
}, '如果按下鼠标 停止旋转');
app.on(THING.EventType.MouseWheel, function () {
stopRotate();
}, '如果滚动鼠标 停止旋转');
setTimeout(startRotate, 1000);
第四个小功能-物体沟边:
物体沟边同样也是是官方示例中的代码,但是由于较为简单,因此只选择其中的一小部分进行使用,使用全局绑定 selection 集合事件,当选择了GeoBuilding属性的物体后,让该物体沟边,同样绑定Deselect事件,则取消物体沟边

// 全局绑定 selection 集合事件
app.on(THING.EventType.Select, '.GeoBuilding', function (ev) {
ev.object.style.outlineColor = '#00ff00'; // 集合中的物体沟边
});
app.on(THING.EventType.Deselect, '.GeoBuilding', function (ev) {
ev.object.style.outlineColor = null;
})
第五个小功能-视角归位:
视角归位需要我们选取一个最初视角,最初视角可以在CityBuilder中获取,方法是打开CityBuilder对应的项目文件,点击项目名右侧的菜单栏,点击视角设置,移动到一个合适的视角,并且拾取该视角。同时视角归位使用的也是app这个全局变量所绑定的click方法,通过判断是鼠标左键还是右键来确定是飞到物体上去还是视角归位。

相关功能代码如下:
app.on('click', function (ev) {
if (ev.button == 0) { // 鼠标左键
if (ev.object.type == 'GeoBuilding') {
cameraFly(ev.object); // 摄像机飞行到建筑
console.log(ev.object.userData.name) // 输出建筑的名字
app.selection.select(ev.object); // 将建筑放进 selection 集合中
}
} else if (ev.button == 2) { // 鼠标右键
app.selection.clear(); // 清空集合
// 摄像机飞行到指定位置
app.camera.earthFlyTo({
time: 2000,
lonlat: [116.46531369922128, 39.98585330794342, -0.009057496674358845],
heading: -16.67619746802896,
height: 276.80479009170085,
pitch: 33.76486653158114
});
}
});
最后附上完整代码:
var app = new THING.App();
// 设置app背景为黑色
app.background = [0, 0, 0];
// 引用地图组件脚本
THING.Utils.dynamicLoad(["https://www.thingjs.com/uearth/uearth.min.js"], function () {
app.create({
type: "Map",
url: "https://www.thingjs.com/citybuilder_console/mapProject/config/TVRnNE1EUT1DaXR5QnVpbGRlckAyMDE5",
complete: function (event) {
// 自定义顶牌
function create_html() {
var sign =
`<div class="sign" id="board" style="font-size: 12px;width: 120px;text-align: center;border: 3px solid #eeeeee;border-radius: 8px;color: #eee;position: absolute;top: 0;left: 0;z-index: 10;display: none;">
<div class="s1" style="margin: 5px 0px 5px 0px;line-height: 32px;overflow: hidden;">
<span class="span-l icon" style="float: left;width: 30px;height: 30px;background:url(https://www.thingjs.com/static/images/example/hydrant.png) no-repeat center;margin: 1px 1px 1px 5px;"></span>
<span class="span-l font" style="float: left;margin: 0px 0px 0px 3px;">优锘科技有限公司</span>
<span class="span-r point" style="float: right;width: 12px;height: 12px;border-radius: 50%;margin: 10px 5px 10px 0px;"></span>
</div>
<div class="s2" style="margin: 5px 0px 10px 0px;line-height: 18px;font-size: 10px;overflow: hidden;">
<span class="span-l font1" style="float: left;margin: 0px 10px 0px 10px;">地区</span>
<span class="span-l font2" style="float: left;width: 70px;">朝阳区</span>
</div>
<div class="point-top" style="position: absolute;top: -7px;right: -7px;width: 10px;height: 10px;border: 3px solid #eee;border-radius: 50%;"></div>
</div>`
$('#div3d').append($(sign));
}
create_html();
// 生成一个新面板
function create_element() {
var srcElem = document.getElementById('board');
var newElem = srcElem.cloneNode(true);
newElem.style.display = "block";
app.domElement.insertBefore(newElem, srcElem);
return newElem;
}
// 物体顶界面
var ui = null;
function test_create_ui() {
ui = app.create({
type: 'UIAnchor',
parent: app.query('北京优锘科技有限公司')[0], // 顶牌的对象
element: create_element(),
localPosition: [0, 2, 0],
pivot: [0.5, 1] // [0,0]即以界面左上角定位,[1,1]即以界面右下角进行定位
});
}
var timer;
// 设置停止操作的时间
var stopTime = 5 * 1000;
// 开始旋转
function startRotate() {
// 绕某看点位置 或者 某物体 环绕
app.camera.earthFlyRotateBySpeed({
target: app.camera.target, // 围绕摄像机当前目标点
speed: 3, // 环绕飞行的时间(3min)
});
clearTimer();
}
// 停止旋转
function stopRotate() {
app.camera.stopEarthFly();
resetTimer();
}
// 清除定时器
function clearTimer() {
if (timer) {
clearTimeout(timer);
timer = null;
}
}
// 重置定时器
function resetTimer() {
clearTimer();
timer = setTimeout(function () {
startRotate();
}, stopTime)
}
app.on(THING.EventType.MouseDown, function () {
stopRotate();
}, '如果按下鼠标 停止旋转');
app.on(THING.EventType.MouseWheel, function () {
stopRotate();
}, '如果滚动鼠标 停止旋转');
setTimeout(startRotate, 1000);
test_create_ui();
app.on('click', function (ev) {
if (ev.button == 0) { // 鼠标左键
if (ev.object.type == 'GeoBuilding') {
cameraFly(ev.object); // 摄像机飞行到建筑
console.log(ev.object.userData.name) // 输出建筑的名字
app.selection.select(ev.object); // 将建筑放进 selection 集合中
}
} else if (ev.button == 2) { // 鼠标右键
app.selection.clear(); // 清空集合
// 摄像机飞行到指定位置
app.camera.earthFlyTo({
time: 2000,
lonlat: [116.46531369922128, 39.98585330794342, -0.009057496674358845],
heading: -16.67619746802896,
height: 276.80479009170085,
pitch: 33.76486653158114
});
}
});
// 全局绑定 selection 集合事件
app.on(THING.EventType.Select, '.GeoBuilding', function (ev) {
ev.object.style.outlineColor = '#00ff00'; // 集合中的物体沟边
});
app.on(THING.EventType.Deselect, '.GeoBuilding', function (ev) {
ev.object.style.outlineColor = null;
})
function cameraFly(object) {
app.camera.earthFlyTo({
time: 2000,
object: object
});
}
}
});
});
- 纯CSS炫酷的3D旋转
<html><head><meta charset="utf-8"><title>纯CSS炫酷的3D旋转</title> ...
- 基于jQuery和CSS3炫酷图片3D旋转幻灯片特效
在线预览 源码下载 iPresenter是一款效果非常炫酷的jQuery和CSS3 3D旋转幻灯片特效插件.你可以使用它来制作产品展示.图片画廊或者各种幻灯片和轮播图特效.这款幻灯片插件的特点有: ...
- WebGIS简单实现一个区域炫酷的3D立体地图效果
1.别人的效果 作为一个GIS专业的,做一个高大上的GIS系统一直是我的梦想,虽然至今为止还没有做出一个理想中的系统,但是偶尔看看别人做的,学习下别人的技术还是很有必要的.眼睛是最容易误导我们的,有时 ...
- canvas - 炫酷的3D星空
1.国际惯例,先上效果 (⊙o⊙)… 效果图看上去效果并不很炫酷啊,直接戳 这里 看效果吧! 2代码部分 html: <canvas id="canvas" width=&q ...
- 【pano2vr】网页Flash中简单实现炫酷的3D模型制作
花了两天时间学习如何能够高效的实现3D模型效果,毕竟是从0开始学习,感觉pano2vr这款软件挺容易上手,并且可以很容易实现简单的热点交互,可以根据交互需求设置皮肤,故将这一款软件推荐给大家: 1.简 ...
- 24、Cocos2dx 3.0游戏开发找小三之网格动作:高炫酷的3D动作
重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/37596763 网格动作类似于动作特效,能够实现翻转. ...
- 用AI制作炫酷效果
PART1:制作第一个效果 步骤一:新建一个800*600的画布. 骤二:从工具栏选“矩形工具”,创建一个800*600的矩形.白色的是画布,浅红色(我的AI之前保留的填充颜色,每个人都不一样)的是你 ...
- 炫酷的可视化工具包——cufflinks
前言 学过Python数据分析的朋友都知道,在可视化的工具中,有很多优秀的三方库,比如matplotlib,seaborn,plotly,Boken,pyecharts等等.这些可视化库都有自己的特点 ...
- [开源硬件DIY] 自制一款精致炫酷的蓝牙土壤温湿度传感器,用于做盆栽呵护类产品(API开放,开发者可自行DIY微信小程序\安卓IOS应用)
目录 前言: 1. 成品展示 2. 原理图解析 3. pcb设计 4. 嵌入式对外提供接口 4.1 蓝牙广播 4.2 蓝牙服务和属性 4.3 数据包格式 4.4 数据通信模型 重要 . 前言: 本期给 ...
随机推荐
- Maven 创建项目之简单示例
maven 是一个项目管理工具.可以用来管理jar包依赖,构建项目等. 那么接下来,就在eclipse中使用maven创建一个简单的项目. 1,依次点击File-> New -> Othe ...
- Mybatis源码解析,一步一步从浅入深(七):执行查询
一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...
- Leetcode 96.不同的搜索二叉树
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ / ...
- tomcat下配置jndi数据源c3p0
Tomcat下通过JNDI配置数据源,使用c3p0连接池 首先在打开tomcat找到在conf文件下,找到server.xml 在server.xml文件中找到标签 在下面添加如下配置 <Res ...
- 【django】ajax,上传文件,图片预览
1.ajax 概述: AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味 ...
- asp.netcore 自动挡Docker Nginx Redis(滴滴滴,自动挡)
前言 上一章介绍了Docker通过多条命令创建启动运行Docker容器,由此可见这样一个个去创建单独的容器也是相当麻烦的,比如要在某个复杂项目中用DB.缓存.消息等等,这样我们还要去一个个再创建,为此 ...
- 节点操作--JavaScript
1 - 概念 网页中的所有内容都是节点(标签.属性.文本.注释),在DOM中,节点使用node来表示. HTML DOM树中的所有节点均可通过JS进行访问,所有HTML元素(节点)均可被修改,也可以创 ...
- Kafka常用命令合集
在上一篇文章<Linux安装Kafka>中,已经介绍了如何在Linux安装Kafka,以及Kafka的启动/关闭和创建发话题并产生消息和消费消息.这篇文章就介绍介绍Kafka的那些常用的命 ...
- Web前端开发的应用和前景——web 1.0到web 3.0
Web前端开发的应用和前景--web 1.0到web 3.0 Web1.0:(只读时代) 以静态.单向阅读为主,网站内信息可以直接和其他网站信息进行交互,能通过第三方信息平台同时对多家网站信息进行整合 ...
- mysql 分页offset过大性能问题解决思路
在公司干活一般使用sqlserver数据库.rownumber分页贼好用. 但是晚上下班搞自己的事情就不用sqlserver了.原因就是自己的渣渣1核2g的小服务器完全扛不住sqlserver那么大的 ...