飞码网-免费源码博客分享网站

点击这里给我发消息

如何使用WRLD创建实时数据的室内商城地图|-JavaScript教程

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站

本文是与WRLD合作创建的。

作为Web开发人员,有时您会发现自己处于实施地图的位置。您的首选是使用Google地图,对吗?

谷歌地图

看起来还好 但是,可能需要您借助标记在地图上叠加其他信息。您可以使用此方法,也可以找到更好的解决方案,使您可以在室内3D地图中创建标记!多么酷啊?使用室内标记,您可以为用户提供独特的体验,使他们能够访问信息并与地图内的UI进行交互。

购物中心地图

在本教程中,我们将创建两个演示,演示WRLD映射的功能。您将学习如何创建可在3D地图上叠加实时信息的自定义应用。在第一个演示中,我们将交互式标记添加到购物中心的现有室内地图中。在第二个演示中,我们将在停车场上方放置彩色多边形,以指示容量。

您可以在此GitHub存储库中找到两个演示的完成项目。

先决条件

对于本文,您只需要对以下主题有基本的了解:

  • JavaScript DOM
  • ES6语法
  • ES6模块

我假设这是您第一次使用WRLD映射。但是,我建议您至少快速阅读该文章:

  • 建立动态3D地图

您还需要在系统上安装Node.js和npm的最新版本(在撰写本文时,8.10 LTS是最新的稳定版本)。对于Windows用户,我强烈建议您使用Git Bash或任何其他能够处理基本Linux命令的终端。

本教程将使用yarn进行软件包安装。如果您更喜欢使用npm,如果您不熟悉纱线命令,请参考本指南。

获取API密钥

在开始之前,您需要在WRLD上创建一个免费帐户。登录并验证电子邮件地址后,您需要获取一个API密钥。有关如何获取地图的详细说明,请查看“ Building Dynamic 3D Maps”中的“入门”部分,该文件已被详细记录。

构造地图的方法

WRLD地图的创建是一项重大技术成就,对许多行业都具有巨大的潜在利益。扩展平台功能的主要方法有两种:

  • 使用内置工具,例如“地图设计器”和“位置设计器”
  • 构建自定义应用

让我分解一下如何使用每种方法来获得期望的结果。

 

 

1.使用地图设计器和位置设计器

对于我们的第一个演示,我们可以使用Places Designer创建商店卡。这将要求我们创建一个将保留Collection Set所有Point of Interest标记位置既可以在WRLD生态系统中访问此集,也可以通过API密钥从外部访问此集。我们可以将此数据传递给使用“地图设计器”创建的自定义地图。使用此工具,我们可以使用其生成的链接与他人共享地图。如果您想了解更多有关此过程的信息,请观看此YouTube播放列表上的视频教程。

地图工具

这种方法的优点是不需要编码。但是,就我们而言,它确实有局限性:

  • 受限的用户界面设计–我们只能使用Places Designer随附的用户界面
  • 限制性数据集–我们无法显示超出提供范围的其他信息

为了克服这些限制,我们需要使用第二种方法来应对我们的购物中心地图挑战。

 

2.构建自定义应用

构建自定义应用程序是最灵活的选择。尽管需要一些编码工作,但它确实使我们能够全面利用WRLD平台提供的丰富潜力。通过构建自定义应用程序,我们可以创建自己的UI,添加更多字段并实时访问外部数据库。这是我们在本教程中将使用的方法。

构建应用

首先创建一个基本映射,稍后再向其添加更多功能。转到您的工作区目录并为您的项目创建一个新文件夹。叫它mall-map

