forked from platypush/platypush
Added route to dynamically generate logo.svg.
This commit is contained in:
parent
c5aee0a65d
commit
075efde58c
3 changed files with 229 additions and 0 deletions
188
platypush/backend/http/app/routes/logo.py
Normal file
188
platypush/backend/http/app/routes/logo.py
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import math
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
from flask import Blueprint, make_response, request
|
||||||
|
|
||||||
|
|
||||||
|
logo = Blueprint('logo', __name__)
|
||||||
|
|
||||||
|
# Declare routes list
|
||||||
|
__routes__ = [
|
||||||
|
logo,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Gear:
|
||||||
|
"""
|
||||||
|
A utility class used to model the gears in the application's logo.
|
||||||
|
"""
|
||||||
|
|
||||||
|
center: Tuple[float, float]
|
||||||
|
outer_radius: float
|
||||||
|
inner_radius: float
|
||||||
|
color: str = "currentColor"
|
||||||
|
background: str = ""
|
||||||
|
num_spikes: int = 0
|
||||||
|
spike_max_base: float = 0
|
||||||
|
spike_min_base: float = 0
|
||||||
|
spike_height: float = 0
|
||||||
|
alpha_offset: float = 0
|
||||||
|
|
||||||
|
def to_svg(self) -> str:
|
||||||
|
"""
|
||||||
|
Returns the SVG representation of a gear.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Generate the basic circle
|
||||||
|
svg = f"""
|
||||||
|
<circle
|
||||||
|
cx="{self.center[0]}" cy="{self.center[1]}"
|
||||||
|
r="{self.outer_radius - (self.inner_radius / math.pi)}"
|
||||||
|
stroke-width="{self.inner_radius}"
|
||||||
|
stroke="{self.color}"
|
||||||
|
fill="none" />
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Generate the spikes
|
||||||
|
for i in range(self.num_spikes):
|
||||||
|
# Iterate for alpha -> [0, 2*pi]
|
||||||
|
alpha = (2 * math.pi * i) / self.num_spikes
|
||||||
|
# Calculate the base angle for the major base of the gear polygon
|
||||||
|
maj_delta_alpha = math.asin(self.spike_max_base / (2 * self.outer_radius))
|
||||||
|
# Calculate the points of the gear polygon's major base
|
||||||
|
maj_base = (
|
||||||
|
(
|
||||||
|
self.center[0]
|
||||||
|
+ self.outer_radius
|
||||||
|
* math.cos(alpha + maj_delta_alpha + self.alpha_offset),
|
||||||
|
self.center[1]
|
||||||
|
+ self.outer_radius
|
||||||
|
* math.sin(alpha + maj_delta_alpha + self.alpha_offset),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.center[0]
|
||||||
|
+ self.outer_radius
|
||||||
|
* math.cos(alpha - maj_delta_alpha + self.alpha_offset),
|
||||||
|
self.center[1]
|
||||||
|
+ self.outer_radius
|
||||||
|
* math.sin(alpha - maj_delta_alpha + self.alpha_offset),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Height of the gear relative to the circle's center
|
||||||
|
h = self.outer_radius * math.cos(maj_delta_alpha) + self.spike_height
|
||||||
|
# Calculate the base angle for the minor base of the gear polygon
|
||||||
|
min_delta_alpha = math.asin(self.spike_min_base / (2 * h))
|
||||||
|
# Calculate the points of the gear polygon's minor base
|
||||||
|
min_base = (
|
||||||
|
(
|
||||||
|
self.center[0]
|
||||||
|
+ h * math.cos(alpha - min_delta_alpha + self.alpha_offset),
|
||||||
|
self.center[1]
|
||||||
|
+ h * math.sin(alpha - min_delta_alpha + self.alpha_offset),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
self.center[0]
|
||||||
|
+ h * math.cos(alpha + min_delta_alpha + self.alpha_offset),
|
||||||
|
self.center[1]
|
||||||
|
+ h * math.sin(alpha + min_delta_alpha + self.alpha_offset),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Flatten the polygon's points
|
||||||
|
svg_points = " ".join(
|
||||||
|
[f"{point[0]},{point[1]}" for point in [*maj_base, *min_base]]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Serialize the gear polygon to SVG
|
||||||
|
svg += f"""
|
||||||
|
<polygon points="{svg_points}" stroke="{self.color}" fill="{self.color}" />"""
|
||||||
|
|
||||||
|
return svg
|
||||||
|
|
||||||
|
|
||||||
|
# Properties of the two gears on the logo
|
||||||
|
gears = [
|
||||||
|
Gear(
|
||||||
|
center=(32.9, 34.5),
|
||||||
|
outer_radius=22.6,
|
||||||
|
inner_radius=12.4,
|
||||||
|
num_spikes=12,
|
||||||
|
spike_max_base=9,
|
||||||
|
spike_min_base=4.3,
|
||||||
|
spike_height=10.16,
|
||||||
|
),
|
||||||
|
Gear(
|
||||||
|
center=(65.5, 70.5),
|
||||||
|
outer_radius=14.4,
|
||||||
|
inner_radius=8.5,
|
||||||
|
num_spikes=7,
|
||||||
|
spike_max_base=9,
|
||||||
|
spike_min_base=4.3,
|
||||||
|
spike_height=7.5,
|
||||||
|
alpha_offset=math.pi / 6.6,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
template_start = """
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.1"
|
||||||
|
width="{width}" height="{height}"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="triangleGradient">
|
||||||
|
<stop offset="0%" stop-color="#8acb45" />
|
||||||
|
<stop offset="50%" stop-color="#6bbb4c" />
|
||||||
|
<stop offset="100%" stop-color="#5cb450" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="100%" height="100%" fill="{bg_color}" />
|
||||||
|
"""
|
||||||
|
|
||||||
|
template_end = "\n</svg>"
|
||||||
|
|
||||||
|
|
||||||
|
@logo.route('/logo.svg', methods=['GET'])
|
||||||
|
def logo_path():
|
||||||
|
"""
|
||||||
|
This path dynamically generates the logo image as a parametrizable vector SVG.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- ``size``: Size of the image in pixels (default: 256)
|
||||||
|
- ``bg``: Background color (default: "none")
|
||||||
|
- ``fg``: Foreground color (default: "currentColor")
|
||||||
|
|
||||||
|
"""
|
||||||
|
size = request.args.get("size", 256)
|
||||||
|
bg = request.args.get("bg", "none")
|
||||||
|
fg = request.args.get("fg", "currentColor")
|
||||||
|
svg = template_start.format(
|
||||||
|
width=size,
|
||||||
|
height=size,
|
||||||
|
bg_color=bg,
|
||||||
|
)
|
||||||
|
|
||||||
|
for gear in gears:
|
||||||
|
gear.color = fg
|
||||||
|
gear.background = bg
|
||||||
|
svg += gear.to_svg()
|
||||||
|
|
||||||
|
# "Play" triangle on the logo
|
||||||
|
svg += """\n\t\t<polygon points="67,47 67,3 99,25.3" fill="url(#triangleGradient)" />"""
|
||||||
|
svg += template_end
|
||||||
|
|
||||||
|
rs = make_response(svg)
|
||||||
|
rs.headers.update({"Content-Type": "image/svg+xml"})
|
||||||
|
return rs
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
41
platypush/backend/http/webapp/dist/img/icons/favicon.svg
vendored
Normal file
41
platypush/backend/http/webapp/dist/img/icons/favicon.svg
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.1"
|
||||||
|
width="256" height="256"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="triangleGradient">
|
||||||
|
<stop offset="0%" stop-color="#8acb45" />
|
||||||
|
<stop offset="50%" stop-color="#6bbb4c" />
|
||||||
|
<stop offset="100%" stop-color="#5cb450" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="100%" height="100%" fill="none" />
|
||||||
|
<circle cx="32.9" cy="34.5" r="18.652957411320997" stroke-width="12.4" stroke="#000000" fill="none" />
|
||||||
|
<polygon points="55.047460351019936,39.0 55.047460351019936,30.0 65.13584176553678,32.35 65.13584176553678,36.65" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="49.830263293291885,49.47084449253994 54.330263293291885,41.67661585847999 61.89205788133026,48.755966264631844 59.742057881330254,52.479875500904924" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="40.07661585848,55.93026329329189 47.870844492539945,51.43026329329188 50.87987550090493,61.342057881330255 47.15596626463184,63.492057881330254" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="28.4,56.64746035101994 37.4,56.64746035101993 35.050000000000004,66.73584176553678 30.75,66.73584176553678" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="17.92915550746006,51.43026329329189 25.72338414152001,55.93026329329189 18.644033735368154,63.492057881330254 14.920124499095078,61.34205788133026" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="11.469736706708115,41.67661585847999 15.969736706708115,49.47084449253994 6.0579421186697395,52.479875500904924 3.9079421186697445,48.75596626463185" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="10.752539648980061,30.000000000000004 10.752539648980065,39.0 0.6641582344632226,36.65 0.6641582344632226,32.35000000000001" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="15.969736706708108,19.52915550746006 11.469736706708112,27.323384141520012 3.907942118669741,20.24403373536816 6.057942118669736,16.520124499095083" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="25.723384141519993,13.06973670670812 17.92915550746005,17.569736706708124 14.92012449909506,7.657942118669752 18.644033735368136,5.507942118669753" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="37.39999999999999,12.352539648980063 28.399999999999995,12.352539648980066 30.749999999999996,2.264158234463224 35.04999999999999,2.264158234463224" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="47.870844492539945,17.569736706708117 40.07661585848,13.069736706708117 47.15596626463185,5.507942118669746 50.87987550090493,7.6579421186697445" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="54.33026329329188,27.323384141519995 49.83026329329188,19.52915550746005 59.74205788133025,16.52012449909506 61.892057881330246,20.244033735368134" stroke="#000000" fill="#000000" />
|
||||||
|
|
||||||
|
<circle cx="65.5" cy="70.5" r="11.69436596743778" stroke-width="8.5" stroke="#000000" fill="none" />
|
||||||
|
<polygon points="75.59619697596976,80.76775567601894 79.72023567151646,72.76823663812462 85.21241914871936,78.24356296406287 83.2420451052915,82.06555539327904" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="63.76722121027272,84.79536560098661 72.59279310784501,83.03205034817951 71.73633099741353,90.73982242421863 67.51966886857343,91.58229526722646" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="53.24306321548609,78.05827365609566 60.1243326673541,83.85897453881562 53.56415840708632,87.99508278180117 50.276440780082716,85.22363680450164" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="51.94862861538407,65.62964748747973 51.70385937197527,74.62631842830451 44.379917983020505,72.07618897003609 44.49686328820471,67.7777795205309" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="60.85865306549732,56.86849609787744 53.67216135948117,62.28646037972363 51.09953008890019,54.970392715438265 54.53307612621901,52.381809780778426" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="73.2637064235145,58.37214517857838 64.54706708723641,56.131565190885546 68.66298975389094,49.55870749237323 72.82760632566824,50.62920681982647" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="79.82253049387555,69.00831630296325 76.13955073459155,60.796394475966565 83.84465362096915,59.916242652069755 85.60429950596037,63.83971641385705" stroke="#000000" fill="#000000" />
|
||||||
|
<polygon points="67,47 67,3 99,25.3" fill="url(#triangleGradient)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
BIN
platypush/backend/http/webapp/dist/img/logo.png
vendored
BIN
platypush/backend/http/webapp/dist/img/logo.png
vendored
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
Loading…
Reference in a new issue