我们正在为位于不同地点的工业工厂构建网络可视化。目前,我们在概述页面中使用表格布局。每行代表一个工厂及其最重要的状态和价值。
现在需要另外显示带有标记的地图。每个标记的颜色应代表当前状态(绿色= ok,红色=错误,黄色=警告等)。
在我们当前基于表的页面中,我们使用knockout.js将各个工厂属性从viewmodel绑定到表行(以及其中的相应div等)。只要状态或值发生变化,viewmodel的值就会通过signalr更新,因此您可以将其视为工厂状态的实时,基于事件的表示。
由于这个视图模型已经包含了我们需要在地图上显示的所有信息,我想将传单标记绑定到视图模型,但我看不出如何做到这一点的方法。问题是我没有可以使用data-bind
属性的标记元素。
准确地说:我可以为每个工厂添加(静态)标记,这不是问题,但是我无法将它们数据绑定到viewmodel,以便动态地表示viewmodel中的变化值。有办法吗?
我真的很想继续传单,因为它完全符合我们的需求。 Web应用程序需要在永久断开连接到互联网的特殊网络中运行,因此我们需要提供自己的磁贴(适用于传单和Maperetive)。如果除了传单之外还有其他解决方案可以满足我们的需求,请告诉我。谢谢!
更新:这是我的viewmodel的实际json数据。每行代表一个站。每个电台的纬度/经度尚未添加,但我猜这个问题可以忽略不计。
{
"Rows":[
{
"StationId":1,
"Text":"MCU SE (SE 1/1) DAE",
"IsDialInStation":false,
"ConnectState":{
"StationId":1,
"DpId":14,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1400149092000)\/"
},
"ConnectStateText":"Nicht verbunden. Hier klicken für Anwahl!",
"HasActualData":{
"StationId":1,
"DpId":10,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1404890137000)\/"
},
"Anlage":{
"StationId":1,
"DpId":20101,
"Name":"Anlage",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteAnlage":{
"StationId":1,
"DpId":20013,
"Name":"cmdAnlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Kurzzeit":{
"StationId":1,
"DpId":20104,
"Name":"Kurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteKurzzeit":{
"StationId":1,
"DpId":20012,
"Name":"cmdKurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Handbetrieb":{
"StationId":1,
"DpId":20160,
"Name":"Handbetrieb",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Betriebsbereit":{
"StationId":1,
"DpId":20121,
"Name":"Betriebsbereit",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Heizt":{
"StationId":1,
"DpId":20451,
"Name":"Heizt",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Sammelstoerung":{
"StationId":1,
"DpId":20140,
"Name":"Sammelstoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"SammelstoerungTechnisch":{
"StationId":1,
"DpId":20129,
"Name":"SammelstoerungTechnisch",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerung":{
"StationId":1,
"DpId":20138,
"Name":"KommunikationsStoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerungKE":{
"StationId":1,
"DpId":20137,
"Name":"KommunikationsStoerungKE",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"AllowCommands":true,
"AllowParameters":true
},
{
"StationId":2,
"Text":"MCU SE (SE 2/1) Turm",
"IsDialInStation":false,
"ConnectState":{
"StationId":2,
"DpId":14,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1402984603000)\/"
},
"ConnectStateText":"Nicht verbunden. Hier klicken für Anwahl!",
"HasActualData":{
"StationId":2,
"DpId":10,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1404890136000)\/"
},
"Anlage":{
"StationId":2,
"DpId":20101,
"Name":"Anlage",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteAnlage":{
"StationId":2,
"DpId":20013,
"Name":"cmdAnlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Kurzzeit":{
"StationId":2,
"DpId":20104,
"Name":"Kurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteKurzzeit":{
"StationId":2,
"DpId":20012,
"Name":"cmdKurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Handbetrieb":{
"StationId":2,
"DpId":20160,
"Name":"Handbetrieb",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Betriebsbereit":{
"StationId":2,
"DpId":20121,
"Name":"Betriebsbereit",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Heizt":{
"StationId":2,
"DpId":20451,
"Name":"Heizt",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Sammelstoerung":{
"StationId":2,
"DpId":20140,
"Name":"Sammelstoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"SammelstoerungTechnisch":{
"StationId":2,
"DpId":20129,
"Name":"SammelstoerungTechnisch",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerung":{
"StationId":2,
"DpId":20138,
"Name":"KommunikationsStoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerungKE":{
"StationId":2,
"DpId":20137,
"Name":"KommunikationsStoerungKE",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"AllowCommands":true,
"AllowParameters":true
},
{
"StationId":4,
"Text":"Test W 1",
"IsDialInStation":false,
"ConnectState":{
"StationId":4,
"DpId":14,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1402996083000)\/"
},
"ConnectStateText":"Nicht verbunden. Hier klicken für Anwahl!",
"HasActualData":{
"StationId":4,
"DpId":10,
"Name":null,
"Value":0,
"TimeStamp":"\/Date(1404890134000)\/"
},
"Anlage":{
"StationId":4,
"DpId":20101,
"Name":"Anlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteAnlage":{
"StationId":4,
"DpId":20013,
"Name":"cmdAnlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Kurzzeit":{
"StationId":4,
"DpId":20104,
"Name":"Kurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteKurzzeit":{
"StationId":4,
"DpId":20012,
"Name":"cmdKurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Handbetrieb":{
"StationId":4,
"DpId":20160,
"Name":"Handbetrieb",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Betriebsbereit":{
"StationId":4,
"DpId":20121,
"Name":"Betriebsbereit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Heizt":{
"StationId":4,
"DpId":20451,
"Name":"Heizt",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Sammelstoerung":{
"StationId":4,
"DpId":20140,
"Name":"Sammelstoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"SammelstoerungTechnisch":{
"StationId":4,
"DpId":20129,
"Name":"SammelstoerungTechnisch",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerung":{
"StationId":4,
"DpId":20138,
"Name":"KommunikationsStoerung",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerungKE":{
"StationId":4,
"DpId":20137,
"Name":"KommunikationsStoerungKE",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"AllowCommands":true,
"AllowParameters":true
},
{
"StationId":3,
"Text":"Test W 2",
"IsDialInStation":false,
"ConnectState":{
"StationId":3,
"DpId":14,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1402996031000)\/"
},
"ConnectStateText":"Nicht verbunden. Hier klicken für Anwahl!",
"HasActualData":{
"StationId":3,
"DpId":10,
"Name":null,
"Value":1,
"TimeStamp":"\/Date(1405488343000)\/"
},
"Anlage":{
"StationId":3,
"DpId":20101,
"Name":"Anlage",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteAnlage":{
"StationId":3,
"DpId":20013,
"Name":"cmdAnlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Kurzzeit":{
"StationId":3,
"DpId":20104,
"Name":"Kurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"cmdSchalteKurzzeit":{
"StationId":3,
"DpId":20012,
"Name":"cmdKurzzeit",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Handbetrieb":{
"StationId":3,
"DpId":20160,
"Name":"Handbetrieb",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Betriebsbereit":{
"StationId":3,
"DpId":20121,
"Name":"Betriebsbereit",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Heizt":{
"StationId":3,
"DpId":20451,
"Name":"Heizt",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"Sammelstoerung":{
"StationId":3,
"DpId":20140,
"Name":"Sammelstoerung",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"SammelstoerungTechnisch":{
"StationId":3,
"DpId":20129,
"Name":"SammelstoerungTechnisch",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerung":{
"StationId":3,
"DpId":20138,
"Name":"KommunikationsStoerung",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"KommunikationsStoerungKE":{
"StationId":3,
"DpId":20137,
"Name":"KommunikationsStoerungKE",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/"
},
"AllowCommands":true,
"AllowParameters":true
}
]
}
答案 0 :(得分:2)
我已经使用OpenLayers做到了这一点,所以这个答案可能不是最好的,但它可能会让你深入了解如何采用标记的视图模型并将其“绑定”到地图上以便任何更改视图模型反映在地图上。对我而言,关键是编写一个呈现航路点的订户功能。
这是我的基本视图模型。我称它们为航点,但它们是OpenLayers.Geometry.Point对象,所以我愿意猜测它们与Leaflet标记类似。
G.WaypointsViewModel = function() {
// The list of waypoints.
this.waypoints = ko.observableArray([])
}
我建立了这样的订户;评论来自我的实际代码,所以我猜我们都遇到了同样的问题!
// We cannot bind the OpenLayers line that links these waypoints to the
// waypoint list, so we need a manual subscription to update the line.
this.waypoints.subscribe(function(new_waypoints) {
}
理想情况下,我会编写一些聪明的代码来解决视图模型中发生了哪些变化,并且只进行正确的更新,但为了简单起见,我的函数所做的第一件事是摆脱所有当前的航点:
this.waypoints.subscribe(function(new_waypoints) {
// Don't continue with an empty array.
if (new_waypoints.length == 0) return
// Get rid of the current drawings.
this.removeMarkers()
...
在OpenLayers中,删除标记很容易;我只是在代表标记层的变量上调用destroyFeatures:
this.marker_layer = new OpenLayers.Layer.Vector("Markers Layer", {
style: G.default_line_style
})
this.removeMarkers = function() {
marker_layer.destroyFeatures()
}
然后我重新绘制所有标记:
while (waypoint = this.waypoints()[i]) {
marker = new OpenLayers.Feature.Vector(
waypoint, {type: 'waypoint', index: i}
)
this.marker_layer.addFeatures(marker)
// Next...
i++
}
现在这已全部设置,用户在应用程序中执行的任何导致航点更改的内容(例如删除航点,移动航点等)都意味着地图会由KO订户自动更新。
这个视图模型的完整代码(其他一些事情正在进行中)在这里:
http://simonlikesmaps.appspot.com/js/app/view_models/G.WaypointsViewModel.js
使用它的应用程序在这里:
http://simonlikesmaps.appspot.com/
希望通过Leaflet为您提供相同的灵感。
事实上,我一直想阅读Leaflet一段时间,所以我去阅读,并将上面的模式描绘成一个应该与Leaflet一起使用的ViewModel。警告 - 这是未经测试的 - 所以肯定会有一些错误!
MarkersVM = function() {
// Create leaflet map
this.map = L.map('map').setView([51.505, -0.09], 13);
// Add a marker layer
this.addMarkerLayer();
// Turn your JSON into an array of station, each with a lat/lon
this.markers = ko.observableArray([
{
"StationId":1,
"DpId":20101,
"Name":"Anlage",
"Value":1,
"TimeStamp":"\/Date(-62135596800000)\/",
"lat": "51",
"lon": "0"
},
{
"StationId":1,
"DpId":20013,
"Name":"cmdAnlage",
"Value":0,
"TimeStamp":"\/Date(-62135596800000)\/",
"lat": "52",
"lon": "1"
},
]);
// Subscribe to the array, to redraw the map.
this.markers.subscribe(function(new_markers) {
// Don't bother with an empty array
if (new_markers.length == 0) return;
// Start be removing all current markers; to do this, remove the marker layer.
map.removeLayer(this.markers);
// Add a fresh marker layer.
this.addMarkerLayer();
// Now add the points.
var i = 0, marker;
while (station = this.markers()[i]) {
var marker = L.marker(station.lat, station.lon)
// You can manipulate the marker here, eg add the name, the text, etc
this.markers.add(marker);
}
}, this);
this.addMarkerLayer = function() {
this.markers = new L.FeatureGroup();
map.addLayer(this.markers);
}
}
这样,对JSON所做的任何更改都将更改视图模型中的markers数组,通过订阅函数将销毁地图上的标记,然后绘制新标记,确保新信息自动显示在地图中。