欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

初级开发者也能码出专业炫酷的3D地图吗?

程序员文章站 2023-02-04 08:19:48
好看的3D地图搭建出来,一定是要能为开发者所用与业务系统开发中才能真正地体现价值。基因于此,CityBuilder建立了与ThingJS的通道——直转ThingJS代码,支持将配置完成的3D地图一键转为代码,不仅减少开发者的工作量,还能作为非GISer开发者的地图教学工具,使一般开发者也能码出专业、... ......

         好看的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()这个方法。

初级开发者也能码出专业炫酷的3D地图吗?

// 添加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);

初级开发者也能码出专业炫酷的3D地图吗?

修改后的代码如下:

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事件,则取消物体沟边

初级开发者也能码出专业炫酷的3D地图吗?

// 全局绑定 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方法,通过判断是鼠标左键还是右键来确定是飞到物体上去还是视角归位。

初级开发者也能码出专业炫酷的3D地图吗?

相关功能代码如下:

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
});
}
}
});
});