Various fixes
This commit is contained in:
parent
18044ff22b
commit
07fd8f404a
14 changed files with 154 additions and 60 deletions
|
@ -10,6 +10,10 @@ export class BBox {
|
|||
readonly minLat: number;
|
||||
readonly minLon: number;
|
||||
|
||||
/***
|
||||
* Coordinates should be [[lon, lat],[lon, lat]]
|
||||
* @param coordinates
|
||||
*/
|
||||
constructor(coordinates) {
|
||||
this.maxLat = -90;
|
||||
this.maxLon = -180;
|
||||
|
@ -45,6 +49,21 @@ export class BBox {
|
|||
return feature.bbox;
|
||||
}
|
||||
|
||||
static bboxAroundAll(bboxes: BBox[]): BBox{
|
||||
let maxLat: number = -90;
|
||||
let maxLon: number= -180;
|
||||
let minLat: number= 80;
|
||||
let minLon: number= 180;
|
||||
|
||||
for (const bbox of bboxes) {
|
||||
maxLat = Math.max(maxLat, bbox.maxLat)
|
||||
maxLon = Math.max(maxLon, bbox.maxLon)
|
||||
minLat = Math.min(minLat, bbox.minLat)
|
||||
minLon = Math.min(minLon, bbox.minLon)
|
||||
}
|
||||
return new BBox([[maxLon, maxLat],[minLon,minLat]])
|
||||
}
|
||||
|
||||
static fromTile(z: number, x: number, y: number): BBox {
|
||||
return new BBox(Tiles.tile_bounds_lon_lat(z, x, y))
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface ExtraFuncParams {
|
|||
*/
|
||||
getFeaturesWithin: (layerId: string, bbox: BBox) => any[][],
|
||||
memberships: RelationsTracker
|
||||
getFeatureById: (id:string) => any
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,20 +80,19 @@ class DistanceToFunc implements ExtraFunction {
|
|||
}
|
||||
if (typeof arg0 === "number") {
|
||||
// Feature._lon and ._lat is conveniently place by one of the other metatags
|
||||
return GeoOperations.distanceBetween([arg0, lat], [feature._lon, feature._lat]);
|
||||
return GeoOperations.distanceBetween([arg0, lat], GeoOperations.centerpointCoordinates(feature));
|
||||
}
|
||||
if (typeof arg0 === "string") {
|
||||
// This is an identifier
|
||||
// TODO FIXME
|
||||
const feature = undefined // State.state.allElements.ContainingFeatures.get(arg0);
|
||||
const feature = featuresPerLayer.getFeatureById(arg0)
|
||||
if (feature === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
arg0 = feature;
|
||||
}
|
||||
|
||||
// arg0 is probably a feature
|
||||
return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), [feature._lon, feature._lat])
|
||||
// arg0 is probably a geojsonfeature
|
||||
return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), GeoOperations.centerpointCoordinates(feature))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -448,11 +448,12 @@ export default class FeaturePipeline {
|
|||
window.setTimeout(
|
||||
() => {
|
||||
const layerDef = src.layer.layerDef;
|
||||
const somethingChanged = MetaTagging.addMetatags(
|
||||
MetaTagging.addMetatags(
|
||||
src.features.data,
|
||||
{
|
||||
memberships: this.relationTracker,
|
||||
getFeaturesWithin: (layerId, bbox: BBox) => self.GetFeaturesWithin(layerId, bbox)
|
||||
getFeaturesWithin: (layerId, bbox: BBox) => self.GetFeaturesWithin(layerId, bbox),
|
||||
getFeatureById: (id:string) => self.state.allElements.ContainingFeatures.get(id)
|
||||
},
|
||||
layerDef,
|
||||
{
|
||||
|
|
|
@ -178,8 +178,6 @@ export default class MetaTagging {
|
|||
|
||||
try {
|
||||
const functions = MetaTagging.createFunctionsForFeature(layer.id, calculatedTags)
|
||||
|
||||
|
||||
ExtraFunctions.FullPatchFeature(params, feature);
|
||||
for (const f of functions) {
|
||||
f(feature);
|
||||
|
|
|
@ -8,6 +8,7 @@ import {UIEventSource} from "../UIEventSource";
|
|||
import MapState from "./MapState";
|
||||
import SelectedFeatureHandler from "../Actors/SelectedFeatureHandler";
|
||||
import Hash from "../Web/Hash";
|
||||
import {BBox} from "../BBox";
|
||||
|
||||
export default class FeaturePipelineState extends MapState {
|
||||
|
||||
|
@ -29,6 +30,8 @@ export default class FeaturePipelineState extends MapState {
|
|||
|
||||
clusterCounter.addTile(source)
|
||||
|
||||
const sourceBBox = source.features.map(allFeatures => BBox.bboxAroundAll(allFeatures.map(f => BBox.get(f.feature))))
|
||||
|
||||
// Do show features indicates if the 'showDataLayer' should be shown
|
||||
const doShowFeatures = source.features.map(
|
||||
f => {
|
||||
|
@ -44,7 +47,7 @@ export default class FeaturePipelineState extends MapState {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!source.bbox.overlapsWith(bounds)) {
|
||||
if (!sourceBBox.data.overlapsWith(bounds)) {
|
||||
// Not within range -> features are hidden
|
||||
return false
|
||||
}
|
||||
|
@ -81,7 +84,7 @@ export default class FeaturePipelineState extends MapState {
|
|||
|
||||
|
||||
return true
|
||||
}, [this.currentBounds, source.layer.isDisplayed]
|
||||
}, [this.currentBounds, source.layer.isDisplayed, sourceBBox]
|
||||
)
|
||||
|
||||
new ShowDataLayer(
|
||||
|
|
|
@ -2,7 +2,7 @@ import {Utils} from "../Utils";
|
|||
|
||||
export default class Constants {
|
||||
|
||||
public static vNumber = "0.13.0-alpha-2";
|
||||
public static vNumber = "0.13.0-alpha-3";
|
||||
public static ImgurApiKey = '7070e7167f0a25a'
|
||||
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ export default class DependencyCalculator {
|
|||
let currentKey = undefined
|
||||
let currentLine = undefined
|
||||
const params: ExtraFuncParams = {
|
||||
getFeatureById: _ => undefined,
|
||||
getFeaturesWithin: (layerId, _) => {
|
||||
|
||||
if(layerId === '*'){
|
||||
|
|
|
@ -219,7 +219,7 @@ export interface LayoutConfigJson {
|
|||
* If clustering is defined, defaults to 25
|
||||
*/
|
||||
minNeededElements?: number
|
||||
},
|
||||
} | false,
|
||||
|
||||
/**
|
||||
* The URL of a custom CSS stylesheet to modify the layout
|
||||
|
|
|
@ -5,9 +5,9 @@ export default class SourceConfig {
|
|||
|
||||
public readonly osmTags?: TagsFilter;
|
||||
public readonly overpassScript?: string;
|
||||
public readonly geojsonSource?: string;
|
||||
public readonly geojsonZoomLevel?: number;
|
||||
public readonly isOsmCacheLayer: boolean;
|
||||
public geojsonSource?: string;
|
||||
public geojsonZoomLevel?: number;
|
||||
public isOsmCacheLayer: boolean;
|
||||
public readonly mercatorCrs: boolean;
|
||||
|
||||
constructor(params: {
|
||||
|
|
2
Utils.ts
2
Utils.ts
|
@ -212,7 +212,7 @@ Note that these values can be prepare with javascript in the theme by using a [c
|
|||
}
|
||||
|
||||
if(v.InnerConstructElement !== undefined){
|
||||
console.warn("SubstituteKeys received a BaseUIElement to substitute in - this is probably a bug and will be downcast to a string", v)
|
||||
console.warn("SubstituteKeys received a BaseUIElement to substitute in - this is probably a bug and will be downcast to a string\nThe key is", key,"\nThe value is", v)
|
||||
v = ( <HTMLElement> v.InnerConstructElement())?.innerText
|
||||
}
|
||||
|
||||
|
|
12
assets/themes/postal_codes/license_info.json
Normal file
12
assets/themes/postal_codes/license_info.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{
|
||||
"path": "townhall.svg",
|
||||
"license": "CC0",
|
||||
"authors": [
|
||||
"Nebulon42"
|
||||
],
|
||||
"sources": [
|
||||
"https://wiki.openstreetmap.org/wiki/File:Town-hall-16.svg"
|
||||
]
|
||||
}
|
||||
]
|
|
@ -13,7 +13,7 @@
|
|||
"en"
|
||||
],
|
||||
"maintainer": "",
|
||||
"icon": "./assets/svg/bug.svg",
|
||||
"icon": "./assets/themes/postal_codes/townhall.svg",
|
||||
"version": "0",
|
||||
"startLat": 0,
|
||||
"startLon": 0,
|
||||
|
@ -21,13 +21,15 @@
|
|||
"widenFactor": 0.05,
|
||||
"socialImage": "",
|
||||
"hideFromOverview": true,
|
||||
"clustering": false,
|
||||
"overpassTimeout": 180,
|
||||
"layers": [
|
||||
{
|
||||
"id": "postal_codes",
|
||||
"id": "postal_code_boundary",
|
||||
"name": {
|
||||
"en": "postal codes"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"minzoom": 8,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "Postal code {postal_code}"
|
||||
|
@ -42,11 +44,7 @@
|
|||
}
|
||||
}
|
||||
],
|
||||
"presets": [],
|
||||
"source": {
|
||||
"isOsmCache": true,
|
||||
"geoJson": "http://127.0.0.1:8080/postal_codes_postal_codes_{z}_{x}_{y}.geojson",
|
||||
"geoJsonZoomLevel": 1,
|
||||
"osmTags": {
|
||||
"or": [
|
||||
"boundary=postal_code",
|
||||
|
@ -61,12 +59,7 @@
|
|||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "./assets/svg/bug.svg"
|
||||
},
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
"label": "<div class='text-xl bg-white rounded-full pl-2 pr-2 break-normal'>{postal_code}</div>",
|
||||
"location": [
|
||||
"point",
|
||||
"centroid"
|
||||
|
@ -77,8 +70,10 @@
|
|||
"render": "#00f"
|
||||
},
|
||||
"width": {
|
||||
"render": "8"
|
||||
}
|
||||
"render": "4"
|
||||
},
|
||||
"fill": "no",
|
||||
"dashArray": "8 8"
|
||||
}
|
||||
],
|
||||
"isShown": {
|
||||
|
@ -90,34 +85,30 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"id": "town_halls",
|
||||
"id": "town_hall",
|
||||
"name": {
|
||||
"en": "town halls"
|
||||
},
|
||||
"minzoom": 12,
|
||||
"title": {
|
||||
"render": {
|
||||
"en": "Town halls"
|
||||
"en": "Town hall {name}"
|
||||
}
|
||||
},
|
||||
"calculatedTags": [
|
||||
"_postal_code=feat.overlapWith('postal_codes')[0]?.feat?.properties?.postal_code"
|
||||
],
|
||||
"_postal_code_properties=(() => { const f = feat.overlapWith('postal_code_boundary'); if(f.length===0){return {};}; const p = f[0]?.feat?.properties; return {id:p.id, postal_code: p.postal_code, _closest_town_hall: p._closest_town_hall}; })()",
|
||||
"_postal_code=feat.get('_postal_code_properties')?.postal_code",
|
||||
"_postal_code_center_distance=feat.distanceTo(feat.get('_postal_code_properties').id)"
|
||||
],
|
||||
"description": {},
|
||||
"tagRenderings": [
|
||||
],
|
||||
"presets": [],
|
||||
"source": {
|
||||
"isOsmCache": true,
|
||||
"geoJson": "http://127.0.0.1:8080/postal_codes_town_hall_{z}_{x}_{y}.geojson",
|
||||
"geoJsonZoomLevel": 1,
|
||||
"osmTags": "amenity=townhall"
|
||||
},
|
||||
"mapRendering": [
|
||||
{
|
||||
"icon": {
|
||||
"render": "./assets/svg/bug.svg"
|
||||
},
|
||||
{ "icon": "./assets/themes/postal_codes/townhall.svg",
|
||||
"iconSize": {
|
||||
"render": "40,40,center"
|
||||
},
|
||||
|
@ -125,14 +116,6 @@
|
|||
"point",
|
||||
"centroid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"color": {
|
||||
"render": "#00f"
|
||||
},
|
||||
"width": {
|
||||
"render": "8"
|
||||
}
|
||||
}
|
||||
],
|
||||
"isShown": {
|
25
assets/themes/postal_codes/townhall.svg
Normal file
25
assets/themes/postal_codes/townhall.svg
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
id="svg2">
|
||||
<metadata id="metadata8">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs6"/>
|
||||
<rect width="16" height="16" x="0" y="0" id="canvas" style="fill:none;stroke:none;visibility:hidden"/>
|
||||
<path d="M 7,0 C 6.75,0.0032 6.5,0.1644239 6.5,0.5 L 6.5,4.375 1,7 13,7 7.5,4.375 7.5,0.5 C 7.5,0.1516409 7.25,-0.0031957 7,0 z M 8,0 8,3 12,3 10,1.5 12,0 z m -7,8 0,1 1,0 0,4 -1,0 0,1 12,0 0,-1 -1,0 0,-4 1,0 0,-1 z m 6,1.5 c 1,0 2,0.5 2,1.5 l 0,2 -4,0 0,-2 C 5,10 6,9.5 7,9.5 z" id="town-hall" style="fill:#734a08;fill-opacity:1;stroke:none" transform="translate(1,1)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -24,7 +24,6 @@ import {GeoOperations} from "../Logic/GeoOperations";
|
|||
import SimpleMetaTaggers from "../Logic/SimpleMetaTagger";
|
||||
import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource";
|
||||
import Loc from "../Models/Loc";
|
||||
|
||||
ScriptUtils.fixUtils()
|
||||
|
||||
|
||||
|
@ -181,6 +180,23 @@ function loadAllTiles(targetdir: string, r: TileRange, theme: LayoutConfig, extr
|
|||
function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relationsTracker: RelationsTracker, targetdir: string, pointsOnlyLayers: string[]) {
|
||||
const skippedLayers = new Set<string>()
|
||||
|
||||
const indexedFeatures : Map<string, any> = new Map<string, any>()
|
||||
let indexisBuilt = false;
|
||||
function buildIndex(){
|
||||
for (const ff of allFeatures.features.data) {
|
||||
const f = ff.feature
|
||||
indexedFeatures.set(f.properties.id, f)
|
||||
}
|
||||
indexisBuilt = true;
|
||||
}
|
||||
|
||||
function getFeatureById(id){
|
||||
if(!indexisBuilt){
|
||||
buildIndex()
|
||||
}
|
||||
return indexedFeatures.get(id)
|
||||
}
|
||||
|
||||
async function handleLayer(source: FeatureSourceForLayer) {
|
||||
const layer = source.layer.layerDef;
|
||||
const targetZoomLevel = layer.source.geojsonZoomLevel ?? 0
|
||||
|
@ -199,7 +215,8 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
|
|||
memberships: relationsTracker,
|
||||
getFeaturesWithin: _ => {
|
||||
return [allFeatures.features.data.map(f => f.feature)]
|
||||
}
|
||||
},
|
||||
getFeatureById: getFeatureById
|
||||
},
|
||||
layer,
|
||||
{
|
||||
|
@ -237,6 +254,7 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
|
|||
new UIEventSource<any>(undefined)
|
||||
)
|
||||
|
||||
console.log("Tile "+layer.id+"."+tileIndex+" contains "+filteredTile.features.data.length+" features after filtering ("+tile.features.data.length+") features before")
|
||||
if (filteredTile.features.data.length === 0) {
|
||||
return
|
||||
}
|
||||
|
@ -252,7 +270,7 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
|
|||
const calculatedTagKeys = tile.layer.layerDef.calculatedTags.map(ct => ct[0])
|
||||
featureCount++
|
||||
for (const calculatedTagKey of calculatedTagKeys) {
|
||||
const strict = feature.feature.properties[calculatedTagKey]
|
||||
const strict = feature.feature.properties[calculatedTagKey]
|
||||
feature.feature.properties[calculatedTagKey] =strict
|
||||
strictlyCalculated ++;
|
||||
if(strictlyCalculated % 100 === 0){
|
||||
|
@ -292,7 +310,18 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
|
|||
|
||||
// And, if needed, to create a points-only layer
|
||||
if (pointsOnlyLayers.indexOf(layer.id) >= 0) {
|
||||
const features = source.features.data.map(f => f.feature)
|
||||
|
||||
const filtered = new FilteringFeatureSource({
|
||||
locationControl: new UIEventSource<Loc>(undefined),
|
||||
allElements: undefined,
|
||||
selectedElement: new UIEventSource<any>(undefined)
|
||||
},
|
||||
Tiles.tile_index(0,0,0),
|
||||
source,
|
||||
new UIEventSource<any>(undefined)
|
||||
)
|
||||
const features = filtered.features.data.map(f => f.feature)
|
||||
|
||||
const points = features.map(feature => GeoOperations.centerpoint(feature))
|
||||
console.log("Writing points overview for ", layerId)
|
||||
const targetPath = targetdir + "_" + layerId + "_points.geojson"
|
||||
|
@ -325,7 +354,7 @@ async function main(args: string[]) {
|
|||
|
||||
console.log("Cache builder started with args ", args.join(", "))
|
||||
if (args.length < 6) {
|
||||
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...]\n" +
|
||||
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...] [--force-zoom-level z] \n" +
|
||||
"Note: a new directory named <theme> will be created in targetdirectory")
|
||||
return;
|
||||
}
|
||||
|
@ -343,10 +372,7 @@ async function main(args: string[]) {
|
|||
const lat1 = Number(args[5])
|
||||
const lon1 = Number(args[6])
|
||||
|
||||
let generatePointLayersFor = []
|
||||
if (args[7] == "--generate-point-overview") {
|
||||
generatePointLayersFor = args[8].split(",")
|
||||
}
|
||||
|
||||
|
||||
|
||||
const tileRange = Tiles.TileRangeBetween(zoomlevel, lat0, lon0, lat1, lon1)
|
||||
|
@ -365,6 +391,32 @@ async function main(args: string[]) {
|
|||
console.error("The theme " + theme + " was not found; try one of ", keys);
|
||||
return
|
||||
}
|
||||
|
||||
let generatePointLayersFor = []
|
||||
if (args[7] == "--generate-point-overview") {
|
||||
if(args[8] === undefined){
|
||||
throw "--generate-point-overview needs a list of layers to generate the overview for (or * for all)"
|
||||
}else if (args[8] === '*'){
|
||||
generatePointLayersFor = theme.layers.map(l => l.id)
|
||||
}else{
|
||||
generatePointLayersFor = args[8].split(",")
|
||||
}
|
||||
console.log("Also generating a point overview for layers ", generatePointLayersFor.join(","))
|
||||
}
|
||||
{
|
||||
|
||||
const index = args.indexOf("--force-zoom-level")
|
||||
if(index >= 0){
|
||||
const forcedZoomLevel = Number(args[index + 1])
|
||||
for (const layer of theme.layers) {
|
||||
layer.source.geojsonSource = "https://127.0.0.1/cache_{layer}_{z}_{x}_{y}.geojson"
|
||||
layer.source.isOsmCacheLayer = true
|
||||
layer.source.geojsonZoomLevel = forcedZoomLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const relationTracker = new RelationsTracker()
|
||||
|
||||
let failed = 0;
|
||||
|
|
Loading…
Reference in a new issue