mall-map在代码编辑器中打开文件夹。如果您具有VSCode,请使用Ctrl +`访问终端并在项目目录中执行以下命令:

# Initialize package.json
npm init -f

# Create project directories
mkdir src
mkdir src/js src/css

# Create project files
touch src/index.html
touch src/js/app.js
touch src/css/app.css
touch env.js

这是您的项目结构的外观:

 项目结构

现在我们已经有了项目结构,我们可以开始编写代码了。我们将从开始index.html插入以下代码:

<!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">
  <link rel="stylesheet" href="./css/app.css" />
  <title>Shopping Mall</title>
</head>
<body>
  <div ></div>
  <script src="js/app.js"></script>
</body>
</html>

接下来,让我们继续css/app.css我为整个项目提供了完整的样式,因此我们不必再次访问此文件。在适当的时间,您将了解本教程的内容。

@import "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.1/leaflet.css";
@import "https://cdn-webgl.wrld3d.com/wrldjs/addons/resources/latest/css/wrld.css";
@import "https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.min.css";

html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

#map {
  width: 100%;
  height: 100%;
  background-color: #000000;
}

/* -------- POPUP CONTENT -------- */
.main-wrapper > .segment {
  padding: 0px;
  width: 300px;
}

.contacts > span {
  display: block;
  padding-top: 5px;
}

现在我们需要开始为编写代码app.js但是,我们需要几个节点依赖项:

yarn add wrld.js axios

如前所述,我们将利用现代JavaScript语法编写代码。因此,我们需要使用babel将现代代码编译为与大多数浏览器兼容的格式。这需要安装babel依赖项并通过.babelrc文件进行配置确保将它们安装为dev-dependencies

 

 

yarn add babel-core babel-plugin-transform-runtime babel-runtime --dev
touch .babelrc

将此代码复制到.babelrc文件中:

{
  "plugins": [
    [
      "transform-runtime",
      {
        "polyfill": false,
        "regenerator": true
      }
    ]
  ]
}

我们还需要以下软件包来运行我们的项目:

  • 包裹打包程序–就像Webpack的简化版,配置几乎为零
  • JSON服务器–用于创建虚拟API服务器

像这样全局安装软件包:

yarn global add parcel-bundler json-server

# Alternative command for npm users
npm install -g parcel-bundler json-server

这就是我们项目所需的所有节点依赖关系。现在让我们编写一些JavaScript代码。首先,在以下位置提供您的WRLD API密钥env.js

module.exports = {
  WRLD_KEY: '<put api key here>',
 };

然后打开js/app.js并复制以下代码:

const Wrld = require('wrld.js');
const env = require('../../env');

const keys = {
  wrld: env.WRLD_KEY,
};

window.addEventListener('load', async () => {
  const map = await Wrld.map('map', keys.wrld, {
    center: [56.459733, -2.973371],
    zoom: 17,
    indoorsEnabled: true,
  });
});

前三个语句非常明显。我们已将所有代码放入window.addEventListener函数中。这是为了确保我们的代码在index.html加载了JavaScript依赖项之后执行,稍后我们将在中指定在此函数内部,我们通过传递几个参数来初始化地图:

  • map –我们在中指定的div容器的ID index.html
  • keys.wrld – API密钥
  • center –位于苏格兰邓迪的Overgate购物中心的经度和纬度
  • zoom –高程
  • indoorsEnabled –允许用户访问室内地图

让我们启动我们的项目。转到终端并执行:

parcel src/index.html

等待几秒钟,项目完成捆绑。完成后,打开浏览器并访问localhost:1234。根据您的互联网速度,地图加载时间不会太长。

建筑图

美丽,不是吗?随时单击蓝色图标。它将带您进入室内。导航以查看其他商店。但是,您很快就会意识到您无法访问其他楼层。也没有退出室内地图的按钮。让我们在下一章中进行修复。

创建室内控件

为了允许用户在不同楼层之间切换,我们将为他们提供一个控件,使他们能够执行此操作。只需将以下脚本添加到public/index.html文件的开头部分

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdn-webgl.wrld3d.com/wrldjs/addons/indoor_control/latest/indoor_control.js"></script>

仍在html文件中,在div部分的主体部分添加此#mapdiv:

<div  ></div>

现在让我们更新js/app.js以初始化小部件。将此代码放在地图初始化部分之后:

 

 

const indoorControl = new WrldIndoorControl('widget-container', map);

现在刷新页面,然后单击“进入室内”图标。您应该有一个控件,可以在各个楼层之间切换。只需上下拖动控件即可在地板之间流畅地移动。

室内控制

太神奇了,不是吗?现在,让我们看看如何使我们的地图对用户更方便。

自动进入室内

您难道不觉得每次我们需要测试地图时都需要单击“室内”图标有点烦吗?用户可能会开始导航到其他位置,而这并不是此应用程序的意图。要解决此问题,我们需要在应用启动时自动在室内导航,而无需任何用户交互。首先,我们要求indoor map id实现此功能。我们可以从indoormapenter活动中找到此信息您可以在此处找到所有与室内相关的方法。

js/app.js文件中添加以下代码

...
// Place this code right after the Wrld.map() statement
map.indoors.on('indoormapenter', async (event) => {
  console.log(event.indoorMap.getIndoorMapId());
});
...

刷新页面,然后检出控制台。您应该将此ID打印出来:EIM-e16a94b1-f64f-41ed-a3c6-8397d9cfe607现在让我们编写将执行实际导航的代码:

const indoorMapId = 'EIM-e16a94b1-f64f-41ed-a3c6-8397d9cfe607';

map.on('initialstreamingcomplete', () => {
  map.indoors.enter(indoorMapId);
});

保存文件后,刷新页面,看看会发生什么。

室内购物中心地图应自动导航。接下来,我们将研究如何为每个商店创建卡片。但是首先,我们需要确定数据的来源。

购物中心地图规划

要为我们的地图创建存储卡,我们需要以下几项:

  • 商店的确切经度/纬度坐标
  • 存储联系方式和营业时间
  • 商店卡的设计模板

商店卡座标

要获取经度/纬度坐标,我们需要访问maps.wrld3d.com。等待地图完成加载,然后56.459733, -2.973371在搜索框中输入地址按Enter键,地图将快速导航到Overgate Mall。单击Overgate购物中心的蓝色室内图标,您将被带到购物中心的室内地图。加载后,找到“ Next”存储,然后右键单击以打开上下文菜单。点击“这是什么地方?选项。坐标弹出窗口应出现。

地点坐标

点击“复制坐标”按钮。这将为您提供商店的确切经度/纬度坐标。将此位置地址临时保存在某处。

商店卡信息

您还需要从每个商店收集联系信息,包括:

 

 

  • 图片
  • 描述
  • 电话
  • 电子邮件
  • 网路
  • 推特
  • 营业时间

您可以从Google获得大部分此类信息。幸运的是,我已经为您收集了数据。在本教程中,我们仅处理一楼的四个商店。要访问信息,只需在项目的根目录下创建一个文件夹,并将其命名为data。接下来,将此文件从GitHub保存在data文件夹中。确保将其另存为db.json这是我们将使用的数据示例:

{
  "id":1,
  "title": "JD Sports",
  "lat": 56.4593425,
  "long": -2.9741433,
  "floor_id": 0,
  "image_url": "https://cdn-03.belfasttelegraph.co.uk/business/news/...image.jpg",
  "description":"Retail chain specialising in training shoes, sportswear & accessories.",
  "phone": "+44 138 221 4545",
  "email": "customercare@jdsports.co.uk",
  "web": "https://www.jdsports.co.uk/",
  "twitter": "@jdhelpteam",
  "tags": "sports shopping",
  "open_time":[
    { "day": "Mon",
      "time": "9:30am - 6:00pm"
    },]
}

数据存储在标记为“ pois”的数组中。POI代表景点。现在我们有了可用的数据,我们可以通过运行JSON服务器,轻松地通过API REST点对其进行访问。只需打开一个新终端并执行以下命令:

json-server --watch data/db.json

API可能需要几秒钟才能启动。完全加载后,您可以使用浏览器在localhost:3000 / pois对其进行测试。您还可以使用以下语法获取单个POI:

- localhost:3000/pois/{id}

例如,localhost:3000 / pois / 3应该poi以JSON格式返回ID为3记录。

商店卡设计

我们将使用简洁优雅的主题,通过几个标签来整齐地显示联系信息和开放时间。我们将创建一个标记,当单击该标记时将显示一个弹出窗口。该弹出窗口将具有以下UI。

存储卡模板

用于此HTML设计的代码在这里有点长。您可以从此链接查看和下载文件。该设计仅具有三个依赖性:

  • 语义UI CSS
  • jQuery的
  • 语义UI JS

现在我们有了所需的数据和设计,现在应该准备开始在室内地图上工作了。

在室内地图中实施存储卡

首先,让我们创建一个服务,该服务将允许我们从JSON REST API访问数据。该数据将用于用必要的信息填充存储卡。创建文件js/api-service.js并复制以下代码:

const axios = require('axios');

const client = axios.create({
  baseURL: 'http://127.0.0.1:3000',
  timeout: 1000,
});

module.exports = {
  getPOIs: async () => {
    try {
      const response = await client.get('/pois');
      return response.data;
    } catch (error) {
      console.error(error);
    }
    return [];
  },
  getPOI: async (id) => {
    try {
      const response = await client.get(`/pois/${id}`);
      return response.data;
    } catch (error) {
      console.error(error);
    }
    return {};
  },
}

在这里,我们利用库axios从JSON服务器请求数据。

接下来,我们将存储卡的静态HTML设计转换为允许我们呈现数据的格式。我们将为此使用JsRender。我们将静态设计分为三个模板:

  • 基本模板–具有用于菜单,信息和时间选项卡的容器。
  • 信息模板–用于存储联系信息的选项卡。
  • 时间模板–商店营业时间的标签。

首先,打开index.html这些脚本并将其添加到headjQuery和室内控制脚本之后的部分中:

 

 

<head>
  ...
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/0.9.90/jsrender.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.0/semantic.min.js"></script>
  ...
</head>

接下来,将这部分代码复制到widget-containerdiv之前

  ...
  <!-- Menu Tabs UI -->
 <script  type="text/x-jsrender">
    <div >
      <div >
        <div > </div>
        <div   data-tab="Info"></div>
        <div   data-tab="Time"></div>
      </div>
    </div>
  </script>

  <!-- Info Data Tab -->
  <script  type="text/x-jsrender">
    <div >
      <div >
        <img src={{:image_url}}>
      </div>
      <div >
        <div >{{:title}}</div>
        <div >
          {{:description}}
        </div>
      </div>
      <div >
        <span>
          <i ></i>
          <a href="{{:web}}" target="_blank">{{:web}}</a>
        </span>
        <span>
          <i ></i>
          {{:email}}
        </span>
        <span>
          <i ></i>
          {{:phone}}
        </span>
      </div>
    </div>
  </script>

  <!-- Opening Times Data Tab -->
  <script  type="text/x-jsrender">
    <table >
      <thead>
        <tr>
          <th>Day</th>
          <th>Time</th>
        </tr>
      </thead>
      <tbody>
        {{for open_time}}
        <tr>
          <td>{{:day}}</td>
          <td>{{:time}}</td>
        </tr>
        {{/for}}
      </tbody>
    </table>
  </script>
  ...

这就是index.html的完整代码的外观。

接下来,让我们创建另一个服务,该服务将管理的创建Popups创建文件js/popup-service.js并复制以下代码:

const Wrld = require('wrld.js');
const { getPOI } = require('./api-service');

const baseTemplate = $.templates('#baseTemplate');
const infoTemplate = $.templates('#infoTemplate');
const timeTemplate = $.templates('#timeTemplate');

const popupOptions = {
  indoorMapId: 'EIM-e16a94b1-f64f-41ed-a3c6-8397d9cfe607',
  indoorMapFloorIndex: 0,
  autoClose: true,
  closeOnClick: true,
  elevation: 5,
};

让我逐步解释每个块:

  • 块1:创建时需要WRLD PopupgetPOI数据获取时需要功能
  • 块2:前面讨论的模板是使用 jsrender
  • 块3:在Popup实例化期间将传递的参数这是参考文档。

接下来,让我们添加用于切换标签的标签菜单。只需将此代码添加到js/popup-service.js

const createMenuLink = (linkName, iconClass) => {
  const link = document.createElement('a');
  link.className = 'item';
  const icon = document.createElement('i');
  icon.className = `${iconClass} icon`;
  link.appendChild(icon);
  link.appendChild(document.createTextNode(` ${linkName}`));
  link.setAttribute('data-tab', linkName);
  link.addEventListener('click', () => {
    $.tab('change tab', linkName);
    $('.item').toggleClass('active');
  });
  return link;
};

const createMenu = (menuParent) => {
  const infoLink = createMenuLink('Info', 'info circle');
  infoLink.className += ' active';
  menuParent.appendChild(infoLink);
  const timeLink = createMenuLink('Time', 'clock');
  menuParent.appendChild(timeLink);
};

您可能想知道为什么我们使用复杂的方法来创建菜单链接。理想情况下,我们应该能够使用HTML创建它们,然后添加一个小的JavaScript脚本来激活选项卡。不幸的是,这在的上下文中不起作用Popup相反,我们需要使用DOM操作方法来创建可点击的元素。

接下来,添加以下代码以完成基本内容部分:

const buildBaseContent = () => {
  const htmlOutput = baseTemplate.render({});
  const parent = $.parseHTML(htmlOutput)[1];
  const menuParent = parent.childNodes[1].childNodes[1];
  createMenu(menuParent);
  return parent;
};

const baseContent = buildBaseContent();

在这里,我们将基本模板渲染为HTML。然后,将其转换为DOM,以使我们能够附加DOM菜单。然后,我们调出该buildBaseContent()函数以创建我们的基本DOM,稍后再将其附加到信息和时间标签的内容上。

在下一节中,我们将创建一个名为的函数showPopup稍后我们将为每个商店创建标记。当用户单击标记时,将出现一个包含存储卡的弹出窗口。将此代码添加到js/popup-service.js

// Clear existing tab content before adding another
const clearTab = (tab) => {
  while (tab.firstChild) {
    tab.removeChild(tab.firstChild);
  }
};

module.exports = {
  showPopup: async (event) => {
    // Fetch co-ordinates and map objects from event
    const latlang = event.target._latlng;
    const map = event.target._map;
    // Create an instance of Popup
    const popup = Wrld.popup(popupOptions)
      .setLatLng(latlang);
    try {
      // Fetch data from api-service
      const poi = await getPOI(event.target.options.id);
      // Bind data with templates to render html outputs
      const infoHTML = infoTemplate.render(poi);
      const timeHTML = timeTemplate.render(poi);
      // Convert HTML outputs to DOM objects
      const infoDOM = $.parseHTML(infoHTML)[1];
      const timeDOM = $.parseHTML(timeHTML)[1];
      // Populate Tabs with DOM objects
      const infoTab = baseContent.childNodes[1].childNodes[3];
      clearTab(infoTab); // Clear existing content if any
      infoTab.appendChild(infoDOM);
      const timeTab = baseContent.childNodes[1].childNodes[5];
      clearTab(timeTab); // Clear existing content if any
      timeTab.appendChild(timeDOM);

      // Populate popup with DOM content
      popup.setContent(baseContent);
      // Display the popup
      popup.addTo(map);
      // Navigate map to properly view the Popup
      map.setView(latlang, 18);
    } catch (error) {
      popup.setContent('Oops! Something went wrong');
      popup.addTo(map);
    }
  },
};

这里有很多事情。我在代码中插入了注释,解释了每个部分的功能。如果您对完整代码的外观有任何疑问,可以从此链接查看。

接下来,我们需要为中定义的每个POI创建标记db.json每个标记都有一个click事件侦听器,它将触发该showPopup()功能。更新js/app.js如下:

..
const { getPOIs } = require('./api-service');
const { showPopup } = require('./popup-service');
...

// Place within window.addEventListener('load')
const placeMarkers = (pois) => {
  let marker;
  pois.forEach((poi) => {
    const latlang = [poi.lat, poi.long];
    marker = Wrld.marker(latlang, {
      id: poi.id,
      title: poi.title,
      indoorMapId,
      indoorMapFloorId: 1,
    }).addTo(map);
    marker.on('click', showPopup);
  });
};

map.indoors.on('indoormapenter', async (event) => {
  if (event.indoorMap.getIndoorMapId() === indoorMapId) {
    // Center map properly when indoors
    map.indoors.setFloor(0);
    map.setView([56.459342, -2.9741433], 18);

    // Create markers for each store.
    const pois = await getPOIs();
    placeMarkers(pois);
  }
});

Take note that we’re passing the POI ID to the marker via the Options object parameter. If you refer back to the showPopup function, you’ll see we are extracting this id via the event object. If in doubt about how the complete code should look, view it from this link.

Now it’s time to test our code. I’ll assume you still have the JSON server running in the background. If you not, please refer back on how to run it. Let’s also start the parcel bundler. Once it’s started, refresh your browser in case it hasn’t. You should now have multiple markers available for you to click. Clicking a marker will result in a popup like this:

 

 

存储卡完成

The above demo illustrates how Store Cards work for an indoor map. Now, let’s look at another Wrld.js feature where we can overlay parking availability information over multiple parking areas.

停车位

您是否曾经因为寻找停车位而感到压力大?好吧,让我们尝试看看是否可以解决此问题。我们将使用WRLD地图突出显示停车区。我们将使用不同的颜色指示每个停车区的状态:

  • 绿色:有停车位
  • 黄色:占用80%的停车位
  • 红色:已占用停车位的100%

当然,您可以定义更多的颜色代码以提供更详细的停车位级别。但是,请记住,人们可能很着急,他们需要在几毫秒内处理这些信息。让我们一次一次创建此地图。

1.停车场的位置图

让我们从创建parking.html开始js/parking.js我们将独立于购物中心地图逻辑来运行此解决方案。创建HTML文件后,复制以下代码:

<!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">
  <link rel="stylesheet" href="./css/app.css" />
  <title>Parking Availability</title>
</head>
<body>
  <div ></div>

  <script src="js/parking.js"></script>
</body>
</html>

接下来,将此代码复制为js/parking.js

const Wrld = require('wrld.js');
const env = require('../../env');

const keys = {
  wrld: env.WRLD_KEY,
};

window.addEventListener('load', async () => {
  // Create map instance
  const map = await Wrld.map('map', keys.wrld, {
    center: [56.460087, -2.975432],
    zoom: 17.5,
  });
});

现在运行我们的代码。我们将parcel为此使用parcel首先使用Ctrl + C停止现有实例要启动停车演示,请执行:

parcel src/parking.html

等待包裹完成编译。完成后,导航到localhost:1234。您应该对停车场有以下看法:

停车区开始

2.突出停车

Let’s now learn how to highlight an area using a Polygon instance. First, we’ll need to collect coordinates for each corner of the area we need to highlight. We can do this by visiting maps.wrld3d.com and searching for Overgate in order to locate the parking areas. Zoom in towards the parking section and use the middle mouse button to adjust the tilt of the camera such that you can view straight down. This will make it easy to accurately place mouse clicks. Next, pick one of the parking zones and right-click any corner. Click ‘What is this place?’:

停车坐标

Click the copy coordinates and save it somewhere. You should get the Longitude and Latitude coordinates of the point you clicked.

- 56.460080, -2.974528

 

 

对每个角落执行此操作。接下来使用此数据构造一个Polygon实例。这是已添加到中的示例js/parking.js将此代码放在map初始化语句之后。

  const polygonPoints1 = [
    [56.459857, -2.974004],
    [56.459889, -2.974036],
    [56.459836, -2.974188],
    [56.460079, -2.974526],
    [56.460254, -2.974096],
    [56.459954, -2.973698]];
  const parking1 = Wrld.polygon(polygonPoints1).addTo(map);

如果没有,请刷新localhost:1234。您现在应该具有以下视图:

停车场高光

既然我们已经学会了突出显示,我们应该收集我们感兴趣的每个停车区的坐标。我们还需要一种使这些数据远离我们接下来将要研究的代码的方法。但是首先,删除这部分代码,因为我们将用更好的代码替换它。

3.用于停车数据的Rest API

我们将利用JSON服务器数据库来存储所有停车坐标。幸运的是,我已经收集了这些数据并将其放在中db.json这是一个停车区的数据示例:

{
      "id": 1,
      "name" : "parking 1",
      "polygonPoints": [
        [
          56.459837,
          -2.973982
        ],
        [
          56.459952,
          -2.973691
        ],
        [
          56.460256,
          -2.974093
        ],
        [
          56.460079,
          -2.974530
        ],
        [
          56.459832,
          -2.974188
        ],
        [
          56.459888,
          -2.974035
        ]
      ],
      "totalSlots": 55,
      "usedSlots": 55
    },

请注意,对可用停车位的总数有一个粗略的估计。我还对使用过的停车位进行了猜测,稍后我们将对其进行探讨。db.json您之前复制文件已经具有此数据。现在我们有了可用的停车区数据,我们应该创建一个帮助服务来获取此信息。我们只需要js/api-service使用新功能进行更新复制此代码,然后将其放在最后一个get函数之后module.exports

 getParkingAreas: async () => {
    try {
      const url = id ? `/parkingAreas/${id}` : '/parkingAreas';
      const response = await client.get(url);
      return response.data;
    } catch (error) {
       console.error(error);
    }
    return [];
  },

此功能旨在处理是否提取所有“停车区”记录,或仅提取一条记录,具体取决于是否填充了ID字段。现在让我们看一下如何从JSON服务器提取此数据并将其覆盖在地图上。

3.彩色编码停车区

js/parking.js使用这些颜色代码进行更新将此代码放在keys声明之后。

// Color Codes
const fullColor = [255, 0, 0, 128]; // Completely full, 100%
const almostColor = [255, 165, 0, 128]; // Few parking slots left, 80% full
const availableColor = [0, 255, 0, 128]; // Plenty of parking space available

const getColorCode = (parkingArea) => {
  const occupied = (parkingArea.usedSlots / parkingArea.totalSlots) * 100;
  if (occupied === 100) {
    return fullColor;
  } else if (occupied >= 80) {
    return almostColor;
  }
  return availableColor;
};

颜色代码只是表示rgba值的数组,即红色,绿色,蓝色和alpha。还有一个功能getColorCode可以根据已用插槽的百分比确定要使用的颜色代码。接下来,让我们从JSON服务器中提取Parking Areas数据,并为每条记录创建一个Polygon实例:

  // Place this at the top after other imports
  const { getParkingAreas } = require('./api-service');
  const parkPolys = [];
  ....
  // Place after `map` function
  map.on('initialstreamingcomplete', async () => {
    // Highlight Parking Areas
    const parkingAreas = await getParkingAreas();
    parkingAreas.forEach((parkingArea) => {
      const colorCode = getColorCode(parkingArea);
      const poly = Wrld.polygon(parkingArea.polygonPoints, { color: colorCode })
        .addTo(map);
      parkPolys.push({ id: parkingArea.id, poly });
    });
  });
  ...

请注意,我们将多边形的关联保存parkingArea.id在数组中。我们稍后将对此进行处理,以使我们的地图实时。确保JSON服务器正在运行,此代码才能正常工作。现在,刷新页面以查看更新的结果:

停车颜色代码

很酷,不是吗?随意添加颜色代码标签以指示其含义。现在,地图的当前限制是,除非刷新整个页面,否则用户看不到地图更新。让我们看看如何解决这个问题。

4.实时停车区

为此,我们将使用该sockets.io库来实现实时更新。json server我们正在使用程序本身不支持sockets.io因此,我们需要编写自己的自定义实现。首先,让我们安装必要的依赖项:

 

 

yarn add json-server socket.io socket.io-client

接下来,server.js在项目的根目录下创建文件并复制以下代码:

const jsonServer = require('json-server');
// Initialize Socket.IO Server
const socketServer = require('http').createServer();
const io = require('socket.io')(socketServer);

// Initialize JSON Server
const server = jsonServer.create();
const router = jsonServer.router('./data/db.json');

// Set default middlewares (logger, static, cors and no-cache)
const middlewares = jsonServer.defaults();
server.use(middlewares);

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(jsonServer.bodyParser);

// Broadcast `parkingAreas` PATCH requests
server.patch('/parkingAreas/:id', (req, res, next) => {
  const { id } = req.params;
  const { usedSlots } = req.body;
  console.log(`Parking Area ${id} updated to ${usedSlots} Used Slots`);
  io.emit('parkingAreas', { id, usedSlots });
  next(); // pass on to default logic
});

// Use default router
server.use(router);

// Bind JSON Server
server.listen(3000, () => {
  console.log('JSON Server is running at port 3000');
});

// Bind Socket.IO Server
socketServer.listen(3001, () => {
  console.log('Socket.IO Server is running at port 3001');
});

在上面的代码中,我们正在设置两个将同时运行的服务器实例。第一个实例json server将在端口3000上提供API服务。第二个实例socket server将为将在端口3001上与其连接的套接字客户端提供实时。

在本文中,我们将使用Postman发送usedSlots每个停车场的容量级别(更新我们将使用的HTTP方法是PATCH,这将允许我们仅更新记录的一部分。我们不能使用UPDATE方法,因为它将覆盖整个记录,从而导致我们丢失多边形点数据。

回到我们的服务器代码,您会注意到我们有一个patch功能。在此函数中,将提取idusedSlots数据,然后将其广播到任何侦听的socket.io客户端。

现在我们已经设置了服务器,是时候设置客户端代码以接收实时更新了。返回js/parking.js并复制以下代码:

// Place this at the top section
const io = require('socket.io-client');
...
  // Place after `getColorCode` function
const updateParkingArea = async ({ id }) => {
  const parkingArea = await getParkingAreas(id);
  if (parkingArea) {
    const parkPoly = parkPolys.find(target => parkingArea.id === target.id);
    if (parkPoly) {
      parkPoly.poly.setColor(getColorCode(parkingArea));
    }
  }
};

const socket = io.connect('http://localhost:3001');

socket.on('connect', () => {
  console.log('connected to socket 3001');
  socket.on('parkingAreas', (data) => {
    console.log('parkingAreas event received');
    updateParkingArea(data);
  });
});

这里的客户端代码非常简单。我们创建绑定到端口3001的套接字客户端实例。然后将其设置为侦听parkingAreas事件,然后updateParkingArea()执行函数。

如果对代码的排列方式有疑问,请参考完整的parking.js。

现在让我们做一个实验。首先,您需要取消任何现有过程。接下来,在单独的终端上启动定制JSON服务器代码。然后parking.html在单独的终端上启动代码:

# Start server first
node server

# Start Parking Map App
parcel src/parking.html

现在打开或刷新页面localhost:1234。要将更新发送到JSON服务器,我们将使用Postman。如果没有它,只需安装它。打开后,创建一个新的请求并输入以下参数:

  • 方法–补丁
  • 网址–本地主机:3000 / parkingAreas / 2
  • 内容类型– application / json
  • 编码-原始JSON(应用程序/ json)
  • 身体{ "usedSlots": 75 }

如果您不知道该字段在哪里Content-Type,只需单击“页眉”选项卡。这是邮递员的屏幕截图:

邮差补丁

当您点击发送时,地图上的更新会立即发生:

实时更新

随时尝试使用usedSlots其他记录的值,并查看地图更新本身。相当辉煌!

概要

既然我们已经完成了本教程的结尾,我希望您对WRLD的3D地图可以做的事情感到惊讶。这些可以与现实世界数据集成的演示以及现实世界中WRLD的应用程序无穷无尽。

例如,我们可以构建一个从实际停车传感器中获取数据的服务。对于购物中心地图,我们可以显示更多有趣的信息,例如可以吸引更多人参观购物中心的每日报价。这种技术不仅适用于购物中心,还可以适用于其他类型的企业和机构。例如,您可以将此地图技术与库存管理系统集成。该地图可用于可视化设备在营业场所的位置。

使用WRLD映射平台提供创新产品完全取决于您。

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站
赞 ()
内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: