kopia lustrzana https://github.com/hholzgra/ocitysmap
fix Umap marker Icon rendering to work with both .fr and .de servers
rodzic
1c4e28fcb6
commit
ac4e730a5a
|
@ -37,6 +37,8 @@ import copy
|
||||||
from colour import Color
|
from colour import Color
|
||||||
from jsonpath_ng import parse
|
from jsonpath_ng import parse
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
import validators
|
||||||
|
import glob
|
||||||
|
|
||||||
LOG = logging.getLogger('ocitysmap')
|
LOG = logging.getLogger('ocitysmap')
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ def get_default_properties(json, umap_defaults, create_copy=True):
|
||||||
|
|
||||||
for path in ['$.properties.*', '$.properties._storage.*', '$._storage.*', '$.properties._storage_options.*', '$._storage_options.*', '$.properties._umap_options.*', '$._umap_options.*']:
|
for path in ['$.properties.*', '$.properties._storage.*', '$._storage.*', '$.properties._storage_options.*', '$._storage_options.*', '$.properties._umap_options.*', '$._umap_options.*']:
|
||||||
for key,value in flattened(json, path).items():
|
for key,value in flattened(json, path).items():
|
||||||
if key in ['opacity', 'fillOpacity', 'weight', 'dashArray', 'iconClass', 'iconUrl']:
|
if key in ['name', 'opacity', 'fillOpacity', 'weight', 'dashArray', 'iconClass', 'iconUrl']:
|
||||||
if value == True:
|
if value == True:
|
||||||
value = 'yes'
|
value = 'yes'
|
||||||
umap_defaults[key] = value
|
umap_defaults[key] = value
|
||||||
|
@ -89,6 +91,13 @@ def get_default_properties(json, umap_defaults, create_copy=True):
|
||||||
if create_copy:
|
if create_copy:
|
||||||
return umap_defaults
|
return umap_defaults
|
||||||
|
|
||||||
|
def _find_icon(basedir, basename):
|
||||||
|
for match in glob.glob("%s/%s*" % (basedir, basename)):
|
||||||
|
if os.path.isfile(match):
|
||||||
|
return match
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class UmapProcessor:
|
class UmapProcessor:
|
||||||
def __init__(self, umap_file):
|
def __init__(self, umap_file):
|
||||||
fp = codecs.open(umap_file, 'r', 'utf-8-sig')
|
fp = codecs.open(umap_file, 'r', 'utf-8-sig')
|
||||||
|
@ -131,7 +140,6 @@ class UmapProcessor:
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class UmapStylesheet(Stylesheet):
|
class UmapStylesheet(Stylesheet):
|
||||||
def __init__(self, umap_file, tmpdir):
|
def __init__(self, umap_file, tmpdir):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -164,11 +172,16 @@ class UmapStylesheet(Stylesheet):
|
||||||
self.path = style_filename
|
self.path = style_filename
|
||||||
|
|
||||||
def umap_preprocess(self, umap_file, tmpdir):
|
def umap_preprocess(self, umap_file, tmpdir):
|
||||||
icon_dir = os.path.realpath(
|
maki_icon_dir = os.path.realpath(
|
||||||
os.path.join(
|
os.path.join(
|
||||||
os.path.dirname(__file__),
|
os.path.dirname(__file__),
|
||||||
'../../templates/umap/maki/icons'))
|
'../../templates/umap/maki/icons'))
|
||||||
|
|
||||||
|
osmic_icon_dir = os.path.realpath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'../../templates/umap/osmic'))
|
||||||
|
|
||||||
umap_defaults = {
|
umap_defaults = {
|
||||||
'color' :'#0000ff',
|
'color' :'#0000ff',
|
||||||
'opacity' : 0.5,
|
'opacity' : 0.5,
|
||||||
|
@ -180,7 +193,8 @@ class UmapStylesheet(Stylesheet):
|
||||||
'stroke' : 'yes',
|
'stroke' : 'yes',
|
||||||
'name' : '',
|
'name' : '',
|
||||||
'iconClass' : 'Square',
|
'iconClass' : 'Square',
|
||||||
'iconUrl' : icon_dir + '/circle-15.svg',
|
'iconUrl' : maki_icon_dir + '/circle-15.svg',
|
||||||
|
'iconFill' : "white",
|
||||||
}
|
}
|
||||||
|
|
||||||
marker_offsets = {
|
marker_offsets = {
|
||||||
|
@ -225,60 +239,75 @@ class UmapStylesheet(Stylesheet):
|
||||||
|
|
||||||
# now go over the actual geometry features in that layer
|
# now go over the actual geometry features in that layer
|
||||||
for feature in layer['features']:
|
for feature in layer['features']:
|
||||||
# feature properties override previous defaults
|
try:
|
||||||
new_props = get_default_properties(feature, layer_defaults)
|
# feature properties override previous defaults
|
||||||
|
new_props = get_default_properties(feature, layer_defaults)
|
||||||
|
|
||||||
# POINT features require special handling as they actually
|
# POINT features require special handling as they actually
|
||||||
# usually represent a marker
|
# usually represent a marker
|
||||||
if feature['geometry']['type'] == 'Point':
|
if feature['geometry']['type'] == 'Point':
|
||||||
iconClass = layer_defaults['iconClass']
|
iconClass = new_props['iconClass']
|
||||||
iconUrl = layer_defaults['iconUrl']
|
iconUrl = new_props['iconUrl']
|
||||||
|
|
||||||
# if icon class is one of those used by Umap:
|
# if icon class is one of those used by Umap:
|
||||||
if iconClass in ['Square', 'Drop', 'Default']:
|
if iconClass in ['Square', 'Drop', 'Default']:
|
||||||
# check whether one of the default UMAP icons is used
|
# check whether one of the default UMAP icons is used
|
||||||
# by known URL pattern, or external
|
# by known URL pattern, or external
|
||||||
m = re.match(r'/uploads/pictogram/(.*)-24(.*)\.png', iconUrl)
|
if validators.url(iconUrl):
|
||||||
if m:
|
# external URL: use cached if present already,
|
||||||
# known UMAP icon URL -> replace with local files on our server
|
# otherwise download it and cache for later re-use
|
||||||
new_props['iconUrl'] = icon_dir + '/' + m.group(1) + "-15.svg"
|
if iconUrl in icon_cache:
|
||||||
if m.group(2) == '':
|
new_props['iconUrl'] = icon_cache[iconUrl]
|
||||||
new_props['iconFill'] = 'black'
|
else:
|
||||||
else:
|
try:
|
||||||
new_props['iconFill'] = 'white'
|
filename, file_extension = os.path.splitext(iconUrl)
|
||||||
else:
|
response = http.request('GET', iconUrl)
|
||||||
# external URL: use cached if present already,
|
iconFile = tempfile.NamedTemporaryFile(suffix=file_extension, delete=False, mode='wb', dir=tmpdir)
|
||||||
# otherwise download it and cache for later re-use
|
iconFile.write(response.data)
|
||||||
if iconUrl in icon_cache:
|
iconFile.close()
|
||||||
new_props['iconUrl'] = icon_cache[iconUrl]
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
filename, file_extension = os.path.splitext(iconUrl)
|
|
||||||
response = http.request('GET', iconUrl)
|
|
||||||
iconFile = tempfile.NamedTemporaryFile(suffix=file_extension, delete=False, mode='wb', dir=tmpdir)
|
|
||||||
iconFile.write(response.data)
|
|
||||||
iconFile.close()
|
|
||||||
|
|
||||||
iconPath = os.path.realpath(iconFile.name)
|
iconPath = os.path.realpath(iconFile.name)
|
||||||
except Exception as Argument:
|
except Exception as Argument:
|
||||||
LOG.exception("Could not get icon from URL %s" % iconUrl)
|
LOG.exception("Could not get icon from URL %s" % iconUrl)
|
||||||
iconPath = icon_dir + '/circle-15.svg'
|
iconPath = maki_icon_dir + '/circle-15.svg'
|
||||||
|
|
||||||
new_props['iconUrl'] = iconPath
|
new_props['iconUrl'] = iconPath
|
||||||
icon_cache[iconUrl] = iconPath
|
icon_cache[iconUrl] = iconPath
|
||||||
|
elif m := re.match(r'/uploads/pictogram/(.*)-24(.*)\.png', iconUrl):
|
||||||
|
# known UMAP icon URL -> replace with local files on our server
|
||||||
|
# there are different naming conventions
|
||||||
|
# the .fr server has basename-24.png for black maki icons
|
||||||
|
# and basename-24_1.png for white ones
|
||||||
|
# the .de server has basename-24_???????.png for black osmic icons
|
||||||
|
if m.group(2) == '':
|
||||||
|
new_props['iconUrl'] = maki_icon_dir + '/' + m.group(1) + "-15.svg"
|
||||||
|
new_props['iconFill'] = 'white'
|
||||||
|
elif m.group(2) == '_1':
|
||||||
|
new_props['iconUrl'] = maki_icon_dir + '/' + m.group(1) + "-15.svg"
|
||||||
|
new_props['iconFill'] = 'white'
|
||||||
|
else:
|
||||||
|
icon_path = _find_icon(osmic_icon_dir + "/*", m.group(1))
|
||||||
|
if icon_path is None:
|
||||||
|
icon_path = maki_icon_dir + '/circle-15.svg'
|
||||||
|
new_props['iconUrl'] = icon_path
|
||||||
|
new_props['iconFill'] = 'black'
|
||||||
|
elif len(iconUrl) < 10:
|
||||||
|
new_props['iconLabel'] = iconUrl
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_props['offset'] = marker_offsets[iconClass]
|
new_props['offset'] = marker_offsets[iconClass]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
new_props['weight'] = float(new_props['weight']) / 4
|
new_props['weight'] = float(new_props['weight']) / 4
|
||||||
|
|
||||||
new_features.append({
|
new_features.append({
|
||||||
'type' : 'Feature',
|
'type' : 'Feature',
|
||||||
'properties' : new_props,
|
'properties' : new_props,
|
||||||
'geometry' : feature['geometry']
|
'geometry' : feature['geometry']
|
||||||
})
|
})
|
||||||
|
except Exception as Argument:
|
||||||
|
LOG.warning("Exception: %s" % Argument)
|
||||||
|
|
||||||
new_umap = {
|
new_umap = {
|
||||||
'type' : 'FeatureCollection',
|
'type' : 'FeatureCollection',
|
||||||
|
|
|
@ -25,14 +25,22 @@
|
||||||
|
|
||||||
<Style name="point">
|
<Style name="point">
|
||||||
<Rule>
|
<Rule>
|
||||||
|
<!-- the marker outline -->
|
||||||
<Filter>[mapnik::geometry_type]=point</Filter>
|
<Filter>[mapnik::geometry_type]=point</Filter>
|
||||||
<MarkersSymbolizer file="${basedir}/markers/[iconClass].svg" allow-overlap="true" transform='translate(0,[offset])' fill='[color]'/>
|
<MarkersSymbolizer file="${basedir}/markers/[iconClass].svg" allow-overlap="true" transform='translate(0,[offset])' fill='[color]'/>
|
||||||
</Rule>
|
</Rule>
|
||||||
<Rule>
|
<Rule>
|
||||||
|
<!-- the marker symbol if given -->
|
||||||
<Filter>(not ([iconUrl] = null or [iconUrl] = '')) and ([mapnik::geometry_type]=point)</Filter>
|
<Filter>(not ([iconUrl] = null or [iconUrl] = '')) and ([mapnik::geometry_type]=point)</Filter>
|
||||||
<MarkersSymbolizer base="root" file="[iconUrl]" allow-overlap="true" transform='translate(0,-23)' fill='[iconFill]' width='20'/>
|
<MarkersSymbolizer base="root" file="[iconUrl]" allow-overlap="true" transform='translate(0,-23)' fill='[iconFill]' width='20'/>
|
||||||
</Rule>
|
</Rule>
|
||||||
<Rule>
|
<Rule>
|
||||||
|
<!-- the in-marker text instead of an icon if given -->
|
||||||
|
<Filter>(not ([iconLabel] = null or [iconLabel] = '')) and ([mapnik::geometry_type]=point)</Filter>
|
||||||
|
<TextSymbolizer face-name="DejaVu Sans Book" size="10" placement="point" allow-overlap="true" dy="[offset]" fill="white" horizontal_alignment='middle' vertical_alignement='middle'>[iconLabel]</TextSymbolizer>
|
||||||
|
</Rule>
|
||||||
|
<Rule>
|
||||||
|
<!-- marker label under the actual marker -->
|
||||||
<Filter>(not ([name] = null or [name] = '')) and ([mapnik::geometry_type]=point)</Filter>
|
<Filter>(not ([name] = null or [name] = '')) and ([mapnik::geometry_type]=point)</Filter>
|
||||||
<TextSymbolizer face-name="DejaVu Sans Book" size="10" placement="point" allow-overlap="true" dy="10" halo-fill="white" halo-radius="1" fill="[color]">[name]</TextSymbolizer>
|
<TextSymbolizer face-name="DejaVu Sans Book" size="10" placement="point" allow-overlap="true" dy="10" halo-fill="white" halo-radius="1" fill="[color]">[name]</TextSymbolizer>
|
||||||
</Rule>
|
</Rule>
|
||||||
|
|
Ładowanie…
Reference in New Issue