diff --git a/sno/diff-view.html b/sno/diff-view.html
index e56d3ffa5..9679d8577 100644
--- a/sno/diff-view.html
+++ b/sno/diff-view.html
@@ -125,8 +125,8 @@
}).addTo(map)
var layerGroup = L.featureGroup()
- for (let [dataset, diff] of Object.entries(DATA['sno.diff/v1+hexwkb'])) {
- if (!diff.featureChanges.length) {
+ for (let [dataset, diff] of Object.entries(DATA)) {
+ if (!diff.features.length) {
continue
}
@@ -139,16 +139,18 @@
layers[dataset] = {}
featureMap[dataset] = {}
- for (let change of diff.featureChanges) {
- const fOld = change['-']
- const fNew = change['+']
- if (fOld && fNew) {
- fc['updateOld'].push(fOld)
- fc['updateNew'].push(fNew)
- } else if (fOld) {
- fc['delete'].push(fOld)
- } else if (fNew) {
- fc['insert'].push(fNew)
+ for (let change of diff.features) {
+ const id = change['id']
+ if (id.startsWith('U+::')) {
+ fc['updateNew'].push(change)
+ } else if (id.startsWith('U-::')) {
+ fc['updateOld'].push(change)
+ } else if (id.startsWith('D::')) {
+ fc['delete'].push(change)
+ } else if (id.startsWith('I::')) {
+ fc['insert'].push(change)
+ } else {
+ console.log('unknown ID format: ' + id)
}
}
@@ -224,14 +226,40 @@
}
selectedFeature = [row, f]
}
+ function getFeaturesByRealId(diff) {
+ let featuresByRealId = {}
+ for (let fc of diff.features) {
+ const id = fc['id']
+ const realId = id.split('::')[1]
+ if (id.startsWith('U')) {
+ if (!featuresByRealId[realId]) {
+ featuresByRealId[realId] = [null, null]
+ }
+ if (id.startsWith('U+::')) {
+ // 'new'
+ featuresByRealId[realId][1] = fc
+ } else {
+ // 'old'
+ featuresByRealId[realId][0] = fc
+ }
+ } else if (id.startsWith('D::')) {
+ featuresByRealId[realId] = [fc, null]
+ } else if (id.startsWith('I::')) {
+ featuresByRealId[realId] = [fc, null]
+ } else {
+ console.log('unknown ID format: ' + id)
+ continue
+ }
+ }
+ return featuresByRealId
+ }
- function getSchema(diff) {
+ function getSchema(featuresByRealId) {
// if schema has changed then it'll show up in every single feature
let oldSchema = null
let newSchema = null
- for (let change of diff.featureChanges) {
- const fOld = change['-']
- const fNew = change['+']
+ for (let [realId, change] of Object.entries(featuresByRealId)) {
+ let [fOld, fNew] = change
if (fOld && !oldSchema) {
oldSchema = Object.keys(fOld.properties)
oldSchema.splice(0, 0, GEOM)
@@ -273,8 +301,8 @@
return isArrayEqual(a.coordinates, b.coordinates)
}
- for (let [dataset, diff] of Object.entries(DATA['sno.diff/v1+hexwkb'])) {
- if (!diff.featureChanges.length) {
+ for (let [dataset, diff] of Object.entries(DATA)) {
+ if (!diff.features.length) {
continue
}
@@ -288,7 +316,8 @@
let thead = table.createTHead()
let row = thead.insertRow()
- let schema = getSchema(diff)
+ let features = getFeaturesByRealId(diff)
+ let schema = getSchema(features)
for (let col of schema) {
let th = document.createElement("th")
@@ -300,10 +329,9 @@
}
let tbody = table.createTBody()
- for (let fc of diff.featureChanges) {
- let fOld = fc['-']
- let fNew = fc['+']
- let change;
+ for (let [realId, fc] of Object.entries(features)) {
+ let [fOld, fNew] = fc
+ let change
if (fOld && fNew) {
change = 'update'
} else if (fOld) {
@@ -311,7 +339,6 @@
} else {
change = 'insert'
}
-
fOld = fOld || {properties: {}}
fNew = fNew || {properties: {}}
let oldRow = document.createElement('tr')
diff --git a/sno/diff_output.py b/sno/diff_output.py
index 5429aa31e..fec460398 100644
--- a/sno/diff_output.py
+++ b/sno/diff_output.py
@@ -1,13 +1,14 @@
import contextlib
import io
import json
+import os
import string
import sys
+import tempfile
import webbrowser
from pathlib import Path
import click
-from osgeo import ogr
from . import gpkg
from .output_util import dump_json_output, resolve_output_path
@@ -154,7 +155,7 @@ def repr_row(row, prefix="", exclude=None):
@contextlib.contextmanager
-def diff_output_geojson(*, output_path, dataset_count, json_style, **kwargs):
+def diff_output_geojson(*, output_path, dataset_count, json_style='pretty', **kwargs):
"""
Contextmanager.
@@ -196,6 +197,8 @@ def diff_output_geojson(*, output_path, dataset_count, json_style, **kwargs):
def _out(dataset, diff):
if not output_path or output_path == '-':
fp = sys.stdout
+ elif isinstance(output_path, io.StringIO):
+ fp = output_path
elif output_path.is_dir():
fp = (output_path / f"{dataset.name}.geojson").open("w")
else:
@@ -343,13 +346,6 @@ def diff_output_html(*, output_path, repo, base, target, dataset_count, **kwargs
raise click.BadParameter(
"Directory is not valid for --output with --html", param_hint="--output"
)
-
- json_data = io.StringIO()
- with diff_output_json(
- output_path=json_data, dataset_count=dataset_count
- ) as json_writer:
- yield json_writer
-
with open(
Path(__file__).resolve().with_name("diff-view.html"), "r", encoding="utf8"
) as ft:
@@ -357,13 +353,30 @@ def diff_output_html(*, output_path, repo, base, target, dataset_count, **kwargs
title = f"{Path(repo.path).name}: {base.short_id} .. {target.short_id if target else 'working-copy'}"
- if not output_path:
- output_path = Path(repo.path) / "DIFF.html"
- fo = resolve_output_path(output_path)
+ with tempfile.TemporaryDirectory() as tempdir:
+ tempdir = Path(tempdir)
+ # Write a bunch of geojson files to a temporary directory
+ with diff_output_geojson(
+ output_path=tempdir, dataset_count=dataset_count, json_style="extracompact",
+ ) as json_writer:
+ yield json_writer
- fo.write(
- template.substitute({"title": title, "geojson_data": json_data.getvalue()})
- )
+ if not output_path:
+ output_path = Path(repo.path) / "DIFF.html"
+ fo = resolve_output_path(output_path)
+
+ # Read all the geojson back in, and stick them in a dict
+ all_datasets_geojson = {}
+ for filename in os.listdir(tempdir):
+ with open(tempdir / filename) as json_file:
+ all_datasets_geojson[os.path.splitext(filename)[0]] = json.load(
+ json_file
+ )
+ fo.write(
+ template.substitute(
+ {"title": title, "geojson_data": json.dumps(all_datasets_geojson)}
+ )
+ )
if fo != sys.stdout:
fo.close()
webbrowser.open_new(f"file://{output_path.resolve()}")