mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-01-16 18:04:34 -05:00
script to generate trump precedence chart
This commit is contained in:
239
bin/build-trump-chart
Executable file
239
bin/build-trump-chart
Executable file
@@ -0,0 +1,239 @@
|
||||
#! /usr/bin/python3
|
||||
#
|
||||
# This generates the trump precedence chart
|
||||
# It is a bit of an awful hack but it gets the job done.
|
||||
# The arrows are particularly fragile: change some of the
|
||||
# chart settings and they will likely break.
|
||||
|
||||
class Chart:
|
||||
def __init__(
|
||||
self,
|
||||
chart_width: int,
|
||||
chart_height: int,
|
||||
box_width: int,
|
||||
box_height: int,
|
||||
gutter: int,
|
||||
x: int,
|
||||
y: int,
|
||||
y_offset: int,
|
||||
radius: int
|
||||
):
|
||||
self.chart_width = chart_width
|
||||
self.chart_height = chart_height
|
||||
self.box_width = box_width
|
||||
self.box_height = box_height
|
||||
self.gutter = gutter
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.y_offset = y_offset
|
||||
self.radius = radius
|
||||
self.column_count = 0
|
||||
self.dist = 10 # spline distance for arcs
|
||||
self.gradient = [
|
||||
"#3dda07",
|
||||
"#46c819",
|
||||
"#43b72a",
|
||||
"#56a63b",
|
||||
"#5f944d",
|
||||
]
|
||||
self.head_css = "font-family=\"sans-serif\" font-size=\"14\" font-weight=\"bolder\" dominant-baseline=\"middle\" text-anchor=\"middle\""
|
||||
self.text_css = "font-family=\"sans-serif\" font-size=\"12\" font-weight=\"bold\" dominant-baseline=\"middle\" text-anchor=\"middle\""
|
||||
self.path_color = "#dffcd7"
|
||||
self.box_color = "#ebf9e7"
|
||||
|
||||
def head_box(self, x: int, y: int, height: int, text: str, bg_color: str) -> str:
|
||||
para = text.split('/')
|
||||
box = f"<rect x=\"{x}\" y=\"{y}\" width=\"{self.box_width}\" height=\"{height}\" rx=\"3\" ry=\"3\" fill=\"{bg_color}\" stroke=\"{self.box_color}\" stroke-width=\"2\" />\n"
|
||||
x_mid = x + int(self.box_width / 2)
|
||||
y_begin = y + int(height / (len(para) + 1)) + 3
|
||||
for line in para:
|
||||
box += f"<text x=\"{x_mid}\" y=\"{y_begin}\" {self.head_css}>{line}</text>\n"
|
||||
y_begin += 18
|
||||
return box + "\n"
|
||||
|
||||
def box(self, x: int, y: int, height: int, text: str, bg_color: str) -> str:
|
||||
para = text.split('/')
|
||||
box = f"<rect x=\"{x}\" y=\"{y}\" width=\"{self.box_width}\" height=\"{height}\" rx=\"3\" ry=\"3\" fill=\"{bg_color}\" stroke=\"{self.box_color}\" stroke-width=\"1\" />\n"
|
||||
x_mid = x + int(self.box_width / 2)
|
||||
y_begin = y + int(height / (len(para) + 1)) + 2
|
||||
for line in para:
|
||||
box += f"<text x=\"{x_mid}\" y=\"{y_begin}\" {self.text_css}>{line}</text>\n"
|
||||
y_begin += 16
|
||||
return box
|
||||
|
||||
def line(self, x1: int, y1: int, x2: int, y2: int) -> str:
|
||||
return f"<line x1=\"{x1}\" y1=\"{y1}\" x2=\"{x2}\" y2=\"{y2}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n"
|
||||
|
||||
def arc_ne(self, x: int, y: int) -> str:
|
||||
return f"<path d=\"M {x} {y} C {x} {y-self.dist}, {x+self.dist} {y-self.radius}, {x+self.radius} {y-self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n"
|
||||
|
||||
def arc_nw(self, x: int, y: int) -> str:
|
||||
return f"<path d=\"M {x} {y} C {x} {y-self.dist}, {x-self.dist} {y-self.radius}, {x-self.radius} {y-self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n"
|
||||
|
||||
def arc_se(self, x: int, y: int) -> str:
|
||||
return f"<path d=\"M {x} {y} C {x} {y+self.dist}, {x+self.dist} {y+self.radius}, {x+self.radius} {y+self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n"
|
||||
|
||||
def arc_sw(self, x: int, y: int) -> str:
|
||||
return f"<path d=\"M {x} {y} C {x} {y+self.dist}, {x-self.dist} {y+self.radius}, {x-self.radius} {y+self.radius}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n"
|
||||
|
||||
def side_arrow_head(self, x: int, y: int, direction: int) -> str:
|
||||
return f"<polygon points=\"{x},{y} {x - 6 * direction},{y - 3} {x - 6 * direction},{y + 3}\" fill=\"{self.path_color}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n"
|
||||
|
||||
def up_arrow_head(self, x: int, y: int) -> str:
|
||||
return f"<polygon points=\"{x},{y - 8} {x - 4},{y} {x + 4},{y}\" fill=\"{self.path_color}\" stroke=\"{self.path_color}\" />\n"
|
||||
|
||||
def up_arrow(self, x: int, y: int) -> str:
|
||||
x_mid = x + int(self.box_width/2)
|
||||
return f"<line x1=\"{x_mid}\" y1=\"{y}\" x2=\"{x_mid}\" y2=\"{y - 10}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" + self.up_arrow_head(x_mid, y - 10) + "\n"
|
||||
|
||||
def column(self, name: str, dependent: list[str]):
|
||||
x = self.x + self.column_count * (self.box_width + self.gutter)
|
||||
self.column_count += 1
|
||||
y = self.box_height
|
||||
out = self.head_box(x, y - 20, self.box_height + 20, name, "#abe797")
|
||||
|
||||
n = 0
|
||||
for item in dependent:
|
||||
y += self.y_offset
|
||||
out += self.box(x, y, self.box_height, item, self.gradient[n]) + self.up_arrow(x, y)
|
||||
n += 1
|
||||
|
||||
return out
|
||||
|
||||
def dependent_column(self, right: bool, dependent: dict) -> str:
|
||||
x = self.x + self.column_count * (self.box_width + self.gutter)
|
||||
y = self.box_height
|
||||
|
||||
# curving arrow to each adjacent columns
|
||||
out = ""
|
||||
for direction in [-1, 1]:
|
||||
if direction == 1 and not right:
|
||||
continue
|
||||
x_mid = int(self.box_width / 2)
|
||||
x_begin = x + x_mid
|
||||
x_end = x_begin + (x_mid + self.gutter - 3) * direction
|
||||
y_begin = y + self.y_offset
|
||||
y_end = y_begin - self.box_height - 10
|
||||
out += f"\n<path d=\"M {x_begin} {y_begin} C {x_begin} {y_begin-self.box_height+5}, {x_end-40 * direction} {y_end}, {x_end} {y_end}\" fill=\"transparent\" stroke-width=\"2\" stroke=\"{self.path_color}\"/>\n"
|
||||
out += self.side_arrow_head(x_end, y_end, direction) + "\n"
|
||||
|
||||
n = 0
|
||||
for item in dependent:
|
||||
y += self.y_offset
|
||||
out += self.box(x, y, self.box_height, item, self.gradient[n])
|
||||
if n:
|
||||
out += self.up_arrow(x, y)
|
||||
n += 1
|
||||
|
||||
self.column_count += 1
|
||||
return out
|
||||
|
||||
def horizontal(self, top: int, color: str, dependent: list[str]) -> str:
|
||||
x = self.gutter
|
||||
y = top
|
||||
x_offset = self.box_width + self.gutter
|
||||
out = ""
|
||||
n = 0
|
||||
for item in dependent:
|
||||
y_mid = y + int(self.box_height / 2)
|
||||
out += self.box(x, y, self.box_height, item, color)
|
||||
if n:
|
||||
out +=f"<line x1=\"{x - self.gutter}\" y1=\"{y_mid}\" x2=\"{x - 2}\" y2=\"{y_mid}\" stroke-width=\"2\" stroke=\"{self.path_color}\" />\n" + self.side_arrow_head(x - 2, y_mid, 1)
|
||||
n += 1
|
||||
x += x_offset
|
||||
return out
|
||||
|
||||
def svg(self) -> str:
|
||||
out = (f"""
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="{self.chart_height}" width="{self.chart_width}">
|
||||
<rect width="{self.chart_width}" height="{self.chart_height}" rx="8" ry="8" fill="#112709" stroke="#000" stroke-width="2" />
|
||||
""").strip()
|
||||
|
||||
out += self.column("MP3 V0", [
|
||||
"V2",
|
||||
"any VBR",
|
||||
])
|
||||
|
||||
self.column_count += 1
|
||||
cbr = [
|
||||
"256 CBR",
|
||||
"224 CBR",
|
||||
"192 CBR",
|
||||
"< 192 CBR",
|
||||
]
|
||||
|
||||
out += self.column("MP3 320", cbr)
|
||||
|
||||
# draw the arrows from the CBR boxes to V0
|
||||
x = self.x + 2 * (self.box_width + self.gutter)
|
||||
x_end = x - 59
|
||||
y = 3 * (self.box_height)
|
||||
for n in range(0, len(cbr)):
|
||||
out += self.line(x, y, x_end, y)
|
||||
out += self.arc_se(x_end - self.radius, y - self.radius)
|
||||
y += self.y_offset
|
||||
|
||||
y_top = self.chart_height - self.box_height - 20
|
||||
out += self.horizontal(y_top, self.gradient[4], [
|
||||
"192 AAC",
|
||||
"256 AAC",
|
||||
"320 AAC",
|
||||
])
|
||||
|
||||
# line from first horizontal box
|
||||
x = self.gutter + int(self.box_width / 2)
|
||||
out += self.arc_ne(x, y_top)
|
||||
out += self.arc_sw(x + self.box_width + self.gutter, y_top - self.radius * 2)
|
||||
x += self.radius - 1
|
||||
x_end = x + int((self.box_width + self.gutter) / 2) + 20
|
||||
y = y_top - self.radius
|
||||
out += self.line(x, y, x_end, y)
|
||||
|
||||
# line from middle horizontal box
|
||||
x_end += self.radius
|
||||
y_end = self.chart_height - self.box_height - 80
|
||||
out += self.line(x_end, y_end + self.radius * 2, x_end, y_end)
|
||||
|
||||
# line from third horizontal box
|
||||
out += self.arc_se(x_end, y_end)
|
||||
x = int(self.gutter) / 2 + self.box_width * 2 - 10
|
||||
x_end = x + self.box_width - self.gutter + 10
|
||||
out += self.arc_nw(x_end, y_top)
|
||||
|
||||
y = y_top - self.radius
|
||||
out += self.line(x, y, x_end - self.radius, y)
|
||||
|
||||
# line to top
|
||||
x = self.x + int(self.gutter + 3/2 * self.box_width)
|
||||
y_begin = self.y + int(self.box_height * 2 - 20)
|
||||
out += self.line(x, y_begin, x, y_end)
|
||||
out += self.arc_nw(x, y_begin)
|
||||
y = y_begin - self.radius
|
||||
x_end = x - int(self.box_width / 2) - self.gutter + 2
|
||||
out += self.line(x - self.radius, y, x_end, y)
|
||||
out += self.side_arrow_head(x_end, y, -1)
|
||||
|
||||
out += self.column("FLAC 100% Log/+ Cue + Checksum", [
|
||||
"FLAC 100% Log + Cue/No Checksum",
|
||||
"FLAC 100% Log/No Checksum",
|
||||
])
|
||||
|
||||
out += self.dependent_column(False, [
|
||||
"FLAC < 100% Log/or No log",
|
||||
])
|
||||
|
||||
return out + "</svg>"
|
||||
|
||||
c = Chart(
|
||||
810,
|
||||
450,
|
||||
138, # box width
|
||||
40, # box height
|
||||
20, # gutter
|
||||
20, # x
|
||||
20, # y
|
||||
60, # y_offset, how far below the next box is placed
|
||||
30, # radius of arcs
|
||||
)
|
||||
|
||||
print(c.svg())
|
||||
90
public/static/svg/trump-chart.svg
Normal file
90
public/static/svg/trump-chart.svg
Normal file
@@ -0,0 +1,90 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="450" width="810">
|
||||
<rect width="810" height="450" rx="8" ry="8" fill="#112709" stroke="#000" stroke-width="2" /><rect x="20" y="20" width="138" height="60" rx="3" ry="3" fill="#abe797" stroke="#ebf9e7" stroke-width="2" />
|
||||
<text x="89" y="53" font-family="sans-serif" font-size="14" font-weight="bolder" dominant-baseline="middle" text-anchor="middle">MP3 V0</text>
|
||||
|
||||
<rect x="20" y="100" width="138" height="40" rx="3" ry="3" fill="#3dda07" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="89" y="122" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">V2</text>
|
||||
<line x1="89" y1="100" x2="89" y2="90" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="89,82 85,90 93,90" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="20" y="160" width="138" height="40" rx="3" ry="3" fill="#46c819" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="89" y="182" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">any VBR</text>
|
||||
<line x1="89" y1="160" x2="89" y2="150" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="89,142 85,150 93,150" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="336" y="20" width="138" height="60" rx="3" ry="3" fill="#abe797" stroke="#ebf9e7" stroke-width="2" />
|
||||
<text x="405" y="53" font-family="sans-serif" font-size="14" font-weight="bolder" dominant-baseline="middle" text-anchor="middle">MP3 320</text>
|
||||
|
||||
<rect x="336" y="100" width="138" height="40" rx="3" ry="3" fill="#3dda07" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="405" y="122" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">256 CBR</text>
|
||||
<line x1="405" y1="100" x2="405" y2="90" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="405,82 401,90 409,90" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="336" y="160" width="138" height="40" rx="3" ry="3" fill="#46c819" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="405" y="182" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">224 CBR</text>
|
||||
<line x1="405" y1="160" x2="405" y2="150" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="405,142 401,150 409,150" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="336" y="220" width="138" height="40" rx="3" ry="3" fill="#43b72a" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="405" y="242" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">192 CBR</text>
|
||||
<line x1="405" y1="220" x2="405" y2="210" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="405,202 401,210 409,210" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="336" y="280" width="138" height="40" rx="3" ry="3" fill="#56a63b" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="405" y="302" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">< 192 CBR</text>
|
||||
<line x1="405" y1="280" x2="405" y2="270" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="405,262 401,270 409,270" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<line x1="336" y1="120" x2="277" y2="120" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 90 C 247 100, 257 120, 277 120" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="336" y1="180" x2="277" y2="180" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 150 C 247 160, 257 180, 277 180" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="336" y1="240" x2="277" y2="240" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 210 C 247 220, 257 240, 277 240" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="336" y1="300" x2="277" y2="300" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 270 C 247 280, 257 300, 277 300" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<rect x="20" y="390" width="138" height="40" rx="3" ry="3" fill="#5f944d" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="89" y="412" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">192 AAC</text>
|
||||
<rect x="178" y="390" width="138" height="40" rx="3" ry="3" fill="#5f944d" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="247" y="412" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">256 AAC</text>
|
||||
<line x1="158" y1="410" x2="176" y2="410" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="176,410 170,407 170,413" fill="#dffcd7" stroke-width="2" stroke="#dffcd7" />
|
||||
<rect x="336" y="390" width="138" height="40" rx="3" ry="3" fill="#5f944d" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="405" y="412" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">320 AAC</text>
|
||||
<line x1="316" y1="410" x2="334" y2="410" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="334,410 328,407 328,413" fill="#dffcd7" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 89 390 C 89 380, 99 360, 119 360" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<path d="M 247 330 C 247 340, 237 360, 217 360" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="118" y1="360" x2="217" y2="360" stroke-width="2" stroke="#dffcd7" />
|
||||
<line x1="247" y1="390" x2="247" y2="330" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 330 C 247 340, 257 360, 277 360" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<path d="M 404.0 390 C 404.0 380, 394.0 360, 374.0 360" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="276.0" y1="360" x2="374.0" y2="360" stroke-width="2" stroke="#dffcd7" />
|
||||
<line x1="247" y1="80" x2="247" y2="330" stroke-width="2" stroke="#dffcd7" />
|
||||
<path d="M 247 80 C 247 70, 237 50, 217 50" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<line x1="217" y1="50" x2="160" y2="50" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="160,50 166,47 166,53" fill="#dffcd7" stroke-width="2" stroke="#dffcd7" />
|
||||
<rect x="494" y="20" width="138" height="60" rx="3" ry="3" fill="#abe797" stroke="#ebf9e7" stroke-width="2" />
|
||||
<text x="563" y="43" font-family="sans-serif" font-size="14" font-weight="bolder" dominant-baseline="middle" text-anchor="middle">FLAC 100% Log</text>
|
||||
<text x="563" y="61" font-family="sans-serif" font-size="14" font-weight="bolder" dominant-baseline="middle" text-anchor="middle">+ Cue + Checksum</text>
|
||||
|
||||
<rect x="494" y="100" width="138" height="40" rx="3" ry="3" fill="#3dda07" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="563" y="115" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">FLAC 100% Log + Cue</text>
|
||||
<text x="563" y="131" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">No Checksum</text>
|
||||
<line x1="563" y1="100" x2="563" y2="90" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="563,82 559,90 567,90" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
<rect x="494" y="160" width="138" height="40" rx="3" ry="3" fill="#46c819" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="563" y="175" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">FLAC 100% Log</text>
|
||||
<text x="563" y="191" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">No Checksum</text>
|
||||
<line x1="563" y1="160" x2="563" y2="150" stroke-width="2" stroke="#dffcd7" />
|
||||
<polygon points="563,142 559,150 567,150" fill="#dffcd7" stroke="#dffcd7" />
|
||||
|
||||
|
||||
<path d="M 721 100 C 721 65, 675 50, 635 50" fill="transparent" stroke-width="2" stroke="#dffcd7"/>
|
||||
<polygon points="635,50 641,47 641,53" fill="#dffcd7" stroke-width="2" stroke="#dffcd7" />
|
||||
|
||||
<rect x="652" y="100" width="138" height="40" rx="3" ry="3" fill="#3dda07" stroke="#ebf9e7" stroke-width="1" />
|
||||
<text x="721" y="115" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">FLAC < 100% Log</text>
|
||||
<text x="721" y="131" font-family="sans-serif" font-size="12" font-weight="bold" dominant-baseline="middle" text-anchor="middle">or No log</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.0 KiB |
Reference in New Issue
Block a user