Generate standalone SVG
This commit is contained in:
parent
286534188a
commit
d8fe6a9d46
2 changed files with 49 additions and 29 deletions
|
@ -46,7 +46,10 @@ class OutputPaths:
|
|||
raise AttributeError(f'Path exists but is not a directory: {path}')
|
||||
os.makedirs(path, exist_ok=True)
|
||||
self.path = path
|
||||
self.svg_path = os.path.join(path, 'map.svg')
|
||||
self.svg_web_path = os.path.join(path, 'web.svg')
|
||||
self.svg_standalone_path = os.path.join(path, 'standalone.svg')
|
||||
self.font_path = os.path.join(path, 'style/font.ttf')
|
||||
self.css_path = os.path.join(path, 'style/erfamap.css')
|
||||
self.png_path = os.path.join(path, 'map.png')
|
||||
self.html_path = os.path.join(path, 'erfamap.html')
|
||||
self.imagemap_path = os.path.join(path, 'imagemap.html')
|
||||
|
@ -258,6 +261,8 @@ class Erfa(Drawable):
|
|||
self.lat = lat
|
||||
self.x, self.y = ns.projection(lon, lat)
|
||||
self.display_name = display_name if display_name is not None else name
|
||||
if city.lower() not in self.display_name.lower():
|
||||
self.display_name += f' ({city})'
|
||||
self.web = web
|
||||
self.radius = radius
|
||||
|
||||
|
@ -322,7 +327,7 @@ class Erfa(Drawable):
|
|||
return None
|
||||
|
||||
@classmethod
|
||||
def from_api(cls, name, attr, radius, ns):
|
||||
def from_api(cls, ns, name, attr, radius):
|
||||
city = attr['Chaostreff-City'][0]
|
||||
location = cls.address_lookup(attr)
|
||||
if location is None:
|
||||
|
@ -393,6 +398,7 @@ class Erfa(Drawable):
|
|||
erfa = cls.from_api(ns, name, attr['printouts'], radius)
|
||||
erfas.append(erfa)
|
||||
except BaseException as e:
|
||||
breakpoint()
|
||||
print(e)
|
||||
continue
|
||||
|
||||
|
@ -615,10 +621,9 @@ def compute_bbox(ns):
|
|||
]
|
||||
|
||||
|
||||
def optimize_text_layout(ns, erfas, chaostreffs, width, svg):
|
||||
def optimize_text_layout(ns, font, erfas, chaostreffs, width, svg):
|
||||
|
||||
# Load the font and measure its various different heights
|
||||
font = ImageFont.truetype(ns.font, ns.font_size)
|
||||
# Measure the various different font heights
|
||||
pil = ImageDraw(Image.new('P', (1, 1)))
|
||||
xheight = -pil.textbbox((0,0), 'x', font=font, anchor='ls')[1]
|
||||
capheight = -pil.textbbox((0,0), 'A', font=font, anchor='ls')[1]
|
||||
|
@ -763,6 +768,9 @@ def create_imagemap(ns, size, parent, erfas, chaostreffs, texts):
|
|||
def create_svg(ns, bbox):
|
||||
print('Creating SVG image')
|
||||
|
||||
# Load the font used for the labels
|
||||
font = ImageFont.truetype(ns.font, ns.font_size)
|
||||
|
||||
# Convert from WGS84 lon, lat to chosen projection
|
||||
svg_box = ns.projection.setup(ns.scale_x, ns.scale_y, bbox=bbox)
|
||||
rectbox = [0, 0, svg_box[0], svg_box[1]]
|
||||
|
@ -786,22 +794,27 @@ def create_svg(ns, bbox):
|
|||
rectbox[3] = max(y, rectbox[3])
|
||||
|
||||
print('Copying stylesheet and font')
|
||||
dst = os.path.join(ns.output_directory.path, ns.stylesheet)
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
shutil.copyfile(ns.stylesheet, dst)
|
||||
dst = os.path.join(ns.output_directory.path, ns.font)
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
shutil.copyfile(ns.font, dst)
|
||||
os.makedirs(os.path.dirname(ns.output_directory.font_path), exist_ok=True)
|
||||
shutil.copyfile(ns.font, ns.output_directory.font_path)
|
||||
os.makedirs(os.path.dirname(ns.output_directory.css_path), exist_ok=True)
|
||||
fontrelpath = os.path.relpath(ns.output_directory.font_path,
|
||||
start=os.path.dirname(ns.output_directory.css_path))
|
||||
with open(ns.stylesheet, 'r') as src:
|
||||
with open(ns.output_directory.css_path, 'w') as dst:
|
||||
dst.write(f'''
|
||||
@font-face {{
|
||||
font-family: "{font.font.family}";
|
||||
src: url("{fontrelpath}");
|
||||
}}
|
||||
|
||||
''')
|
||||
dst.write(src.read())
|
||||
|
||||
svg = etree.Element('svg',
|
||||
xmlns='http://www.w3.org/2000/svg',
|
||||
viewBox=f'0 0 {svg_box[0]} {svg_box[1]}',
|
||||
width=str(svg_box[0]), height=str(svg_box[1]))
|
||||
|
||||
style = etree.Element('style', type='text/css')
|
||||
style.text = f'@import url({ns.stylesheet})'
|
||||
svg.append(style)
|
||||
|
||||
bg = etree.Element('rect',
|
||||
id='background',
|
||||
x=str(rectbox[0]),
|
||||
|
@ -813,7 +826,7 @@ def create_svg(ns, bbox):
|
|||
|
||||
# This can take some time, especially if lots of candidates are generated
|
||||
print('Layouting labels')
|
||||
texts = optimize_text_layout(ns, erfas, chaostreffs, width=svg_box[0], svg=svg)
|
||||
texts = optimize_text_layout(ns, font, erfas, chaostreffs, width=svg_box[0], svg=svg)
|
||||
|
||||
# Render shortest shapes last s.t. Berlin, Hamburg and Bremen are rendered on top of their surrounding states
|
||||
states = sorted(states, key=lambda x: -len(x))
|
||||
|
@ -827,24 +840,36 @@ def create_svg(ns, bbox):
|
|||
|
||||
# Generate SVG, PNG and HTML output files
|
||||
|
||||
print('Writing SVG')
|
||||
with open(ns.output_directory.svg_path, 'wb') as mapfile:
|
||||
print('Writing Web SVG')
|
||||
with open(ns.output_directory.svg_web_path, 'wb') as mapfile:
|
||||
root = etree.ElementTree(svg)
|
||||
root.write(mapfile)
|
||||
|
||||
style = etree.Element('style', type='text/css')
|
||||
with open(ns.stylesheet, 'r') as css:
|
||||
style.text = css.read()
|
||||
svg.insert(0, style)
|
||||
|
||||
print('Writing Standalone SVG')
|
||||
with open(ns.output_directory.svg_standalone_path, 'wb') as mapfile:
|
||||
root = etree.ElementTree(svg)
|
||||
root.write(mapfile)
|
||||
|
||||
|
||||
|
||||
print('Writing PNG')
|
||||
cairosvg.svg2png(url=ns.output_directory.svg_path, write_to=ns.output_directory.png_path,
|
||||
cairosvg.svg2png(url=ns.output_directory.svg_web_path, write_to=ns.output_directory.png_path,
|
||||
scale=ns.png_scale)
|
||||
|
||||
print('Writing HTML SVG page')
|
||||
html = etree.Element('html')
|
||||
head = etree.Element('head')
|
||||
link = etree.Element('link', rel='stylesheet', href=ns.stylesheet)
|
||||
link = etree.Element('link', rel='stylesheet', href=ns.output_directory.rel(ns.output_directory.css_path))
|
||||
head.append(link)
|
||||
html.append(head)
|
||||
body = etree.Element('body')
|
||||
obj = etree.Element('object',
|
||||
data=ns.output_directory.rel(ns.output_directory.svg_path),
|
||||
data=ns.output_directory.rel(ns.output_directory.svg_web_path),
|
||||
width=str(svg_box[0]), height=str(svg_box[1]))
|
||||
create_imagemap(ns, svg_box, obj, erfas, chaostreffs, texts)
|
||||
body.append(obj)
|
||||
|
@ -856,7 +881,7 @@ def create_svg(ns, bbox):
|
|||
print('Writing HTML Image Map')
|
||||
html = etree.Element('html')
|
||||
head = etree.Element('head')
|
||||
link = etree.Element('link', rel='stylesheet', href=ns.stylesheet)
|
||||
link = etree.Element('link', rel='stylesheet', href=ns.output_directory.rel(ns.output_directory.css_path))
|
||||
head.append(link)
|
||||
html.append(head)
|
||||
body = etree.Element('body')
|
||||
|
@ -916,7 +941,7 @@ def main():
|
|||
if os.path.exists(ns.cache_directory.chaostreff_info):
|
||||
os.unlink(ns.cache_directory.chaostreff_info)
|
||||
print('Retrieving Chaostreffs information')
|
||||
Chaostreff.fetch(target=ns.cache_directory.chaostreff_info, radius=ns.dotsize_treff)
|
||||
Chaostreff.fetch(ns, target=ns.cache_directory.chaostreff_info, radius=ns.dotsize_treff)
|
||||
|
||||
bbox = compute_bbox(ns)
|
||||
|
||||
|
|
|
@ -51,13 +51,8 @@ a:hover > text {
|
|||
fill: #5b8ca7;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'concertone';
|
||||
src: url('./concertone-regular.ttf');
|
||||
}
|
||||
|
||||
text.erfalabel {
|
||||
font-family: concertone;
|
||||
font-family: "Concert One";
|
||||
font-size: 45px;
|
||||
z-index: 100;
|
||||
user-select: none;
|
||||
|
|
Loading…
Reference in a new issue