Languages: English简体中文繁體中文

SensorThings API - 数据驱动样式设计

第一部分中, 我们:

  • 使用Leaflet制作了一个简单地图
  • 使用多伦多自行车共享站点的位置信息Locations填充了这张地图
在这一部分中,我们会介绍如何基于SensorThings服务器取回的真实数据来设计地图。 而且,我们会向您展示如何在地图上制作不同颜色标记,来指示在特定位置可用的自行车数量。

首先,调整地图

在我们深入了解数据驱动样式设计的细节之前,让我们对地图进行一些微调。

  • 把标记改成圆圈
  • 为了使用户了解数据来源,增加一行代码来注明地图中所提供的开放数据属于自于多伦多市

在 SensorThings Share 上查看代码
pointToLayer现在引入了一个函数,它回传了圆形标记(circleMarker)来替代预设的标记图案。

var geoJsonLayerGroup = L.geoJSON(geoJsonFeatures, {

  // Change the default marker to a circle
  pointToLayer: function(geoJsonPoint, latlng) {
    return L.circleMarker(latlng);
  }

});
这行代码注明了地图中所提供的开放数据属于自于多伦多市。

map.attributionControl.addAttribution("Contains information licensed under the Open Government Licence – Toronto.");

自行车的去向?

现在,我们已经在地图上放置了很多点,它们看起来还不错,但不够特别。因为虽然我们知道了自行车共享站点的位置,但如果能进一步知道每个共享站点有多少自行车将会更好。现在我们就来做这件事。

在SensorThings中,例如“可用的自行车(available bikes)”这样的信息,可称为观测属性ObservedProperty。 此次教程中的使用的SensorThings服务器包含了两个观测属性ObservedProperties

  • 可用的自行车(Available bikes)
  • 可用的站点(Available docks)

请参考以下代码

GET {{staBaseUrl}}/ObservedProperties

虽然对我们而言,可用的自行车和可用的站点都是重要的信息。但依需要,这部分教程将只关注可用的自行车数量。

现在我们要做的,是找到在特定的Location中可用自行车的数量。在SensorThings中,这类的信息被存储在观测值Observation中。我们必须通过SensorThings中多个其他的实体(entities)来获取观测值Observation。具体来说,我们需要先获取在这个位置LocationThings,以及Things对应的数据流Datastreams (因为只有Datastream包含可用自行车的信息),然后我们再获取每个数据流Datastream中的观测值Observations(我们只要最新的一份数据)。这些虽然看起来繁琐,但这些实体可支持您进行复杂特定的查询。

GET {{staBaseUrl}}/Locations?$expand=Things/Datastreams($filter=ObservedProperty/name eq 'available_bikes'),Things/Datastreams/Observations($orderby=phenomenonTime desc;$top=1)

以上这个查询看起来似乎有些难度,但实际上并不复杂。

  • /Locations: 对Locations的端点进行请求,与之前的请求相同。

  • $expand=Things/Datastreams($filter=ObservedProperty/name eq 'available_bikes'): 通过扩展这个Location来获取Things以及它对应的多个Datastreams,然后在结果中过滤其他Datastreams,仅保留ObservedProperty中属性名为'available_bikes'的结果。

  • Things/Datastreams/Observations($orderby=phenomenonTime desc;$top=1): 这是扩展$expand参数的第二部分。这部分对于剩下未被过滤的Datastreams扩展获得观测值Observations,并且获取根据phenomenonTime排序后的最新一份数据。因此只会传回最新的观测值Observation

这些响应包括:

  • Location的经度和纬度座标(之前取回过)

  • Location最新一些的可用自行车数量(本次新增)

这里的结果我们将不会带您逐行阅读,但您可以自行阅读以加深理解,包括哪些数据是有用的以及结构如何。毕竟数据是建立用户界面的原始材料!

整合到地图

现在我们知道如何从每个站点取回可用自行车的数量,接下来就准备建立我们的地图了。

在 SensorThings Share 上查看代码
我们在GeoJSON Features里增加了一行properties: location,以便LeaFlet来访问SensorThings响应中的Things,Datastreams, 和Observations

var geoJsonFeatures = success.data.value.map(function(location) {
  return {
    type: 'Feature',
    geometry: location.location,
    properties: location
  };
});
最后,我们改变了标记的颜色,用于区分"足够的"自行车(显示为蓝色, 或十六进制颜色#38f)和"不足的"的自行车(显示为红色)。我们姑且设定了一个值(5),超过五辆自行车即为“足够的”,小于则为“不足的”。

pointToLayer: function(geoJsonPoint, latlng) {
  var enoughBikeColor = "#38f";
  var fewBikesColor = "red";
  var availableBikes = geoJsonPoint.properties.Things[0].Datastreams[0].Observations[0].result;
  return L.circleMarker(latlng, {
    color: availableBikes > 5 ? enoughBikeColor : fewBikesColor
  });
}

下一步?

您是那种会告诉老师他们错了的学生吗?如果您是,此刻您肯定会举手,事实上,也许此刻您会疯狂地挥舞手臂引起老师注意。 那是因为您可能发现了,/Locations的响应中"@iot.count": 199,但其实只有100个 Locations被传回来。您也许还会注意到这里暗藏了一个@iot.nextLink属性。

我们还没有显示所有的自行车分享站点。

所以,接下来请继续第三部分。

第三部分 - 可视化更多的位置(Location)