在 Cesium.js 中使用 GeoJsonDataSource 加载更新数据
Loading updated data with GeoJsonDataSource in Cesium.js
我正在尝试将 Cesium 1.11 与现有后端发送 GeoJSON 集成。我能够从第一条消息成功地将数据加载到视图中,但是对 load() 的后续调用不会更新显示。
我已将问题简化为以下内容,也可作为 fiddle 使用。
- 我预计第二次加载调用会更新显示以将标记移至纽约,但它仍保留在伦敦。
- 特征 window 仍然显示 "foo" 属性 为 123,我预计是 456。
代码
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
viewer.dataSources.add(source);
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 123,
},
geometry: {
type: "Point",
coordinates: [0.1275, 51.5072] // London
},
id: "123"
}]
});
// workaround, but has side effect of destroying feature window
// source.entities.removeAll();
// sometime later...
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 456,
},
geometry: {
type: "Point",
coordinates: [-75.1890, 42.3482] // New York
},
id: "123"
}]
});
我试过的
"forced" 通过调用 source.entities.removeAll()
进行更新,但是如果它在更新期间处于打开状态,这会产生关闭功能 window 的副作用。我每秒都收到消息,所以这是不可取的。
是的,我知道专有的 CZML 系统,但是对于这个相对简单的系统,我想坚持使用 GeoJSON。
更新:进一步调试。这个问题似乎是一个设计特征...
- GeoJsonDataSource 中的 load() 辅助方法调用
that._entityCollection.removeAll()
。这是在 suspendEvents() 和 resumeEvents() 之间,因此不会导致功能 window 关闭。
- 在 resumeEvents() "change" 事件被触发后,即使实际上已经重新创建了实体
- 由 Cesium.Viewer 创建的现有 BillboardVisualizer 将缓存实例保存到它第一次呈现时使用的实体
- BillboardVisualizer.update() 一直从 'stale' 实体实例中读取第一个位置,因此没有看到更新。
这看起来像是 Cesium 中的错误我刚刚提交了问题 #2891 and will try and get a fix into the 1.12 release on August 3rd. In the meantime, you should be able to workaround the issue using your removeAll
strategy combined with resetting the selected entity after the load (which should keep the InfoBox around, which is what I assume you mean by feature window.) Here's a complete example that you can based into Sandcastle 以查看它的实际效果。
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
viewer.dataSources.add(source);
Sandcastle.addToolbarButton('Load 1', function(){
source.entities.removeAll();
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 123
},
geometry: {
type: "Point",
coordinates: [0.1275, 51.5072] // London
},
id: "123"
}]
}).then(function(){
viewer.selectedEntity = source.entities.values[0];
});
});
Sandcastle.addToolbarButton('Load 2', function() {
source.entities.removeAll();
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 456
},
geometry: {
type: "Point",
coordinates: [-75.1890, 42.3482] // New York
},
id: "123"
}]
}).then(function(){
viewer.selectedEntity = source.entities.values[0];
});
});
另一种解决方案是仅使用 GeoJsonDataSource 从 JSON 创建实体,然后将 adding/updating 手动添加到查看器全局实体集合
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
// don't add source to viewer
source.load(...);
// sometime later...
source.load(...);
// manually update
viewer.entities.suspendEvents();
source.entities.values.forEach(function(entity) {
var existing = viewer.entities.getById(entity.id);
if (existing === undefined) {
viewer.entities.add(entity);
} else {
entity.propertyNames.forEach(function(name) {
existing[name] = entity[name];
});
}
}, this);
viewer.entities.resumeEvents();
我正在尝试将 Cesium 1.11 与现有后端发送 GeoJSON 集成。我能够从第一条消息成功地将数据加载到视图中,但是对 load() 的后续调用不会更新显示。
我已将问题简化为以下内容,也可作为 fiddle 使用。
- 我预计第二次加载调用会更新显示以将标记移至纽约,但它仍保留在伦敦。
- 特征 window 仍然显示 "foo" 属性 为 123,我预计是 456。
代码
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
viewer.dataSources.add(source);
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 123,
},
geometry: {
type: "Point",
coordinates: [0.1275, 51.5072] // London
},
id: "123"
}]
});
// workaround, but has side effect of destroying feature window
// source.entities.removeAll();
// sometime later...
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 456,
},
geometry: {
type: "Point",
coordinates: [-75.1890, 42.3482] // New York
},
id: "123"
}]
});
我试过的
"forced" 通过调用
source.entities.removeAll()
进行更新,但是如果它在更新期间处于打开状态,这会产生关闭功能 window 的副作用。我每秒都收到消息,所以这是不可取的。是的,我知道专有的 CZML 系统,但是对于这个相对简单的系统,我想坚持使用 GeoJSON。
更新:进一步调试。这个问题似乎是一个设计特征...
- GeoJsonDataSource 中的 load() 辅助方法调用
that._entityCollection.removeAll()
。这是在 suspendEvents() 和 resumeEvents() 之间,因此不会导致功能 window 关闭。 - 在 resumeEvents() "change" 事件被触发后,即使实际上已经重新创建了实体
- 由 Cesium.Viewer 创建的现有 BillboardVisualizer 将缓存实例保存到它第一次呈现时使用的实体
- BillboardVisualizer.update() 一直从 'stale' 实体实例中读取第一个位置,因此没有看到更新。
这看起来像是 Cesium 中的错误我刚刚提交了问题 #2891 and will try and get a fix into the 1.12 release on August 3rd. In the meantime, you should be able to workaround the issue using your removeAll
strategy combined with resetting the selected entity after the load (which should keep the InfoBox around, which is what I assume you mean by feature window.) Here's a complete example that you can based into Sandcastle 以查看它的实际效果。
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
viewer.dataSources.add(source);
Sandcastle.addToolbarButton('Load 1', function(){
source.entities.removeAll();
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 123
},
geometry: {
type: "Point",
coordinates: [0.1275, 51.5072] // London
},
id: "123"
}]
}).then(function(){
viewer.selectedEntity = source.entities.values[0];
});
});
Sandcastle.addToolbarButton('Load 2', function() {
source.entities.removeAll();
source.load({
type: "FeatureCollection",
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
features: [{
type: "Feature",
properties: {
foo: 456
},
geometry: {
type: "Point",
coordinates: [-75.1890, 42.3482] // New York
},
id: "123"
}]
}).then(function(){
viewer.selectedEntity = source.entities.values[0];
});
});
另一种解决方案是仅使用 GeoJsonDataSource 从 JSON 创建实体,然后将 adding/updating 手动添加到查看器全局实体集合
var viewer = new Cesium.Viewer('cesiumContainer');
var source = new Cesium.GeoJsonDataSource("name123");
// don't add source to viewer
source.load(...);
// sometime later...
source.load(...);
// manually update
viewer.entities.suspendEvents();
source.entities.values.forEach(function(entity) {
var existing = viewer.entities.getById(entity.id);
if (existing === undefined) {
viewer.entities.add(entity);
} else {
entity.propertyNames.forEach(function(name) {
existing[name] = entity[name];
});
}
}, this);
viewer.entities.resumeEvents();