From 084f13493b4553a29239013f32677304e10199b1 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Sat, 22 Feb 2025 20:02:49 +0100 Subject: [PATCH 01/12] =?UTF-8?q?=C3=96versatt=20till=20TypeScript?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + package-lock.json | 29 ++++ package.json | 16 +++ render.html | 54 ++++---- config.json => src/config.ts | 57 +++++++- graphics.js => src/graphics.ts | 12 +- render.js => src/render.ts | 241 ++++++++++++--------------------- src/typedefs.ts | 147 ++++++++++++++++++++ utils.js => src/utils.ts | 28 ++-- tsconfig.json | 34 +++++ 10 files changed, 423 insertions(+), 198 deletions(-) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json rename config.json => src/config.ts (74%) rename graphics.js => src/graphics.ts (84%) rename render.js => src/render.ts (75%) create mode 100644 src/typedefs.ts rename utils.js => src/utils.ts (69%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b56ca80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/dist/ +/node_modules/ +*.tsbuildinfo \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..d52f949 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "skyltprogram", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "skyltprogram", + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "typescript": "^5.7.3" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..34b7490 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "skyltprogram", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "index.js", + "scripts": { + "start": "tsc --watch", + "build": "tsc" + }, + "author": "axelw3", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "typescript": "^5.7.3" + } +} diff --git a/render.html b/render.html index b292035..240b8e0 100644 --- a/render.html +++ b/render.html @@ -6,36 +6,40 @@ - - - diff --git a/config.json b/src/config.ts similarity index 74% rename from config.json rename to src/config.ts index 00cdde0..77a5d6b 100644 --- a/config.json +++ b/src/config.ts @@ -1,11 +1,12 @@ -{ +import { ConfigData } from "./typedefs.js" + +const CONFIG: ConfigData = { "properties": { - "inherit": ["color", "background", "font", "borderRadius", "lineHeight", "lineSpacing"], "globalDefaults": { "borderFeatures": {}, "borderWidth": 0, "padding": 0 }, - "rootDefaults": { "background": "#06a", "color": "white", "borderRadius": 8, "font": "sans-serif", "lineHeight": 46, "lineSpacing": 4, "fillCorners": true }, + "rootDefaults": { "background": "#06a", "color": "white", "borderRadius": 8, "font": "sans-serif", "lineHeight": 46, "lineSpacing": 4, "fillCorners": true, "xSpacing": 8 }, "defaults": { ".": { "borderWidth": 4, "padding": 8 }, - "skylt": { "padding": 6, "blockDisplay": false, "passAnchor": false, "alignContentsV": "middle", "alignContents": "left", "xSpacing": 8 }, + "skylt": { "padding": 6, "blockDisplay": false, "passAnchor": false, "alignContentsV": "middle" }, "vagnr": { "value": "000", "borderWidth": 3, "borderRadius": 7, "dashedInset": false, "padding": [14, 2] }, "text": { "value": "Text" }, "newline": {}, @@ -98,5 +99,51 @@ "h": "w-x1*k+sqrt((2*bra-x1*x1))+(sqrt((k*k+1))+k-1*bw/2)+margin", "cover": true } + }, + "templates": { + "avfart": (no = "1") => ({ + "type": "skylt", + "properties": { + "padding": 0, + "background": "#aaa", + "color": "black" + }, + "elements": [ + { + "type": "skylt", + "properties": { + "background": "#fd0", + "borderWidth": 4, + "borderRadius": 22, + "padding": [5, 0] + }, + "elements": [ + { + "type": "symbol", + "properties": { "type": "exit" } + }, + { + "type": "text", + "properties": { + "value": no + } + } + ] + } + ] + }), + "vagnr": (no = "000") => ({ + "type": "vagnr", + "properties": { + "value": no + } + }), + "symgroup": (...s: (string | string[])[]) => ({ + "type": "skylt", + "properties": {"padding": 0, "xSpacing": 0, "borderWidth": [3, 0, 0, 0], "borderRadius": 0, "color": "black", "background": "white"}, + "elements": s.map(x => ({"type": "symbol", "properties": {"type": Array.isArray(x) ? x[0] : x, "variant": Array.isArray(x) ? x[1] : undefined , "borderWidth": [0, 3, 3, 3], "padding": 1}})) + }) } -} \ No newline at end of file +} + +export default CONFIG; \ No newline at end of file diff --git a/graphics.js b/src/graphics.ts similarity index 84% rename from graphics.js rename to src/graphics.ts index ccb4db9..f951009 100644 --- a/graphics.js +++ b/src/graphics.ts @@ -1,9 +1,11 @@ -function roundedFrame(ctx, x0, y0, innerWidth, innerHeight, nominalLineWidth = [4, 4, 4, 4], color = "#000", borderRadius = [0, 0, 0, 0], lineDash = [1, 0]){ +import type { DrawingContext, Vec4, Vec2 } from "./typedefs.js"; + +export function roundedFrame(ctx: DrawingContext, x0: number, y0: number, innerWidth: number, innerHeight: number, nominalLineWidth: Vec4 = [4, 4, 4, 4], color: string = "#000", borderRadius: Vec4 = [0, 0, 0, 0], lineDash: Vec2 = [1, 0]){ // lineDash = [längd, mellanrum] if(Math.max(...nominalLineWidth) <= 0) return; - let drawCorner = (cx, cy, signX, signY, i) => { + let drawCorner = (cx: number, cy: number, signX: number, signY: number, i: number) => { let w0 = nominalLineWidth[(Math.ceil(i / 2) * 2) % 4], w1 = nominalLineWidth[Math.floor(i / 2) * 2 + 1], br = borderRadius[i]; @@ -38,7 +40,7 @@ function roundedFrame(ctx, x0, y0, innerWidth, innerHeight, nominalLineWidth = [ drawCorner(x0 + innerWidth, y0 + innerHeight, 1, 1, 2); drawCorner(x0, y0 + innerHeight, -1, 1, 3); - let drawLineDash = (innerLength, cb) => { + let drawLineDash = (innerLength: number, cb: (z: number, s: number) => void) => { let actualLineDash = [lineDash[0], lineDash[1]]; let r = 0; @@ -84,7 +86,7 @@ function roundedFrame(ctx, x0, y0, innerWidth, innerHeight, nominalLineWidth = [ } -function roundedFill(ctx, x0, y0, innerWidth, innerHeight, borderWidth = [4, 4, 4, 4], borderRadius = [0, 0, 0, 0], background = "#fff", fillCorners = false){ +export function roundedFill(ctx: DrawingContext, x0: number, y0: number, innerWidth: number, innerHeight: number, borderWidth: Vec4 = [4, 4, 4, 4], borderRadius: Vec4 = [0, 0, 0, 0], background: string = "#fff", fillCorners: boolean = false){ // lineDash = [längd, mellanrum] ctx.fillStyle = background; @@ -94,7 +96,7 @@ function roundedFill(ctx, x0, y0, innerWidth, innerHeight, borderWidth = [4, 4, return; } - let drawCorner = (cx, cy, signX, signY, i) => { + let drawCorner = (cx: number, cy: number, signX: number, signY: number, i: number) => { let arx = borderRadius[i] + borderWidth[(Math.ceil(i / 2) * 2) % 4] / 2, ary = borderRadius[i] + borderWidth[Math.floor(i / 2) * 2 + 1] / 2; diff --git a/render.js b/src/render.ts similarity index 75% rename from render.js rename to src/render.ts index 1f638a4..22144d6 100644 --- a/render.js +++ b/src/render.ts @@ -1,6 +1,7 @@ -(async function(){ - -const CONFIG = JSON.parse(await getText("config.json")); +import type {MathEnv, Vec4, SignElementProperties, DrawingContext, SignElementOptions, SignElementBaseProperties, RenderingResult} from "./typedefs.js" +import CONFIG from "./config.js"; +import {roundedFill, roundedFrame} from "./graphics.js"; +import {mathEval, parseVarStr, getText} from "./utils.js"; // Priority: // 1. Specified value @@ -8,7 +9,6 @@ const CONFIG = JSON.parse(await getText("config.json")); // 3. Default value (from DEFAULT_PROPERTIES) // 4. Global defaults (GLOBAL_DEFAULTS) -//const INHERITED = CONFIG.properties.inherit; // properties that can be inherited const GLOBAL_DEFAULTS = CONFIG.properties.globalDefaults; const DEFAULTS = CONFIG.properties.rootDefaults; const DEFAULT_PROPERTIES = CONFIG.properties.defaults; @@ -21,68 +21,29 @@ const SYMBOLER = CONFIG.symbols; // F9 (samlingsmärke för vägvisning). const BORDER_FEATURES = CONFIG.borderFeatures; -const TEMPLATES = { - "avfart": (no = "1") => ({ - "type": "skylt", - "properties": { - "padding": 0, - "background": "#aaa", - "color": "black" - }, - "elements": [ - { - "type": "skylt", - "properties": { - "background": "#fd0", - "borderWidth": 4, - "borderRadius": 22, - "padding": [5, 0] - }, - "elements": [ - { - "type": "symbol", - "properties": { "type": "exit" } - }, - { - "type": "text", - "properties": { - "value": no - } - } - ] - } - ] - }), - "vagnr": (no = "000") => ({ - "type": "vagnr", - "properties": { - "value": no - } - }), - "symgroup": (...s) => ({ - "type": "skylt", - "properties": {"padding": 0, "xSpacing": 0, "borderWidth": [3, 0, 0, 0], "borderRadius": 0, "color": "black", "background": "white"}, - "elements": s.map(x => ({"type": "symbol", "properties": {"type": Array.isArray(x) ? x[0] : x, "variant": Array.isArray(x) ? x[1] : undefined , "borderWidth": [0, 3, 3, 3], "padding": 1}})) - }) -}; - -function to4EForm(data){ +const TEMPLATES = CONFIG.templates; + +function to4EForm(data: number[] | number): Vec4{ if(!Array.isArray(data)) data = [ data, data ]; if(data.length != 4) data = [ data[0], data[1], data[0], data[1] ]; - return data; + return [data[0], data[1], data[2], data[3]]; } class BorderElement{ - constructor(featureName, bw, brA, brB, sideLength){ + env: MathEnv; + w: number; + h: number; + n: string; + + constructor(featureName: string, bw: number, brA: number, brB: number, sideLength: number){ let w0 = BORDER_FEATURES[featureName].w, - h0 = BORDER_FEATURES[featureName].h, cvr = !!BORDER_FEATURES[featureName].cover; if(cvr) w0 = sideLength - bw; this.env = BorderElement.calculateEnv(featureName, bw, brA, brB, w0); - if(cvr) h0 = mathEval(h0, this.env); + let h0 = mathEval(BORDER_FEATURES[featureName].h, this.env); this.env["h"] = h0; @@ -91,8 +52,8 @@ class BorderElement{ this.n = featureName; } - static calculateEnv(featureName, bw, brA, brB, w0){ - let env = {bra: brA, brb: brB, bw: bw, w: w0}; + static calculateEnv(featureName: string, bw: number, brA: number, brB: number, w0: number): MathEnv{ + let env: MathEnv = {bra: brA, brb: brB, bw: bw, w: w0}; let feature = BORDER_FEATURES[featureName]; if(!Array.isArray(feature.vars)) return env; @@ -106,19 +67,22 @@ class BorderElement{ } class BorderDimensions{ - constructor(heights){ - this.h = [0, 0, 0, 0].map((_, i) => heights[i]); + h: Vec4; + el: (BorderElement | null)[]; + + constructor(heights: Vec4){ + this.h = [...heights]; this.el = [null, null, null, null]; } - set(i, el){ + set(i: number, el: BorderElement){ this.el[i] = el; this.h[i] = Math.floor(el.h); } } -class SignElement{ - static borderSize(innerWidth, innerHeight, properties){ +export default class SignElement{ + static borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ let bs = new BorderDimensions(properties.borderWidth); if(properties.borderFeatures["left"] !== undefined) @@ -136,7 +100,7 @@ class SignElement{ return bs; } - static calculateAlignmentOffset(alignMode, innerWidth, outerWidth){ + static calculateAlignmentOffset(alignMode: string | undefined, innerWidth: number, outerWidth: number){ switch(alignMode){ case "center": return Math.floor((outerWidth - innerWidth) / 2); @@ -148,7 +112,7 @@ class SignElement{ } } - static renderBorderFeature(ctx, x0, y0, featureName, side, properties, bs, borderBoxInnerW, innerHeight){ + static renderBorderFeature(ctx: DrawingContext, x0: number, y0: number, featureName: string, side: string, properties: SignElementProperties, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ let color = properties.color, background = properties.background; @@ -156,7 +120,7 @@ class SignElement{ let bri = lr ? (side === "left" ? 0 : 2) : (side === "top" ? 1 : 3); let bw = properties.borderWidth[bri]; - let s = [bs.el[bri].w, bs.el[bri].h]; + let s = [bs.el[bri]?.w || 0, bs.h[bri]]; let feature = BORDER_FEATURES[featureName]; @@ -198,7 +162,7 @@ class SignElement{ feature.paths.forEach(path => { let p = new Path2D(); - p.addPath(new Path2D(parseVarStr(path.p, bs.el[bri].env)), tm); + p.addPath(new Path2D(parseVarStr(path.p, bs.el[bri]?.env)), tm); if(path.f !== undefined){ ctx.fillStyle = [color, background][Math.abs(path.f)-1]; @@ -212,7 +176,12 @@ class SignElement{ }); } - constructor(data, parentProperties){ + type: string; + properties: SignElementProperties; + children: SignElement[]; + nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}} + + constructor(data: SignElementOptions, parentProperties: SignElementBaseProperties | null){ while(data.type.startsWith("#")){ let templateName = data.type.slice(1); if(!TEMPLATES[templateName]){ @@ -245,22 +214,28 @@ class SignElement{ this.children = (data.elements || []).map(element => new SignElement(element, inh)); - this.nodes = (data.nodes || {}); - Object.keys(this.nodes).forEach(key => this.nodes[key].signelement = new SignElement(this.nodes[key].data, inh)); + this.nodes = {}; + Object.entries(data.nodes || {}).forEach(e => { + this.nodes[e[0]] = { + signelement: new SignElement(e[1].data, inh), + anchor: e[1].anchor + } + }); } - _getInhProperties(){ - const { background, borderRadius, color, font, lineHeight, lineSpacing } = this.properties; - return { background, borderRadius, color, font, lineHeight, lineSpacing }; + _getInhProperties(): SignElementBaseProperties{ + const { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing } = this.properties; + return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; } - render(){ - let firstLastCenter = null; // [cx_first, cy_firstrow, cx_last, cy_lastrow] + render(): RenderingResult{ + let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] let padding = Array.from(this.properties.padding); let width = 0, height = 0, maxHeight = 0; - let renderPromise = (ctx, x0, y0, _) => Promise.resolve(); + let renderPromise: (ctx: DrawingContext, x0: number, y0: number, maxInnerHeight: number) => Promise + = () => Promise.resolve(); if(this.type == "skylt"){ let w = [0], h = [0], j = 0; @@ -268,19 +243,16 @@ class SignElement{ let totalLineSpacing = 0; let ch = this.children.map((c, i) => { - let c2 = { isn: c.type == "newline" }; + let re = c.render(); + let c2 = { isn: c.type == "newline", r: re, bs: re.bs, row: j, x: 0 }; if(c2.isn || (i > 0 && this.properties.blockDisplay)){ - j++; + c2.row = ++j; w.push(0); h.push(0); totalLineSpacing += (this.properties.blockDisplay ? this.properties.lineSpacing : c.properties.lineSpacing); } - c2.r = c.render(); - c2.row = j; - c2.bs = c2.r.bs; - if(!c2.isn){ if(w[j] > 0){ w[j] += this.properties.xSpacing; @@ -349,18 +321,17 @@ class SignElement{ x0 + padding[0] + c2.x, y0 + padding[1] + y, dx, this.children[i].properties, - this.properties, h[c2.row] - c2.bs[1] - c2.bs[3], + this.properties.alignContentsV, iw ); - })); + })).then(() => {}); }else if(this.type == "vagnr" || this.type == "text"){ - let ctx_temp = document.createElement("canvas").getContext("2d"); - ctx_temp.font = "32px " + this.properties.font; + let ctx_temp = document.createElement("canvas").getContext("2d") as DrawingContext; - let box = ctx_temp.measureText(this.properties.value); + ctx_temp.font = "32px " + this.properties.font; - width = Math.floor(box.width); + width = Math.floor(ctx_temp.measureText(this.properties.value || "").width); height = this.properties.lineHeight; renderPromise = (ctx, x0, y0, _) => new Promise(res => { @@ -380,20 +351,19 @@ class SignElement{ ctx.font = "32px " + this.properties.font; ctx.textBaseline = "middle"; - ctx.textAlign = "left"; ctx.fillStyle = this.properties.color; - ctx.fillText(this.properties.value, x0 + padding[0], y0 + firstLastCenter[1]); + ctx.fillText(this.properties.value || "", x0 + padding[0], y0 + firstLastCenter[1]); res(); }); }else if(this.type == "symbol"){ - let symbolType = SYMBOLER[this.properties.type]; - let img = document.createElement("img"); + let symbolType = SYMBOLER[this.properties.type || ""]; - width = img.width = symbolType.width; - height = symbolType.height[0]; - img.height = maxHeight = symbolType.height[1]; + width = symbolType.width; + [height, maxHeight] = symbolType.height; + + let img = new Image(width, maxHeight); renderPromise = (ctx, x0, y0, maxInnerHeight) => new Promise((res, rej) => { img.addEventListener("load", () => { @@ -408,7 +378,7 @@ class SignElement{ }); img.addEventListener("error", rej); - let url = "svg/symbol/" + window.encodeURIComponent(this.properties.type) + ".svg"; + let url = "svg/symbol/" + window.encodeURIComponent(this.properties.type || "") + ".svg"; getText(url).then(xml => { img.src = "data:image/svg+xml;utf8," @@ -423,9 +393,7 @@ class SignElement{ let t = SKYLTTYPER[this.type.slice(1)]; let keys = Object.keys(t.nodes).sort().filter(nodeName => !!this.nodes[nodeName]); - let svg = document.createElement("img"); - svg.width = t.width; - svg.height = t.height; + let svg = new Image(t.width, t.height); let svgBox = Array.from(t.core); keys.forEach(nodeName => { @@ -456,40 +424,41 @@ class SignElement{ let rse = [ result.w + bs[0] + bs[2], result.h + bs[1] + bs[3] ]; - let leftX = tn.x.map(x => x * t.width).map(Math.floor), topY = tn.y.map(y => y * t.height).map(Math.floor); + let lx = tn.x.map(x => x * t.width).map(Math.floor), ty = tn.y.map(y => y * t.height).map(Math.floor); + let leftX: number = 0, topY: number = 0; switch(n.anchor.x){ case "right": - leftX = leftX[1] - rse[0]; + leftX = lx[1] - rse[0]; break; case "center": - leftX = Math.floor((leftX[0] + leftX[1]) / 2 - Math.floor(rse[0] / 2)); + leftX = Math.floor((lx[0] + lx[1]) / 2 - Math.floor(rse[0] / 2)); break; case "center-first": - leftX = Math.floor((leftX[0] + leftX[1]) / 2) - result.flc[0]; + leftX = Math.floor((lx[0] + lx[1]) / 2) - result.flc[0]; break; case "center-last": - leftX = Math.floor((leftX[0] + leftX[1]) / 2) - result.flc[2]; + leftX = Math.floor((lx[0] + lx[1]) / 2) - result.flc[2]; break; default: - leftX = leftX[0]; + leftX = lx[0]; } switch(n.anchor.y){ case "bottom": - topY = topY[1] - rse[1]; + topY = ty[1] - rse[1]; break; case "middle": - topY = Math.floor((topY[0] + topY[1]) / 2) - Math.floor(rse[1] / 2); + topY = Math.floor((ty[0] + ty[1]) / 2) - Math.floor(rse[1] / 2); break; case "middle-first": - topY = Math.floor((topY[0] + topY[1]) / 2) - result.flc[1] - bs[1]; + topY = Math.floor((ty[0] + ty[1]) / 2) - result.flc[1] - bs[1]; break; case "middle-last": - topY = Math.floor((topY[0] + topY[1]) / 2) - result.flc[3] - bs[1]; + topY = Math.floor((ty[0] + ty[1]) / 2) - result.flc[3] - bs[1]; break; default: - topY = topY[0]; + topY = ty[0]; } boundingBox = [ @@ -511,7 +480,7 @@ class SignElement{ let dx = 0; - return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.p, this.properties, res.renderPromise.h); + return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.p, res.renderPromise.h, this.properties.alignContentsV); })).then(() => { if(t.width == 0 || t.height == 0) return; @@ -534,7 +503,7 @@ class SignElement{ }).then(() => { let svgRasterized = document.createElement("canvas"); Object.assign(svgRasterized, { width: t.width, height: t.height }); - svgRasterized.getContext("2d").drawImage(svg, 0, 0, t.width, t.height); + (svgRasterized.getContext("2d") as DrawingContext).drawImage(svg, 0, 0, t.width, t.height); ctx.drawImage( svgRasterized, @@ -554,12 +523,13 @@ class SignElement{ let bs = SignElement.borderSize(width + padding[0] + padding[2], height + padding[1] + padding[3], this.properties); - if(firstLastCenter === null){ + if(firstLastCenter.some(isNaN)){ firstLastCenter = [ + Math.floor((width + padding[0] + padding[2]) / 2), + Math.floor((height + padding[1] + padding[3]) / 2), Math.floor((width + padding[0] + padding[2]) / 2), Math.floor((height + padding[1] + padding[3]) / 2) ]; - firstLastCenter.push(...firstLastCenter); } if(maxHeight < height) maxHeight = height; @@ -569,7 +539,7 @@ class SignElement{ w: width + padding[0] + padding[2], h: height + padding[1] + padding[3], bs: bs.h, - doRender: async (ctx, x0, y0, dx, prop, parentProperties = {}, maxInnerHeight, iw = 0) => { + doRender: async (ctx: DrawingContext, x0: number, y0: number, dx: number, prop: SignElementProperties, maxInnerHeight, verticalAlign?: string, iw = 0) => { const dy = 0; const innerWidth = iw === 0 ? (width + padding[0] + padding[2]) : iw; let innerHeight = height + padding[1] + padding[3]; @@ -578,7 +548,7 @@ class SignElement{ innerHeight = Math.min(maxInnerHeight, padding[1] + padding[3] + maxHeight); } - switch (parentProperties.alignContentsV) { + switch (verticalAlign) { case "middle": y0 += Math.floor((maxInnerHeight - innerHeight) / 2); break; @@ -593,17 +563,19 @@ class SignElement{ return bf !== undefined && BORDER_FEATURES[bf].cover; // cover => hel, täcker hela kantens längd }); - let br = Array.from(prop.borderRadius); + let br: Vec4 = [...prop.borderRadius], + bw: Vec4 = [...prop.borderWidth]; for(let i = 0; i < 4; i++){ if(bfs[i] || bfs[(i + 1) % 4]) br[i] = 0; + if(bfs[i]) bw[i] = 0; } roundedFill( ctx, x0 + bs.h[0], y0 + bs.h[1], innerWidth, innerHeight, - prop.borderWidth.map((x, i) => bfs[i] ? 0 : x), + bw, br, prop.background, !!prop.fillCorners @@ -615,7 +587,7 @@ class SignElement{ ctx, x0 + bs.h[0], y0 + bs.h[1], innerWidth, innerHeight, - prop.borderWidth.map((x, i) => bfs[i] ? 0 : x), + bw, prop.color, br ); @@ -626,37 +598,4 @@ class SignElement{ } }; } -} - -const canvas = document.getElementsByTagName("canvas")[0]; -const ctx = canvas.getContext("2d"); - -const tratex = new FontFace( - "Tratex", - "url(TratexSvart-Regular.otf)", -); - -const tratexVersal = new FontFace( - "TratexVersal", - "url(TRATEXPOSVERSAL-POSVERSAL.otf)", -); - -document.fonts.add(tratex); -document.fonts.add(tratexVersal); - -Promise.all([tratex.load(), tratexVersal.load()]).then(() => { - let url = new URL(window.location.href); - if(!url.searchParams.has("data")) return; - - let data = JSON.parse(url.searchParams.get("data")); - - let sign = new SignElement(data, null); - let r = sign.render(); - - let bs = r.bs; - Object.assign(canvas, { width: r.w + bs[0] + bs[2], height: r.h + bs[1] + bs[3] }); - - r.doRender(ctx, 0, 0, 0, sign.properties, {}, r.h); -}); - -})(); \ No newline at end of file +} \ No newline at end of file diff --git a/src/typedefs.ts b/src/typedefs.ts new file mode 100644 index 0000000..603894f --- /dev/null +++ b/src/typedefs.ts @@ -0,0 +1,147 @@ +export type MathEnv = { [key: string]: number}; + +export type Vec2 = [number, number]; +export type Vec4 = [number, number, number, number]; + +type BorderFeatureDefinition = { + vars?: string[][]; + paths: {p: string, f?: number, s?: number}[]; + w: number; + h: number | string; + cover: boolean; +}; + +type SignTypeDefinition = { + nodes: { + [key: string]: { + x: number[]; + y: number[]; + ax?: string; + ay?: string; + } + }; + width: number; + height: number; + core: number[]; +}; + +type SignSymbolDefinition = { + width: number; + height: number[]; + default: string; +}; + +export type ConfigData = { + properties: { + globalDefaults: SignElementUserProperties; + rootDefaults: SignElementBaseProperties & SignElementUserProperties; + defaults: {[key: string]: SignElementUserProperties}; + }, + signTypes: { + [key: string]: SignTypeDefinition + }, + symbols: { + [key: string]: SignSymbolDefinition + }, + borderFeatures: { + [key: string]: BorderFeatureDefinition + }, + templates: { + [key: string]: (...args: any[]) => SignElementOptions + } +}; + +export type RenderingResult = { + flc: Vec4; + w: number; + h: number; + bs: Vec4; + doRender: (ctx: DrawingContext, x0: number, y0: number, dx: number, prop: any, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; +}; + +// properties som ärvs +export type SignElementBaseProperties = { + background: string; + borderRadius: number[] | number; + color: string; + font: string; + lineHeight: number; + lineSpacing: number; + xSpacing: number; +}; + +type SignElementOptionalUserProperties = { + alignContents?: string; + alignContentsV?: string; + blockDisplay?: boolean; + dashedInset?: boolean; + fillCorners?: boolean; + grow?: boolean; + passAnchor?: boolean; + type?: string; // symbol + value?: string; // text, vagnr + variant?: string; // symbol + + borderFeatures?: {[key: string]: string}; + borderWidth?: number[] | number; + padding?: number[] | number; +} + +type SignElementUserProperties = Partial & SignElementOptionalUserProperties; + +// formatet som this.properties följer +export interface SignElementProperties extends SignElementOptionalUserProperties, SignElementBaseProperties{ + borderFeatures: {[key: string]: string}; + borderRadius: Vec4; + borderWidth: Vec4; + padding: Vec4; +}; + +type SignElementNode = { + anchor: { + x?: string; + y?: string; + }; + data: SignElementOptions; +}; + +// data som ges av användaren +export type SignElementOptions = { + format?: number; + type: string; + properties?: any; + elements?: SignElementOptions[]; + nodes?: {[key: string]: SignElementNode}; + params?: any[]; +} + +export interface GenericDrawingContext{ + transform(a: number, b: number, c: number, d: number, e: number, f: number): void; + + measureText(text: string): {width: number}; + + set fillStyle(x: string); + set strokeStyle(x: string); + set lineWidth(x: number); + + set font(x: string); + set textBaseline(x: string); + + beginPath(): void; + moveTo(x: number, y: number): void; + lineTo(x: number, y: number): void; + ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise: boolean): void; + + fill(): void; + fill(path: Path2D): void; + stroke(path: Path2D): void; + + fillRect(x: number, y: number, w: number, h: number): void; + fillText(text: string, x: number, y: number): void; + + drawImage(image: CanvasImageSource, dx: number, dy: number): void; + drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; + drawImage(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; +} + +export type DrawingContext = CanvasRenderingContext2D | GenericDrawingContext; \ No newline at end of file diff --git a/utils.js b/src/utils.ts similarity index 69% rename from utils.js rename to src/utils.ts index 3c71a38..87451da 100644 --- a/utils.js +++ b/src/utils.ts @@ -1,7 +1,11 @@ -function mathEval(str = "", vars = {}){ - let values = [0], operators = ["+"], tmp = ""; +import type { MathEnv } from "./typedefs.js"; - let doOp = (a, op, b) => { +export function mathEval(str: string | number, vars: MathEnv = {}): number{ + if(typeof str === "number") return str; + + let v = [0], operators = ["+"], tmp = ""; + + let doOp = (a: number = 0, op: string = "+", b: number = 0): number => { switch(op){ case "+": a += b; @@ -30,7 +34,7 @@ function mathEval(str = "", vars = {}){ case " ": continue; case "(": - values.push(0); + v.push(0); if(tmp.length > 0){ operators.push(tmp); tmp = ""; @@ -43,15 +47,15 @@ function mathEval(str = "", vars = {}){ case "/": case "+": case "-": - let x0 = tmp.length > 0 ? doOp(values.pop(), operators.pop(), isNaN(tmp) ? vars[tmp] : parseFloat(tmp)) : values.pop(); + let x0 = tmp.length > 0 ? doOp(v.pop(), operators.pop(), isNaN(parseFloat(tmp)) ? vars[tmp] : parseFloat(tmp)) : v.pop(); tmp = ""; if(c === ")"){ - values[values.length - 1] = doOp(values[values.length - 1], operators.pop(), x0); + v[v.length - 1] = doOp(v[v.length - 1], operators.pop(), x0); break; } - values.push(x0); + v.push(x0 || 0); operators.push(c); break; default: @@ -59,13 +63,13 @@ function mathEval(str = "", vars = {}){ } } - return values[0]; + return v[0]; } -function parseVarStr(str, vars = {}){ +export function parseVarStr(str: string, vars = {}): string{ const EXPRESSION = new RegExp(/\$\{([^\{\}]+)\}/g); - let result = []; + let result: string[] = []; let i = 0; while(true){ @@ -81,8 +85,8 @@ function parseVarStr(str, vars = {}){ return result.join("") + str.substring(i); } -function getText(url){ - return new Promise((resolve, reject) => { +export function getText(url: string): Promise{ + return new Promise(resolve => { let req = new XMLHttpRequest(); req.addEventListener("load", () => { resolve(req.responseText); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..869e806 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + /* Language and Environment */ + "target": "es2017", + "noLib": false, + + /* Modules */ + "module": "NodeNext", + "rootDir": "./src", + "moduleResolution": "nodenext", + + /* Emit */ + "outDir": "./dist", + "removeComments": true, + + /* Interop Constraints */ + "esModuleInterop": false, + "forceConsistentCasingInFileNames": true, + + /* Type Checking */ + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": false, + "noImplicitOverride": true + } +} From eb691cc97a7cc80ed5345c47c912e4260c36b875 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Mon, 24 Feb 2025 18:11:04 +0100 Subject: [PATCH 02/12] =?UTF-8?q?L=C3=A4gg=20till=20st=C3=B6d=20f=C3=B6r?= =?UTF-8?q?=20node.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- TRATEXPOSVERSAL-POSVERSAL.otf | Bin 11424 -> 0 bytes TratexSvart-Regular.otf | Bin 18044 -> 0 bytes formatver.json | 1 - index.html | 79 ----- package-lock.json | 548 ++++++++++++++++++++++++++++++++-- package.json | 20 +- render.html | 46 --- src/browser.ts | 22 ++ src/main.ts | 24 ++ src/render.ts | 108 ++++--- src/typedefs.ts | 129 ++++---- styles.css | 45 --- templates.json | 150 ---------- tsconfig.json | 10 +- utils/clean.js | 21 ++ 16 files changed, 747 insertions(+), 459 deletions(-) delete mode 100644 TRATEXPOSVERSAL-POSVERSAL.otf delete mode 100644 TratexSvart-Regular.otf delete mode 100644 formatver.json delete mode 100644 index.html delete mode 100644 render.html create mode 100644 src/browser.ts create mode 100644 src/main.ts delete mode 100644 styles.css delete mode 100644 templates.json create mode 100644 utils/clean.js diff --git a/.gitignore b/.gitignore index b56ca80..9af227b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /dist/ /node_modules/ -*.tsbuildinfo \ No newline at end of file +*.tsbuildinfo +/index*.js \ No newline at end of file diff --git a/TRATEXPOSVERSAL-POSVERSAL.otf b/TRATEXPOSVERSAL-POSVERSAL.otf deleted file mode 100644 index 60762aa2594096c98e87fd3b47e03b755fa00934..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11424 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 RzjHu;L}7y9r8f$~{{vk0$Xoyb diff --git a/formatver.json b/formatver.json deleted file mode 100644 index c0e9afb..0000000 --- a/formatver.json +++ /dev/null @@ -1 +0,0 @@ -["4b2b419"] \ No newline at end of file diff --git a/index.html b/index.html deleted file mode 100644 index 14f55ef..0000000 --- a/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Skyltprogram - - - - - -
-
- -
- - - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d52f949..c626569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,29 +1,525 @@ { - "name": "skyltprogram", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "skyltprogram", - "version": "1.0.0", - "license": "AGPL-3.0-or-later", - "devDependencies": { - "typescript": "^5.7.3" - } - }, - "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } + "name": "skyltrendering", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "skyltrendering", + "version": "1.0.0", + "hasInstallScript": true, + "license": "AGPL-3.0-or-later", + "dependencies": { + "@napi-rs/canvas": "^0.1.67" + }, + "devDependencies": { + "@types/node": "^22.13.5", + "esbuild": "^0.25.0", + "typescript": "^5.7.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.67", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.67.tgz", + "integrity": "sha512-VA4Khm/5Kg2bQGx3jXotTC4MloOG8b1Ung80exafUK0k5u6yJmIz3Q2iXeeWZs5weV+LQOEB+CPKsYwEYaGAjw==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.67", + "@napi-rs/canvas-darwin-arm64": "0.1.67", + "@napi-rs/canvas-darwin-x64": "0.1.67", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.67", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.67", + "@napi-rs/canvas-linux-arm64-musl": "0.1.67", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.67", + "@napi-rs/canvas-linux-x64-gnu": "0.1.67", + "@napi-rs/canvas-linux-x64-musl": "0.1.67", + "@napi-rs/canvas-win32-x64-msvc": "0.1.67" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.67", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.67.tgz", + "integrity": "sha512-K/JmkOFbc4iRZYUqJhj0jwqfHA/wNQEmTiGNsgZ6d59yF/IBNp5T0D5eg3B8ghjI8GxDYCiSJ6DNX8mC3Oh2EQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/node": { + "version": "22.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz", + "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", + "dev": true, + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" + } + }, + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + } } - } } diff --git a/package.json b/package.json index 34b7490..72f9eda 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,24 @@ { - "name": "skyltprogram", + "name": "skyltrendering", "version": "1.0.0", "description": "", - "type": "module", - "main": "index.js", + "main": "dist/main.js", + "browser": "index.esm.js", "scripts": { - "start": "tsc --watch", - "build": "tsc" + "clean": "node ./utils/clean.js ./dist/", + "install": "npm run build", + "build": "npm run clean && npm run build-node && npm run build-web", + "build-node": "tsc", + "build-web": "esbuild ./src/browser.ts --format=esm --bundle --outfile=./index.esm.js" }, "author": "axelw3", "license": "AGPL-3.0-or-later", "devDependencies": { - "typescript": "^5.7.3" + "@types/node": "^22.13.5", + "typescript": "^5.7.3", + "esbuild": "^0.25.0" + }, + "dependencies": { + "@napi-rs/canvas": "^0.1.67" } } diff --git a/render.html b/render.html deleted file mode 100644 index 240b8e0..0000000 --- a/render.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - Skyltprogram (rendering) - - - - - - - \ No newline at end of file diff --git a/src/browser.ts b/src/browser.ts new file mode 100644 index 0000000..dd3d668 --- /dev/null +++ b/src/browser.ts @@ -0,0 +1,22 @@ +import { SignElement as _SignElement } from "./render.js"; +import { SignElementBaseProperties, SignElementOptions, Vec6, Path2D as _Path2D } from "./typedefs.js"; + + +export class SignElement extends _SignElement{ + constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ + opt = _SignElement.resolveTemplate(opt); + super(opt, popt); + this.addCN(SignElement, opt); + } + + protected override _createCanvas(w?: number, h?: number): HTMLCanvasElement { + return Object.assign(document.createElement("canvas"), {width: w || 300, height: h || 150}); + } + + protected override _createPath2D(s: string, m?: Vec6): _Path2D { + let p = new Path2D(); + let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; + p.addPath(new Path2D(s), {a, b, c, d, e, f}); + return p; + } +}; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..d81abff --- /dev/null +++ b/src/main.ts @@ -0,0 +1,24 @@ +import { SignElement as _SignElement } from "./render.js"; +import { SignElementBaseProperties, SignElementOptions, Vec6, Path2D as _Path2D } from "./typedefs.js"; + +import {createCanvas, Canvas, Path2D} from "@napi-rs/canvas"; + + +export class SignElement extends _SignElement{ + constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ + opt = _SignElement.resolveTemplate(opt); + super(opt, popt); + this.addCN(SignElement, opt); + } + + protected override _createCanvas(w?: number, h?: number): Canvas { + return createCanvas(w || 300, h || 150); + } + + protected override _createPath2D(s: string, m?: Vec6): _Path2D { + let p = new Path2D(); + let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; + p.addPath(new Path2D(s), {a, b, c, d, e, f}); + return p; + } +}; \ No newline at end of file diff --git a/src/render.ts b/src/render.ts index 22144d6..5b3cc47 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,4 +1,4 @@ -import type {MathEnv, Vec4, SignElementProperties, DrawingContext, SignElementOptions, SignElementBaseProperties, RenderingResult} from "./typedefs.js" +import type {MathEnv, Vec4, SignElementProperties, DrawingContext, SignElementOptions, SignElementBaseProperties, RenderingResult, DrawingCanvas, Vec6, Path2D} from "./typedefs.js" import CONFIG from "./config.js"; import {roundedFill, roundedFrame} from "./graphics.js"; import {mathEval, parseVarStr, getText} from "./utils.js"; @@ -81,8 +81,11 @@ class BorderDimensions{ } } -export default class SignElement{ - static borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ +export abstract class SignElement{ + protected abstract _createCanvas(w?: number, h?: number): T; + protected abstract _createPath2D(s: string, m?: Vec6): Path2D; + + private static borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ let bs = new BorderDimensions(properties.borderWidth); if(properties.borderFeatures["left"] !== undefined) @@ -100,7 +103,7 @@ export default class SignElement{ return bs; } - static calculateAlignmentOffset(alignMode: string | undefined, innerWidth: number, outerWidth: number){ + private static calculateAlignmentOffset(alignMode: string | undefined, innerWidth: number, outerWidth: number){ switch(alignMode){ case "center": return Math.floor((outerWidth - innerWidth) / 2); @@ -112,14 +115,14 @@ export default class SignElement{ } } - static renderBorderFeature(ctx: DrawingContext, x0: number, y0: number, featureName: string, side: string, properties: SignElementProperties, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ - let color = properties.color, - background = properties.background; + private renderBorderFeature(ctx: DrawingContext, x0: number, y0: number, featureName: string, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ + let color = this.properties.color, + background = this.properties.background; let lr = (side === "left" || side === "right"); let bri = lr ? (side === "left" ? 0 : 2) : (side === "top" ? 1 : 3); - let bw = properties.borderWidth[bri]; + let bw = this.properties.borderWidth[bri]; let s = [bs.el[bri]?.w || 0, bs.h[bri]]; let feature = BORDER_FEATURES[featureName]; @@ -148,9 +151,9 @@ export default class SignElement{ let sr = lr ? (side === "left" ? 1 : (-1)) : 0, cr = lr ? 0 : (side === "top" ? (-1) : 1); let [a, b] = [(s[0] - bw) / 2, (s[1] - bw) / 2]; - let tm = new DOMMatrix().translateSelf(x0 + w / 2, y0 + h / 2).multiplySelf(new DOMMatrix([ - cr, sr, -sr, cr, -a*cr + b*sr, -a*sr - b*cr - ])); + let tm: Vec6 = [ + cr, sr, -sr, cr, (x0 + w / 2) - a*cr + b*sr, (y0 + h / 2) - a*sr - b*cr + ]; //ctx.fillStyle="#000"; //ctx.fillRect(x0, y0, w, h); @@ -161,27 +164,26 @@ export default class SignElement{ ctx.lineWidth = bw; feature.paths.forEach(path => { - let p = new Path2D(); - p.addPath(new Path2D(parseVarStr(path.p, bs.el[bri]?.env)), tm); + let p = this._createPath2D(parseVarStr(path.p, bs.el[bri]?.env), tm); if(path.f !== undefined){ ctx.fillStyle = [color, background][Math.abs(path.f)-1]; - if(path.f > 0 || properties.fillCorners) ctx.fill(p); + if(path.f > 0 || this.properties.fillCorners) ctx.fill(p); } if(path.s !== undefined){ ctx.strokeStyle = [color, background][Math.abs(path.s)-1]; - if(path.s > 0 || properties.fillCorners) ctx.stroke(p); + if(path.s > 0 || this.properties.fillCorners) ctx.stroke(p); } }); } - type: string; - properties: SignElementProperties; - children: SignElement[]; - nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}} + private type: string; + private properties: SignElementProperties; + private children: SignElement[]; + private nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}}; - constructor(data: SignElementOptions, parentProperties: SignElementBaseProperties | null){ + protected static resolveTemplate(data: SignElementOptions): SignElementOptions{ while(data.type.startsWith("#")){ let templateName = data.type.slice(1); if(!TEMPLATES[templateName]){ @@ -190,10 +192,14 @@ export default class SignElement{ } let template = TEMPLATES[templateName](...(data.params || [])); - Object.assign(template.properties, data.properties); + template.properties = Object.assign(template.properties || {}, data.properties); data = template; } + return data; + } + + protected constructor(data: SignElementOptions, parentProperties: SignElementBaseProperties | null){ this.type = data.type; let prop = Object.assign( @@ -210,25 +216,29 @@ export default class SignElement{ borderWidth: to4EForm(prop.borderWidth) }); - let inh = this._getInhProperties(); + this.children = []; + this.nodes = {}; + } - this.children = (data.elements || []).map(element => new SignElement(element, inh)); + protected addCN>(Cl: new (opt: any, inh: SignElementBaseProperties | null) => X, data: SignElementOptions){ + let inh = this.getInhProperties(); + + this.children = (data.elements || []).map(element => new Cl(element, inh)); - this.nodes = {}; Object.entries(data.nodes || {}).forEach(e => { this.nodes[e[0]] = { - signelement: new SignElement(e[1].data, inh), + signelement: new Cl(e[1].data, inh), anchor: e[1].anchor } }); } - _getInhProperties(): SignElementBaseProperties{ + private getInhProperties(): SignElementBaseProperties{ const { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing } = this.properties; return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; } - render(): RenderingResult{ + private _render(): RenderingResult{ let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] let padding = Array.from(this.properties.padding); @@ -243,7 +253,7 @@ export default class SignElement{ let totalLineSpacing = 0; let ch = this.children.map((c, i) => { - let re = c.render(); + let re = c._render(); let c2 = { isn: c.type == "newline", r: re, bs: re.bs, row: j, x: 0 }; if(c2.isn || (i > 0 && this.properties.blockDisplay)){ @@ -320,14 +330,13 @@ export default class SignElement{ ctx, x0 + padding[0] + c2.x, y0 + padding[1] + y, dx, - this.children[i].properties, h[c2.row] - c2.bs[1] - c2.bs[3], this.properties.alignContentsV, iw ); })).then(() => {}); }else if(this.type == "vagnr" || this.type == "text"){ - let ctx_temp = document.createElement("canvas").getContext("2d") as DrawingContext; + let ctx_temp = this._createCanvas().getContext("2d") as DrawingContext; ctx_temp.font = "32px " + this.properties.font; @@ -419,7 +428,7 @@ export default class SignElement{ n.anchor = Object.assign({ "x": tn.ax, "y": tn.ay }, n.anchor); - let result = s.render(); + let result = s._render(); let bs = result.bs; let rse = [ result.w + bs[0] + bs[2], result.h + bs[1] + bs[3] ]; @@ -480,7 +489,7 @@ export default class SignElement{ let dx = 0; - return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.p, res.renderPromise.h, this.properties.alignContentsV); + return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.renderPromise.h, this.properties.alignContentsV); })).then(() => { if(t.width == 0 || t.height == 0) return; @@ -501,8 +510,7 @@ export default class SignElement{ svg.onerror = reject; svg.src = "svg/" + this.type.slice(1) + ".svg#" + keys.join("_"); }).then(() => { - let svgRasterized = document.createElement("canvas"); - Object.assign(svgRasterized, { width: t.width, height: t.height }); + let svgRasterized = this._createCanvas(t.width, t.height); (svgRasterized.getContext("2d") as DrawingContext).drawImage(svg, 0, 0, t.width, t.height); ctx.drawImage( @@ -539,7 +547,7 @@ export default class SignElement{ w: width + padding[0] + padding[2], h: height + padding[1] + padding[3], bs: bs.h, - doRender: async (ctx: DrawingContext, x0: number, y0: number, dx: number, prop: SignElementProperties, maxInnerHeight, verticalAlign?: string, iw = 0) => { + doRender: async (ctx: DrawingContext, x0: number, y0: number, dx: number, maxInnerHeight, verticalAlign?: string, iw = 0) => { const dy = 0; const innerWidth = iw === 0 ? (width + padding[0] + padding[2]) : iw; let innerHeight = height + padding[1] + padding[3]; @@ -559,12 +567,12 @@ export default class SignElement{ // tag bort rundade hörn på sidor med hela kantutsmyckningar let bfs = ["left", "top", "right", "bottom"].map(s => { - let bf = prop.borderFeatures[s]; + let bf = this.properties.borderFeatures[s]; return bf !== undefined && BORDER_FEATURES[bf].cover; // cover => hel, täcker hela kantens längd }); - let br: Vec4 = [...prop.borderRadius], - bw: Vec4 = [...prop.borderWidth]; + let br: Vec4 = [...this.properties.borderRadius], + bw: Vec4 = [...this.properties.borderWidth]; for(let i = 0; i < 4; i++){ if(bfs[i] || bfs[(i + 1) % 4]) br[i] = 0; @@ -577,8 +585,8 @@ export default class SignElement{ innerWidth, innerHeight, bw, br, - prop.background, - !!prop.fillCorners + this.properties.background, + !!this.properties.fillCorners ); await renderPromise(ctx, x0 + dx + bs.h[0], y0 + dy + bs.h[1], innerHeight); @@ -588,14 +596,28 @@ export default class SignElement{ x0 + bs.h[0], y0 + bs.h[1], innerWidth, innerHeight, bw, - prop.color, + this.properties.color, br ); - Object.entries(prop.borderFeatures).forEach(feature => { - SignElement.renderBorderFeature(ctx, x0, y0, feature[1], feature[0], prop, bs, innerWidth, innerHeight); + Object.entries(this.properties.borderFeatures).forEach(feature => { + this.renderBorderFeature(ctx, x0, y0, feature[1], feature[0], bs, innerWidth, innerHeight); }); } }; } + + public render(): Promise{ + let canv = this._createCanvas(); + + let r = this._render(); + + let bs = r.bs; + Object.assign(canv, { width: r.w + bs[0] + bs[2], height: r.h + bs[1] + bs[3] }); + + let ctx = canv.getContext("2d"); + if(ctx === null) throw new Error("Fel: Kunde inte hitta tvådimensionell renderingskontext."); + + return r.doRender(ctx, 0, 0, 0, r.h).then(() => canv); + } } \ No newline at end of file diff --git a/src/typedefs.ts b/src/typedefs.ts index 603894f..f665386 100644 --- a/src/typedefs.ts +++ b/src/typedefs.ts @@ -2,6 +2,7 @@ export type MathEnv = { [key: string]: number}; export type Vec2 = [number, number]; export type Vec4 = [number, number, number, number]; +export type Vec6 = [number, number, number, number, number, number]; type BorderFeatureDefinition = { vars?: string[][]; @@ -31,35 +32,7 @@ type SignSymbolDefinition = { default: string; }; -export type ConfigData = { - properties: { - globalDefaults: SignElementUserProperties; - rootDefaults: SignElementBaseProperties & SignElementUserProperties; - defaults: {[key: string]: SignElementUserProperties}; - }, - signTypes: { - [key: string]: SignTypeDefinition - }, - symbols: { - [key: string]: SignSymbolDefinition - }, - borderFeatures: { - [key: string]: BorderFeatureDefinition - }, - templates: { - [key: string]: (...args: any[]) => SignElementOptions - } -}; - -export type RenderingResult = { - flc: Vec4; - w: number; - h: number; - bs: Vec4; - doRender: (ctx: DrawingContext, x0: number, y0: number, dx: number, prop: any, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; -}; - -// properties som ärvs +// properties som ärvs (måste därför specificeras av rootDefaults) export type SignElementBaseProperties = { background: string; borderRadius: number[] | number; @@ -70,58 +43,92 @@ export type SignElementBaseProperties = { xSpacing: number; }; -type SignElementOptionalUserProperties = { - alignContents?: string; - alignContentsV?: string; - blockDisplay?: boolean; - dashedInset?: boolean; - fillCorners?: boolean; - grow?: boolean; - passAnchor?: boolean; - type?: string; // symbol - value?: string; // text, vagnr - variant?: string; // symbol - - borderFeatures?: {[key: string]: string}; - borderWidth?: number[] | number; - padding?: number[] | number; +// properties (utöver de i SignElementBaseProperties) som alltid måste finnas +// dessa måste alltså specificeras av globalDefaults +type SignElementRequiredProperties = { + borderFeatures: {[key: string]: string;}; + borderWidth: number[] | number; + padding: number[] | number; +}; + +// properties som inte alltid finns i this.properties (dvs. aldrig obligatoriska) +type SignElementOptionalProperties = { + alignContents: string; + alignContentsV: string; + blockDisplay: boolean; + dashedInset: boolean; + fillCorners: boolean; + grow: boolean; + passAnchor: boolean; + type: string; // symbol + value: string; // text, vagnr + variant: string; // symbol } -type SignElementUserProperties = Partial & SignElementOptionalUserProperties; +// properties som kan specificeras av användaren (inga är obligatoriska) +type SignElementUserProperties = Partial; // formatet som this.properties följer -export interface SignElementProperties extends SignElementOptionalUserProperties, SignElementBaseProperties{ +export interface SignElementProperties extends SignElementBaseProperties, SignElementRequiredProperties, Partial{ borderFeatures: {[key: string]: string}; borderRadius: Vec4; borderWidth: Vec4; padding: Vec4; }; +export type SignElementAnchor = { x: string; } | { y: string; }; + type SignElementNode = { - anchor: { - x?: string; - y?: string; - }; + anchor: SignElementAnchor; data: SignElementOptions; }; // data som ges av användaren export type SignElementOptions = { - format?: number; + format?: number; // not currently used type: string; - properties?: any; + properties?: SignElementUserProperties; elements?: SignElementOptions[]; nodes?: {[key: string]: SignElementNode}; params?: any[]; } -export interface GenericDrawingContext{ +export type ConfigData = { + properties: { + globalDefaults: SignElementUserProperties & SignElementRequiredProperties; + rootDefaults: SignElementBaseProperties & SignElementUserProperties; + defaults: {[key: string]: SignElementUserProperties}; + }, + signTypes: { + [key: string]: SignTypeDefinition; + }, + symbols: { + [key: string]: SignSymbolDefinition; + }, + borderFeatures: { + [key: string]: BorderFeatureDefinition; + }, + templates: { + [key: string]: (...args: any[]) => SignElementOptions; + } +}; + +export type RenderingResult = { + flc: Vec4; + w: number; + h: number; + bs: Vec4; + doRender: (ctx: DrawingContext, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; +}; + + +export interface DrawingContext{ transform(a: number, b: number, c: number, d: number, e: number, f: number): void; measureText(text: string): {width: number}; - set fillStyle(x: string); - set strokeStyle(x: string); + set fillStyle(x: string | any); + set strokeStyle(x: string | any); set lineWidth(x: number); set font(x: string); @@ -139,9 +146,13 @@ export interface GenericDrawingContext{ fillRect(x: number, y: number, w: number, h: number): void; fillText(text: string, x: number, y: number): void; - drawImage(image: CanvasImageSource, dx: number, dy: number): void; - drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; - drawImage(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; + drawImage(image: any, dx: number, dy: number): void; + drawImage(image: any, dx: number, dy: number, dw: number, dh: number): void; + drawImage(image: any, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; +} + +export type DrawingCanvas = { + getContext: (...s: any[]) => DrawingContext | null; } -export type DrawingContext = CanvasRenderingContext2D | GenericDrawingContext; \ No newline at end of file +export interface Path2D{}; \ No newline at end of file diff --git a/styles.css b/styles.css deleted file mode 100644 index a141d91..0000000 --- a/styles.css +++ /dev/null @@ -1,45 +0,0 @@ -body, html{ - margin: 0; - padding: 0; - width: 100%; - height: 100%; - overflow: hidden; -} - -#left, #right{ - width: 50%; - height: 100%; - float: left; -} - -#input{ - outline: none; - height: calc(100% - 4px); - width: calc(100% - 4px); - padding: 2px; - margin: 0; -} - -#render{ - height: 100%; - width: 100%; -} - -#input, #render{ - border: 0; - resize: none; -} - -#header, #main{ - width: 100%; - float: left; -} - -#header{ - height: 24px; - background: #eee; -} - -#main{ - height: calc(100% - 24px); -} \ No newline at end of file diff --git a/templates.json b/templates.json deleted file mode 100644 index a36ad9e..0000000 --- a/templates.json +++ /dev/null @@ -1,150 +0,0 @@ -[ - { - "name": "F1-1. Orienteringstavla, enkelt exempel", - "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"center-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"vagnr","properties":{"value":"40"}},{"type":"text","properties":{"value":"JÖNKÖPING"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"text","properties":{"value":"HALMSTAD"}},{"type":"newline"},{"type":"text","properties":{"value":"GISLAVED"}}]}}}} - }, - { - "name": "F1-1. Orienteringstavla, exempel", - "json": {"type": ".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"text","properties":{"value":"OSLO"}},{"type":"newline"},{"type":"vagnr","properties":{"value":"66"}},{"type":"text","properties":{"value":"SÄLEN"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"text","properties":{"value":"GÄVLE"}},{"type":"newline"},{"type":"text","properties":{"value":"BORLÄNGE"}}]}}}} - }, - { - "name": "F1-1. Orienteringstavla, mer invecklat exempel", - "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"vagnr","properties":{"value":"40"}},{"type":"text","properties":{"value":"JÖNKÖPING"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"borderWidth":3,"background":"#097"},"elements":[{"type":"vagnr","properties":{"value":"26","background":"#06a"}},{"type":"text","properties":{"value":"HALMSTAD"}},{"type":"newline"},{"type":"text","properties":{"value":"GISLAVED"}},{"type":"newline"},{"type":"text","properties":{"value":"Sjukhus","font":"\"Tratex\"","color":"black","background":"white"}}]}}}} - }, - { - "name": "F1-1. Orienteringstavla, Transportstyrelsens exempel", - "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"left"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]}},"right":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"LINDESBERG"}}]}}}} - }, - { - "name": "F1-1. Orienteringstavla, exempel med pilar i olika höjd", - "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"center"},"data":{"type":"skylt","properties":{"xSpacing":0},"elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"vagnr","properties":{"value":"66"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"text","properties":{"value":"SKAMHED"}}},"lright":{"anchor":{"y":"middle-first"},"data":{"type":"text","properties":{"value":"SKÅLÖ"}}}}} - }, - { - "name": "F1-2. Orienteringstavla, exempel", - "json": {"type":".roundabout","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"LISTA"}}]}},"fwd":{"anchor":{"x":"center"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E20","background":"#097"}},{"type":"text","properties":{"value":"GÖTEBORG"}},{"type":"newline"},{"type":"vagnr","properties":{"value":"56"}},{"type":"text","properties":{"value":"NORRKÖPING"}}]}},"right":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"TUMBO"}}]}}}} - }, - { - "name": "F1-2. Orienteringstavla, Transportstyrelsens exempel", - "json": {"type":".roundabout","properties":{"borderWidth":4,"font":"\"Tratex\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"text","properties":{"value":"KUMLA","font":"\"TratexVersal\""}}},"fwd":{"anchor":{"x":"center"},"data":{"type":"text","properties":{"value":"ÖREBRO","font":"\"TratexVersal\""}}},"right":{"anchor":{"y":"middle"},"data":{"type":"text","properties":{"value":"KATRINEHOLM","font":"\"TratexVersal\""}}}}} - }, - { - "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, Transportstyrelsens exempel", - "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"BODA"}}]}}}} - }, - { - "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel", - "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"background":"#097","value":"E22"}},{"type":"text","properties":{"value":"KALMAR"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fd0","color":"#c00","borderWidth":3,"font":"\"Tratex\""},"elements":[{"type":"text","properties":{"value":"Saltvik","color":"black"}},{"type":"newline"},{"type":"skylt","properties":{"color":"black","background":"white"},"elements":[{"type":"text","properties":{"value":"Glabo"}},{"type":"newline"},{"type":"text","properties":{"value":"båthamn"}}]}]}}}} - }, - { - "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel med infogad H-skylt", - "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"68"}},{"type":"text","properties":{"value":"GÄVLE"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fc0","color":"#c00","borderWidth":4,"font":"\"Tratex\"","lineSpacing":0},"elements":[{"type":"text","properties":{"value":"Övre","color":"black"}},{"type":"newline"},{"type":"text","properties":{"value":"Källfallet","color":"black"}},{"type":"newline"},{"type":"skylt","properties":{"background":"white","color":"black","blockDisplay": true},"elements":[{"type":"text","properties":{"value":"Teater-"}},{"type":"text","properties":{"value":"maskinen"}},{"type":"#symgroup","params":["h19"]}]}]}}}} - }, - { - "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel med högerpil", - "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"left"},"data":{"type":"skylt","properties":{"xSpacing":0},"elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"vagnr","properties":{"value":"68"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fd0","color":"#c00","borderWidth":3,"font":"\"Tratex\""},"elements":[{"type":"text","properties":{"value":"Käpphagen","color":"black"}}]}}}} - }, - { - "name": "F3. Tabellorienteringstavla, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3,"background":"#06a","fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"80"}}]},{"type":"newline"},{"type":"skylt","properties":{"padding":0,"blockDisplay":true,"background":"#06a"},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"vagnr","properties":{"value":"272"}},{"type":"text","properties":{"value":"BOLLNÄS"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"FORSBACKA"}}]},{"type":"skylt","properties":{"borderWidth":3,"alignContents":"center"},"elements":[{"type":"text","properties":{"value":"500 m"}}]}]}]} - }, - { - "name": "F4. Avfartsorienteringstavla, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3,"background":"#06a","fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"50"}}]},{"type":"newline"},{"type":"skylt","properties":{"background":"#06a","borderWidth":3,"fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"exit"}},{"type":"skylt","properties":{"padding":0},"elements":[{"type":"text","properties":{"value":"ORNÄS"}},{"type":"newline"},{"type":"text","properties":{"value":"500 m"}}]}]}]} - }, - { - "name": "F5. Vägvisare, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"borderWidth":3,"borderRadius":7,"borderFeatures":{"right":"arrow"},"padding":6,"font":"\"TratexVersal\""},"elements":[{"type":"text","properties":{"value":"NYKÖPING"}},{"type":"text","properties":{"value":"23","padding":[12,0,0,0]}}]} - }, - { - "name": "F5. Vägvisare, exempel med vägnummer", - "json": {"type":"skylt","properties":{"background":"#097","borderWidth":3,"borderRadius":7,"borderFeatures":{"right":"arrow"},"font":"\"TratexVersal\"","padding":[0,0,5,0]},"elements":[{"type":"text","properties":{"value":"73","borderRadius":0,"borderWidth":[0,0,3,0],"padding":5,"background":"#06a"}},{"type":"text","properties":{"value":"STOCKHOLM"}}]} - }, - { - "name": "F6. Tabellvägvisare, enkelt exempel", - "json": {"type":"skylt","properties":{"padding":0,"blockDisplay":true,"lineSpacing":0,"borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"text","properties":{"value":"STOCKHOLM"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"GÖTEBORG"}}]}]} - }, - { - "name": "F6. Tabellvägvisare, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"padding":0,"blockDisplay":true,"lineSpacing":0,"borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"80"}},{"type":"text","properties":{"value":"GÄVLE"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"vagnr","properties":{"value":"272"}},{"type":"text","properties":{"value":"BOLLNÄS"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"FORSBACKA"}}]}]} - }, - { - "name": "F7. Avfartsvisare, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"borderWidth":4,"borderFeatures":{"right":"diag"},"padding":6,"font":"\"TratexVersal\"","fillCorners":true},"elements":[{"type":"vagnr","properties":{"value":"70"}},{"type":"text","properties":{"value":"MORA"}},{"type":"newline"},{"type":"text","properties":{"value":"ENKÖPING"}}]} - }, - { - "name": "F8. Körfältsvägvisare, exempel med infogade H-skyltar", - "json": {"type":"skylt","properties":{"borderWidth":3,"font":"\"Tratex\"","background":"white","color":"black"},"elements":[{"type":"skylt","properties":{"blockDisplay":true,"padding":0},"elements":[{"type":"text","properties":{"value":"Lindvallen"}},{"type":"#symgroup","params":["h6","h7","h10","h15","h18"]}]},{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}}]} - }, - { - "name": "F8. Körfältsvägvisare, Transportstyrelsens exempel 1/2", - "json": {"type":"skylt","properties":{"borderWidth":4,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"text","properties":{"value":"BODA"}}]} - }, - { - "name": "F8. Körfältsvägvisare, Transportstyrelsens exempel 2/2", - "json": {"type":"skylt","properties":{"borderWidth":4,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]} - }, - { - "name": "F8. Körfältsvägvisare, komplicerat exempel", - "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"alignContents":"right","background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"alignContentsV":"top","background":"#097","borderWidth":3,"fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"skylt","properties":{"padding":0,"alignContents":"center"},"elements":[{"type":"vagnr","properties":{"value":"E4","dashedInset":true}},{"type":"vagnr","properties":{"value":"E18"}},{"type":"newline"},{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"KISTA"}}]},{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"skylt","properties":{"padding":0,"alignContents":"center"},"elements":[{"type":"skylt","properties":{"background":"#06a","borderWidth":3,"padding":10},"elements":[{"type":"vagnr","properties":{"value":"279"}},{"type":"text","properties":{"value":"SOLNA"}},{"type":"newline"},{"type":"text","properties":{"value":"SUNDBYBERG"}},{"type":"newline"},{"type":"skylt","properties":{"background":"white","color":"black","padding":[7,0]},"elements":[{"type":"text","properties":{"value":"RINKEBY"}},{"type":"newline"},{"type":"text","properties":{"value":"Bromma","font":"\"Tratex\""}}]}]},{"type":"newline"},{"type":"text","properties":{"value":"100 m"}}]}]},{"type":"newline"},{"type":"#avfart","params":["158"]}]} - }, - { - "name": "F9. Samlingsmärke för vägvisning, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"alignContents":"center","borderWidth":3,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"skylt","properties":{"borderWidth":3,"borderFeatures":{"bottom":"bracket"},"alignContents":"center"},"elements":[{"type":"text","properties":{"value":"PAJALA"}},{"type":"newline"},{"type":"text","properties":{"value":"ÖVERTORNEÅ"}}]},{"type":"newline"},{"type":"text","properties":{"value":"KIRUNA"}}]} - }, - { - "name": "F10. Platsmärke, Transportstyrelsens exempel", - "json": {"type":"text","properties":{"borderWidth":3,"font":"\"TratexVersal\"","value":"NYKÖPING","padding":8}} - }, - { - "name": "F11. Vägnamn, Transportstyrelsens exempel", - "json": {"type":"text","properties":{"background":"white","color":"black","borderWidth":3,"font":"\"Tratex\"","value":"Hemvägen","padding":8}} - }, - { - "name": "F12. Vattendrag, Transportstyrelsens exempel", - "json": {"type":".water","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"name":{"data":{"type":"text","properties":{"value":"DALÄLVEN"}}}}} - }, - { - "name": "F13. Avståndstavla, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"borderWidth":3,"font":"\"TratexVersal\"","padding":4},"elements":[{"type":"skylt","elements":[{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"SÖDERTÄLJE"}}]},{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"text","properties":{"value":"105"}},{"type":"newline"},{"type":"text","properties":{"value":"71"}}]}]} - }, - { - "name": "F13. Avståndstavla, exempel med vägnummer", - "json": {"type":"skylt","properties":{"padding":4,"alignContents":"center","font":"\"TratexVersal\"","borderWidth":3},"elements":[{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"123"}}]},{"type":"newline"},{"type":"skylt","elements":[{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"SÖDERTÄLJE"}}]},{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"text","properties":{"value":"105"}},{"type":"newline"},{"type":"text","properties":{"value":"71"}}]}]} - }, - { - "name": "F14. Vägnummer, Transportstyrelsens exempel", - "json": {"type":"vagnr","properties":{"background":"#097","value":"E4","font":"\"TratexVersal\""}} - }, - { - "name": "F14-2. Vägnummer, Transportstyrelsens exempel", - "json": {"type":"vagnr","properties":{"background":"#097","value":"E4","dashedInset":true,"font":"\"TratexVersal\""}} - }, - { - "name": "F14-3. Vägnummer, Transportstyrelsens exempel", - "json": {"type":"vagnr","properties":{"background":"#06a","value":"58","font":"\"TratexVersal\""}} - }, - { - "name": "F14-4. Vägnummer, Transportstyrelsens exempel", - "json": {"type":"vagnr","properties":{"background":"#06a","value":"58","dashedInset":true,"font":"\"TratexVersal\""}} - }, - { - "name": "F15. Omledning, Transportstyrelsens exempel", - "json": {"type":"vagnr","properties":{"background":"white","color":"#06a","value":"58","font":"\"TratexVersal\""}} - }, - { - "name": "F27. Trafikplatsnummer, Transportstyrelsens exempel", - "json": {"type":"#avfart","properties":{"font":"\"TratexVersal\""},"params":["75"]} - }, - { - "name": "G3. Radiostation för vägtrafikinformation, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"padding":[17,17,17,2],"borderWidth":3,"alignContents":"center","font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"alignContents":"center","background":"white","color":"black","padding":12},"elements":[{"type":"text","properties":{"value":"Radio","font":"\"Tratex\""}},{"type":"newline"},{"type":"text","properties":{"value":"FM4"}}]},{"type":"newline"},{"type":"text","properties":{"value":"98,7"}}]} - }, - { - "name": "H23. Förberedande upplysning om vägnära service, enkelt exempel", - "json": {"type":"skylt","properties":{"borderWidth":4,"borderRadius":8,"padding":8,"font":"\"Tratex\"","fillCorners":true,"blockDisplay":true},"elements":[{"type":"skylt","properties":{"background":"white","color":"black","padding":8},"elements":[{"type":"#symgroup","params":["h13"]},{"type":"text","properties":{"value":"Strandkanten"}},{"type":"newline"},{"type":"#symgroup","params":["h6","h7","h15"]}]},{"type":"text","properties":{"font":"\"TratexVersal\"","value":"18 km","alignContents":"center"}}]} - }, - { - "name": "J2. Upplysningsmärke, Transportstyrelsens exempel", - "json": {"type":"skylt","properties":{"background":"#fd0","color":"black","borderWidth":4,"font":"\"TratexVersal\"","padding":8,"alignContents":"center","lineSpacing":0},"elements":[{"type":"text","properties":{"value":"VÄGSALTNING"}},{"type":"newline"},{"type":"text","properties":{"value":"UPPHÖR"}}]} - } -] \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 869e806..c0ca91a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,11 +5,12 @@ "noLib": false, /* Modules */ - "module": "NodeNext", + "module": "node16", "rootDir": "./src", - "moduleResolution": "nodenext", + "moduleResolution": "node16", /* Emit */ + "declaration": true, "outDir": "./dist", "removeComments": true, @@ -30,5 +31,8 @@ "noImplicitReturns": true, "noUncheckedIndexedAccess": false, "noImplicitOverride": true - } + }, + "files": ["./src/main.ts"], + "include": ["./src/**.ts"], + "exclude": ["./src/browser.ts"] } diff --git a/utils/clean.js b/utils/clean.js new file mode 100644 index 0000000..d56a47b --- /dev/null +++ b/utils/clean.js @@ -0,0 +1,21 @@ +(function(){ + const fs = require('fs'); + + function rmFile(path){ + console.log("rm " + path); + fs.rmSync(path); + } + + process.argv.slice(2).map(x => { + let s = fs.statSync(x, {throwIfNoEntry: false}); + if(s === undefined) return; + + if(s.isDirectory()){ + fs.readdirSync(x, {recursive: false, withFileTypes: true}).filter(y => y.isFile()).map(y => rmFile(x + y.name)); + }else{ + rmFile(x); + } + }); + + process.exit(0); +})(); \ No newline at end of file From 8dccb8b610ca8f44f7fae464576bd7a89507ce31 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Wed, 26 Feb 2025 02:50:52 +0100 Subject: [PATCH 03/12] =?UTF-8?q?F=C3=B6rb=C3=A4ttrad=20node-kompatibilite?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser.ts | 109 +++++++++++++++++++++++++++++++++++++++++---- src/graphics.ts | 30 +++++++------ src/main.ts | 105 ++++++++++++++++++++++++++++++++++++++----- src/render.ts | 98 +++++++++++++++------------------------- src/typedefs.ts | 41 ++++++++--------- src/utils.ts | 11 ----- svg/junction.svg | 2 +- svg/roundabout.svg | 2 +- svg/spanish.svg | 2 +- svg/water.svg | 3 +- 10 files changed, 273 insertions(+), 130 deletions(-) diff --git a/src/browser.ts b/src/browser.ts index dd3d668..5762435 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,22 +1,113 @@ import { SignElement as _SignElement } from "./render.js"; -import { SignElementBaseProperties, SignElementOptions, Vec6, Path2D as _Path2D } from "./typedefs.js"; +import { SignElementBaseProperties, SignElementOptions, Vec6, NewDrawingArea } from "./typedefs.js"; -export class SignElement extends _SignElement{ +class BrowserDrawingArea implements NewDrawingArea{ + canv: HTMLCanvasElement; + private ctx: CanvasRenderingContext2D; + + constructor(w?: number, h?: number){ + this.canv = Object.assign(document.createElement("canvas"), {width: w || 300, height: h || 150}); + this.ctx = this.canv.getContext("2d") as CanvasRenderingContext2D; + } + + createPath2D(s?: string | undefined, m?: Vec6 | undefined): Path2D { + let p = new window.Path2D(); + let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; + p.addPath(new window.Path2D(s), {a, b, c, d, e, f}); + return p; + } + + set width(x: number) { + this.canv.width = x; + } + + set height(x: number) { + this.canv.height = x; + } + + transform(a: number, b: number, c: number, d: number, e: number, f: number): void { + this.ctx.transform(a, b, c, d, e, f); + } + + measureText(text: string): { width: number; } { + return this.ctx.measureText(text); + } + + set fillStyle(x: string) { + this.ctx.fillStyle = x; + } + + set strokeStyle(x: string) { + this.ctx.strokeStyle = x; + } + + set lineWidth(x: number) { + this.ctx.lineWidth = x; + } + + set font(x: string) { + this.ctx.font = x; + } + + set textBaseline(x: string) { + this.ctx.textBaseline = x as CanvasTextBaseline; + } + + fill(path: Path2D): void { + this.ctx.fill(path); + } + + stroke(path: Path2D): void { + this.ctx.stroke(path); + } + + fillRect(x: number, y: number, w: number, h: number): void { + this.ctx.fillRect(x, y, w, h); + } + + fillText(text: string, x: number, y: number): void { + this.ctx.fillText(text, x, y); + } + + drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void { + this.ctx.drawImage(image.canv, sx, sy, sw, sh, dx, dy, dw, dh); + } + + drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise { + return new Promise((res, rej) => { + let img = new Image(); + + img.addEventListener("load", () => { + this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); + res(); + }); + + img.addEventListener("error", rej); + img.src = url; + }); + } +} + +export class SignElement extends _SignElement{ constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ opt = _SignElement.resolveTemplate(opt); super(opt, popt); this.addCN(SignElement, opt); } - protected override _createCanvas(w?: number, h?: number): HTMLCanvasElement { - return Object.assign(document.createElement("canvas"), {width: w || 300, height: h || 150}); + protected override createCanvas(w?: number, h?: number): BrowserDrawingArea { + return new BrowserDrawingArea(w, h); } - protected override _createPath2D(s: string, m?: Vec6): _Path2D { - let p = new Path2D(); - let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; - p.addPath(new Path2D(s), {a, b, c, d, e, f}); - return p; + protected getText(url: string): Promise { + return new Promise(resolve => { + let req = new XMLHttpRequest(); + req.addEventListener("load", () => { + resolve(req.responseText); + }); + req.open("GET", url); + req.send(); + }); } }; \ No newline at end of file diff --git a/src/graphics.ts b/src/graphics.ts index f951009..e836c21 100644 --- a/src/graphics.ts +++ b/src/graphics.ts @@ -1,6 +1,6 @@ -import type { DrawingContext, Vec4, Vec2 } from "./typedefs.js"; +import type { Vec4, Vec2, NewDrawingArea } from "./typedefs.js"; -export function roundedFrame(ctx: DrawingContext, x0: number, y0: number, innerWidth: number, innerHeight: number, nominalLineWidth: Vec4 = [4, 4, 4, 4], color: string = "#000", borderRadius: Vec4 = [0, 0, 0, 0], lineDash: Vec2 = [1, 0]){ +export function roundedFrame(ctx: NewDrawingArea, x0: number, y0: number, innerWidth: number, innerHeight: number, nominalLineWidth: Vec4 = [4, 4, 4, 4], color: string = "#000", borderRadius: Vec4 = [0, 0, 0, 0], lineDash: Vec2 = [1, 0]){ // lineDash = [längd, mellanrum] if(Math.max(...nominalLineWidth) <= 0) return; @@ -21,18 +21,18 @@ export function roundedFrame(ctx: DrawingContext, x0: number, y0: number, innerW let v1 = startAngle - signX*signY*Math.PI/4, v2 = startAngle + signX*signY*Math.PI/4; - ctx.beginPath(); + let p = ctx.createPath2D(); //ctx.moveTo(cx + signX * arx, cy); - ctx.moveTo(cx + signX*(arx+w0), cy); - ctx.lineTo(cx + signX*(arx+w0), cy + signY * Math.max(0, w1 - br)); - ctx.ellipse(cx + signX*Math.max(0, w0 - br), cy + signY * Math.max(0, w1 - br), br, br, 0, v1, v2, signX !== signY); - ctx.lineTo(cx, cy + signY*(ary+w1)); - ctx.lineTo(cx, cy + signY*ary); - ctx.ellipse(cx, cy, arx, ary, 0, v2, v1, signX === signY); + p.moveTo(cx + signX*(arx+w0), cy); + p.lineTo(cx + signX*(arx+w0), cy + signY * Math.max(0, w1 - br)); + p.ellipse(cx + signX*Math.max(0, w0 - br), cy + signY * Math.max(0, w1 - br), br, br, 0, v1, v2, signX !== signY); + p.lineTo(cx, cy + signY*(ary+w1)); + p.lineTo(cx, cy + signY*ary); + p.ellipse(cx, cy, arx, ary, 0, v2, v1, signX === signY); //ctx.closePath(); ctx.fillStyle = color; - ctx.fill(); + ctx.fill(p); }; drawCorner(x0, y0, -1, -1, 0); @@ -86,7 +86,7 @@ export function roundedFrame(ctx: DrawingContext, x0: number, y0: number, innerW } -export function roundedFill(ctx: DrawingContext, x0: number, y0: number, innerWidth: number, innerHeight: number, borderWidth: Vec4 = [4, 4, 4, 4], borderRadius: Vec4 = [0, 0, 0, 0], background: string = "#fff", fillCorners: boolean = false){ +export function roundedFill(ctx: NewDrawingArea, x0: number, y0: number, innerWidth: number, innerHeight: number, borderWidth: Vec4 = [4, 4, 4, 4], borderRadius: Vec4 = [0, 0, 0, 0], background: string = "#fff", fillCorners: boolean = false){ // lineDash = [längd, mellanrum] ctx.fillStyle = background; @@ -96,12 +96,14 @@ export function roundedFill(ctx: DrawingContext, x0: number, y0: number, innerWi return; } + let p = ctx.createPath2D(); + let drawCorner = (cx: number, cy: number, signX: number, signY: number, i: number) => { let arx = borderRadius[i] + borderWidth[(Math.ceil(i / 2) * 2) % 4] / 2, ary = borderRadius[i] + borderWidth[Math.floor(i / 2) * 2 + 1] / 2; let startAngle = ((i - 2) * Math.PI) / 2; - ctx.ellipse( + p.ellipse( cx - signX * borderRadius[i], cy - signY * borderRadius[i], arx, ary, 0, @@ -110,12 +112,12 @@ export function roundedFill(ctx: DrawingContext, x0: number, y0: number, innerWi ); }; - ctx.beginPath(); drawCorner(x0, y0, -1, -1, 0); drawCorner(x0 + innerWidth, y0, 1, -1, 1); drawCorner(x0 + innerWidth, y0 + innerHeight, 1, 1, 2); drawCorner(x0, y0 + innerHeight, -1, 1, 3); - ctx.fill(); + + ctx.fill(p); // mitten ctx.fillRect( diff --git a/src/main.ts b/src/main.ts index d81abff..7f2bec6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,24 +1,109 @@ import { SignElement as _SignElement } from "./render.js"; -import { SignElementBaseProperties, SignElementOptions, Vec6, Path2D as _Path2D } from "./typedefs.js"; +import { SignElementBaseProperties, SignElementOptions, Vec6, NewDrawingArea, Path2D as _Path2D } from "./typedefs.js"; -import {createCanvas, Canvas, Path2D} from "@napi-rs/canvas"; +import { createCanvas, Canvas, Path2D, SKRSContext2D, Image } from "@napi-rs/canvas"; +import { readFile } from "fs/promises" +class NodeDrawingArea implements NewDrawingArea{ + canv: Canvas; + private ctx: SKRSContext2D; -export class SignElement extends _SignElement{ + constructor(w: number, h: number){ + this.canv = createCanvas(w, h); + this.ctx = this.canv.getContext("2d"); + } + + createPath2D(s?: string, m?: Vec6 | undefined): Path2D { + let p = new Path2D(); + let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; + p.addPath(new Path2D(s), {a, b, c, d, e, f}); + return p; + } + + set width(x: number) { + this.canv.width = x; + } + + set height(x: number) { + this.canv.height = x; + } + + transform(a: number, b: number, c: number, d: number, e: number, f: number): void { + this.ctx.transform(a, b, c, d, e, f); + } + + measureText(text: string): { width: number; } { + return this.ctx.measureText(text); + } + + set fillStyle(x: string) { + this.ctx.fillStyle = x; + } + + set strokeStyle(x: string) { + this.ctx.strokeStyle = x; + } + + set lineWidth(x: number) { + this.ctx.lineWidth = x; + } + + set font(x: string) { + this.ctx.font = x; + } + + set textBaseline(x: string) { + this.ctx.textBaseline = x as CanvasTextBaseline; + } + + fill(path: Path2D): void{ + this.ctx.fill(path); + } + + stroke(path: Path2D): void { + this.ctx.stroke(path); + } + + fillRect(x: number, y: number, w: number, h: number): void { + this.ctx.fillRect(x, y, w, h); + } + + fillText(text: string, x: number, y: number): void { + this.ctx.fillText(text, x, y); + } + + drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void { + this.ctx.drawImage(image.canv, sx, sy, sw, sh, dx, dy, dw, dh); + } + + drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise { + return new Promise((res, rej) => { + let img = new Image(); + + img.onload = () => { + this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); + res(); + }; + + img.onerror = rej; + img.src = url; + }); + } +} + + +export class SignElement extends _SignElement{ constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ opt = _SignElement.resolveTemplate(opt); super(opt, popt); this.addCN(SignElement, opt); } - protected override _createCanvas(w?: number, h?: number): Canvas { - return createCanvas(w || 300, h || 150); + protected override createCanvas(w?: number, h?: number): NodeDrawingArea { + return new NodeDrawingArea(w || 300, h || 150); } - protected override _createPath2D(s: string, m?: Vec6): _Path2D { - let p = new Path2D(); - let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; - p.addPath(new Path2D(s), {a, b, c, d, e, f}); - return p; + protected override getText(url: string): Promise { + return readFile(url, {encoding: "utf8"}); } }; \ No newline at end of file diff --git a/src/render.ts b/src/render.ts index 5b3cc47..1ab61f1 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,7 +1,7 @@ -import type {MathEnv, Vec4, SignElementProperties, DrawingContext, SignElementOptions, SignElementBaseProperties, RenderingResult, DrawingCanvas, Vec6, Path2D} from "./typedefs.js" +import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea } from "./typedefs.js" import CONFIG from "./config.js"; -import {roundedFill, roundedFrame} from "./graphics.js"; -import {mathEval, parseVarStr, getText} from "./utils.js"; +import { roundedFill, roundedFrame } from "./graphics.js"; +import { mathEval, parseVarStr } from "./utils.js"; // Priority: // 1. Specified value @@ -81,9 +81,9 @@ class BorderDimensions{ } } -export abstract class SignElement{ - protected abstract _createCanvas(w?: number, h?: number): T; - protected abstract _createPath2D(s: string, m?: Vec6): Path2D; +export abstract class SignElement>{ + protected abstract createCanvas(w?: number, h?: number): T; + protected abstract getText(url: string): Promise; private static borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ let bs = new BorderDimensions(properties.borderWidth); @@ -115,7 +115,7 @@ export abstract class SignElement{ } } - private renderBorderFeature(ctx: DrawingContext, x0: number, y0: number, featureName: string, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ + private renderBorderFeature(ctx: NewDrawingArea, x0: number, y0: number, featureName: string, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ let color = this.properties.color, background = this.properties.background; @@ -164,7 +164,7 @@ export abstract class SignElement{ ctx.lineWidth = bw; feature.paths.forEach(path => { - let p = this._createPath2D(parseVarStr(path.p, bs.el[bri]?.env), tm); + let p = ctx.createPath2D(parseVarStr(path.p, bs.el[bri]?.env), tm); if(path.f !== undefined){ ctx.fillStyle = [color, background][Math.abs(path.f)-1]; @@ -180,8 +180,8 @@ export abstract class SignElement{ private type: string; private properties: SignElementProperties; - private children: SignElement[]; - private nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}}; + private children: SignElement[]; + private nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}}; protected static resolveTemplate(data: SignElementOptions): SignElementOptions{ while(data.type.startsWith("#")){ @@ -220,7 +220,7 @@ export abstract class SignElement{ this.nodes = {}; } - protected addCN>(Cl: new (opt: any, inh: SignElementBaseProperties | null) => X, data: SignElementOptions){ + protected addCN>(Cl: new (opt: any, inh: SignElementBaseProperties | null) => X, data: SignElementOptions){ let inh = this.getInhProperties(); this.children = (data.elements || []).map(element => new Cl(element, inh)); @@ -238,13 +238,13 @@ export abstract class SignElement{ return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; } - private _render(): RenderingResult{ + private _render(): RenderingResult{ let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] let padding = Array.from(this.properties.padding); let width = 0, height = 0, maxHeight = 0; - let renderPromise: (ctx: DrawingContext, x0: number, y0: number, maxInnerHeight: number) => Promise + let renderPromise: (ctx: T, x0: number, y0: number, maxInnerHeight: number) => Promise = () => Promise.resolve(); if(this.type == "skylt"){ @@ -336,7 +336,7 @@ export abstract class SignElement{ ); })).then(() => {}); }else if(this.type == "vagnr" || this.type == "text"){ - let ctx_temp = this._createCanvas().getContext("2d") as DrawingContext; + let ctx_temp = this.createCanvas(); ctx_temp.font = "32px " + this.properties.font; @@ -372,28 +372,18 @@ export abstract class SignElement{ width = symbolType.width; [height, maxHeight] = symbolType.height; - let img = new Image(width, maxHeight); - renderPromise = (ctx, x0, y0, maxInnerHeight) => new Promise((res, rej) => { - img.addEventListener("load", () => { - ctx.drawImage( - img, - 0, 0, - img.width, maxInnerHeight - padding[1] - padding[3], - x0 + padding[0], y0 + padding[1], - img.width, maxInnerHeight - padding[1] - padding[3] + let url = "svg/symbol/" + (this.properties.type || "") + ".svg"; + + this.getText(url).then(xml => { + return ctx.drawSVG( + "data:image/svg+xml;utf8," + + encodeURIComponent(xml.replace(/currentColor/g, this.properties.color)) + + "#" + encodeURIComponent(this.properties.variant || symbolType.default), + x0 + padding[0], y0 + padding[1], // dx, dy + width, maxInnerHeight - padding[1] - padding[3] // dw=sw, dh=sh ); - res(); - }); - img.addEventListener("error", rej); - - let url = "svg/symbol/" + window.encodeURIComponent(this.properties.type || "") + ".svg"; - - getText(url).then(xml => { - img.src = "data:image/svg+xml;utf8," - + window.encodeURIComponent(String(xml).replace(/currentColor/g, this.properties.color)) - + "#" + window.encodeURIComponent(this.properties.variant || symbolType.default); - }); + }).then(res, rej); }); }else if(this.type == "newline"){ width = 0; @@ -402,8 +392,6 @@ export abstract class SignElement{ let t = SKYLTTYPER[this.type.slice(1)]; let keys = Object.keys(t.nodes).sort().filter(nodeName => !!this.nodes[nodeName]); - let svg = new Image(t.width, t.height); - let svgBox = Array.from(t.core); keys.forEach(nodeName => { svgBox[0] = Math.min(svgBox[0], t.nodes[nodeName].x[0]); @@ -505,25 +493,13 @@ export abstract class SignElement{ (svgBox[3] - svgBox[2]) * t.height ]; // [x0, y0, w, h] - return new Promise((resolve, reject) => { - svg.onload = resolve; - svg.onerror = reject; - svg.src = "svg/" + this.type.slice(1) + ".svg#" + keys.join("_"); - }).then(() => { - let svgRasterized = this._createCanvas(t.width, t.height); - (svgRasterized.getContext("2d") as DrawingContext).drawImage(svg, 0, 0, t.width, t.height); - - ctx.drawImage( - svgRasterized, - crop[0], crop[1], // sx, sy - crop[2], crop[3], // sw, sh - x0 + this.properties.padding[0] - boundingBox[0] + crop[0], // dx - y0 + this.properties.padding[1] - boundingBox[2] + crop[1], // dy - crop[2], crop[3] // dw, dh - ); - - return; - }); + return ctx.drawSVG( + "svg/" + this.type.slice(1) + ".svg#" + keys.join("_"), + x0 + this.properties.padding[0] - boundingBox[0] + crop[0], // dx + y0 + this.properties.padding[1] - boundingBox[2] + crop[1], // dy + crop[2], crop[3], // dw=sw, dh=sh + crop[0], crop[1] // sx, sy + ); }); }else{ alert("Fel!"); @@ -547,7 +523,7 @@ export abstract class SignElement{ w: width + padding[0] + padding[2], h: height + padding[1] + padding[3], bs: bs.h, - doRender: async (ctx: DrawingContext, x0: number, y0: number, dx: number, maxInnerHeight, verticalAlign?: string, iw = 0) => { + doRender: async (ctx: T, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw = 0) => { const dy = 0; const innerWidth = iw === 0 ? (width + padding[0] + padding[2]) : iw; let innerHeight = height + padding[1] + padding[3]; @@ -607,17 +583,17 @@ export abstract class SignElement{ }; } - public render(): Promise{ - let canv = this._createCanvas(); + public async render(): Promise{ + let canv = this.createCanvas(); let r = this._render(); let bs = r.bs; Object.assign(canv, { width: r.w + bs[0] + bs[2], height: r.h + bs[1] + bs[3] }); - let ctx = canv.getContext("2d"); - if(ctx === null) throw new Error("Fel: Kunde inte hitta tvådimensionell renderingskontext."); + if(canv === null) throw new Error("Fel: Kunde inte hitta tvådimensionell renderingskontext."); - return r.doRender(ctx, 0, 0, 0, r.h).then(() => canv); + await r.doRender(canv, 0, 0, 0, r.h); + return canv.canv; } } \ No newline at end of file diff --git a/src/typedefs.ts b/src/typedefs.ts index f665386..286edae 100644 --- a/src/typedefs.ts +++ b/src/typedefs.ts @@ -113,46 +113,47 @@ export type ConfigData = { } }; -export type RenderingResult = { +export type RenderingResult> = { flc: Vec4; w: number; h: number; bs: Vec4; - doRender: (ctx: DrawingContext, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; + doRender: (ctx: T, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; }; +export interface Path2D{ + moveTo(x: number, y: number): void; + lineTo(x: number, y: number): void; + ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise: boolean): void; + closePath(): void; +}; + +export interface NewDrawingArea{ + canv: T; + + createPath2D(s?: string, m?: Vec6): Path2D; + + set width(x: number); + set height(x: number); -export interface DrawingContext{ transform(a: number, b: number, c: number, d: number, e: number, f: number): void; measureText(text: string): {width: number}; - set fillStyle(x: string | any); - set strokeStyle(x: string | any); + set fillStyle(x: string); + set strokeStyle(x: string); set lineWidth(x: number); set font(x: string); set textBaseline(x: string); - beginPath(): void; - moveTo(x: number, y: number): void; - lineTo(x: number, y: number): void; - ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise: boolean): void; - - fill(): void; fill(path: Path2D): void; stroke(path: Path2D): void; fillRect(x: number, y: number, w: number, h: number): void; fillText(text: string, x: number, y: number): void; - drawImage(image: any, dx: number, dy: number): void; - drawImage(image: any, dx: number, dy: number, dw: number, dh: number): void; - drawImage(image: any, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; -} - -export type DrawingCanvas = { - getContext: (...s: any[]) => DrawingContext | null; -} + drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; -export interface Path2D{}; \ No newline at end of file + drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx?: number, sy?: number, sw?: number, sh?: number): Promise; +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index 87451da..ba33dd5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -83,15 +83,4 @@ export function parseVarStr(str: string, vars = {}): string{ } return result.join("") + str.substring(i); -} - -export function getText(url: string): Promise{ - return new Promise(resolve => { - let req = new XMLHttpRequest(); - req.addEventListener("load", () => { - resolve(req.responseText); - }); - req.open("GET", url); - req.send(); - }); } \ No newline at end of file diff --git a/svg/junction.svg b/svg/junction.svg index aae14e0..f2c33e3 100644 --- a/svg/junction.svg +++ b/svg/junction.svg @@ -1,4 +1,4 @@ - + diff --git a/svg/roundabout.svg b/svg/roundabout.svg index 221a576..770f9f8 100644 --- a/svg/roundabout.svg +++ b/svg/roundabout.svg @@ -1,4 +1,4 @@ - + diff --git a/svg/spanish.svg b/svg/spanish.svg index f54f0a7..6a909ae 100644 --- a/svg/spanish.svg +++ b/svg/spanish.svg @@ -1,4 +1,4 @@ - + diff --git a/svg/water.svg b/svg/water.svg index 7d436fb..5eb7ff6 100644 --- a/svg/water.svg +++ b/svg/water.svg @@ -1,4 +1,3 @@ - - + \ No newline at end of file From c4d4552c5bac9f646905d75de93500c7fd3d2b53 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Wed, 26 Feb 2025 17:07:41 +0100 Subject: [PATCH 04/12] Konvertera SVG-kantlinjer till slingor & ta bort plain.svg --- svg/plain.svg | 1 - svg/roundabout.svg | 9 +++++---- svg/spanish.svg | 6 +++--- svg/water.svg | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 svg/plain.svg diff --git a/svg/plain.svg b/svg/plain.svg deleted file mode 100644 index f665f43..0000000 --- a/svg/plain.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/svg/roundabout.svg b/svg/roundabout.svg index 770f9f8..0755d1c 100644 --- a/svg/roundabout.svg +++ b/svg/roundabout.svg @@ -14,23 +14,24 @@ - + - + + - + - + diff --git a/svg/spanish.svg b/svg/spanish.svg index 6a909ae..5007ca8 100644 --- a/svg/spanish.svg +++ b/svg/spanish.svg @@ -5,9 +5,9 @@ - - - + + + diff --git a/svg/water.svg b/svg/water.svg index 5eb7ff6..30b7538 100644 --- a/svg/water.svg +++ b/svg/water.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file From 6cb501e116de066833d8ee1a6397a57f53a966f1 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Wed, 26 Feb 2025 17:28:19 +0100 Subject: [PATCH 05/12] =?UTF-8?q?Nytt=20format=20f=C3=B6r=20vektorelement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- res/junction.json | 18 +++++++++++++++ res/roundabout.json | 18 +++++++++++++++ res/spanish.json | 20 +++++++++++++++++ res/water.json | 12 ++++++++++ src/browser.ts | 12 ---------- src/main.ts | 12 ---------- src/render.ts | 41 ++++++++++++++++++++++++++++++----- src/typedefs.ts | 21 ++++++++++++------ svg/junction.svg | 53 --------------------------------------------- svg/roundabout.svg | 38 -------------------------------- svg/spanish.svg | 23 -------------------- svg/water.svg | 3 --- 12 files changed, 117 insertions(+), 154 deletions(-) create mode 100644 res/junction.json create mode 100644 res/roundabout.json create mode 100644 res/spanish.json create mode 100644 res/water.json delete mode 100644 svg/junction.svg delete mode 100644 svg/roundabout.svg delete mode 100644 svg/spanish.svg delete mode 100644 svg/water.svg diff --git a/res/junction.json b/res/junction.json new file mode 100644 index 0000000..8e06bdf --- /dev/null +++ b/res/junction.json @@ -0,0 +1,18 @@ +{ + "width": 120, + "height": 240, + "vectorSize": [3, 6], + "defs": { + "pil": {"path": "M1.5,.2l.5.5a.1,.1,0,0,1,-.1,.1h-.3v.8h-.2v-.8h-.3a.1,.1,0,0,1,-.1,-.1z", "fill": "#fff"}, + "hoger": {"path": "M1.5,1.5h.7v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.7z", "fill": "#fff"}, + "vanster": {"path": "M1.5,1.5h-.7v-.3a.1,.1,0,0,0,-.1-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.7z", "fill": "#fff"}, + "linje": {"path": "M1.6,1.5v4.5h-.2v-4.5z", "fill": "#fff"} + }, + "core": [{"use": "linje"}], + "components": { + "fwd": [{"use": "pil"}], + "left": [{"use": "vanster"}], + "right": [{"use": "hoger"}], + "lright": [{"use": "hoger", "translate":[0,1]}] + } +} \ No newline at end of file diff --git a/res/roundabout.json b/res/roundabout.json new file mode 100644 index 0000000..fd682a0 --- /dev/null +++ b/res/roundabout.json @@ -0,0 +1,18 @@ +{ + "width": 240, + "height": 480, + "vectorSize": [6, 12], + "defs": { + "arr_right": {"path": "M4,2.5v-.1h.5v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.5v.1z", "fill": "#fff"}, + "arr_left": {"path": "M2,2.5v-.1h-.5v-.3a.1,.1,0,0,0,-.1,-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.5v.1z", "fill": "#fff"}, + "arr_fwd": {"path": "M3,1.5h-.1v-.5h-.3a.1,.1,0,0,1,-.1,-.1l.5,-.5l.5,.5a.1,.1,0,0,1,-.1.1h-.3v.5h.1z", "fill": "#fff"}, + "c270": {"path": "M2.9,12v-8.6h.1a.9.9,0,1,0-.9-.9v.1h-.2v-.1a1.1,1.1,0,1,1,1.2,1.096v8.404z", "fill": "#fff"}, + "c180": {"path": "M2.9,12v-8.6h.1a.9.9,0,0,0,0-1.8h-.1v-.2h.1a1.1,1.1,0,0,1,.1,2.1955v8.4045z", "fill": "#fff"} + }, + "core": [], + "components": { + "fwd": [{"use": "c180"}, {"use": "arr_fwd"}], + "left": [{"use": "c270"}, {"use": "arr_left"}], + "right": [{"use": "arr_right"}] + } +} \ No newline at end of file diff --git a/res/spanish.json b/res/spanish.json new file mode 100644 index 0000000..c4335de --- /dev/null +++ b/res/spanish.json @@ -0,0 +1,20 @@ +{ + "width": 200, + "height": 360, + "vectorSize": [5, 9], + "defs": { + "bp": {"path": "M.72,2.06h1.4c1.1,0 2.05,1.7 .7,2.65l-.75,.47v.7q0,-.4,.15,-.5l.75,-.47c1.35,-.8,.85,-3,-.85,-3.09h-1.4zM2,.2l-.5.5a.1,.1,0,0,0,.1,.1h.28v7.04h.24v-7.04h.28a.1,.1,0,0,0,.1,-.1z", "fill": "#fff"}, + "sk1": {"path": "M2,2.785a.725.725,0,0,0,0,1.45a.725.725,0,0,0,0,-1.45z", "fill": "#e45"}, + "sk2": {"path": "M2,2.935a.575.575,0,0,0,0,1.15a.575.575,0,0,0,0,-1.15z", "fill": "#fd0"}, + "skvp": {"path": "M1.66,3.26h.45a.2.2,0,0,1,.2.2v.49h-.18v-.47a.05.05,0,0,0-.05-.05h-.42v.05l-.14-.14l.14-.14z", "fill": "#000"}, + "sk3": {"path": "M1.65,3l.85,1l-.08.08l-.85-1z", "fill": "#e45"}, + "arr_left": {"path": "M.28,1.94l.5,.5a.1,.1,0,0,0,.1,-.1v-.8a.1,.1,0,0,0,-.1,-.1l-.5,.5z", "fill": "#fff"}, + "arr_right": {"path": "M4.72,1.94l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.28h-2v-.24h2v-.28a.1,.1,0,0,1,.1,-.1l.5,.5z", "fill": "#fff"} + }, + "core": [{"use": "bp"}, {"use": "sk1"}, {"use": "sk2"}, {"use": "skvp"}, {"use": "sk3"}], + "components": { + "fwd": [], + "left": [{"use": "arr_left"}], + "right": [{"use": "arr_right"}] + } +} \ No newline at end of file diff --git a/res/water.json b/res/water.json new file mode 100644 index 0000000..a5a1fcf --- /dev/null +++ b/res/water.json @@ -0,0 +1,12 @@ +{ + "width": 209, + "height": 19, + "vectorSize": [11, 1], + "defs": { + "vatten": {"path": "M.5,.67a1.093,1.093,0,0,0,1,-.657a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,1,.657v.234a1.327,1.327,0,0,1,-1,-.46a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-1,.46z", "fill": "#fff"} + }, + "core": [{"use": "vatten"}], + "components": { + "name": [] + } +} \ No newline at end of file diff --git a/src/browser.ts b/src/browser.ts index 5762435..846944a 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -18,18 +18,6 @@ class BrowserDrawingArea implements NewDrawingArea{ return p; } - set width(x: number) { - this.canv.width = x; - } - - set height(x: number) { - this.canv.height = x; - } - - transform(a: number, b: number, c: number, d: number, e: number, f: number): void { - this.ctx.transform(a, b, c, d, e, f); - } - measureText(text: string): { width: number; } { return this.ctx.measureText(text); } diff --git a/src/main.ts b/src/main.ts index 7f2bec6..07c9a13 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,18 +20,6 @@ class NodeDrawingArea implements NewDrawingArea{ return p; } - set width(x: number) { - this.canv.width = x; - } - - set height(x: number) { - this.canv.height = x; - } - - transform(a: number, b: number, c: number, d: number, e: number, f: number): void { - this.ctx.transform(a, b, c, d, e, f); - } - measureText(text: string): { width: number; } { return this.ctx.measureText(text); } diff --git a/src/render.ts b/src/render.ts index 1ab61f1..740c97e 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,4 +1,4 @@ -import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea } from "./typedefs.js" +import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea, JSONVec, JSONVecReference } from "./typedefs.js" import CONFIG from "./config.js"; import { roundedFill, roundedFrame } from "./graphics.js"; import { mathEval, parseVarStr } from "./utils.js"; @@ -178,6 +178,37 @@ export abstract class SignElement>{ }); } + private drawVec(ctx: T, href: string, components: string[], dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise{ + return this.getText(href).then(rawJson => { + let vecImgData = JSON.parse(rawJson) as JSONVec; + let ctx2: T = this.createCanvas(sw, sh); + + let xf = vecImgData.width / vecImgData.vectorSize[0], + yf = vecImgData.height / vecImgData.vectorSize[1]; + + let tm: Vec6 = [ + xf, 0, 0, + yf, 0, 0 + ]; + + let els: JSONVecReference[] = vecImgData.core.concat(...components.map(name => vecImgData.components[name])); + els.forEach(el => { + let def = vecImgData.defs[el.use]; + + let tra = el.translate || [0, 0]; + + [tm[4], tm[5]] = [tra[0] * xf, tra[1] * yf]; + tm[4] -= sx; tm[5] -= sy; + + let path = ctx2.createPath2D(def.path, tm); + ctx2.fillStyle = def.fill; + ctx2.fill(path); + }); + + ctx.drawImage(ctx2, 0, 0, sw, sh, dx, dy, dw, dh); + }); + } + private type: string; private properties: SignElementProperties; private children: SignElement[]; @@ -493,8 +524,8 @@ export abstract class SignElement>{ (svgBox[3] - svgBox[2]) * t.height ]; // [x0, y0, w, h] - return ctx.drawSVG( - "svg/" + this.type.slice(1) + ".svg#" + keys.join("_"), + return this.drawVec( + ctx, "res/" + this.type.slice(1) + ".json", keys, x0 + this.properties.padding[0] - boundingBox[0] + crop[0], // dx y0 + this.properties.padding[1] - boundingBox[2] + crop[1], // dy crop[2], crop[3], // dw=sw, dh=sh @@ -584,12 +615,10 @@ export abstract class SignElement>{ } public async render(): Promise{ - let canv = this.createCanvas(); - let r = this._render(); let bs = r.bs; - Object.assign(canv, { width: r.w + bs[0] + bs[2], height: r.h + bs[1] + bs[3] }); + let canv = this.createCanvas(r.w + bs[0] + bs[2], r.h + bs[1] + bs[3]); if(canv === null) throw new Error("Fel: Kunde inte hitta tvådimensionell renderingskontext."); diff --git a/src/typedefs.ts b/src/typedefs.ts index 286edae..6720170 100644 --- a/src/typedefs.ts +++ b/src/typedefs.ts @@ -63,7 +63,7 @@ type SignElementOptionalProperties = { type: string; // symbol value: string; // text, vagnr variant: string; // symbol -} +}; // properties som kan specificeras av användaren (inga är obligatoriska) type SignElementUserProperties = Partial; @@ -128,16 +128,23 @@ export interface Path2D{ closePath(): void; }; +type JSONVecElement = {path: string, fill: string}; +export type JSONVecReference = {use: string, translate?: [number, number]}; + +export type JSONVec = { + width: number; + height: number; + vectorSize: [number, number]; + defs: {[key: string]: JSONVecElement;}; + core: JSONVecReference[]; + components: {[key: string]: JSONVecReference[]}; +}; + export interface NewDrawingArea{ canv: T; createPath2D(s?: string, m?: Vec6): Path2D; - set width(x: number); - set height(x: number); - - transform(a: number, b: number, c: number, d: number, e: number, f: number): void; - measureText(text: string): {width: number}; set fillStyle(x: string); @@ -156,4 +163,4 @@ export interface NewDrawingArea{ drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx?: number, sy?: number, sw?: number, sh?: number): Promise; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/svg/junction.svg b/svg/junction.svg deleted file mode 100644 index f2c33e3..0000000 --- a/svg/junction.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/svg/roundabout.svg b/svg/roundabout.svg deleted file mode 100644 index 0755d1c..0000000 --- a/svg/roundabout.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/svg/spanish.svg b/svg/spanish.svg deleted file mode 100644 index 5007ca8..0000000 --- a/svg/spanish.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/svg/water.svg b/svg/water.svg deleted file mode 100644 index 30b7538..0000000 --- a/svg/water.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file From 0b80c5fd26e6f1c1d34c04d3b30b94f81b008f29 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Thu, 27 Feb 2025 19:27:03 +0100 Subject: [PATCH 06/12] Konvertera symboler till det nya vektorformatet --- res/junction.json | 22 +++++++------- res/roundabout.json | 21 +++++++------ res/spanish.json | 24 +++++++-------- res/symbol/arrow-small.json | 17 +++++++++++ res/symbol/exit.json | 8 +++++ res/symbol/h1.json | 9 ++++++ res/symbol/h10.json | 9 ++++++ res/symbol/h11.json | 9 ++++++ res/symbol/h12.json | 10 +++++++ res/symbol/h13.json | 8 +++++ res/symbol/h14.json | 9 ++++++ res/symbol/h15.json | 8 +++++ res/symbol/h16.json | 8 +++++ res/symbol/h17.json | 8 +++++ res/symbol/h18.json | 9 ++++++ res/symbol/h19.json | 9 ++++++ res/symbol/h2.json | 8 +++++ res/symbol/h20.json | 8 +++++ res/symbol/h21.json | 9 ++++++ res/symbol/h22.json | 9 ++++++ res/symbol/h24.json | 10 +++++++ res/symbol/h25.json | 15 ++++++++++ res/symbol/h26.json | 8 +++++ res/symbol/h27.json | 10 +++++++ res/symbol/h28.json | 9 ++++++ res/symbol/h3.json | 9 ++++++ res/symbol/h4.json | 27 +++++++++++++++++ res/symbol/h5.json | 9 ++++++ res/symbol/h6.json | 8 +++++ res/symbol/h7.json | 9 ++++++ res/symbol/h8.json | 9 ++++++ res/symbol/h9.json | 9 ++++++ res/water.json | 10 ++----- src/browser.ts | 18 ++--------- src/config.ts | 54 ++++++++++++++++----------------- src/main.ts | 20 ++----------- src/render.ts | 60 ++++++++++++++++++++----------------- src/typedefs.ts | 14 ++++----- svg/symbol/arrow-small.svg | 18 ----------- svg/symbol/exit.svg | 5 ---- svg/symbol/h1.svg | 4 --- svg/symbol/h10.svg | 4 --- svg/symbol/h11.svg | 4 --- svg/symbol/h12.svg | 8 ----- svg/symbol/h13.svg | 3 -- svg/symbol/h14.svg | 6 ---- svg/symbol/h15.svg | 5 ---- svg/symbol/h16.svg | 4 --- svg/symbol/h17.svg | 5 ---- svg/symbol/h18.svg | 4 --- svg/symbol/h19.svg | 5 ---- svg/symbol/h2.svg | 3 -- svg/symbol/h20.svg | 6 ---- svg/symbol/h21.svg | 7 ----- svg/symbol/h22.svg | 8 ----- svg/symbol/h24.svg | 14 --------- svg/symbol/h25.svg | 20 ------------- svg/symbol/h26.svg | 5 ---- svg/symbol/h27.svg | 6 ---- svg/symbol/h28.svg | 9 ------ svg/symbol/h3.svg | 5 ---- svg/symbol/h4.svg | 44 --------------------------- svg/symbol/h5.svg | 4 --- svg/symbol/h6.svg | 3 -- svg/symbol/h7.svg | 4 --- svg/symbol/h8.svg | 4 --- svg/symbol/h9.svg | 8 ----- 67 files changed, 394 insertions(+), 361 deletions(-) create mode 100644 res/symbol/arrow-small.json create mode 100644 res/symbol/exit.json create mode 100644 res/symbol/h1.json create mode 100644 res/symbol/h10.json create mode 100644 res/symbol/h11.json create mode 100644 res/symbol/h12.json create mode 100644 res/symbol/h13.json create mode 100644 res/symbol/h14.json create mode 100644 res/symbol/h15.json create mode 100644 res/symbol/h16.json create mode 100644 res/symbol/h17.json create mode 100644 res/symbol/h18.json create mode 100644 res/symbol/h19.json create mode 100644 res/symbol/h2.json create mode 100644 res/symbol/h20.json create mode 100644 res/symbol/h21.json create mode 100644 res/symbol/h22.json create mode 100644 res/symbol/h24.json create mode 100644 res/symbol/h25.json create mode 100644 res/symbol/h26.json create mode 100644 res/symbol/h27.json create mode 100644 res/symbol/h28.json create mode 100644 res/symbol/h3.json create mode 100644 res/symbol/h4.json create mode 100644 res/symbol/h5.json create mode 100644 res/symbol/h6.json create mode 100644 res/symbol/h7.json create mode 100644 res/symbol/h8.json create mode 100644 res/symbol/h9.json delete mode 100644 svg/symbol/arrow-small.svg delete mode 100644 svg/symbol/exit.svg delete mode 100644 svg/symbol/h1.svg delete mode 100644 svg/symbol/h10.svg delete mode 100644 svg/symbol/h11.svg delete mode 100644 svg/symbol/h12.svg delete mode 100644 svg/symbol/h13.svg delete mode 100644 svg/symbol/h14.svg delete mode 100644 svg/symbol/h15.svg delete mode 100644 svg/symbol/h16.svg delete mode 100644 svg/symbol/h17.svg delete mode 100644 svg/symbol/h18.svg delete mode 100644 svg/symbol/h19.svg delete mode 100644 svg/symbol/h2.svg delete mode 100644 svg/symbol/h20.svg delete mode 100644 svg/symbol/h21.svg delete mode 100644 svg/symbol/h22.svg delete mode 100644 svg/symbol/h24.svg delete mode 100644 svg/symbol/h25.svg delete mode 100644 svg/symbol/h26.svg delete mode 100644 svg/symbol/h27.svg delete mode 100644 svg/symbol/h28.svg delete mode 100644 svg/symbol/h3.svg delete mode 100644 svg/symbol/h4.svg delete mode 100644 svg/symbol/h5.svg delete mode 100644 svg/symbol/h6.svg delete mode 100644 svg/symbol/h7.svg delete mode 100644 svg/symbol/h8.svg delete mode 100644 svg/symbol/h9.svg diff --git a/res/junction.json b/res/junction.json index 8e06bdf..89c0729 100644 --- a/res/junction.json +++ b/res/junction.json @@ -2,17 +2,17 @@ "width": 120, "height": 240, "vectorSize": [3, 6], - "defs": { - "pil": {"path": "M1.5,.2l.5.5a.1,.1,0,0,1,-.1,.1h-.3v.8h-.2v-.8h-.3a.1,.1,0,0,1,-.1,-.1z", "fill": "#fff"}, - "hoger": {"path": "M1.5,1.5h.7v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.7z", "fill": "#fff"}, - "vanster": {"path": "M1.5,1.5h-.7v-.3a.1,.1,0,0,0,-.1-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.7z", "fill": "#fff"}, - "linje": {"path": "M1.6,1.5v4.5h-.2v-4.5z", "fill": "#fff"} - }, - "core": [{"use": "linje"}], + "defs": [ + {"path": "M1.5,.2l.5.5a.1,.1,0,0,1,-.1,.1h-.3v.8h-.2v-.8h-.3a.1,.1,0,0,1,-.1,-.1z", "fill": "currentColor"}, + {"path": "M1.5,1.5h.7v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.7z", "fill": "currentColor"}, + {"path": "M1.5,1.5h-.7v-.3a.1,.1,0,0,0,-.1-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.7z", "fill": "currentColor"}, + {"path": "M1.6,1.5v4.5h-.2v-4.5z", "fill": "currentColor"} + ], + "core": [{"use": 3}], "components": { - "fwd": [{"use": "pil"}], - "left": [{"use": "vanster"}], - "right": [{"use": "hoger"}], - "lright": [{"use": "hoger", "translate":[0,1]}] + "fwd": [{"use": 0}], + "left": [{"use": 2}], + "right": [{"use": 1}], + "lright": [{"use": 1, "translate":[0,1]}] } } \ No newline at end of file diff --git a/res/roundabout.json b/res/roundabout.json index fd682a0..ba40b88 100644 --- a/res/roundabout.json +++ b/res/roundabout.json @@ -2,17 +2,16 @@ "width": 240, "height": 480, "vectorSize": [6, 12], - "defs": { - "arr_right": {"path": "M4,2.5v-.1h.5v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.5v.1z", "fill": "#fff"}, - "arr_left": {"path": "M2,2.5v-.1h-.5v-.3a.1,.1,0,0,0,-.1,-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.5v.1z", "fill": "#fff"}, - "arr_fwd": {"path": "M3,1.5h-.1v-.5h-.3a.1,.1,0,0,1,-.1,-.1l.5,-.5l.5,.5a.1,.1,0,0,1,-.1.1h-.3v.5h.1z", "fill": "#fff"}, - "c270": {"path": "M2.9,12v-8.6h.1a.9.9,0,1,0-.9-.9v.1h-.2v-.1a1.1,1.1,0,1,1,1.2,1.096v8.404z", "fill": "#fff"}, - "c180": {"path": "M2.9,12v-8.6h.1a.9.9,0,0,0,0-1.8h-.1v-.2h.1a1.1,1.1,0,0,1,.1,2.1955v8.4045z", "fill": "#fff"} - }, - "core": [], + "defs": [ + {"path": "M4,2.5v-.1h.5v-.3a.1,.1,0,0,1,.1,-.1l.5,.5l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.3h-.5v.1z", "fill": "currentColor"}, + {"path": "M2,2.5v-.1h-.5v-.3a.1,.1,0,0,0,-.1,-.1l-.5,.5l.5,.5a.1,.1,0,0,0,.1-.1v-.3h.5v.1z", "fill": "currentColor"}, + {"path": "M3,1.5h-.1v-.5h-.3a.1,.1,0,0,1,-.1,-.1l.5,-.5l.5,.5a.1,.1,0,0,1,-.1.1h-.3v.5h.1z", "fill": "currentColor"}, + {"path": "M2.9,12v-8.6h.1a.9.9,0,1,0-.9-.9v.1h-.2v-.1a1.1,1.1,0,1,1,1.2,1.096v8.404z", "fill": "currentColor"}, + {"path": "M2.9,12v-8.6h.1a.9.9,0,0,0,0-1.8h-.1v-.2h.1a1.1,1.1,0,0,1,.1,2.1955v8.4045z", "fill": "currentColor"} + ], "components": { - "fwd": [{"use": "c180"}, {"use": "arr_fwd"}], - "left": [{"use": "c270"}, {"use": "arr_left"}], - "right": [{"use": "arr_right"}] + "fwd": [{"use": 4}, {"use": 2}], + "left": [{"use": 3}, {"use": 1}], + "right": [{"use": 0}] } } \ No newline at end of file diff --git a/res/spanish.json b/res/spanish.json index c4335de..6cfecf6 100644 --- a/res/spanish.json +++ b/res/spanish.json @@ -2,19 +2,19 @@ "width": 200, "height": 360, "vectorSize": [5, 9], - "defs": { - "bp": {"path": "M.72,2.06h1.4c1.1,0 2.05,1.7 .7,2.65l-.75,.47v.7q0,-.4,.15,-.5l.75,-.47c1.35,-.8,.85,-3,-.85,-3.09h-1.4zM2,.2l-.5.5a.1,.1,0,0,0,.1,.1h.28v7.04h.24v-7.04h.28a.1,.1,0,0,0,.1,-.1z", "fill": "#fff"}, - "sk1": {"path": "M2,2.785a.725.725,0,0,0,0,1.45a.725.725,0,0,0,0,-1.45z", "fill": "#e45"}, - "sk2": {"path": "M2,2.935a.575.575,0,0,0,0,1.15a.575.575,0,0,0,0,-1.15z", "fill": "#fd0"}, - "skvp": {"path": "M1.66,3.26h.45a.2.2,0,0,1,.2.2v.49h-.18v-.47a.05.05,0,0,0-.05-.05h-.42v.05l-.14-.14l.14-.14z", "fill": "#000"}, - "sk3": {"path": "M1.65,3l.85,1l-.08.08l-.85-1z", "fill": "#e45"}, - "arr_left": {"path": "M.28,1.94l.5,.5a.1,.1,0,0,0,.1,-.1v-.8a.1,.1,0,0,0,-.1,-.1l-.5,.5z", "fill": "#fff"}, - "arr_right": {"path": "M4.72,1.94l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.28h-2v-.24h2v-.28a.1,.1,0,0,1,.1,-.1l.5,.5z", "fill": "#fff"} - }, - "core": [{"use": "bp"}, {"use": "sk1"}, {"use": "sk2"}, {"use": "skvp"}, {"use": "sk3"}], + "defs": [ + {"path": "M.72,2.06h1.4c1.1,0 2.05,1.7 .7,2.65l-.75,.47v.7q0,-.4,.15,-.5l.75,-.47c1.35,-.8,.85,-3,-.85,-3.09h-1.4zM2,.2l-.5.5a.1,.1,0,0,0,.1,.1h.28v7.04h.24v-7.04h.28a.1,.1,0,0,0,.1,-.1z", "fill": "currentColor"}, + {"path": "M2,2.785a.725.725,0,0,0,0,1.45a.725.725,0,0,0,0,-1.45z", "fill": "#e45"}, + {"path": "M2,2.935a.575.575,0,0,0,0,1.15a.575.575,0,0,0,0,-1.15z", "fill": "#fd0"}, + {"path": "M1.66,3.26h.45a.2.2,0,0,1,.2.2v.49h-.18v-.47a.05.05,0,0,0-.05-.05h-.42v.05l-.14-.14l.14-.14z", "fill": "#000"}, + {"path": "M1.65,3l.85,1l-.08.08l-.85-1z", "fill": "#e45"}, + {"path": "M.28,1.94l.5,.5a.1,.1,0,0,0,.1,-.1v-.8a.1,.1,0,0,0,-.1,-.1l-.5,.5z", "fill": "currentColor"}, + {"path": "M4.72,1.94l-.5,.5a.1,.1,0,0,1,-.1,-.1v-.28h-2v-.24h2v-.28a.1,.1,0,0,1,.1,-.1l.5,.5z", "fill": "currentColor"} + ], + "core": [{"use": 0}, {"use": 1}, {"use": 2}, {"use": 3}, {"use": 4}], "components": { "fwd": [], - "left": [{"use": "arr_left"}], - "right": [{"use": "arr_right"}] + "left": [{"use": 5}], + "right": [{"use": 6}] } } \ No newline at end of file diff --git a/res/symbol/arrow-small.json b/res/symbol/arrow-small.json new file mode 100644 index 0000000..6c0863f --- /dev/null +++ b/res/symbol/arrow-small.json @@ -0,0 +1,17 @@ +{ + "width": 48, + "height": 192, + "vectorSize": [1, 4], + "defs": [ + {"path": "M0,0.4l0.33,0.33a0.07,0.07,0,0,0,0.12,-0.05v-0.19h0.25a0.11,0.11,0,0,1,0.11,0.11v3.4h0.18v-3.4a0.29,0.29,0,0,0,-0.29,-0.29h-0.25v-0.19a0.07,0.07,0,0,0,-0.12,-0.05l-0.33,0.33z", "fill": "currentColor"}, + {"path": "M0,0.4m1,0l-0.33,0.33a0.07,0.07,0,0,1,-0.12,-0.05v-0.19h-0.25a0.11,0.11,0,0,0,-0.11,0.11v3.4h-0.18v-3.4a0.29,0.29,0,0,1,0.29,-0.29h0.25v-0.19a0.07,0.07,0,0,1,0.12,-0.05l0.33,0.33z", "fill": "currentColor"}, + {"path": "M0.5,0.05l0.33,0.33a0.07,0.07,0,0,1,-0.05,0.12h-0.19v3.5h-0.18v-3.5h-0.19a0.07,0.07,0,0,1,-0.05,-0.12z", "fill": "currentColor"}, + {"path": "M0.25,0.45l0.19,-0.19l-0.14,-0.14a0.07,0.07,0,0,1,0.04,-0.12h0.5v0.5a0.07,0.07,0,0,1,-0.12,0.04l-0.14,-0.14l-0.19,0.19q-0.06,0.07,-0.07,0.16v3.25h-0.19v-3.25q0,-0.16,0.12,-0.3z", "fill": "currentColor"} + ], + "components": { + "left": [{"use": 0}], + "right": [{"use": 1}], + "fwd": [{"use": 2}], + "exit": [{"use": 3}] + } +} \ No newline at end of file diff --git a/res/symbol/exit.json b/res/symbol/exit.json new file mode 100644 index 0000000..49911bb --- /dev/null +++ b/res/symbol/exit.json @@ -0,0 +1,8 @@ +{ + "width": 46, + "height": 26, + "vectorSize": [46, 26], + "defs": [ + {"path": "M11,0l-11,26h13l3,-26h-5zM19,0l3,26h13l-11,-26zM46,0h-12l4.5,4.5q-4,3.5,-9,10l5.5,11.5q-1,-8,6.5,-18l4.5,4.5z", "fill": "currentColor"} + ] +} \ No newline at end of file diff --git a/res/symbol/h1.json b/res/symbol/h1.json new file mode 100644 index 0000000..dd4aeb4 --- /dev/null +++ b/res/symbol/h1.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M184.177,66.276c0,-23.441,-19.003,-42.443,-42.444,-42.443c-23.442,0,-42.444,19.002,-42.444,42.443c0,23.441,19.002,42.444,42.444,42.444c23.441,0,42.444,-19.003,42.444,-42.444z", "fill": "#111"}, + {"path": "M201.153,240.297l6.602,0l0,9.902l-132.047,0l0,-9.902l6.602,0c4.503,0,8.821,-1.789,12.005,-4.973c3.184,-3.185,4.973,-7.504,4.973,-12.006l0,-78.285c0,-4.503,-1.789,-8.82,-4.973,-12.005c-3.184,-3.184,-7.502,-4.972,-12.005,-4.972l-6.131,0l0,-9.904l107.997,0l0,105.166c0,4.502,1.788,8.821,4.972,12.006c3.184,3.184,7.502,4.973,12.005,4.973z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h10.json b/res/symbol/h10.json new file mode 100644 index 0000000..2967c9a --- /dev/null +++ b/res/symbol/h10.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M16.376,135.843l125.356,-87.775l125.356,87.775l-16.696,23.842l-22.203,-15.548l0,88.304l-86.457,0l-86.457,0l0,-88.304l-22.204,15.548l-16.695,-23.842z", "fill": "#111"}, + {"path": "M141.732,144.567l-36.378,0l72.755,0l0,28.346l-36.377,0l-36.378,0l0,-28.346l36.378,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h11.json b/res/symbol/h11.json new file mode 100644 index 0000000..700d1a1 --- /dev/null +++ b/res/symbol/h11.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M122.749,71.606l-100.072,173.332l238.11,0l-100.073,-173.332l7.447,-12.898l23.407,-40.543l-37.965,0l-11.871,20.562l-11.872,-20.562l-37.965,0l30.854,53.441z", "fill": "#111"}, + {"path": "M81.732,216.85l-4.725,0l25.195,-43.637l39.53,-68.469l39.53,68.469l25.194,43.637l-4.724,0l-17.48,0l-42.52,-73.646l-42.52,73.646l-17.48,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h12.json b/res/symbol/h12.json new file mode 100644 index 0000000..64df22b --- /dev/null +++ b/res/symbol/h12.json @@ -0,0 +1,10 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M8.555,183.992l0,16.064l3.32,0c-0.215,4.075,2.347,7.783,6.236,9.023c3.889,1.241,8.124,-0.298,10.309,-3.745c2.186,-3.447,1.771,-7.935,-1.011,-10.923c-2.78,-2.987,-7.227,-3.722,-10.821,-1.789l0,-8.63l101.102,0c0,-15.916,12.902,-28.818,28.818,-28.818c15.917,0,28.82,12.902,28.82,28.818l79.842,0c3.383,0,6.627,-1.343,9.02,-3.736c2.392,-2.391,3.736,-5.637,3.736,-9.019l0,-85.483c0,-6.123,-4.204,-11.447,-10.161,-12.867c-75.195,-17.926,-153.522,-18.178,-228.831,-0.736c-5.569,1.29,-9.512,6.251,-9.512,11.967l0,82.866c-0.065,2.899,0.416,5.784,1.418,8.504l-17.008,0l0,8.504l4.724,0zM171.076,183.992c0,-13.568,-10.999,-24.567,-24.568,-24.567c-13.567,0,-24.567,10.999,-24.567,24.567c0,13.569,11,24.568,24.567,24.568c13.569,0,24.568,-10.999,24.568,-24.568z", "fill": "#111"}, + {"path": "M155.484,183.992c0,-4.957,-4.019,-8.976,-8.977,-8.976c-4.957,0,-8.976,4.019,-8.976,8.976c0,4.958,4.019,8.977,8.976,8.977c4.958,0,8.977,-4.019,8.977,-8.977zM157.846,75.331c-1.128,0,-2.209,0.448,-3.007,1.246c-0.797,0.797,-1.245,1.879,-1.245,3.006l0,25.512c0,1.128,0.448,2.209,1.245,3.007c0.798,0.797,1.879,1.245,3.007,1.245l75.591,0c2.348,0,4.252,-1.904,4.252,-4.252l0,-25.512c0,-1.127,-0.448,-2.209,-1.246,-3.006c-0.797,-0.798,-1.879,-1.246,-3.006,-1.246l-75.591,0zM55.799,105.095c0,2.348,1.904,4.252,4.252,4.252l25.511,0c1.128,0,2.21,-0.448,3.007,-1.245c0.798,-0.798,1.246,-1.879,1.246,-3.007l0,-25.512c0,-1.127,-0.448,-2.209,-1.246,-3.006c-0.797,-0.798,-1.879,-1.246,-3.007,-1.246l-25.511,0c-1.128,0,-2.209,0.448,-3.007,1.246c-0.797,0.797,-1.245,1.879,-1.245,3.006l0,25.512z", "fill": "#fff"}, + {"path": "M274.067,233.126l-264.567,0l0,-23.622l264.567,0l0,23.622z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h13.json b/res/symbol/h13.json new file mode 100644 index 0000000..74f0791 --- /dev/null +++ b/res/symbol/h13.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M45.355,208.819l-27.874,0l0,-20.788l80.314,0l0,20.788l-25.511,0l0,28.346l87.402,0l0,-70.393l-70.395,0l42.048,-42.047l-18.425,0l42.52,-42.52l-17.953,0l34.724,-60.144l34.725,60.144l-18.898,0l42.52,42.52l-18.426,0l42.048,42.047l-70.866,0l0,70.393l69.449,0l0,21.732l-235.276,0l0,-21.732l0.472,0l17.953,0l9.449,0l0,-28.346z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h14.json b/res/symbol/h14.json new file mode 100644 index 0000000..2629a40 --- /dev/null +++ b/res/symbol/h14.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M94.488,234.803l94.488,0l0,-186.142l-94.488,0l0,186.142zM91.181,77.008l0,-31.181l101.102,0l0,31.181l6.605,0l15.6,-51.024l-72.756,0l-72.756,0l15.599,51.024l6.606,0zM265.985,257.481l0,-18.899l-248.504,0l0,18.899l124.252,0l124.252,0z", "fill": "#111"}, + {"path": "M127.559,120c5.664,4.067,10.479,9.203,14.173,15.118c3.693,-5.915,8.508,-11.051,14.173,-15.118c4.498,-3.271,7.813,-7.913,9.449,-13.228c1.47,-6.319,-2.399,-12.649,-8.692,-14.223c-6.294,-1.573,-12.687,2.192,-14.363,8.459c-0.041,0.28,-0.253,0.505,-0.531,0.561c-0.31,-0.018,-0.562,-0.254,-0.603,-0.561c-1.676,-6.267,-8.069,-10.032,-14.363,-8.459c-6.294,1.574,-10.162,7.904,-8.692,14.223c1.635,5.315,4.951,9.957,9.449,13.228z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h15.json b/res/symbol/h15.json new file mode 100644 index 0000000..4a85b53 --- /dev/null +++ b/res/symbol/h15.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M14.173,196.064c3.995,-0.421,8.01,0.583,11.338,2.834c18.563,11.338,41.91,11.338,60.473,0c8.084,-3.78,17.428,-3.78,25.512,0c18.562,11.338,41.909,11.338,60.472,0c8.084,-3.78,17.428,-3.78,25.512,0c18.562,11.338,41.909,11.338,60.473,0c3.327,-2.251,7.343,-3.255,11.337,-2.834l0,-33.071c-3.994,-0.421,-8.01,0.583,-11.337,2.834c-18.564,11.338,-41.911,11.338,-60.473,0c-8.084,-3.78,-17.428,-3.78,-25.512,0c-18.563,11.338,-41.91,11.338,-60.472,0c-8.084,-3.78,-17.428,-3.78,-25.512,0c-18.563,11.338,-41.91,11.338,-60.473,0c-3.328,-2.251,-7.343,-3.255,-11.338,-2.834l0,33.071zM269.29,252.756c-3.994,-0.42,-8.01,0.584,-11.337,2.835c-18.564,11.339,-41.911,11.339,-60.473,0c-8.084,-3.78,-17.428,-3.78,-25.512,0c-18.563,11.339,-41.91,11.339,-60.472,0c-8.084,-3.78,-17.428,-3.78,-25.512,0c-18.563,11.339,-41.91,11.339,-60.473,0c-3.328,-2.251,-7.343,-3.255,-11.338,-2.835l0,-33.07c3.995,-0.421,8.01,0.583,11.338,2.834c18.563,11.338,41.91,11.338,60.473,0c8.084,-3.78,17.428,-3.78,25.512,0c18.562,11.338,41.909,11.338,60.472,0c8.084,-3.78,17.428,-3.78,25.512,0c18.562,11.338,41.909,11.338,60.473,0c3.327,-2.251,7.343,-3.255,11.337,-2.834l0,33.07zM229.119,159.668c-11.143,0.27,-22.127,-2.676,-31.639,-8.487c-8.084,-3.779,-17.428,-3.779,-25.512,0c-18.563,11.339,-41.91,11.339,-60.472,0c-8.084,-3.779,-17.428,-3.779,-25.512,0c-9.105,5.562,-19.567,8.504,-30.236,8.504l8.314,-7.558c5.344,-5.645,11.126,-10.858,17.292,-15.591c3.418,-3.228,7.619,-5.508,12.188,-6.614l10.395,-3.78l10.393,-3.78c3.464,-1.326,5.976,-4.377,6.614,-8.031l0.7,-5.947c0.025,-0.42,-0.023,-0.841,-0.144,-1.245c-0.247,-0.747,-0.634,-1.439,-1.142,-2.04c-0.35,-0.397,-0.765,-0.732,-1.227,-0.991c-0.396,-0.217,-0.8,-0.418,-1.212,-0.603l-7.361,-2.804c-0.705,-0.276,-1.418,-0.534,-2.137,-0.773c-1.768,-0.722,-2.963,-2.398,-3.067,-4.305c-0.195,-2.582,-0.606,-5.142,-1.228,-7.654c-1.197,-2.958,-2.207,-5.987,-3.024,-9.071c-0.253,-2.987,-0.253,-5.99,0,-8.976l0.472,-3.78l0.473,-3.78c0.74,-3.883,0.069,-7.904,-1.89,-11.338c-4.717,-10.461,-2.935,-22.71,4.568,-31.393c0.69,-0.779,1.474,-1.47,2.333,-2.058c6.225,-4.177,13.285,-6.949,20.69,-8.124c11.13,-1.562,22.476,-0.283,32.98,3.719c1.728,0.686,3.382,1.545,4.939,2.561c4.332,3.186,7.797,7.406,10.081,12.275c0.513,1.192,0.947,2.418,1.298,3.666c2.586,10.68,4.051,21.599,4.371,32.582l0,4.484c-0.013,0.249,-0.035,0.497,-0.062,0.745c-0.598,4.533,-2.19,8.878,-4.662,12.724l-8.032,14.174c-1.014,2.052,-1.501,4.325,-1.417,6.614l0,6.613c0.064,1.887,0.815,3.685,2.11,5.059c0.604,0.554,1.263,1.046,1.964,1.472c0.4,0.25,0.805,0.493,1.214,0.728c3.498,2.154,7.094,4.146,10.774,5.97l12.756,6.614c9.752,5.037,18.295,12.129,25.04,20.787l8.031,9.449l-0.014,-0.017z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h16.json b/res/symbol/h16.json new file mode 100644 index 0000000..0f1c62f --- /dev/null +++ b/res/symbol/h16.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M152.615,106.043c0.183,3.768,1.942,7.286,4.849,9.69c1.428,0.919,2.737,2.013,3.895,3.254c3.657,3.802,6.843,8.031,9.487,12.595c3.352,4.906,6.203,10.135,8.514,15.609c0.807,2.129,1.577,4.273,2.309,6.429c1.455,4.601,2.98,9.18,4.574,13.734c1.245,2.72,0.722,5.922,-1.322,8.103c-0.673,0.563,-1.532,0.852,-2.408,0.813c-2.376,0.06,-4.54,-1.366,-5.421,-3.574c-2.398,-6.145,-4.526,-12.393,-6.378,-18.724c-0.256,-0.848,-0.637,-1.652,-1.133,-2.386c-2.369,-3.519,-5.123,-6.761,-8.212,-9.668c-0.073,6.016,1.033,11.988,3.255,17.579c2.593,7.056,5.605,13.952,9.019,20.65c3.951,8.091,8.365,15.947,13.22,23.531c-4.14,2.117,-8.442,3.898,-12.866,5.326c3.855,8.012,7.129,16.287,9.801,24.768c3.521,-9.02,7.728,-17.754,12.58,-26.131c3.392,-6.174,6.943,-12.26,10.649,-18.248c3.847,-5.575,6.827,-11.698,8.838,-18.164c1.224,-3.623,1.489,-7.501,0.767,-11.257c-0.432,-1.981,-0.958,-3.939,-1.575,-5.871c-1.806,0.362,-3.681,0.115,-5.332,-0.701c-0.506,-0.265,-0.95,-0.635,-1.302,-1.084c-0.521,-0.741,-0.922,-1.558,-1.188,-2.423c-0.354,-0.953,-0.715,-1.903,-1.084,-2.851c-3.732,-9.474,-6.601,-19.265,-8.568,-29.256c-0.603,-2.096,0.213,-4.342,2.021,-5.562c0.717,-0.576,1.635,-0.844,2.549,-0.743c0.914,0.1,1.752,0.56,2.327,1.278c2.428,3.136,4.636,6.434,6.61,9.872c2.668,-2.678,4.215,-6.272,4.327,-10.051c0.254,-2.085,0.377,-4.185,0.373,-6.285c0.025,-0.68,-0.125,-1.355,-0.436,-1.96c-0.377,-0.989,-0.769,-1.972,-1.178,-2.948c-0.216,-0.503,-0.543,-0.95,-0.955,-1.308c-0.689,-0.575,-1.542,-0.917,-2.437,-0.977c-4.522,-0.197,-8.238,-3.635,-8.785,-8.128c-0.299,-1.751,-0.578,-3.504,-0.839,-5.261c-0.565,-2.961,-0.813,-5.975,-0.739,-8.988c0.613,-4.595,4.234,-8.206,8.83,-8.808c3.347,-0.548,6.779,-0.241,9.975,0.892c0.676,0.278,1.318,0.634,1.91,1.061c2.3,1.907,3.874,4.546,4.46,7.476c0.268,3.024,0.481,6.053,0.639,9.085c0.463,3.014,1.292,5.96,2.469,8.773c0.451,1.179,1.347,2.133,2.496,2.657c2.267,0.96,4.453,2.107,6.533,3.428l-3.092,-12.998c4.004,-1.562,8.135,-2.78,12.346,-3.643c3.766,-0.154,7.156,2.26,8.244,5.868c4.506,17.131,8.801,34.317,12.886,51.553c0.468,3.937,-1.736,7.706,-5.398,9.228c-3.539,1.048,-7.099,2.025,-10.677,2.934c1.328,4.044,1.449,8.386,0.348,12.497c-1.531,5.643,-2.391,11.446,-2.559,17.29c-0.046,8.963,1.495,17.861,4.552,26.285c5.417,14.379,12.526,28.064,21.174,40.765l-15.998,9.409c-6.669,-9.578,-12.822,-19.504,-18.431,-29.741c-5.698,-12.339,-9.913,-25.31,-12.557,-38.644c-8.775,13.603,-16.768,27.697,-23.933,42.215c-3.813,8.519,-7.124,17.256,-9.912,26.162c-6.066,-2.205,-12.108,-4.477,-18.125,-6.817c0.685,-2.228,1.406,-4.447,2.163,-6.652c-5.572,-12.017,-11.947,-23.646,-19.081,-34.807c-7.281,0.081,-14.553,-0.535,-21.715,-1.841c-1.729,9.939,-5.554,19.398,-11.22,27.744c-0.765,1.123,-1.516,2.256,-2.254,3.396c-1.339,2.061,-2.353,4.315,-3.007,6.684c-0.705,2.928,-1.664,5.789,-2.867,8.553c-2.797,-0.85,-5.579,-1.746,-8.345,-2.694c2.45,-7.051,4.845,-14.121,7.185,-21.211c2.439,-8.386,4.418,-16.902,5.927,-25.506c0.458,-2.306,0.944,-4.607,1.458,-6.902c3.522,-16.865,5.519,-34.011,5.967,-51.233c-2.99,5.242,-5.969,10.491,-8.938,15.745c-1.652,2.711,-3.182,5.495,-4.585,8.344c-1.44,2.336,-3.154,4.494,-5.106,6.423c-0.782,0.698,-1.235,1.692,-1.25,2.741c-0.85,3.714,-1.655,7.441,-2.413,11.175c-0.122,0.801,-0.4,1.571,-0.818,2.264c-0.149,0.201,-0.317,0.389,-0.5,0.559c-0.336,0.291,-0.724,0.515,-1.142,0.66c-1.149,0.262,-2.342,0.262,-3.491,0.002c-2.921,-0.52,-5.795,-1.276,-8.592,-2.264c0.256,3.811,0.371,7.631,0.344,11.451c0.225,6.315,0.494,12.625,0.808,18.936c0.281,5.226,1.667,10.332,4.063,14.984c2.256,4.006,4.668,7.922,7.232,11.737c-3.003,2.005,-6.029,3.976,-9.079,5.91c-3.955,-5.43,-7.649,-11.045,-11.071,-16.828c-1.037,-1.422,-1.738,-3.061,-2.051,-4.793c-1.12,-4.922,-2.155,-9.864,-3.106,-14.823c-2.691,4.784,-5.289,9.618,-7.793,14.5c-3.138,6.946,-5.951,14.034,-8.428,21.239c-3.443,-0.877,-6.855,-1.87,-10.231,-2.975c0.667,-2.408,1.471,-4.777,2.409,-7.094c1.923,-4.369,3.716,-8.795,5.377,-13.269c2.809,-6.487,5.259,-13.123,7.338,-19.879c0.744,-3.582,1.248,-7.209,1.507,-10.86c-3.784,2.084,-7.603,4.102,-11.456,6.053c-1.699,0.756,-3.234,1.834,-4.524,3.174c-1.071,1.416,-2.637,2.379,-4.385,2.697c-0.804,0.125,-1.617,-0.164,-2.162,-0.769c-0.545,-0.606,-0.747,-1.446,-0.538,-2.233c0.658,-3.056,2.51,-5.724,5.143,-7.412c2.367,-1.359,4.619,-2.908,6.734,-4.635c2.711,-2.337,5.314,-4.798,7.798,-7.378c2.336,-2.702,4.893,-5.206,7.646,-7.481c1.18,-0.959,2.118,-2.182,2.738,-3.568c0.547,-1.354,-0.014,-2.903,-1.302,-3.59c-0.803,-0.393,-1.609,-0.779,-2.418,-1.158c-1.267,-0.606,-2.157,-1.791,-2.385,-3.177c-0.522,-1.863,-0.778,-3.791,-0.758,-5.726c-0.094,-1.095,-0.116,-2.195,-0.065,-3.293c-0.087,-1.211,0.012,-2.428,0.294,-3.61c0.662,-3.067,2.831,-5.59,5.763,-6.705c3.396,-1.261,7.131,-1.263,10.528,-0.004c2.247,0.817,3.972,2.651,4.653,4.942c0.898,2.239,1.353,4.629,1.342,7.041c0.116,3.402,-0.422,6.795,-1.586,9.995c-0.975,2.168,-0.202,4.724,1.811,5.988c2.08,1.127,4.164,2.244,6.253,3.351c0.829,-2.191,1.619,-4.396,2.37,-6.613c0.63,-1.789,1.195,-3.599,1.693,-5.429c0.118,-1.294,0.727,-2.493,1.702,-3.352c1.927,-2.243,3.727,-4.593,5.389,-7.039c1.927,-3.083,3.685,-6.268,5.268,-9.542c0.589,-1.383,1.121,-2.789,1.596,-4.216c2.987,-10.167,8.009,-19.621,14.761,-27.789c1.759,-1.936,3.347,-4.02,4.744,-6.232c0.166,-0.28,0.298,-0.578,0.394,-0.889c0.526,-1.736,0.469,-3.596,-0.162,-5.297c-0.575,-0.855,-1.363,-1.545,-2.285,-2.002c-2.189,-1.234,-3.81,-3.273,-4.518,-5.684c-0.817,-2.612,-1.047,-5.371,-0.676,-8.082c0.391,-2.142,0.374,-4.338,-0.049,-6.473c-0.494,-1.972,-0.149,-4.061,0.952,-5.77c3.653,-4.862,9.72,-7.27,15.713,-6.237c5.058,1.534,9.03,5.471,10.609,10.516c1.224,3.527,2.869,6.894,4.897,10.03c1.224,2.198,2.933,4.087,4.997,5.523c0.047,0.03,0.089,0.068,0.124,0.111c0.043,0.064,0.06,0.142,0.05,0.219c-0.01,0.045,-0.031,0.088,-0.061,0.123c-0.039,0.042,-0.086,0.079,-0.136,0.107c-0.039,0.017,-0.078,0.034,-0.118,0.049c-4.861,1.972,-9.905,3.46,-15.059,4.441zM67.746,82.787c-0.532,-9.668,3.255,-19.072,10.339,-25.673c12.585,-10.836,27.729,-18.278,43.996,-21.622c22.694,-5.113,45.887,-7.676,69.15,-7.638l43.225,0l0,-14.247l-220.85,0l0,255.413l15.952,0l0,-32.028c-0.303,-17.492,1.488,-34.957,5.336,-52.023c8.718,-33.649,39.073,-57.156,73.834,-57.175l0.025,-12.785c-11.394,-0.194,-22.417,-4.087,-31.406,-11.092c-6.08,-5.342,-9.576,-13.036,-9.601,-21.13z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h17.json b/res/symbol/h17.json new file mode 100644 index 0000000..3ca953a --- /dev/null +++ b/res/symbol/h17.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M200.044,97.842c0.842,-2.807,1.865,-5.557,3.063,-8.232c2.276,0.214,4.457,-0.971,5.517,-2.997c2.737,-4.422,3.909,-9.636,3.327,-14.804c-0.286,-3.803,-2.075,-7.337,-4.969,-9.821c-3.336,-2.52,-7.62,-3.429,-11.692,-2.48c-5.853,-0.207,-11.65,1.213,-16.744,4.102l2.592,3.304c2.967,-2.496,6.365,-4.432,10.026,-5.712c-0.567,0.778,-1.023,1.629,-1.354,2.532c-0.464,1.166,-0.826,2.372,-1.081,3.601c-0.349,1.599,-0.458,3.243,-0.323,4.875c0.399,3.076,1.285,6.069,2.623,8.867c0.283,0.601,0.373,1.274,0.258,1.927c-0.191,1.371,-0.721,2.672,-1.544,3.784c5.079,1.711,8.952,5.868,10.301,11.054zM133.1,69.685c0.349,-0.296,0.655,-0.639,0.909,-1.019c0.807,-1.464,1.504,-2.985,2.085,-4.552c2.67,-7.332,2.574,-15.387,-0.27,-22.654c-1.4,-2.934,-3.844,-5.24,-6.854,-6.47c-4.427,-2.236,-9.676,-2.12,-14,0.309c-7.209,0.372,-14.232,2.423,-20.508,5.99l3.659,4.576c3.963,-3.491,8.586,-6.149,13.597,-7.817c-1.645,2.002,-2.665,4.444,-2.93,7.021c-0.228,3.331,0.421,6.664,1.881,9.666c1.091,1.809,1.858,3.793,2.268,5.865c0.058,2.384,-0.308,4.759,-1.081,7.015c4.8,1.795,8.613,5.543,10.49,10.311c1.324,-2.491,2.64,-4.987,3.946,-7.487c2.215,1.135,4.895,0.838,6.808,-0.754zM186.615,136.763c-0.634,-1.364,-1.131,-2.787,-1.485,-4.249c-0.724,-3.075,-1.078,-6.226,-1.054,-9.385c0.697,3.522,1.732,6.969,3.093,10.292c1.639,4.347,4.205,8.286,7.519,11.543c1.14,1.283,2.658,2.17,4.336,2.533c1.341,0.23,2.694,-0.336,3.472,-1.452c0.109,-0.182,0.214,-0.365,0.316,-0.551c2.62,-4.949,5.049,-9.996,7.283,-15.131c1.486,-3.822,2.748,-7.729,3.779,-11.699c0.744,-3.615,0.879,-7.328,0.4,-10.987c-0.182,-1.876,-0.709,-3.702,-1.555,-5.386c-0.034,-0.058,-0.074,-0.114,-0.119,-0.165c-1.056,-1.179,-2.773,-1.502,-4.185,-0.785c-0.32,0.168,-0.591,0.415,-0.785,0.719c-2.01,3.767,-3.994,7.549,-5.951,11.343c-0.614,-3.98,-1.619,-7.89,-2.999,-11.673c-1.126,-3.439,-3.082,-6.548,-5.696,-9.05c-2.428,-2.382,-5.826,-3.498,-9.194,-3.019c-2.5,0.588,-4.725,2.011,-6.307,4.034l4.231,-15.301l-12.963,-4.054c-3.455,-0.518,-6.798,1.469,-7.994,4.751l-15.45,55.895c-0.657,2.015,-0.444,4.212,0.588,6.063c1.032,1.851,2.79,3.187,4.849,3.686l13.357,3.035c-0.031,1.161,-0.04,2.324,-0.024,3.486c0.053,2.025,0.172,4.049,0.356,6.066c0.27,3.362,0.875,6.69,1.804,9.932c0.333,1.355,0.663,2.71,0.99,4.065c0.305,1.592,0.544,3.195,0.716,4.806c0.049,1.871,-0.054,3.742,-0.309,5.596c-0.309,2.349,-0.788,4.672,-1.432,6.949c-0.72,2.553,-1.482,5.092,-2.285,7.619c-1.467,4.738,-3.279,9.365,-5.418,13.842c-1.839,4.166,-3.912,8.225,-6.207,12.156c-2.342,-7.574,-5.07,-15.023,-8.169,-22.318c-0.064,-0.16,-0.13,-0.32,-0.199,-0.479c-3.712,-9.595,-7.892,-19.006,-12.528,-28.191c-0.061,-0.126,-0.125,-0.252,-0.191,-0.375c-3.441,-7.299,-7.782,-14.137,-12.923,-20.356l3.588,-8.839c-6.074,-6.112,-10.739,-13.477,-13.669,-21.58c-1.93,-4.633,-2.731,-9.658,-2.338,-14.661c0.825,2.993,1.804,5.941,2.935,8.833c2.393,6.965,6.432,13.249,11.774,18.32c0.633,0.577,1.365,1.035,2.162,1.352c1.679,0.404,3.426,-0.328,4.315,-1.809c2.111,-3.475,4.113,-7.016,6.003,-10.616c0.212,-0.408,0.41,-0.822,0.593,-1.243c2.237,-5.42,4.103,-10.985,5.581,-16.659c0.118,-0.495,0.223,-0.992,0.314,-1.493c1.142,-5.518,1.057,-11.219,-0.246,-16.7c-0.174,-0.508,-0.486,-0.957,-0.9,-1.298c-1.211,-0.992,-2.918,-1.106,-4.25,-0.284c-0.098,0.07,-0.193,0.144,-0.284,0.223c-0.504,0.503,-0.941,1.07,-1.3,1.685l-7.435,11.773c-0.44,-6.943,-2.506,-13.684,-6.033,-19.679c-0.566,-0.984,-1.156,-1.953,-1.769,-2.907c-1.807,-2.717,-4.775,-4.438,-8.031,-4.655c-3.255,-0.218,-6.427,1.093,-8.578,3.546l3.678,-14.244l-15.555,-3.164c-2.158,-0.521,-4.433,-0.189,-6.352,0.926c-0.721,0.46,-1.364,1.03,-1.907,1.69c-0.796,0.896,-1.368,1.967,-1.669,3.126l-15.804,59.034c-0.053,0.213,-0.093,0.429,-0.121,0.646c-0.572,4.475,2.345,8.654,6.743,9.658l16.535,3.312l-0.319,1.551l-0.165,0.871c-0.423,2.513,-0.789,5.035,-1.096,7.565l-0.058,1.1l-0.052,1.368l0.07,1.541l0.113,2.092l0.243,1.941l0.223,1.343c0.229,1.269,0.521,2.528,0.874,3.769l0.612,2.601l0.39,2.27l0.58,3.545l0.068,2.699l-0.124,1.944l-0.212,2.592l-0.365,2.009l-0.593,2.059l-0.823,2.73l-0.884,2.391l-1.586,3.754l-1.205,2.777l-1.151,2.326l-2.11,4.362l-3.49,6.808l-2.783,5.219l-3.811,6.672l-3.478,5.89l-4.775,7.311l-5.112,7.795l-7.225,10.687l16.383,13.196l3.028,-4.35l7.389,-11.021c3.609,-5.149,7.036,-10.424,10.272,-15.815l3.124,-5.293c4.455,-7.162,8.603,-14.51,12.435,-22.023c3.323,-6.615,6.52,-13.291,9.59,-20.028c3.133,3.788,6.058,7.743,8.761,11.848l1.141,1.996c3.374,5.801,6.292,11.856,8.728,18.11l1.503,4.132c2.49,7.014,4.818,14.082,6.981,21.202l0.42,1.423c1.712,6.219,3.432,12.436,5.158,18.651l11.476,0.088c1.031,-1.674,2.044,-3.36,3.036,-5.055c1.043,-1.885,2.09,-3.77,3.14,-5.65l4.036,-7.496c3.453,-6.397,6.759,-12.87,9.915,-19.417c0.377,-0.773,0.762,-1.541,1.154,-2.306c2.481,-5.444,4.84,-10.942,7.076,-16.49l0.767,-1.846c1.71,-4.043,3.304,-8.133,4.783,-12.266c2.072,2.86,4.023,5.805,5.844,8.828l0.574,0.965c2.385,4.114,4.511,8.373,6.363,12.75l1.199,2.643c2.483,5.691,4.801,11.451,6.954,17.275l0.716,1.932c2.117,5.543,4.024,11.166,5.715,16.853l2.666,8.346l16.977,-6.41c-1.89,-5.867,-3.828,-11.719,-5.817,-17.553c-2.535,-7.414,-5.392,-14.715,-8.564,-21.879c-2.854,-7.355,-5.975,-14.603,-9.358,-21.73c-2.633,-5.354,-5.515,-10.582,-8.636,-15.667c-2.394,-3.964,-5.039,-7.771,-7.919,-11.398l3.69,-10.53c-2.815,-2.367,-5.344,-5.057,-7.531,-8.014c-1.758,-2.414,-3.288,-4.985,-4.572,-7.68c0,0,0,0,0,-0.001z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h18.json b/res/symbol/h18.json new file mode 100644 index 0000000..65cb5b9 --- /dev/null +++ b/res/symbol/h18.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M3.382,51.902l112.52,-18.5l0.078,0.977l1.824,0.619l0.358,23.841l-26.497,1.805c-11.573,2.024,-19.714,12.509,-18.808,24.223l-0.091,39.084c-1.793,2.78,-3.11,5.84,-3.896,9.053l-7.785,30.763c-0.93,2.545,-0.691,5.371,0.652,7.724c1.344,2.353,3.655,3.995,6.32,4.488l6.095,1.691l0.368,27.344l66.265,-7.725l5.118,58.899l44.075,-5.342c-4.648,-4.018,-10.03,-7.096,-15.85,-9.065c-1.277,-0.724,-2.022,-2.121,-1.914,-3.588l-0.131,-45.71c0.076,-3.004,-1.118,-5.903,-3.289,-7.983c-2.17,-2.08,-5.116,-3.148,-8.115,-2.943l1.571,49.099c0.052,2.463,-0.044,4.928,-0.286,7.379c-1.215,-2.236,-1.928,-4.711,-2.09,-7.25l-1.885,-44.181c-0.23,-4.211,-2.893,-7.901,-6.817,-9.446c-0.096,-0.035,-0.192,-0.066,-0.289,-0.095c-2.794,-0.772,-5.699,-1.069,-8.593,-0.875l-20.617,0.822l-7.492,-21.533c-0.92,-2.018,-1.612,-4.132,-2.061,-6.303c-1.624,-5.704,-3.636,-11.289,-6.022,-16.717c-1.808,-3.135,-4.808,-5.405,-8.316,-6.292c-0.822,-0.246,-1.416,-0.96,-1.509,-1.813c-0.093,-0.852,0.334,-1.678,1.083,-2.094c1.874,-0.731,3.597,-1.799,5.085,-3.15c0.33,-0.312,0.615,-0.667,0.85,-1.055c0.919,-1.559,1.444,-3.318,1.528,-5.125c0.371,-2.638,0.262,-5.32,-0.319,-7.92c-0.134,-0.846,-0.264,-1.693,-0.392,-2.539c-0.213,-3.338,-0.887,-6.63,-2.001,-9.783c-0.162,-0.371,-0.354,-0.729,-0.572,-1.071c-1.706,-2.547,-4.245,-4.423,-7.18,-5.308c-7.092,-2.241,-14.734,1.212,-17.74,8.015l0.022,-9.446c-0.981,-9.752,5.655,-18.636,15.286,-20.461l30.018,-2.045l0,-3.588l-0.358,-23.841l1.088,-2.568l156.787,-25.06l0,-4.785l-157.272,25.138l-0.175,-1.698c-2.258,0.321,-4.462,0.945,-6.553,1.856l0.068,0.852l-112.144,18.437l0,4.789z", "fill": "#111"}, + {"path": "M76.569,110.94c1.548,3.721,3.835,7.089,6.724,9.9c0.303,0.238,0.5,0.586,0.547,0.969c0,0.025,0,0.052,-0.002,0.077c-0.041,0.266,-0.191,0.503,-0.413,0.654c-0.234,0.109,-0.495,0.152,-0.751,0.123c-0.145,-0.027,-0.286,-0.064,-0.424,-0.112c-1.85,-0.535,-3.791,-0.679,-5.699,-0.426l0.026,-11.165l-0.008,-0.02z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h19.json b/res/symbol/h19.json new file mode 100644 index 0000000..f8f4690 --- /dev/null +++ b/res/symbol/h19.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M252.178,200.08c5.133,-4.966,9.658,-10.521,13.484,-16.551c-0.671,4.793,-1.78,9.515,-3.314,14.105c-1.102,2.939,-2.744,5.645,-4.845,7.977c-2.159,1.607,-4.56,2.861,-7.112,3.715l-144.047,58.392l-17.246,0.173l62.804,-25.51c-0.726,-2.179,-1.488,-4.345,-2.287,-6.498l-79.231,32.156l-14.29,-0.056l72.14,-29.275c-3.253,-7.944,-6.585,-15.856,-9.995,-23.735c-2.498,-5.49,-5.323,-10.828,-8.458,-15.981c-6.554,-10.433,-13.34,-20.718,-20.352,-30.849c-2.72,-0.722,-5.388,-1.623,-7.988,-2.698c-1.869,-0.639,-3.041,-2.494,-2.816,-4.456c23.175,7.565,48.297,6.544,70.782,-2.875l-2.536,-12.174c-12.615,5.359,-26.235,7.939,-39.937,7.568l55.238,-53.1l0.962,-0.918l-1.038,0.839l-41.096,32.177l-24.66,20.125c-7.457,-1.039,-14.764,-2.955,-21.772,-5.709l-34.455,70.723l5.588,5.594l-2.34,2.337l-4.78,-4.786l-7.393,15.176l-3.823,-1.862l8.037,-16.498l-4.806,-4.811l2.34,-2.337l3.998,4.003l27.958,-57.385l-39.695,56.524l5.095,5.045l-2.327,2.351l-4.696,-4.65l-9.1,12.958l-3.48,-2.444l9.516,-13.549l-5.396,-5.343l2.327,-2.35l4.996,4.947l50.305,-71.631c-3.206,-9.879,-6.029,-19.878,-8.464,-29.975c-0.506,1.739,-0.573,3.577,-0.194,5.348c1.332,7.49,3.238,14.865,5.7,22.062c0.208,0.506,0.335,1.042,0.374,1.588c-0.017,1.205,-0.688,2.305,-1.752,2.872c-0.634,0.232,-1.32,0.29,-1.984,0.165c-3.495,-0.768,-6.86,-2.04,-9.988,-3.776c-3.618,-1.603,-5.617,-5.521,-4.791,-9.391c0.334,-8.456,1.467,-16.862,3.383,-25.105c0.8,-4.457,2.407,-8.731,4.744,-12.611c1.08,-1.819,2.742,-3.222,4.716,-3.983c1.872,-0.756,3.626,-1.776,5.208,-3.029c0.697,-0.463,1.135,-1.229,1.181,-2.065c0.045,-0.836,-0.307,-1.645,-0.95,-2.181c-2.924,-3.343,-5.946,-6.599,-9.062,-9.763c-1.53,-1.695,-2.636,-3.728,-3.228,-5.933c-1.233,-5.188,-0.91,-10.624,0.927,-15.63c1.204,-2.609,3.355,-4.661,6.017,-5.742c6.195,-2.48,13.148,-2.242,19.16,0.656c2.525,1.629,4.448,4.037,5.478,6.859c1.472,3.906,2.6,7.933,3.374,12.035c0.686,4.525,-1.445,9.014,-5.384,11.343c-1.511,0.557,-2.689,1.766,-3.208,3.29c-0.565,1.832,0.38,3.789,2.165,4.487c9.643,4.162,19.971,6.513,30.465,6.938c12.519,1.179,25.081,1.859,37.655,2.038c5.418,-0.192,10.837,-0.303,16.259,-0.333c1.153,-0.852,2.444,-1.499,3.817,-1.912l95.521,-84.089l6.435,0l-96.007,84.518c1.041,1.35,1.072,3.223,0.076,4.606c-0.713,0.841,-1.572,1.545,-2.537,2.078c-1.344,0.806,-2.85,1.307,-4.408,1.468l-47.871,46.019c1.019,1.949,2.094,3.868,3.224,5.755c7.496,-1.408,14.744,-3.912,21.512,-7.428l4.164,19.986c-5.351,2.268,-10.801,4.296,-16.334,6.078c5.094,9.105,9.523,18.566,13.252,28.309c3.714,10.165,7.1,20.448,10.15,30.831l66.063,-26.808c2.482,-1.045,4.67,-2.684,6.369,-4.774c2.514,-2.909,4.758,-6.041,6.705,-9.356c0.074,3.909,-0.433,7.807,-1.504,11.567c-0.517,2.173,-1.965,4.007,-3.959,5.014c-1.482,0.781,-2.998,1.499,-4.543,2.15l-67.622,27.446c0.627,2.221,1.24,4.447,1.835,6.677l76.479,-31.066c3.914,-1.627,7.644,-3.667,11.123,-6.087z", "fill": "#111"}, + {"path": "M138.41,234.551l9.256,-3.728c-2.373,-5.924,-5.015,-11.736,-7.92,-17.417c-3.033,-7.361,-6.996,-14.304,-11.792,-20.658c-2.263,-2.842,-5.019,-5.254,-8.135,-7.12c6.947,16.013,13.151,32.337,18.591,48.923zM110.137,113.69c-1.451,-2.723,-2.58,-5.605,-3.364,-8.589c5.502,0.117,11.005,-0.162,16.466,-0.837c11.725,-1.551,23.372,-3.635,34.907,-6.244l-39.768,31.138c-2.873,-5.088,-5.622,-10.245,-8.241,-15.468z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h2.json b/res/symbol/h2.json new file mode 100644 index 0000000..73a3da6 --- /dev/null +++ b/res/symbol/h2.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M121.469,19.844c2.524,-0.894,4.896,-2.169,7.035,-3.78l45.827,0l0.472,0l0,31.654l-0.472,0l-18.425,0l0,16.535l18.425,0l0.472,0l0,25.984l-0.472,0l-18.425,0l0,35.906l10.393,0l0,142.205l-49.133,0l0,-142.205l10.393,0l0,-35.906l-49.133,0l0,-25.984l49.133,0l0,-16.535l-49.133,0l0,-19.842c14.701,-0.196,29.26,-2.912,43.043,-8.032z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h20.json b/res/symbol/h20.json new file mode 100644 index 0000000..2661730 --- /dev/null +++ b/res/symbol/h20.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M151.152,55.474c0.81,-0.601,1.454,-1.396,1.873,-2.313c0.203,-0.462,0.319,-0.958,0.342,-1.462c-0.047,-1.047,-0.123,-2.092,-0.228,-3.134c-0.499,-3.188,-1.495,-6.276,-2.952,-9.153c-1.043,-1.964,-2.294,-3.809,-3.735,-5.503c-0.356,-0.369,-0.725,-0.725,-1.106,-1.069c-0.568,-0.443,-1.169,-0.844,-1.797,-1.199c-0.497,-0.201,-0.993,-0.405,-1.487,-0.611c-1.745,-0.578,-3.564,-0.897,-5.401,-0.949c-2.775,0.064,-5.474,0.915,-7.785,2.453c-1.898,1.442,-3.33,3.41,-4.119,5.659c-0.48,1.255,-0.864,2.544,-1.147,3.858c-0.123,0.6,-0.223,1.205,-0.3,1.814c-0.096,0.721,-0.162,1.446,-0.197,2.173c-0.063,2.42,0.331,4.831,1.162,7.106c1.335,3.268,2.914,6.43,4.725,9.46c0.898,2.005,2.052,3.885,3.434,5.593c0.73,0.788,1.815,1.143,2.869,0.937c0.878,-0.467,1.696,-1.038,2.437,-1.702c2.691,-2.364,5.347,-4.768,7.968,-7.211c1.821,-1.56,3.628,-3.138,5.42,-4.733c0.007,-0.006,0.016,-0.011,0.024,-0.014zM129.805,15.086c-1.321,-0.499,-2.653,-0.967,-3.996,-1.404c-1.659,-0.476,-3.445,-0.029,-4.683,1.172c-1.704,1.859,-3.5,3.631,-5.38,5.311c-0.284,0.305,-0.445,0.706,-0.448,1.124c0.013,0.411,0.166,0.806,0.435,1.119c0.904,1.217,2.372,1.881,3.884,1.755c1.125,-0.007,2.25,0.023,3.374,0.088c2.264,0.141,4.524,0.336,6.778,0.585c2.674,0.413,5.344,0.852,8.009,1.316c2.219,0.401,4.405,0.965,6.542,1.688c1.398,0.377,2.808,0.714,4.227,1.008c0.815,0.227,1.681,0.19,2.475,-0.106c0.536,-0.159,1.007,-0.492,1.338,-0.946c0.148,-0.242,0.205,-0.53,0.158,-0.811c-0.016,-0.064,-0.035,-0.128,-0.057,-0.19c-0.141,-0.366,-0.34,-0.706,-0.586,-1.01c-0.334,-0.367,-0.738,-0.66,-1.19,-0.865c-2.029,-0.765,-4.002,-1.672,-5.903,-2.715c-2.154,-1.013,-4.287,-2.068,-6.399,-3.164c-2.764,-1.517,-5.63,-2.838,-8.578,-3.955zM94.451,173.744c-0.237,-0.328,-0.533,-0.607,-0.873,-0.826c-2.944,-2.691,-5.87,-5.402,-8.779,-8.132c-1.884,-1.587,-3.138,-3.797,-3.535,-6.229c-0.333,-2.934,-0.258,-5.9,0.222,-8.814c0.299,-1.52,0.684,-3.021,1.152,-4.497l28.393,-91.016c0.532,-1.581,1.181,-3.122,1.939,-4.609c0.708,-1.076,1.575,-2.038,2.569,-2.857c1.233,-0.836,2.083,-2.129,2.36,-3.594c0.441,-1.963,1.107,-3.87,1.987,-5.681c0.777,-1.846,2.052,-3.439,3.684,-4.6c0.904,-0.665,1.849,-1.273,2.829,-1.819c0.154,-0.087,0.3,-0.186,0.439,-0.296c0.032,-0.028,0.062,-0.059,0.089,-0.093c0.059,-0.079,0.106,-0.165,0.141,-0.256c0.009,-0.024,0.015,-0.048,0.02,-0.073c0.021,-0.148,0.003,-0.297,-0.053,-0.435c-0.099,-0.19,-0.269,-0.333,-0.472,-0.398c-0.909,-0.239,-1.813,-0.493,-2.713,-0.761c-1.043,-0.292,-2.121,-0.433,-3.203,-0.422c-1.738,-0.007,-3.473,0.133,-5.188,0.42c-0.751,0.152,-1.479,0.403,-2.164,0.748c-0.5,0.273,-0.967,0.602,-1.394,0.98c-1.83,1.518,-3.267,3.455,-4.189,5.647c-0.271,0.802,-0.518,1.612,-0.74,2.43c-0.484,1.875,-0.935,3.759,-1.352,5.651c-0.281,1.595,-0.252,3.23,0.086,4.814c0.076,0.201,0.141,0.407,0.195,0.616c0.129,0.976,0.032,1.967,-0.282,2.899l-28.263,90.6c-0.495,1.653,-0.973,3.311,-1.432,4.974c-0.326,1.189,-0.605,2.39,-0.836,3.601c-0.438,2.095,-0.798,4.206,-1.082,6.328c-0.343,2.108,-0.346,4.258,-0.008,6.367c0.347,1.916,0.951,3.775,1.797,5.529c0.816,1.613,1.883,3.087,3.162,4.366c1.434,1.645,3.033,3.139,4.772,4.46c1.154,0.672,2.416,1.141,3.731,1.385c0.97,0.187,1.972,0.129,2.915,-0.168c0.657,-0.256,1.286,-0.583,1.873,-0.975c0.994,-0.605,1.803,-1.471,2.336,-2.505c0.413,-0.886,0.363,-1.918,-0.133,-2.759zM197.097,234.044c0.529,-4.192,0.959,-8.399,1.288,-12.611c0.219,-3.031,0.465,-6.058,0.742,-9.083c0.939,-15.894,1.302,-31.818,1.085,-47.738c0.025,-10.444,-1.233,-20.851,-3.746,-30.988c-0.438,-1.509,-0.922,-3.004,-1.451,-4.483c-1.6,-5.143,-3.258,-10.267,-4.977,-15.372c-1.975,-5.261,-4.389,-10.347,-7.216,-15.204c-1.413,-2.703,-2.848,-5.394,-4.309,-8.072c-0.306,-0.636,-0.561,-1.295,-0.762,-1.972c-0.478,-1.454,-0.757,-2.967,-0.825,-4.496c-0.04,-0.821,0.004,-1.642,0.131,-2.454c0.318,-1.673,0.612,-3.35,0.884,-5.031l1.237,-7.688c0.131,-0.817,0.212,-1.641,0.241,-2.468c0.027,-0.75,0.051,-1.5,0.067,-2.25c-0.024,-0.428,-0.037,-0.857,-0.044,-1.286c-0.035,-1.001,-0.738,-1.853,-1.713,-2.08c-0.459,-0.08,-0.933,-0.01,-1.349,0.201c-0.439,0.334,-0.817,0.739,-1.121,1.2l-18.502,24.679c-0.039,0.053,-0.078,0.106,-0.116,0.16c-0.105,0.152,-0.239,0.283,-0.392,0.385c-0.012,0.008,-0.024,0.015,-0.035,0.022c-0.289,0.144,-0.628,0.148,-0.92,0.009c-0.058,-0.031,-0.112,-0.073,-0.154,-0.122c-0.174,-0.203,-0.264,-0.465,-0.251,-0.732c0.036,-0.247,0.134,-0.482,0.284,-0.681l21.031,-29.633c2.19,-2.612,3.464,-5.869,3.627,-9.273c-0.17,-1.395,-0.58,-2.75,-1.213,-4.006c-1.396,-2.643,-3.791,-4.619,-6.65,-5.488c-1.548,-0.479,-3.098,-0.948,-4.652,-1.407c-3.265,-0.83,-6.479,-1.852,-9.624,-3.062c-2.156,-0.788,-4.361,-1.441,-6.599,-1.955c-0.178,-0.061,-0.369,-0.066,-0.551,-0.015c-0.207,0.056,-0.331,0.268,-0.277,0.476c0.031,0.185,0.092,0.363,0.184,0.527c0.087,0.197,0.175,0.392,0.265,0.588c0.148,0.348,0.293,0.697,0.434,1.048c1.355,2.829,2.543,5.736,3.554,8.706c0.424,1.21,0.721,2.461,0.887,3.734c0.076,0.568,0.439,1.058,0.96,1.298c0.077,0.035,0.157,0.066,0.237,0.094c0.002,0.001,0.004,0.001,0.007,0.001c0.503,0.216,1.007,0.431,1.513,0.644c0.236,0.086,0.47,0.176,0.703,0.272c0.297,0.091,0.537,0.31,0.655,0.597c0.118,0.286,0.104,0.61,-0.041,0.885c-0.03,0.061,-0.064,0.12,-0.1,0.177c-0.561,1.037,-1.198,2.032,-1.905,2.975c-1.268,1.678,-2.707,3.219,-4.294,4.598c-2.68,2.611,-5.452,5.13,-8.305,7.551c-1.637,1.249,-3.222,2.563,-4.755,3.938c-3.076,2.602,-5.92,5.467,-8.501,8.562c-1.035,1.106,-1.907,2.353,-2.59,3.705c-0.866,1.701,-1.365,3.565,-1.462,5.471c0.013,0.985,0.119,1.967,0.314,2.933c0.304,1.278,0.696,2.533,1.175,3.756c0.495,1.158,1.037,2.294,1.627,3.407c1.351,2.441,2.807,4.822,4.363,7.139c6.222,8.349,12.325,16.787,18.305,25.311c0.467,0.614,0.818,1.306,1.037,2.044c0.25,1.017,0.199,2.084,-0.146,3.072c-0.125,0.326,-0.282,0.638,-0.471,0.932c-0.656,0.977,-1.281,1.974,-1.873,2.992c-0.613,0.998,-1.092,2.074,-1.424,3.199c-0.158,0.524,-0.287,1.055,-0.386,1.593c-0.342,1.652,-0.459,3.343,-0.346,5.026c0.046,4.918,0.251,9.832,0.611,14.737c0.611,9.62,1.268,19.236,1.969,28.85c0.141,1.732,-0.017,3.475,-0.463,5.154c-0.363,1.814,-1.228,3.49,-2.496,4.838c-0.805,0.946,-1.655,1.853,-2.549,2.716c-1.28,1.356,-2.618,2.656,-4.01,3.896c-4.651,3.983,-9.149,8.143,-13.485,12.467c-3.307,3.085,-6.691,6.085,-10.15,8.997c-4.069,3.603,-8.293,7.027,-12.66,10.261c-3.344,2.296,-6.669,4.618,-9.975,6.967c-0.459,0.293,-0.909,0.599,-1.351,0.918c-0.158,0.119,-0.31,0.245,-0.456,0.379c-0.094,0.092,-0.183,0.189,-0.269,0.289c-0.455,0.563,-0.757,1.232,-0.879,1.944c-0.029,0.789,0.061,1.577,0.267,2.339c0.871,3.358,2.112,6.611,3.7,9.696c1.332,2.458,2.629,4.934,3.892,7.428c0.777,1.357,1.741,2.599,2.863,3.689c0.878,0.9,2.043,1.465,3.294,1.597c1.142,0.121,2.297,0.056,3.418,-0.192c0.707,-0.169,1.216,-0.787,1.247,-1.512c0,-0.046,-0.001,-0.091,-0.006,-0.137c-0.271,-1.528,-0.522,-3.059,-0.754,-4.593c-0.438,-2.794,-0.485,-5.634,-0.14,-8.441c0.125,-1.57,0.371,-3.129,0.733,-4.661c0.443,-0.666,1.254,-0.984,2.031,-0.798c4.148,2.147,8.333,4.22,12.556,6.215c1.221,0.649,2.729,0.362,3.626,-0.69c1.429,-1.442,2.786,-2.954,4.066,-4.53c7.511,-8.424,14.846,-17.005,21.998,-25.736c4.016,-4.954,7.92,-9.999,11.711,-15.129c1.229,-1.401,2.229,-2.985,2.965,-4.696c1.046,-2.202,1.766,-4.545,2.137,-6.954c0.79,-3.259,1.542,-6.527,2.256,-9.804c0.345,-1.74,0.65,-3.487,0.915,-5.24c0.14,-0.762,0.5,-1.465,1.038,-2.023c0.117,-0.119,0.285,-0.173,0.45,-0.143c0.071,0.018,0.136,0.059,0.183,0.117c0.128,0.151,0.199,0.342,0.203,0.54c0.219,2.645,0.294,5.3,0.222,7.954c-0.095,4.88,-0.584,9.744,-1.464,14.546c-1.356,6.468,-2.564,12.968,-3.623,19.493c-0.676,5.954,-1.742,11.857,-3.191,17.672c-1.123,5.295,-2.5,10.534,-4.13,15.697c-1.162,3.684,-2.339,7.362,-3.533,11.035c-0.078,0.249,-0.128,0.506,-0.15,0.766c0.017,0.7,0.258,1.377,0.688,1.93c0.074,0.08,0.163,0.143,0.263,0.185c1.348,0.475,2.752,0.771,4.177,0.883c2.135,-0.042,4.241,-0.515,6.19,-1.392c0.046,-0.02,0.092,-0.043,0.136,-0.066c5.163,-2.852,10.378,-5.611,15.64,-8.276c1.675,-0.804,2.848,-2.381,3.135,-4.217c0.022,-0.328,0.047,-0.654,0.075,-0.981c1.506,-9.401,2.936,-18.815,4.29,-28.241z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h21.json b/res/symbol/h21.json new file mode 100644 index 0000000..52534ea --- /dev/null +++ b/res/symbol/h21.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M185.624,230.492c3.383,-1.439,6.67,-3.099,9.837,-4.968c2.695,0.072,5.391,-0.054,8.068,-0.376c6.295,-0.682,12.57,-1.53,18.82,-2.542c-6.551,4.668,-12.847,9.683,-18.861,15.026c-5.129,4.461,-9.986,9.225,-14.544,14.268c-1.114,-0.212,-2.201,-0.551,-3.239,-1.009c-4.032,-1.779,-7.922,-3.859,-11.639,-6.224c-3.408,-1.951,-6.514,-4.389,-9.218,-7.236c2.021,-0.719,4.07,-1.354,6.142,-1.905c4.992,-1.326,9.883,-3.007,14.634,-5.034zM204.198,214.55c-18.803,10.91,-39.516,18.132,-61.027,21.275l-14.904,1.367l-15.33,0.791l-16.238,-0.108c4.214,-2.59,8.074,-5.716,11.482,-9.301l3.367,-3.958c2.758,-3.376,4.945,-7.181,6.474,-11.264c0.802,-2.46,1.428,-4.975,1.872,-7.524l0.99,-5.984l16.229,-1.811l12.576,-1.61l8.528,-1.338c4.868,-0.91,9.668,-2.144,14.371,-3.692l15.733,-5.632l12.135,-5.247l12.173,-6.138l11.61,-6.289l9.027,-6.291l11.603,-10.705l8.592,-11.762l-0.585,4.432c-2.362,14.646,-7.729,28.644,-15.764,41.115c-5.249,8.365,-12.11,15.604,-20.182,21.292l-4.181,2.925l-8.551,5.457zM234.396,73.508c-3.484,-2.635,-7.264,-4.857,-11.263,-6.618l-66.77,-27.776l-1.056,-0.468c-0.454,-0.284,-1.049,-0.183,-1.386,0.234c-0.272,0.273,-0.423,0.644,-0.419,1.031c0.004,0.385,0.165,0.753,0.443,1.02l18.606,24.05l3.992,5.652c0.918,1.725,1.451,3.629,1.562,5.579c0.051,1.98,-0.245,3.954,-0.875,5.831l-2.083,4.128l-1.878,2.746c3.685,-0.637,7.373,-1.247,11.067,-1.829c5.485,-1.084,11.048,-1.737,16.636,-1.954c4.321,-0.246,8.649,-0.365,12.977,-0.356c3.725,0.057,7.445,0.299,11.147,0.724c2.316,0.269,4.609,0.701,6.863,1.294c1.732,0.604,3.38,1.426,4.906,2.446c2.365,1.602,4.215,3.858,5.32,6.492c1.047,2.08,1.617,4.366,1.668,6.693c0.849,-2.33,1.221,-4.807,1.094,-7.284c-0.11,-2.769,-0.533,-5.517,-1.265,-8.19c-1.073,-2.921,-2.497,-5.7,-4.243,-8.275c-1.477,-1.772,-3.081,-3.433,-4.801,-4.97c-0.078,-0.07,-0.158,-0.136,-0.242,-0.2zM243.819,143.676c4.472,-5.424,7.759,-11.725,9.647,-18.497c0.832,-3.185,1.457,-6.421,1.874,-9.686c0.353,-2.748,0.292,-5.534,-0.179,-8.266c-0.463,-2.92,-1.252,-5.779,-2.354,-8.523c-0.716,-1.786,-1.598,-3.501,-2.634,-5.123c0.039,1.218,0.083,2.436,0.131,3.653c-0.135,3.098,-0.547,6.178,-1.227,9.204c-0.736,2.73,-1.824,5.353,-3.237,7.802c-1.001,1.924,-2.244,3.713,-3.699,5.321c-1.944,2.279,-4.151,4.321,-6.573,6.083c-2.299,1.791,-4.689,3.464,-7.158,5.013c-2.672,1.676,-5.489,3.11,-8.416,4.285c-2.351,1.08,-4.798,1.936,-7.309,2.559c-3.014,0.912,-6.111,1.522,-9.246,1.821c-2.27,0.262,-4.557,0.362,-6.84,0.3c-0.573,-0.059,-1.045,-0.477,-1.172,-1.038c-0.045,-0.438,0.061,-0.878,0.301,-1.247c0.483,-0.626,0.968,-1.251,1.456,-1.873l12.29,-14.862l-45.026,3.666c-3.601,0.419,-7.244,0.331,-10.821,-0.26c-2.897,-0.454,-5.726,-1.27,-8.419,-2.43c-3.61,-1.727,-7.188,-3.522,-10.732,-5.381l-13.622,37.546c-4.407,1.092,-8.777,2.331,-13.102,3.715c-3.365,1.185,-6.73,2.367,-10.098,3.545c-3.439,1.227,-6.792,2.679,-10.038,4.349c-6.561,3.16,-12.906,6.753,-18.992,10.752c-3.365,2.283,-6.684,4.631,-9.957,7.045c-2.534,2.003,-5.054,4.023,-7.561,6.058l48.975,-173.516l-4.28,-1.137l-50.79,180.678c-3.611,3.48,-6.825,7.351,-9.581,11.542c1.255,0.309,2.506,0.631,3.755,0.964c0.588,0.158,1.172,0.326,1.754,0.505c1.915,0.591,3.829,1.187,5.742,1.787c0.583,0.183,1.165,0.37,1.745,0.562c1.453,0.48,2.889,1.012,4.305,1.594c3.302,1.357,6.584,2.765,9.843,4.222c1.367,0.612,2.71,1.274,4.028,1.986c0.629,0.339,1.231,0.728,1.799,1.162c0.087,0.066,0.161,0.146,0.22,0.239c0.101,0.129,0.19,0.267,0.266,0.412c0.137,0.289,0.145,0.623,0.022,0.918c-0.123,0.296,-0.365,0.525,-0.667,0.632c-2.282,0.496,-4.587,0.879,-6.907,1.146c-3.445,0.566,-6.871,1.236,-10.275,2.009c-3.323,0.815,-6.609,1.776,-9.847,2.882c-2.345,0.733,-4.669,1.529,-6.972,2.388c-2.003,0.656,-3.993,1.346,-5.971,2.073c-0.338,0.046,-0.619,0.284,-0.717,0.61c0.012,0.182,0.105,0.348,0.253,0.453c0.148,0.107,0.336,0.141,0.511,0.094l49.843,3.591c1.467,0.109,2.94,0.074,4.4,-0.105c3.099,-0.307,6.129,-1.107,8.975,-2.37c3.581,-1.673,6.886,-3.881,9.802,-6.548c2.656,-2.465,5.037,-5.21,7.1,-8.188c1.752,-2.752,3.177,-5.698,4.248,-8.78c1.083,-2.919,1.853,-5.944,2.299,-9.025c0.331,-2.47,0.503,-4.959,0.516,-7.451c12.018,-1.044,24.003,-2.422,35.945,-4.131c18.75,-3.254,36.861,-9.473,53.652,-18.427c4.563,-2.309,9.055,-4.754,13.47,-7.334c3.477,-1.824,6.804,-3.925,9.944,-6.282c2.536,-2.085,5.029,-4.222,7.475,-6.411c2.788,-2.586,5.404,-5.35,7.833,-8.275z", "fill": "#111"}, + {"path": "M71.645,194.339c0,-3.561,-2.886,-6.447,-6.447,-6.447c-3.561,0,-6.447,2.886,-6.447,6.447c0,3.56,2.886,6.447,6.447,6.447c3.561,0,6.447,-2.887,6.447,-6.447z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h22.json b/res/symbol/h22.json new file mode 100644 index 0000000..1a82216 --- /dev/null +++ b/res/symbol/h22.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M215.905,120.946l-25.039,0l0,41.574l25.039,0c29.484,0,53.385,23.902,53.385,53.386c0,29.485,-23.901,53.385,-53.385,53.385c-29.484,0,-53.386,-23.9,-53.386,-53.385l0,-25.039l-41.575,0l0,25.039c0,29.485,-23.902,53.385,-53.386,53.385c-29.484,0,-53.385,-23.9,-53.385,-53.385c0,-29.484,23.901,-53.386,53.385,-53.386l25.04,0l0,-41.574l-25.04,0c-29.484,0,-53.385,-23.902,-53.385,-53.387c0,-29.483,23.901,-53.385,53.385,-53.385c29.484,0,53.386,23.902,53.386,53.385l0,25.04l41.575,0l0,-25.04c0,-29.483,23.902,-53.385,53.386,-53.385c29.484,0,53.385,23.902,53.385,53.385c0,29.485,-23.901,53.387,-53.385,53.387z", "fill": "#111"}, + {"path": "M190.867,92.599l0,-25.04c0,-13.828,11.211,-25.039,25.039,-25.039c13.829,0,25.039,11.211,25.039,25.039c0,13.83,-11.21,25.04,-25.039,25.04l-25.039,0zM190.867,215.906c0,13.828,11.211,25.039,25.039,25.039c13.829,0,25.039,-11.211,25.039,-25.039c0,-13.828,-11.21,-25.039,-25.039,-25.039l-25.039,0l0,25.039zM92.598,215.906l0,-25.039l-25.04,0c-10.127,0,-19.257,6.1,-23.133,15.457c-3.876,9.356,-1.733,20.127,5.428,27.287c7.161,7.163,17.931,9.305,27.288,5.428c9.356,-3.875,15.457,-13.006,15.457,-23.133zM92.599,67.559c0,-13.828,-11.211,-25.039,-25.04,-25.039c-13.828,0,-25.039,11.211,-25.039,25.039c0,13.83,11.211,25.04,25.039,25.04l25.04,0l0,-25.04zM120.945,162.52l0,-41.574l41.575,0l0,41.574l-41.575,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h24.json b/res/symbol/h24.json new file mode 100644 index 0000000..3541951 --- /dev/null +++ b/res/symbol/h24.json @@ -0,0 +1,10 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M25.684,25.512l33.515,0c9.468,0,18.09,5.45,22.152,14.002c4.062,8.551,2.838,18.678,-3.143,26.016c7.88,7.221,10.519,18.538,6.645,28.499c-3.874,9.961,-13.465,16.523,-24.153,16.523l-35.016,0l0,-50.024l0,-35.016zM177.459,110.552l-15.383,-19.995c3.545,-7.645,6.377,-15.598,8.465,-23.76l-14.092,-5.221c-1.268,5.233,-2.879,10.375,-4.822,15.396l-10.143,-13.184c2.307,-2.004,4.475,-4.163,6.49,-6.461c6.154,-8.318,5.639,-19.812,-1.238,-27.546c-3.69,-3.122,-8.399,-4.777,-13.231,-4.649c-7.779,-0.044,-14.824,4.585,-17.87,11.742c-1.145,3.593,-1.534,7.383,-1.146,11.133c1.148,4.412,3.011,8.605,5.514,12.414l-0.06,0.038c-12.253,7.024,-17.756,21.786,-13.094,35.118c0.036,0.094,0.074,0.188,0.116,0.28c3.354,8.105,10.749,13.829,19.439,15.043c9.5,1.043,19.014,-1.839,26.338,-7.979l5.871,7.631l18.846,0zM200.252,25.512l33.516,0c9.467,0,18.09,5.45,22.152,14.002c4.061,8.551,2.838,18.678,-3.144,26.016c7.881,7.221,10.519,18.538,6.644,28.499c-3.873,9.961,-13.464,16.523,-24.152,16.523l-35.016,0l0,-50.024l0,-35.016z", "fill": "#111"}, + {"path": "M41.191,59.027l18.009,0c4.973,0,9.004,-4.031,9.004,-9.003c0,-4.973,-4.031,-9.004,-9.004,-9.004l-18.009,0l0,18.007zM60.701,95.044c4.956,-0.005,9.221,-3.506,10.194,-8.366c0.971,-4.861,-1.62,-9.732,-6.193,-11.643c-1.477,-0.332,-2.987,-0.5,-4.502,-0.5l-19.009,0l0,20.509l19.51,0zM130.762,96.165c4.754,-0.127,9.309,-1.934,12.858,-5.101l-14.442,-18.774l-1.564,0.992c-6.047,3.315,-8.893,10.453,-6.781,17.018c1.656,3.815,5.539,6.17,9.687,5.877l0.242,-0.012zM134.629,51.464c1.868,-1.568,3.411,-3.487,4.541,-5.649c0.35,-1.604,0.248,-3.274,-0.293,-4.824c-0.916,-1.39,-2.269,-2.436,-3.845,-2.971c-1.893,-0.66,-3.994,-0.23,-5.477,1.119c-1.117,0.879,-1.828,2.175,-1.965,3.59c-0.343,1.693,-0.084,3.454,0.735,4.977c0.99,2.006,2.332,3.82,3.957,5.359c0.787,-0.527,1.57,-1.06,2.347,-1.601zM215.761,59.027l18.008,0c4.973,0,9.004,-4.031,9.004,-9.003c0,-4.973,-4.031,-9.004,-9.004,-9.004l-18.008,0l0,18.007zM235.268,95.044c4.957,-0.005,9.223,-3.506,10.193,-8.366c0.973,-4.861,-1.617,-9.732,-6.191,-11.643c-1.477,-0.332,-2.986,-0.5,-4.502,-0.5l-19.008,0l0,20.509l19.508,0z", "fill": "#fff"}, + {"path": "M17.007,173.73l0,92.727l19.216,0l0,-19.039l211.018,0l0,19.039l19.215,0l0,-118.201c0,-5.289,-4.276,-9.584,-9.565,-9.608c-5.289,-0.025,-9.603,4.231,-9.65,9.52l0,37.373c-3.524,19.644,-19.709,34.53,-39.578,36.403l-171.44,0l0,-48.214c0,-5.307,-4.302,-9.608,-9.608,-9.608c-5.306,0,-9.608,4.301,-9.608,9.608zM236.295,177.412c-4.562,-5.776,-16.96,-3.588,-27.689,4.888c-10.73,8.476,-15.73,20.03,-11.168,25.806c4.563,5.776,16.961,3.587,27.691,-4.888c10.729,-8.476,15.729,-20.029,11.166,-25.806zM181.573,212.512c2.627,0.086,5.154,-1.015,6.881,-2.997c1.726,-1.983,2.468,-4.637,2.021,-7.228c-0.877,-5.084,-4.209,-9.405,-8.902,-11.547c-40.832,-13.926,-85.129,-13.926,-125.959,0c-5.017,1.712,-8.523,6.259,-8.902,11.547c-0.182,2.538,0.655,5.044,2.326,6.963c1.671,1.919,4.037,3.093,6.576,3.262l125.959,0z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h25.json b/res/symbol/h25.json new file mode 100644 index 0000000..ff9a93c --- /dev/null +++ b/res/symbol/h25.json @@ -0,0 +1,15 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M34.015,30.236l0,9.143l102.284,38.751l72.615,0c11.817,0,22.954,5.527,30.101,14.939c3.068,4.041,8.674,5.149,13.049,2.579c4.376,-2.571,6.137,-8.007,4.101,-12.655c-0.812,-1.856,-0.573,-4.004,0.626,-5.635c1.201,-1.631,3.181,-2.499,5.193,-2.275c2.013,0.224,3.754,1.504,4.567,3.359c3.264,7.452,2.012,16.111,-3.231,22.332c-5.243,6.22,-13.565,8.921,-21.462,6.966l-13.311,31.583c3.756,2.173,7.392,4.545,10.894,7.106c3.916,2.865,7.559,6.087,10.881,9.624c3.432,3.653,6.517,7.616,9.216,11.84c5.651,8.842,8.704,19.095,8.808,29.588c-0.104,10.493,-3.157,20.745,-8.808,29.587c-2.699,4.224,-5.784,8.187,-9.216,11.841c-3.322,3.536,-6.965,6.758,-10.881,9.623c-3.655,2.673,-7.456,5.14,-11.385,7.389c-3.737,2.139,-7.61,4.03,-11.594,5.66c-3.694,1.51,-7.444,2.885,-11.24,4.121c-3.643,1.185,-7.346,2.177,-11.093,2.972c-3.531,0.75,-7.083,1.402,-10.65,1.954c-3.512,0.543,-7.049,0.922,-10.597,1.134c-3.45,0.206,-6.906,0.327,-10.362,0.365c-3.457,-0.038,-6.913,-0.159,-10.364,-0.365c-3.548,-0.212,-7.084,-0.591,-10.596,-1.134c-3.568,-0.552,-7.119,-1.204,-10.65,-1.954c-3.748,-0.795,-7.45,-1.787,-11.094,-2.972c-3.795,-1.236,-7.544,-2.611,-11.239,-4.121c-3.985,-1.63,-7.858,-3.521,-11.595,-5.66c-3.929,-2.249,-7.73,-4.716,-11.385,-7.389c-3.916,-2.865,-7.559,-6.087,-10.881,-9.623c-3.431,-3.654,-6.517,-7.617,-9.216,-11.841c-5.651,-8.842,-8.704,-19.094,-8.808,-29.587c0.104,-10.493,3.157,-20.746,8.808,-29.588c2.699,-4.224,5.785,-8.187,9.216,-11.84c3.322,-3.537,6.965,-6.759,10.881,-9.624c3.502,-2.561,7.139,-4.933,10.894,-7.106l-13.047,-30.957l-49.429,0l0,144.862c0,4.01,-1.593,7.856,-4.428,10.691c-2.835,2.834,-6.681,4.427,-10.69,4.427l-3.78,0l0,-253.228l3.78,0c4.009,0,7.855,1.593,10.69,4.428c2.835,2.835,4.428,6.681,4.428,10.69z", "fill": "#111"}, + {"path": "M101.698,163.382c-3.131,-3.591,-7.685,-5.625,-12.45,-5.557c-4.231,-0.019,-8.271,1.759,-11.116,4.89c-3.465,4.016,-5.36,9.149,-5.336,14.452c-0.024,5.303,1.871,10.436,5.336,14.451c2.845,3.133,6.885,4.91,11.116,4.891c8.104,0.372,15.062,-5.705,15.785,-13.784l0,-7.114l-15.785,0l0,6.803l8.978,0c-0.551,4.386,-4.426,7.584,-8.837,7.29c-2.334,0.059,-4.58,-0.888,-6.166,-2.6c-2.362,-2.77,-3.648,-6.297,-3.624,-9.937c-0.024,-3.64,1.262,-7.167,3.624,-9.937c1.56,-1.685,3.761,-2.63,6.057,-2.602c2.952,-0.062,5.761,1.265,7.588,3.584l4.83,-4.83zM121.838,168.421c-0.665,0.119,-1.319,0.295,-1.954,0.527c-2.928,1.273,-5.298,3.563,-6.67,6.448c-1.69,4.516,-1.69,9.49,0,14.006c1.5,3.297,4.329,5.802,7.782,6.892c1.754,0.42,3.582,0.42,5.336,0c1.648,-0.339,3.198,-1.046,4.535,-2.068l0,1.846l6.803,0l0,-27.591l-6.803,0l0,2.096c-1.062,-0.868,-2.294,-1.504,-3.616,-1.867c2.455,-1.121,3.827,-3.772,3.325,-6.422c-0.503,-2.651,-2.751,-4.616,-5.445,-4.759c-2.694,-0.144,-5.138,1.572,-5.919,4.155c-0.78,2.582,0.304,5.364,2.626,6.737z", "fill": "#fff"}, + {"path": "M127.276,163.378c0,-1.356,-1.1,-2.456,-2.457,-2.456c-1.357,0,-2.457,1.1,-2.457,2.456c0,1.358,1.1,2.458,2.457,2.458c1.357,0,2.457,-1.1,2.457,-2.458zM130.866,185.413c-0.627,2.263,-2.447,4.001,-4.738,4.52c-1.426,0.313,-2.917,-0.019,-4.076,-0.906c-1.592,-1.293,-2.635,-3.14,-2.924,-5.171c-0.148,-1.04,-0.148,-2.097,0,-3.137c0.289,-2.031,1.332,-3.878,2.924,-5.171c1.159,-0.886,2.65,-1.218,4.076,-0.906c2.291,0.52,4.111,2.257,4.738,4.521l0,6.25z", "fill": "#111"}, + {"path": "M146.74,196.072l0,-27.591l6.803,0l0,2.08c3.123,-2.002,6.893,-2.737,10.539,-2.058l0,7.019c-0.774,-0.321,-1.609,-0.471,-2.446,-0.437c-1.432,-0.038,-2.841,0.354,-4.048,1.125c-2.203,1.301,-3.691,3.537,-4.045,6.072l0,13.79l-6.803,0zM177.333,168.948c-2.929,1.273,-5.298,3.563,-6.67,6.448c-1.69,4.516,-1.69,9.49,0,14.006c1.5,3.297,4.328,5.802,7.781,6.892c1.754,0.42,3.582,0.42,5.336,0c1.649,-0.339,3.199,-1.046,4.536,-2.068l0,1.846l6.803,0l0,-37.795l-6.803,0l0,12.3c-1.308,-1.07,-2.871,-1.783,-4.536,-2.074c-2.147,-0.463,-4.382,-0.309,-6.447,0.445z", "fill": "#fff"}, + {"path": "M188.315,185.413c-0.626,2.263,-2.447,4.001,-4.739,4.52c-1.426,0.313,-2.916,-0.019,-4.076,-0.906c-1.591,-1.293,-2.635,-3.14,-2.923,-5.171c-0.148,-1.04,-0.148,-2.097,0,-3.137c0.288,-2.031,1.332,-3.878,2.923,-5.171c1.16,-0.886,2.65,-1.218,4.076,-0.906c2.292,0.52,4.113,2.257,4.739,4.521l0,6.25z", "fill": "#111"}, + {"path": "M206.599,187c1.937,1.308,4.152,2.148,6.468,2.454c1.491,0.207,3.005,0.132,4.466,-0.224c0.55,-0.129,1.034,-0.451,1.365,-0.909c0.319,-0.436,0.4,-1.001,0.216,-1.509c-0.185,-0.508,-0.611,-0.89,-1.136,-1.018l-9.336,-2.222c-3.023,-0.941,-5.133,-3.672,-5.282,-6.834c-0.147,-3.162,1.7,-6.078,4.621,-7.297c1.557,-0.623,3.203,-0.997,4.876,-1.108c4.724,-0.478,9.464,0.753,13.358,3.471l-3.825,5.626c-2.77,-1.768,-6.043,-2.58,-9.319,-2.308c-0.695,0.021,-1.381,0.173,-2.02,0.45c-0.48,0.269,-0.756,0.796,-0.707,1.344c0.049,0.547,0.415,1.015,0.934,1.196c0.221,0.085,0.445,0.16,0.672,0.224l8.671,2c2.648,0.689,4.739,2.716,5.508,5.341c0.77,2.624,0.104,5.46,-1.753,7.469c-1.67,1.645,-3.859,2.66,-6.193,2.874c-2.432,0.309,-4.893,0.309,-7.325,0.001c-2.908,-0.386,-5.662,-1.533,-7.982,-3.327l3.723,-5.694zM121.063,219.972c2.928,1.274,5.297,3.564,6.669,6.447c1.691,4.516,1.691,9.491,0,14.006c-1.499,3.297,-4.328,5.802,-7.781,6.893c-1.754,0.42,-3.582,0.42,-5.336,0c-1.648,-0.34,-3.198,-1.047,-4.535,-2.068l0,1.845l-6.803,0l0,-37.795l6.803,0l0,12.3c1.308,-1.069,2.87,-1.783,4.535,-2.073c2.148,-0.464,4.384,-0.31,6.448,0.445z", "fill": "#fff"}, + {"path": "M110.079,236.436c0.627,2.265,2.447,4.001,4.738,4.522c1.426,0.311,2.917,-0.02,4.077,-0.907c1.591,-1.294,2.635,-3.14,2.923,-5.171c0.148,-1.041,0.148,-2.097,0,-3.137c-0.288,-2.031,-1.332,-3.877,-2.923,-5.171c-1.16,-0.887,-2.651,-1.219,-4.077,-0.906c-2.291,0.519,-4.111,2.256,-4.738,4.521l0,6.249z", "fill": "#111"}, + {"path": "M159.591,247.095l0,-27.59l-6.804,0l0,16.63c0,2.505,-2.03,4.535,-4.535,4.535c-2.505,0,-4.535,-2.03,-4.535,-4.535l0,-16.63l-6.803,0l0,17.764c0,3.765,2.073,7.225,5.394,8.999c3.321,1.776,7.348,1.577,10.479,-0.515l0,1.342l6.804,0zM166.394,219.505l2.645,0l0,-6.913l6.804,-3.292l0,10.205l3.401,0l0,6.803l-3.401,0l0,12.473c0,0.835,0.677,1.512,1.512,1.512l1.152,0l0,6.802l-4.932,0c-2.505,0,-4.536,-2.03,-4.536,-4.535l0,-16.252l-2.645,0l0,-6.803zM187.182,219.505l6.802,0l0,27.59l-6.802,0l0,-27.59zM194.741,212.702c0,-2.296,-1.861,-4.158,-4.157,-4.158c-2.296,0,-4.157,1.862,-4.157,4.158c0,2.296,1.861,4.157,4.157,4.157c2.296,0,4.157,-1.861,4.157,-4.157zM209.859,247.095l0,-8.262l2.787,-2.819l7.695,11.081l8.283,0l-11.113,-16.003l11.454,-11.587l-9.566,0l-9.54,9.651l0,-19.856l-6.803,0l0,37.795l6.803,0zM102.538,77.464l-68.523,-25.96l0,26.626l70.591,0c-0.7,-0.187,-1.391,-0.409,-2.068,-0.666zM101.838,136.439c2.207,-1.104,4.455,-2.124,6.739,-3.058c3.695,-1.511,7.444,-2.886,11.239,-4.121c3.644,-1.186,7.346,-2.178,11.094,-2.973c3.531,-0.75,7.082,-1.401,10.65,-1.953c3.512,-0.545,7.048,-0.923,10.596,-1.135c3.451,-0.206,6.907,-0.327,10.364,-0.364c3.456,0.037,6.912,0.158,10.362,0.364c3.548,0.212,7.085,0.59,10.597,1.135c3.567,0.552,7.119,1.203,10.65,1.953c3.747,0.795,7.45,1.787,11.093,2.973c3.796,1.235,7.546,2.61,11.24,4.121c2.284,0.934,4.531,1.954,6.738,3.058l13.053,-30.969c-1.593,-0.927,-3.059,-2.056,-4.361,-3.359c-4.005,-4.004,-9.437,-6.254,-15.1,-6.254c-5.664,0,-11.095,2.25,-15.1,6.254c-4.004,4.005,-9.436,6.255,-15.1,6.255l-96.586,0l11.832,28.073z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h26.json b/res/symbol/h26.json new file mode 100644 index 0000000..9303961 --- /dev/null +++ b/res/symbol/h26.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M184.927,59.931c-1.231,-0.637,-2.32,-1.515,-3.201,-2.584c-4.003,-4.852,-6.581,-10.719,-7.447,-16.95c-0.424,-3.056,-0.949,-6.097,-1.571,-9.118c-1.059,-5.133,-3.407,-9.912,-6.824,-13.887c-2.229,-2.726,-5.667,-4.167,-9.174,-3.843c-5.9,0.544,-11.516,2.793,-16.161,6.473c-0.753,0.501,-1.393,1.155,-1.879,1.918c-2.714,4.263,-3.439,9.496,-1.986,14.337l3.879,10.027l2.666,8.644c1.281,3.08,4.191,5.174,7.519,5.41c1.445,-0.163,2.91,0.005,4.281,0.492c0.874,0.31,1.54,1.03,1.783,1.926c0.241,0.896,0.026,1.853,-0.574,2.561l-3.048,4.736l-2.306,4.757c-2.244,3.827,-3.41,8.19,-3.377,12.627l1.346,19.317c-0.019,2.534,-0.929,4.98,-2.573,6.91l-17.526,20.579l-0.886,0.755l-6.764,6.058l-5.764,5.096c-2.537,1.763,-3.635,4.969,-2.712,7.917c0.924,2.949,3.656,4.955,6.745,4.955c3.253,-0.054,6.334,-1.474,8.488,-3.913l4.335,-4.277l1.93,2.528l30.691,-27.23c-1.918,27.428,-5.717,54.691,-11.372,81.598c-0.405,2.398,-0.897,4.782,-1.475,7.144c2.114,0.29,4.231,0.566,6.349,0.827c0.002,0.036,0.004,0.073,0.007,0.109c-0.352,13.342,-0.654,26.687,-0.907,40.032c-0.017,0.877,-0.516,1.674,-1.297,2.073c-7.22,3.687,-14.671,6.901,-22.307,9.623c-1.493,0.532,-2.646,1.741,-3.107,3.258c-0.461,1.517,-0.176,3.162,0.769,4.436l35.572,0c0.529,0,1.021,-0.272,1.305,-0.719c3.119,-12.881,6.199,-25.773,9.239,-38.673c1.399,-5.94,2.747,-11.891,4.043,-17.853c9.316,0.679,18.652,1.08,27.993,1.204c0.225,1.072,0.38,2.158,0.467,3.25c1.051,13.35,2.656,26.65,4.809,39.867c0.159,0.973,-0.409,1.92,-1.342,2.237c-4.294,1.461,-8.424,3.374,-12.314,5.706c-0.975,0.585,-1.624,1.587,-1.76,2.715c-0.134,1.129,0.26,2.256,1.07,3.054l23.209,0l15.672,-4.537c0.44,-0.127,0.75,-0.522,0.769,-0.98c0.026,-0.626,-0.011,-1.254,-0.11,-1.872c-2.936,-18.278,-5.847,-36.561,-8.734,-54.847c-0.571,-5.082,-0.951,-10.183,-1.138,-15.294c-0.172,-4.688,-0.562,-9.367,-1.169,-14.019c0.082,-3.208,0.221,-6.414,0.42,-9.617c0.252,-3.423,0.591,-6.839,1.017,-10.246c0.235,-3.525,0.21,-7.064,-0.072,-10.586c-0.354,-6.376,-1.287,-12.708,-2.787,-18.916c-1.248,-5.162,-2.925,-10.21,-5.012,-15.093c-8.834,-20.662,-20.447,-40.021,-34.52,-57.54c-0.863,-1.073,-1.946,-1.947,-3.177,-2.562zM81.382,114.379l-22.846,0c-0.85,0,-1.629,0.475,-2.017,1.23c-0.389,0.756,-0.322,1.666,0.172,2.357c8.49,11.866,10.707,27.109,5.949,40.901c-0.239,0.693,-0.128,1.459,0.297,2.055c0.426,0.598,1.113,0.953,1.847,0.953l16.598,0l16.6,0c0.732,0,1.42,-0.355,1.846,-0.953c0.425,-0.596,0.536,-1.362,0.297,-2.055c-4.758,-13.792,-2.541,-29.035,5.949,-40.901c0.494,-0.691,0.561,-1.601,0.173,-2.357c-0.389,-0.755,-1.167,-1.23,-2.017,-1.23l-22.848,0zM92.72,185.633c0,-0.601,0.239,-1.178,0.664,-1.603c0.426,-0.426,1.002,-0.665,1.604,-0.665l40.819,0c0.601,0,1.178,-0.238,1.603,-0.664c0.425,-0.425,0.665,-1.002,0.665,-1.604l0,-12.471c0,-1.253,-1.016,-2.269,-2.268,-2.269l-108.85,0c-1.253,0,-2.268,1.016,-2.268,2.269l0,12.471c0,0.602,0.239,1.179,0.664,1.604c0.425,0.426,1.002,0.664,1.604,0.664l40.818,0c0.602,0,1.179,0.239,1.604,0.665c0.425,0.425,0.664,1.002,0.664,1.603l0,70.343c0,1.252,-1.015,2.268,-2.268,2.268l-23.811,0c-1.252,0,-2.268,1.014,-2.268,2.267l0,12.473c0,1.252,1.016,2.268,2.268,2.268l74.835,0c1.252,0,2.267,-1.016,2.267,-2.268l0,-12.473c0,-1.253,-1.015,-2.267,-2.267,-2.267l-23.811,0c-1.253,0,-2.268,-1.016,-2.268,-2.268l0,-70.343z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h27.json b/res/symbol/h27.json new file mode 100644 index 0000000..ac8e858 --- /dev/null +++ b/res/symbol/h27.json @@ -0,0 +1,10 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [525.738, 525.738], + "defs": [ + {"path": "M384.249,314.619l0,169.061l141.489,0l0,-213.152c-19.298,-27.956,-54.533,-40.115,-86.966,-30.009c-32.431,10.107,-54.523,40.131,-54.523,74.1z", "fill": "#111"}, + {"path": "M416.563,371.05l51.708,-23.269l-11.376,44.986l-18.773,-6.123l11.532,54.398l41.526,-36.981l-18.757,-6.157l39.282,-89.937l-72.907,34.127l29.473,-57.912l-32.058,-11.376l-19.65,98.244z", "fill": "#e23"}, + {"path": "M0,422.218l0,-163.108l125.736,0l-32.963,-61.997c-30.307,-7.806,-61.477,-11.757,-92.773,-11.757l0,-38.149c34.236,0,68.348,4.134,101.593,12.313c10.539,2.592,19.475,9.551,24.571,19.134l43.793,82.364c25.72,21.446,37.515,55.33,30.673,88.111l-13.701,51.132l0,46.541c0,20.367,-16.511,36.878,-36.878,36.878c-20.366,0,-36.877,-16.511,-36.877,-36.878l0,-24.584l-113.174,0zM201.738,342.651l0.247,0.12l1.289,0.611l0.784,0.375l1.035,0.443l1.12,0.486l1.289,0.549l1.078,0.38l1.33,0.528l1.289,0.422l1.305,0.422l1.162,0.359l1.098,0.274l1.268,0.296l1.12,0.21l1.141,0.233l1.225,0.147l1.139,0.127l1.289,0.085l1.373,-0.022l1.12,-0.021l1.183,-0.126l1.986,-0.296l1.31,-0.295l0.866,-0.254l1.219,-0.425l1.268,-0.464l1.563,-0.634l1.374,-0.654l1.33,-0.676l1.332,-0.675l1.183,-0.697l0.986,-0.556l1.289,-0.76l1.31,-0.802l0.993,-0.57l1.374,-0.823l1.161,-0.654l0.824,-0.486l0.969,-0.526l1.204,-0.655l1.352,-0.697l1.352,-0.653l1.099,-0.465l1.12,-0.465l1.12,-0.442l1.476,-0.465l0.634,-0.212l0.909,-0.273l0.528,-0.106l0.76,-0.211l1.078,-0.212l0.993,-0.232l1.12,-0.126l0.845,-0.147l1.221,-0.148l1.099,-0.085l0.93,-0.084l1.141,-0.063l0.951,-0.064l1.732,0l1.352,0.022l1.204,0.063l0.931,0.033l0.719,0.022l0.971,0.063l0.74,0.042l0.76,0.064l0.888,0.105l0.781,0.063l0.825,0.105l0.845,0.106l0.866,0.085l0.845,0.126l0.845,0.085l0.803,0.127l0.824,0.127l0.823,0.084l0.909,0.147l1.015,0.168l0.823,0.17l0.845,0.126l0.825,0.127l0.823,0.148l0.825,0.148l0.823,0.147l0.846,0.127l0.844,0.169l0,-6.392l2.525,0l0,-15.14l37.852,0l0,7.571l23.94,0c2.092,0,3.786,1.694,3.786,3.784c0,2.091,-1.694,3.785,-3.786,3.785l-23.94,0l0,20.19l23.94,0c2.092,0,3.786,1.694,3.786,3.784c0,2.092,-1.694,3.786,-3.786,3.786l-23.94,0l0,7.571l-37.852,0l0,-15.141l-2.525,0l0,-6.392l-0.844,-0.169l-0.846,-0.127l-0.823,-0.147l-0.825,-0.147l-0.823,-0.148l-0.825,-0.127l-0.845,-0.127l-0.823,-0.169l-1.015,-0.169l-0.909,-0.147l-0.823,-0.085l-0.824,-0.126l-0.803,-0.126l-0.845,-0.085l-0.845,-0.127l-0.866,-0.084l-0.845,-0.105l-0.825,-0.107l-0.781,-0.062l-0.888,-0.107l-0.76,-0.062l-0.74,-0.043l-0.971,-0.064l-0.719,-0.02l-0.931,-0.035l-1.204,-0.062l-1.352,-0.021l-1.732,0l-0.951,0.063l-1.141,0.062l-0.93,0.085l-1.099,0.085l-1.221,0.148l-0.845,0.147l-1.12,0.127l-0.993,0.233l-1.078,0.21l-0.76,0.212l-0.528,0.105l-0.909,0.274l-0.634,0.211l-1.476,0.464l-1.12,0.445l-1.12,0.463l-1.099,0.464l-1.352,0.656l-1.352,0.696l-1.204,0.654l-0.969,0.527l-0.824,0.486l-1.161,0.653l-1.374,0.823l-0.993,0.571l-1.31,0.802l-1.289,0.76l-0.986,0.556l-1.183,0.696l-1.332,0.676l-1.33,0.675l-1.374,0.655l-1.563,0.633l-1.268,0.465l-1.219,0.425l-0.866,0.253l-1.31,0.295l-1.986,0.296l-1.183,0.127l-1.12,0.022l-1.373,0.02l-1.289,-0.084l-1.139,-0.127l-1.225,-0.147l-1.141,-0.233l-1.12,-0.212l-1.268,-0.295l-1.098,-0.274l-1.162,-0.359l-1.305,-0.422l-1.289,-0.422l-1.33,-0.528l-1.078,-0.379l-1.289,-0.549l-1.12,-0.486l-1.035,-0.443l-0.784,-0.376l-1.289,-0.611l-0.824,-0.401l-0.353,-0.159l-0.277,-0.12l0.099,-0.368c0.448,-2.146,0.817,-4.307,1.108,-6.478z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h28.json b/res/symbol/h28.json new file mode 100644 index 0000000..dfb568a --- /dev/null +++ b/res/symbol/h28.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [525.738, 525.738], + "defs": [ + {"path": "M82.778,364.78a33,33,0,0,0,66,0a33,33,0,0,0-66,0zM352.778,364.78a33,33,0,0,0,66,0a33,33,0,0,0-66,0zM56.651,145.327l-6.644,13.288c-0.782,1.564,-1.188,3.289,-1.188,5.038l0,17.85c0,1.749,0.406,3.474,1.188,5.038l6.963,13.926c1.909,3.817,5.809,6.228,10.077,6.228l39.387,0l-37.686,70.662l-35.89,16.452c-4.004,1.836,-6.571,5.836,-6.571,10.241l0,35.719c0,1.791,0.427,3.556,1.245,5.148l6.877,13.383c1.931,3.755,5.798,6.115,10.02,6.115l26.921,0c0,-16.098,8.589,-30.975,22.532,-39.025c13.942,-8.05,31.121,-8.05,45.063,0c13.943,8.05,22.532,22.927,22.532,39.025l180.253,0c0,-24.886,20.176,-45.062,45.063,-45.062c24.888,0,45.063,20.176,45.063,45.062l22.532,0l33.797,0c6.222,0,11.266,-5.043,11.266,-11.264l0,-180.561c0,-6.223,-5.044,-11.267,-11.266,-11.267l-168.082,0c-1.211,0,-2.414,-0.195,-3.562,-0.578l-63.203,-21.068c-1.149,-0.382,-2.352,-0.578,-3.563,-0.578l-183.047,0c-4.267,0,-8.168,2.411,-10.077,6.228z", "fill": "#111"}, + {"path": "M109.538,222.263c1.177,-2.196,3.466,-3.567,5.958,-3.567l47.502,0c1.792,0,3.511,0.713,4.78,1.98c1.267,1.268,1.979,2.987,1.979,4.78l0,45.142l-89.743,6.759l29.524,-55.094zM93.52,193.377l76.607,0c3.733,0,6.759,-3.026,6.759,-6.76l0,-20.278c0,-3.733,-3.026,-6.76,-6.759,-6.76l-76.607,0c-3.734,0,-6.76,3.027,-6.76,6.76l0,20.278c0,3.734,3.026,6.76,6.76,6.76zM217.464,275.025l99.139,0c3.733,0,6.76,-3.026,6.76,-6.759l0,-54.076c0,-3.733,-3.027,-6.76,-6.76,-6.76l-99.139,0c-3.733,0,-6.76,3.027,-6.76,6.76l0,54.076c0,3.733,3.027,6.759,6.76,6.759zM401.833,275.025l54.077,0c3.732,0,6.759,-3.026,6.759,-6.759l0,-54.076c0,-3.733,-3.027,-6.76,-6.759,-6.76l-54.077,0c-3.734,0,-6.759,3.027,-6.759,6.76l0,54.076c0,3.733,3.025,6.759,6.759,6.759z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h3.json b/res/symbol/h3.json new file mode 100644 index 0000000..da7a2b2 --- /dev/null +++ b/res/symbol/h3.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M104.374,118.75l15.118,0l0,144.871l126.388,0l0,-219.968c0,-13.151,-10.66,-23.811,-23.81,-23.811l-78.767,0c-13.15,0,-23.811,10.66,-23.811,23.811l0,1.362l-21.883,0c-23.094,0,-43.309,15.511,-49.286,37.818l-27.036,100.901c-4.257,15.868,1.065,32.762,13.647,43.325c12.582,10.561,30.144,12.877,45.033,5.935c14.889,-6.94,24.407,-21.879,24.407,-38.306l0,-75.938z", "fill": "#111"}, + {"path": "M42.277,189.366c-2.068,7.708,0.518,15.916,6.63,21.048c6.112,5.131,14.644,6.255,21.877,2.884c7.234,-3.372,11.858,-10.63,11.858,-18.61l0,-88.221l23.399,-22.205l13.451,0l0,-19.006l-22.209,0c-12.829,0,-24.06,8.617,-27.38,21.009l-27.626,103.101zM147.811,89.067l0,-44.052l68.176,0l0,44.052l-68.176,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h4.json b/res/symbol/h4.json new file mode 100644 index 0000000..0f69c6b --- /dev/null +++ b/res/symbol/h4.json @@ -0,0 +1,27 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M195.636,94.625v-13.088h47.262v30.539h-26.54v121.006h47.262v-152.489c0,-9.116,-7.389,-16.507,-16.506,-16.507h-54.603c-9.117,0,-16.506,7.391,-16.506,16.507v0.944v13.088h19.631z", "fill": "#059"}, + {"path": "M119.261,163.191h10.48v100.43h87.617v-152.489c0,-9.117,-7.39,-16.507,-16.505,-16.507h-54.604c-9.117,0,-16.508,7.39,-16.508,16.507v0.944h-15.17c-16.009,0,-30.021,10.753,-34.166,26.217l-18.742,69.948c-2.951,10.999,0.738,22.712,9.461,30.033c8.721,7.323,20.897,8.927,31.217,4.116c10.322,-4.812,16.92,-15.168,16.92,-26.556v-52.643z", "fill": "#111"}, + {"path": "M148.374,112.076h47.262v30.539h-47.262zM75.214,212.145c-1.434,5.343,0.359,11.034,4.596,14.591c4.238,3.557,10.152,4.336,15.166,1.998c5.015,-2.336,8.22,-7.368,8.22,-12.9v-61.158l16.221,-15.393h9.324v-13.176h-15.394c-8.895,0,-16.68,5.974,-18.983,14.565l-19.15,71.473z", "fill": "#fff"}, + + {"path": "M159.232,33.137l7.336,-7.337c-4.697,-5.389,-11.527,-8.438,-18.673,-8.337c-6.348,-0.028,-12.409,2.639,-16.676,7.337c-5.197,6.022,-8.039,13.722,-8.004,21.677c-0.035,7.954,2.807,15.654,8.004,21.677c4.267,4.698,10.328,7.364,16.676,7.336c12.154,0.559,22.591,-8.557,23.675,-20.676l0,-10.672l-23.675,0l0,10.338l13.337,0c-0.783,5.789,-5.511,10.24,-11.337,10.672c-0.666,0.052,-1.334,0.052,-2,0c-3.612,0.052,-7.049,-1.544,-9.338,-4.336c-3.274,-4.058,-5.041,-9.125,-5.004,-14.339c-0.037,-5.215,1.73,-10.282,5.004,-14.341c2.289,-2.791,5.726,-4.386,9.338,-4.335c4.408,-0.106,8.609,1.871,11.337,5.336zM67.858,18.141l11.674,0l22.01,37.684l0,-37.684l10.338,0l0,56.693l-11.209,0l-22.473,-38.479l0,38.479l-10.34,0l0,-56.693zM56.692,23.527c-5.084,-4.314,-11.709,-6.363,-18.341,-5.67c-7.723,1.212,-14.475,5.876,-18.342,12.672c-2.547,4.944,-3.809,10.449,-3.668,16.008c-0.088,5.806,1.289,11.541,4.002,16.674c3.709,6.829,10.599,11.339,18.342,12.006c6.525,0.648,13.031,-1.401,18.007,-5.67l-6.728,-7.847c-2.854,2.447,-6.588,3.612,-10.326,3.222c-4.287,-0.346,-8.114,-2.825,-10.184,-6.596c-1.916,-3.648,-2.869,-7.724,-2.771,-11.843c-0.133,-3.818,0.699,-7.608,2.416,-11.02c2.279,-3.886,6.152,-6.573,10.59,-7.348c3.74,-0.321,7.453,0.865,10.316,3.294l6.687,-7.882z", "fill": "#111"}, + + {"path": "M139.561,33.137l7.337,-7.337c-4.698,-5.389,-11.528,-8.438,-18.676,-8.337c-6.347,-0.028,-12.407,2.639,-16.675,7.337c-5.197,6.022,-8.04,13.722,-8.003,21.677c-0.037,7.954,2.806,15.654,8.003,21.676c4.268,4.699,10.328,7.365,16.675,7.337c12.155,0.559,22.593,-8.557,23.678,-20.676l0,-10.672l-23.678,0l0,10.338l13.34,0c-0.785,5.789,-5.513,10.24,-11.339,10.672c-0.666,0.052,-1.335,0.052,-2.001,0c-3.61,0.052,-7.047,-1.544,-9.338,-4.336c-3.273,-4.058,-5.041,-9.125,-5.002,-14.339c-0.039,-5.215,1.729,-10.282,5.002,-14.341c2.291,-2.791,5.728,-4.386,9.338,-4.335c4.409,-0.106,8.61,1.871,11.339,5.336zM67.529,74.834l-10.339,0l0,-56.693l22.011,0c9.301,0,16.841,7.54,16.841,16.841c0,9.301,-7.54,16.841,-16.841,16.841l-11.672,0l0,23.011z", "fill": "#111"}, + {"path": "M67.529,41.485l0,-13.006l11.672,0c3.591,0,6.503,2.912,6.503,6.503c0,3.592,-2.912,6.503,-6.503,6.503l-11.672,0z", "fill": "#fff"}, + {"path": "M30.18,41.485l0,23.011l18.009,0l0,10.338l-28.347,0l0,-33.349l0,-23.344l10.338,0l0,23.344z", "fill": "#111"}, + + {"path": "M25.916,63.366l17.94,0l0,10.312l-28.252,0l0,-56.506l10.312,0l0,46.193zM61.584,17.173l11.654,0l21.895,37.576l0,-37.576l10.312,0l0,56.506l-11.053,0l-22.497,-38.467l0,38.467l-10.312,0l0,-56.506zM149.026,27.3l-0.494,0c-3.72,0,-6.757,1.437,-9.112,4.309c-3.344,4.144,-5.015,8.853,-5.015,14.126l0,0.353c0,5.274,1.671,9.983,5.015,14.126c2.354,2.873,5.392,4.309,9.112,4.309l0.212,0c0.328,0,0.658,0,0.989,0c0.282,0,0.61,0,0.989,0c2.871,-0.188,5.367,-1.282,7.486,-3.285c2.119,-2.001,3.391,-4.461,3.815,-7.381l-13.278,0l0,-10.242l23.591,0l0,10.595c-0.519,5.839,-2.943,10.736,-7.276,14.691c-4.332,3.955,-9.44,5.933,-15.326,5.933c-0.331,0,-0.66,0,-0.989,0c-6.65,0,-12.207,-2.448,-16.67,-7.346c-5.322,-6.121,-7.981,-13.255,-7.981,-21.401l0,-0.353c0,-8.098,2.66,-15.232,7.981,-21.401c4.463,-4.897,10.02,-7.346,16.67,-7.346l0.282,0c7.392,0,13.491,2.779,18.294,8.335l-7.276,7.275c-2.826,-3.532,-6.498,-5.297,-11.019,-5.297z", "fill": "#111"}, + + {"path": "M24.5,74.217l0,-56.506l10.312,0l0,21.26l20.907,0l0,-21.26l10.312,0l0,56.506l-10.312,0l0,-24.934l-20.907,0l0,24.934l-10.312,0zM104.446,82.529l0,5.707l-22.711,0c0,-0.21,0,-0.419,0,-0.63c0,-2.702,0.656,-5.222,1.968,-7.558c1.312,-2.335,3.122,-4.158,5.432,-5.471l7.754,-4.448c0.787,-0.472,1.338,-1.141,1.653,-2.007c0.183,-0.472,0.276,-0.97,0.276,-1.496c0,-0.498,-0.092,-0.983,-0.276,-1.456c-0.42,-1.207,-1.22,-2.02,-2.4,-2.441c-0.972,-0.262,-1.956,-0.394,-2.952,-0.394c-0.998,0,-1.982,0.132,-2.953,0.394c-0.84,0.289,-1.509,0.787,-2.007,1.496c-0.499,0.708,-0.747,1.496,-0.747,2.362c0,0.105,0,0.183,0,0.236l-5.747,0c0,-0.079,0,-0.197,0,-0.355c0,-2.047,0.597,-3.903,1.791,-5.569c1.194,-1.666,2.748,-2.84,4.664,-3.522c1.678,-0.498,3.397,-0.748,5.156,-0.748c1.522,0,3.004,0.197,4.448,0.591c2.938,1.023,4.972,2.991,6.1,5.903c0.394,1.129,0.59,2.297,0.59,3.503c0,1.208,-0.197,2.376,-0.59,3.503c-0.865,2.204,-2.282,3.871,-4.251,4.999l-7.754,4.409c-1.207,0.787,-2.191,1.785,-2.952,2.991l15.508,0z", "fill": "#111"} + ], + "core": [{"use": 0}, {"use": 1}, {"use": 2}], + "components": { + "cng": [{"use": 3}], + "lpg": [{"use": 4}, {"use": 5}, {"use": 6}], + "lng": [{"use": 7}], + "hydrogen": [{"use": 8}] + } +} \ No newline at end of file diff --git a/res/symbol/h5.json b/res/symbol/h5.json new file mode 100644 index 0000000..43cd3a1 --- /dev/null +++ b/res/symbol/h5.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M191.572,199.37c6.026,-9.719,10.71,-20.208,13.928,-31.18c26.248,-1.992,46.856,-23.307,47.961,-49.607l0,-43.937l-40.186,0l1.217,-27.874l-72.999,0l-73.944,0l4.023,92.126c1.09,21.43,7.591,42.235,18.897,60.472l-75.59,0c-2.096,0.779,-3.68,2.532,-4.245,4.695c-0.564,2.164,-0.038,4.467,1.409,6.171c17.51,17.277,40.653,27.674,65.197,29.291l64.252,0l64.251,0c24.545,-1.617,47.688,-12.014,65.197,-29.291c1.45,-1.704,1.975,-4.007,1.411,-6.171c-0.565,-2.163,-2.149,-3.916,-4.245,-4.695l-76.535,0z", "fill": "#111"}, + {"path": "M209.335,150.236c14.549,-3.939,25.036,-16.622,26.173,-31.653l0,-25.984l-23.019,0l-2.021,46.299c-0.192,3.79,-0.555,7.568,-1.086,11.326c-0.002,0.01,-0.01,0.019,-0.02,0.022c-0.009,0.003,-0.021,-0.001,-0.027,-0.01z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h6.json b/res/symbol/h6.json new file mode 100644 index 0000000..af422d2 --- /dev/null +++ b/res/symbol/h6.json @@ -0,0 +1,8 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M247.559,218.338l-80.391,-74.367l-2.884,-2.668l25.718,-27.281c10.471,4.26,22.387,2.914,31.645,-3.572c1.365,-1.154,2.703,-2.338,4.014,-3.553l35.571,-35.102c3.028,-3.304,2.958,-8.395,-0.16,-11.614c-3.117,-3.219,-8.203,-3.451,-11.601,-0.53l-36.291,36.087c-0.313,0.271,-0.672,0.483,-1.061,0.626c-1.859,0.585,-3.888,-0.005,-5.144,-1.498c-1.256,-1.491,-1.493,-3.591,-0.6,-5.325c0.1,-0.177,0.22,-0.342,0.359,-0.49l36.651,-36.443c0.056,-0.065,0.107,-0.135,0.154,-0.209c2.045,-3.358,1.602,-7.667,-1.082,-10.541c-2.808,-2.645,-7.017,-3.142,-10.365,-1.225c-0.192,0.119,-0.372,0.257,-0.537,0.411l-36.094,36.001c-0.426,0.381,-0.902,0.7,-1.416,0.949c-1.772,0.629,-3.748,0.172,-5.065,-1.172c-1.317,-1.343,-1.734,-3.328,-1.07,-5.088c0.158,-0.32,0.362,-0.616,0.606,-0.878l36.177,-36.084c2.936,-3.386,2.724,-8.473,-0.482,-11.604c-3.206,-3.131,-8.297,-3.222,-11.611,-0.207l-35.85,36.029c-1.254,1.265,-2.404,2.629,-3.437,4.078c-6.131,9.147,-7.342,20.732,-3.234,30.948l-28.304,26.464l-16.861,-15.597c5.524,-15.051,0.533,-31.944,-12.283,-41.576c-15.544,-14.305,-34.4,-24.522,-54.872,-29.733c-0.725,-0.159,-1.46,-0.273,-2.199,-0.34c-4.069,-0.262,-8.139,0.483,-11.851,2.168c-0.912,0.427,-1.794,0.914,-2.64,1.46c-1.983,1.39,-3.645,3.189,-4.874,5.274c-2.232,4.136,-3.243,8.821,-2.917,13.509c0.049,0.674,0.152,1.344,0.309,2.002c5.247,20.507,15.519,39.384,29.89,54.927c9.661,12.794,26.564,17.746,41.603,12.188l14.931,16.067l-86.562,80.935c-0.943,1.118,-1.794,2.312,-2.542,3.569c-3.96,7.751,-2.263,17.191,4.149,23.076c6.075,6.673,15.952,8.265,23.816,3.84c1.02,-0.596,1.968,-1.309,2.823,-2.124l80.516,-85.408l2.986,3.214l73.674,79.276c0.617,0.59,1.27,1.141,1.955,1.647c8.063,5.019,18.571,3.472,24.844,-3.657c6.887,-6.088,8.562,-16.169,4.016,-24.156c-0.653,-0.944,-1.364,-1.847,-2.127,-2.703z", "fill": "#111"} + ] +} \ No newline at end of file diff --git a/res/symbol/h7.json b/res/symbol/h7.json new file mode 100644 index 0000000..136f36a --- /dev/null +++ b/res/symbol/h7.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M268.347,198.638c0.002,-1.887,-0.146,-3.771,-0.444,-5.634c-11.218,-40.291,-45.112,-70.196,-86.486,-76.311c-6.219,-7.126,-13.561,-13.19,-21.732,-17.952l0,-67.56c-0.26,-8.945,-7.586,-16.062,-16.536,-16.062c-8.949,0,-16.276,7.117,-16.535,16.062l0,21.733l-75.591,0l0,-21.733c-0.259,-8.945,-7.586,-16.062,-16.535,-16.062c-8.95,0,-16.276,7.117,-16.536,16.062l0,159.685c1.262,8.156,8.283,14.173,16.536,14.173c8.253,0,15.273,-6.017,16.535,-14.173l0,-33.543l61.417,51.535l0,42.481c0.768,8.56,7.942,15.118,16.536,15.118c8.594,0,15.767,-6.558,16.535,-15.118l0,-41.575l89.763,0l0,41.575c0.769,8.56,7.942,15.118,16.537,15.118c8.593,0,15.766,-6.558,16.536,-15.118l0,-52.824l0,0.123z", "fill": "#111"}, + {"path": "M79.842,125.671c29.482,-16.632,64.511,-20.39,96.85,-10.394c-34.093,-32.181,-85.409,-37.811,-125.669,-13.788l28.819,24.182z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h8.json b/res/symbol/h8.json new file mode 100644 index 0000000..990d13a --- /dev/null +++ b/res/symbol/h8.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M49.133,137.008c-2.016,24.12,-14.877,46.019,-34.96,59.527c13.189,3.566,27.248,1.873,39.212,-4.723l0,34.488l-40.157,0l0,21.731l254.173,0l0.473,0l0,-21.731l-0.473,0l-10.866,0l0,-108.189l18.897,0l-89.054,-92.22l-89.055,92.22l18.897,0l0,108.189l-48.662,0l0,-34.488c12.846,6.501,27.598,8.176,41.575,4.723c-21.203,-12.488,-34.564,-34.935,-35.433,-59.527c8.202,7.117,18.467,11.422,29.292,12.283c-23.51,-22.127,-38.268,-51.978,-41.575,-84.094c-4.059,31.698,-18.321,61.215,-40.63,84.094c10.479,-1.114,20.368,-5.4,28.346,-12.283z", "fill": "#111"}, + {"path": "M167.715,170.079l0,56.221l37.796,0l0,-56.221l-37.796,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/symbol/h9.json b/res/symbol/h9.json new file mode 100644 index 0000000..82d0d29 --- /dev/null +++ b/res/symbol/h9.json @@ -0,0 +1,9 @@ +{ + "width": 40, + "height": 40, + "vectorSize": [283.465, 283.465], + "defs": [ + {"path": "M151.304,57.05l58.225,-40.77l58.226,40.77l-7.754,11.074l-10.314,-7.222l0,41.015l-40.158,0l-40.157,0l0,-41.015l-10.314,7.222l-7.754,-11.074zM5.775,96.785l78.904,-55.249l78.903,55.249l-10.508,15.007l-13.976,-9.786l0,55.582l-54.419,0l-54.419,0l0,-55.582l-13.977,9.786l-10.508,-15.007zM89.656,194.744l94.017,-65.831l94.016,65.831l-12.52,17.881l-16.654,-11.66l0,66.228l-64.842,0l-64.843,0l0,-66.228l-16.654,11.66l-12.52,-17.881z", "fill": "#111"}, + {"path": "M192.633,74.268l0,-13.166l33.795,0l0,13.166l-33.795,0zM61.78,120.119l0,-17.842l45.796,0l0,17.842l-45.796,0zM156.391,222.547l0,-21.26l54.566,0l0,21.26l-54.566,0z", "fill": "#fff"} + ] +} \ No newline at end of file diff --git a/res/water.json b/res/water.json index a5a1fcf..ec35bd3 100644 --- a/res/water.json +++ b/res/water.json @@ -2,11 +2,7 @@ "width": 209, "height": 19, "vectorSize": [11, 1], - "defs": { - "vatten": {"path": "M.5,.67a1.093,1.093,0,0,0,1,-.657a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,1,.657v.234a1.327,1.327,0,0,1,-1,-.46a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-1,.46z", "fill": "#fff"} - }, - "core": [{"use": "vatten"}], - "components": { - "name": [] - } + "defs": [ + {"path": "M.5,.67a1.093,1.093,0,0,0,1,-.657a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,2,0a1.093,1.093,0,0,0,1,.657v.234a1.327,1.327,0,0,1,-1,-.46a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-2,0a1.327,1.327,0,0,1,-1,.46z", "fill": "currentColor"} + ] } \ No newline at end of file diff --git a/src/browser.ts b/src/browser.ts index 846944a..1e9aa8b 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -58,22 +58,8 @@ class BrowserDrawingArea implements NewDrawingArea{ this.ctx.fillText(text, x, y); } - drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void { - this.ctx.drawImage(image.canv, sx, sy, sw, sh, dx, dy, dw, dh); - } - - drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise { - return new Promise((res, rej) => { - let img = new Image(); - - img.addEventListener("load", () => { - this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); - res(); - }); - - img.addEventListener("error", rej); - img.src = url; - }); + drawImage(image: NewDrawingArea, dx: number, dy: number): void { + this.ctx.drawImage(image.canv, dx, dy); } } diff --git a/src/config.ts b/src/config.ts index 77a5d6b..a54388a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -56,34 +56,34 @@ const CONFIG: ConfigData = { }, "symbols": { "arrow-small": { "width": 48, "height": [48, 192], "default": "left" }, - "exit": { "width": 46, "height": [26, 26], "default": "" }, - "h1": { "width": 40, "height": [40, 40], "default": "" }, - "h2": { "width": 40, "height": [40, 40], "default": "" }, - "h3": { "width": 40, "height": [40, 40], "default": "" }, + "exit": { "width": 46, "height": [26, 26] }, + "h1": { "width": 40, "height": [40, 40] }, + "h2": { "width": 40, "height": [40, 40] }, + "h3": { "width": 40, "height": [40, 40] }, "h4": { "width": 40, "height": [40, 40], "default": "cng" }, - "h5": { "width": 40, "height": [40, 40], "default": "" }, - "h6": { "width": 40, "height": [40, 40], "default": "" }, - "h7": { "width": 40, "height": [40, 40], "default": "" }, - "h8": { "width": 40, "height": [40, 40], "default": "" }, - "h9": { "width": 40, "height": [40, 40], "default": "" }, - "h10": { "width": 40, "height": [40, 40], "default": "" }, - "h11": { "width": 40, "height": [40, 40], "default": "" }, - "h12": { "width": 40, "height": [40, 40], "default": "" }, - "h13": { "width": 40, "height": [40, 40], "default": "" }, - "h14": { "width": 40, "height": [40, 40], "default": "" }, - "h15": { "width": 40, "height": [40, 40], "default": "" }, - "h16": { "width": 40, "height": [40, 40], "default": "" }, - "h17": { "width": 40, "height": [40, 40], "default": "" }, - "h18": { "width": 40, "height": [40, 40], "default": "" }, - "h19": { "width": 40, "height": [40, 40], "default": "" }, - "h20": { "width": 40, "height": [40, 40], "default": "" }, - "h21": { "width": 40, "height": [40, 40], "default": "" }, - "h22": { "width": 40, "height": [40, 40], "default": "" }, - "h24": { "width": 40, "height": [40, 40], "default": "" }, - "h25": { "width": 40, "height": [40, 40], "default": "" }, - "h26": { "width": 40, "height": [40, 40], "default": "" }, - "h27": { "width": 40, "height": [40, 40], "default": "" }, - "h28": { "width": 40, "height": [40, 40], "default": "" } + "h5": { "width": 40, "height": [40, 40] }, + "h6": { "width": 40, "height": [40, 40] }, + "h7": { "width": 40, "height": [40, 40] }, + "h8": { "width": 40, "height": [40, 40] }, + "h9": { "width": 40, "height": [40, 40] }, + "h10": { "width": 40, "height": [40, 40] }, + "h11": { "width": 40, "height": [40, 40] }, + "h12": { "width": 40, "height": [40, 40] }, + "h13": { "width": 40, "height": [40, 40] }, + "h14": { "width": 40, "height": [40, 40] }, + "h15": { "width": 40, "height": [40, 40] }, + "h16": { "width": 40, "height": [40, 40] }, + "h17": { "width": 40, "height": [40, 40] }, + "h18": { "width": 40, "height": [40, 40] }, + "h19": { "width": 40, "height": [40, 40] }, + "h20": { "width": 40, "height": [40, 40] }, + "h21": { "width": 40, "height": [40, 40] }, + "h22": { "width": 40, "height": [40, 40] }, + "h24": { "width": 40, "height": [40, 40] }, + "h25": { "width": 40, "height": [40, 40] }, + "h26": { "width": 40, "height": [40, 40] }, + "h27": { "width": 40, "height": [40, 40] }, + "h28": { "width": 40, "height": [40, 40] } }, "borderFeatures": { "bracket": { "paths": [{ "p": "M-${bw/2},0H0L22,27L44,0H${bw/2+w}", "s": 1, "f": 2 }], "w": 44, "h": 27, "cover": false }, diff --git a/src/main.ts b/src/main.ts index 07c9a13..1181118 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import { SignElement as _SignElement } from "./render.js"; import { SignElementBaseProperties, SignElementOptions, Vec6, NewDrawingArea, Path2D as _Path2D } from "./typedefs.js"; -import { createCanvas, Canvas, Path2D, SKRSContext2D, Image } from "@napi-rs/canvas"; +import { createCanvas, Canvas, Path2D, SKRSContext2D } from "@napi-rs/canvas"; import { readFile } from "fs/promises" class NodeDrawingArea implements NewDrawingArea{ @@ -60,22 +60,8 @@ class NodeDrawingArea implements NewDrawingArea{ this.ctx.fillText(text, x, y); } - drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void { - this.ctx.drawImage(image.canv, sx, sy, sw, sh, dx, dy, dw, dh); - } - - drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise { - return new Promise((res, rej) => { - let img = new Image(); - - img.onload = () => { - this.ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh); - res(); - }; - - img.onerror = rej; - img.src = url; - }); + drawImage(image: NewDrawingArea, dx: number, dy: number): void { + this.ctx.drawImage(image.canv, dx, dy); } } diff --git a/src/render.ts b/src/render.ts index 740c97e..1bd9967 100644 --- a/src/render.ts +++ b/src/render.ts @@ -178,34 +178,45 @@ export abstract class SignElement>{ }); } - private drawVec(ctx: T, href: string, components: string[], dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise{ + private drawVec(ctx: T, href: string, currentColor: string, components: string[], dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise{ return this.getText(href).then(rawJson => { let vecImgData = JSON.parse(rawJson) as JSONVec; - let ctx2: T = this.createCanvas(sw, sh); + let ctx2: T = this.createCanvas(dw, dh); - let xf = vecImgData.width / vecImgData.vectorSize[0], - yf = vecImgData.height / vecImgData.vectorSize[1]; + let xf = (dw/sw) * vecImgData.width / vecImgData.vectorSize[0], + yf = (dh/sh) * vecImgData.height / vecImgData.vectorSize[1]; let tm: Vec6 = [ xf, 0, 0, yf, 0, 0 ]; - let els: JSONVecReference[] = vecImgData.core.concat(...components.map(name => vecImgData.components[name])); + let els: JSONVecReference[]; + if(vecImgData.components !== undefined){ + els = vecImgData.core || []; + Object.entries(vecImgData.components).filter(e => components.includes(e[0])).forEach(e => els.push(...e[1])); + }else{ + els = vecImgData.defs.map(function(_: any, i: number): JSONVecReference{ + return {use: i}; + }); + } + els.forEach(el => { let def = vecImgData.defs[el.use]; let tra = el.translate || [0, 0]; [tm[4], tm[5]] = [tra[0] * xf, tra[1] * yf]; - tm[4] -= sx; tm[5] -= sy; + + tm[4] -= sx * dw/sw; + tm[5] -= sy * dh/sh; let path = ctx2.createPath2D(def.path, tm); - ctx2.fillStyle = def.fill; + ctx2.fillStyle = def.fill === "currentColor" ? currentColor : def.fill; ctx2.fill(path); }); - ctx.drawImage(ctx2, 0, 0, sw, sh, dx, dy, dw, dh); + ctx.drawImage(ctx2, dx, dy); }); } @@ -278,14 +289,14 @@ export abstract class SignElement>{ let renderPromise: (ctx: T, x0: number, y0: number, maxInnerHeight: number) => Promise = () => Promise.resolve(); - if(this.type == "skylt"){ + if(this.type === "skylt"){ let w = [0], h = [0], j = 0; let totalLineSpacing = 0; let ch = this.children.map((c, i) => { let re = c._render(); - let c2 = { isn: c.type == "newline", r: re, bs: re.bs, row: j, x: 0 }; + let c2 = { isn: c.type === "newline", r: re, bs: re.bs, row: j, x: 0 }; if(c2.isn || (i > 0 && this.properties.blockDisplay)){ c2.row = ++j; @@ -366,7 +377,7 @@ export abstract class SignElement>{ iw ); })).then(() => {}); - }else if(this.type == "vagnr" || this.type == "text"){ + }else if(this.type === "vagnr" || this.type === "text"){ let ctx_temp = this.createCanvas(); ctx_temp.font = "32px " + this.properties.font; @@ -397,26 +408,21 @@ export abstract class SignElement>{ res(); }); - }else if(this.type == "symbol"){ + }else if(this.type === "symbol"){ let symbolType = SYMBOLER[this.properties.type || ""]; width = symbolType.width; [height, maxHeight] = symbolType.height; - renderPromise = (ctx, x0, y0, maxInnerHeight) => new Promise((res, rej) => { - let url = "svg/symbol/" + (this.properties.type || "") + ".svg"; + let url = "res/symbol/" + (this.properties.type || "") + ".json"; + let v: string | undefined = this.properties.variant || symbolType.default; - this.getText(url).then(xml => { - return ctx.drawSVG( - "data:image/svg+xml;utf8," - + encodeURIComponent(xml.replace(/currentColor/g, this.properties.color)) - + "#" + encodeURIComponent(this.properties.variant || symbolType.default), - x0 + padding[0], y0 + padding[1], // dx, dy - width, maxInnerHeight - padding[1] - padding[3] // dw=sw, dh=sh - ); - }).then(res, rej); - }); - }else if(this.type == "newline"){ + renderPromise = (ctx, x0, y0, maxInnerHeight) => this.drawVec( + ctx, url, this.properties.color, v === undefined ? [] : [v], + x0 + padding[0], y0 + padding[1], // dx, dy + width, maxInnerHeight - padding[1] - padding[3] // dw=sw, dh=sh + ); + }else if(this.type === "newline"){ width = 0; height = 0; }else if(this.type.startsWith(".")){ @@ -510,7 +516,7 @@ export abstract class SignElement>{ return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.renderPromise.h, this.properties.alignContentsV); })).then(() => { - if(t.width == 0 || t.height == 0) return; + if(t.width === 0 || t.height === 0) return; svgBox[0] = Math.min(1, Math.max(0, boundingBox[0] / t.width)); svgBox[1] = Math.max(0, Math.min(1, boundingBox[1] / t.width)); @@ -525,7 +531,7 @@ export abstract class SignElement>{ ]; // [x0, y0, w, h] return this.drawVec( - ctx, "res/" + this.type.slice(1) + ".json", keys, + ctx, "res/" + this.type.slice(1) + ".json", this.properties.color, keys, x0 + this.properties.padding[0] - boundingBox[0] + crop[0], // dx y0 + this.properties.padding[1] - boundingBox[2] + crop[1], // dy crop[2], crop[3], // dw=sw, dh=sh diff --git a/src/typedefs.ts b/src/typedefs.ts index 6720170..300910b 100644 --- a/src/typedefs.ts +++ b/src/typedefs.ts @@ -29,7 +29,7 @@ type SignTypeDefinition = { type SignSymbolDefinition = { width: number; height: number[]; - default: string; + default?: string; }; // properties som ärvs (måste därför specificeras av rootDefaults) @@ -129,15 +129,15 @@ export interface Path2D{ }; type JSONVecElement = {path: string, fill: string}; -export type JSONVecReference = {use: string, translate?: [number, number]}; +export type JSONVecReference = {use: number, translate?: [number, number]}; export type JSONVec = { width: number; height: number; vectorSize: [number, number]; - defs: {[key: string]: JSONVecElement;}; - core: JSONVecReference[]; - components: {[key: string]: JSONVecReference[]}; + defs: JSONVecElement[]; + core?: JSONVecReference[]; + components?: {[key: string]: JSONVecReference[]}; }; export interface NewDrawingArea{ @@ -160,7 +160,5 @@ export interface NewDrawingArea{ fillRect(x: number, y: number, w: number, h: number): void; fillText(text: string, x: number, y: number): void; - drawImage(image: NewDrawingArea, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; - - drawSVG(url: string, dx: number, dy: number, dw: number, dh: number, sx?: number, sy?: number, sw?: number, sh?: number): Promise; + drawImage(image: NewDrawingArea, dx: number, dy: number): void; }; \ No newline at end of file diff --git a/svg/symbol/arrow-small.svg b/svg/symbol/arrow-small.svg deleted file mode 100644 index 01fd0d7..0000000 --- a/svg/symbol/arrow-small.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/svg/symbol/exit.svg b/svg/symbol/exit.svg deleted file mode 100644 index 2112420..0000000 --- a/svg/symbol/exit.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/svg/symbol/h1.svg b/svg/symbol/h1.svg deleted file mode 100644 index 5835a83..0000000 --- a/svg/symbol/h1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h10.svg b/svg/symbol/h10.svg deleted file mode 100644 index 9422c77..0000000 --- a/svg/symbol/h10.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h11.svg b/svg/symbol/h11.svg deleted file mode 100644 index 02f5b66..0000000 --- a/svg/symbol/h11.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h12.svg b/svg/symbol/h12.svg deleted file mode 100644 index abf0fc2..0000000 --- a/svg/symbol/h12.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/svg/symbol/h13.svg b/svg/symbol/h13.svg deleted file mode 100644 index 4faa744..0000000 --- a/svg/symbol/h13.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/svg/symbol/h14.svg b/svg/symbol/h14.svg deleted file mode 100644 index 16c3e6e..0000000 --- a/svg/symbol/h14.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/svg/symbol/h15.svg b/svg/symbol/h15.svg deleted file mode 100644 index f76d604..0000000 --- a/svg/symbol/h15.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/svg/symbol/h16.svg b/svg/symbol/h16.svg deleted file mode 100644 index 12d35b7..0000000 --- a/svg/symbol/h16.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h17.svg b/svg/symbol/h17.svg deleted file mode 100644 index 26ab80e..0000000 --- a/svg/symbol/h17.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/svg/symbol/h18.svg b/svg/symbol/h18.svg deleted file mode 100644 index f1ba666..0000000 --- a/svg/symbol/h18.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h19.svg b/svg/symbol/h19.svg deleted file mode 100644 index 86733a4..0000000 --- a/svg/symbol/h19.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/svg/symbol/h2.svg b/svg/symbol/h2.svg deleted file mode 100644 index 031ad0d..0000000 --- a/svg/symbol/h2.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/svg/symbol/h20.svg b/svg/symbol/h20.svg deleted file mode 100644 index 9fd0e97..0000000 --- a/svg/symbol/h20.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/svg/symbol/h21.svg b/svg/symbol/h21.svg deleted file mode 100644 index 0f1fbe4..0000000 --- a/svg/symbol/h21.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/svg/symbol/h22.svg b/svg/symbol/h22.svg deleted file mode 100644 index 7c778b7..0000000 --- a/svg/symbol/h22.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/svg/symbol/h24.svg b/svg/symbol/h24.svg deleted file mode 100644 index 26962c3..0000000 --- a/svg/symbol/h24.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/svg/symbol/h25.svg b/svg/symbol/h25.svg deleted file mode 100644 index 5c8d5ed..0000000 --- a/svg/symbol/h25.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/svg/symbol/h26.svg b/svg/symbol/h26.svg deleted file mode 100644 index e89ae68..0000000 --- a/svg/symbol/h26.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/svg/symbol/h27.svg b/svg/symbol/h27.svg deleted file mode 100644 index 3db4de6..0000000 --- a/svg/symbol/h27.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/svg/symbol/h28.svg b/svg/symbol/h28.svg deleted file mode 100644 index 1e6e811..0000000 --- a/svg/symbol/h28.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/svg/symbol/h3.svg b/svg/symbol/h3.svg deleted file mode 100644 index 5b34529..0000000 --- a/svg/symbol/h3.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/svg/symbol/h4.svg b/svg/symbol/h4.svg deleted file mode 100644 index 44ae70b..0000000 --- a/svg/symbol/h4.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/svg/symbol/h5.svg b/svg/symbol/h5.svg deleted file mode 100644 index 4c95f8a..0000000 --- a/svg/symbol/h5.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h6.svg b/svg/symbol/h6.svg deleted file mode 100644 index 83d4875..0000000 --- a/svg/symbol/h6.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/svg/symbol/h7.svg b/svg/symbol/h7.svg deleted file mode 100644 index ac74451..0000000 --- a/svg/symbol/h7.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h8.svg b/svg/symbol/h8.svg deleted file mode 100644 index ab42c01..0000000 --- a/svg/symbol/h8.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/svg/symbol/h9.svg b/svg/symbol/h9.svg deleted file mode 100644 index e5baccd..0000000 --- a/svg/symbol/h9.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From 8b3a3a0d924bc14e5d2e41c3f723a3901cd2a59c Mon Sep 17 00:00:00 2001 From: axelw3 Date: Thu, 27 Feb 2025 22:28:51 +0100 Subject: [PATCH 07/12] Sortera alla JavaScript-filer under dist --- package.json | 11 +++++------ tsconfig.json | 2 +- utils/clean.js | 22 +++++++++++++++++----- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 72f9eda..3ac454c 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,13 @@ "name": "skyltrendering", "version": "1.0.0", "description": "", - "main": "dist/main.js", - "browser": "index.esm.js", + "main": "dist/node/main.js", + "browser": "dist/browser/index.esm.js", "scripts": { "clean": "node ./utils/clean.js ./dist/", - "install": "npm run build", - "build": "npm run clean && npm run build-node && npm run build-web", - "build-node": "tsc", - "build-web": "esbuild ./src/browser.ts --format=esm --bundle --outfile=./index.esm.js" + "build": "npm run clean && npm run build:node && npm run build:esm", + "build:node": "tsc", + "build:esm": "esbuild ./src/browser.ts --format=esm --bundle --outfile=./dist/browser/index.esm.js" }, "author": "axelw3", "license": "AGPL-3.0-or-later", diff --git a/tsconfig.json b/tsconfig.json index c0ca91a..1b75592 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ /* Emit */ "declaration": true, - "outDir": "./dist", + "outDir": "./dist/node", "removeComments": true, /* Interop Constraints */ diff --git a/utils/clean.js b/utils/clean.js index d56a47b..5f0cddb 100644 --- a/utils/clean.js +++ b/utils/clean.js @@ -6,12 +6,24 @@ fs.rmSync(path); } - process.argv.slice(2).map(x => { - let s = fs.statSync(x, {throwIfNoEntry: false}); - if(s === undefined) return; + function rmDirectory(path, rmSelf = true){ + fs.readdirSync(path, {recursive: false, withFileTypes: true}).map(y => { + if(y.isFile()){ + rmFile(path + y.name); + }else if(y.isDirectory()){ + rmDirectory(path + y.name + "/"); + } + }); + + if(!rmSelf) return; - if(s.isDirectory()){ - fs.readdirSync(x, {recursive: false, withFileTypes: true}).filter(y => y.isFile()).map(y => rmFile(x + y.name)); + console.log("rmdir " + path); + fs.rmdirSync(path); + } + + process.argv.slice(2).map(x => { + if(x.endsWith("/")){ + rmDirectory(x, false); }else{ rmFile(x); } From 2ef738f301819d97ae1962e005943e49746c1cd9 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Fri, 28 Feb 2025 18:06:44 +0100 Subject: [PATCH 08/12] =?UTF-8?q?Till=C3=A5t=20anpassade=20konfigurationer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser.ts | 14 +-- src/config.ts | 149 ------------------------ src/main.ts | 12 +- src/render.ts | 299 +++++++++++++++++++++++------------------------- src/typedefs.ts | 35 ++++-- 5 files changed, 178 insertions(+), 331 deletions(-) delete mode 100644 src/config.ts diff --git a/src/browser.ts b/src/browser.ts index 1e9aa8b..13a46ca 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -1,5 +1,5 @@ -import { SignElement as _SignElement } from "./render.js"; -import { SignElementBaseProperties, SignElementOptions, Vec6, NewDrawingArea } from "./typedefs.js"; +import { SignRenderer as _SignRenderer } from "./render.js"; +import { Vec6, NewDrawingArea } from "./typedefs.js"; class BrowserDrawingArea implements NewDrawingArea{ @@ -63,18 +63,12 @@ class BrowserDrawingArea implements NewDrawingArea{ } } -export class SignElement extends _SignElement{ - constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ - opt = _SignElement.resolveTemplate(opt); - super(opt, popt); - this.addCN(SignElement, opt); - } - +export class SignRenderer extends _SignRenderer{ protected override createCanvas(w?: number, h?: number): BrowserDrawingArea { return new BrowserDrawingArea(w, h); } - protected getText(url: string): Promise { + protected override getText(url: string): Promise { return new Promise(resolve => { let req = new XMLHttpRequest(); req.addEventListener("load", () => { diff --git a/src/config.ts b/src/config.ts deleted file mode 100644 index a54388a..0000000 --- a/src/config.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { ConfigData } from "./typedefs.js" - -const CONFIG: ConfigData = { - "properties": { - "globalDefaults": { "borderFeatures": {}, "borderWidth": 0, "padding": 0 }, - "rootDefaults": { "background": "#06a", "color": "white", "borderRadius": 8, "font": "sans-serif", "lineHeight": 46, "lineSpacing": 4, "fillCorners": true, "xSpacing": 8 }, - "defaults": { - ".": { "borderWidth": 4, "padding": 8 }, - "skylt": { "padding": 6, "blockDisplay": false, "passAnchor": false, "alignContentsV": "middle" }, - "vagnr": { "value": "000", "borderWidth": 3, "borderRadius": 7, "dashedInset": false, "padding": [14, 2] }, - "text": { "value": "Text" }, - "newline": {}, - "symbol": { "padding": 5, "type": "arrow-small", "grow": true } - } - }, - "signTypes": { - "junction": { - "width": 120, - "height": 240, - "core": [0.4, 0.6, 0.15, 0.44], - "nodes": { - "fwd": { "x": [0.2, 0.8], "y": [0, 0], "ay": "bottom" }, - "right": { "x": [1, 1], "y": [0.27, 0.27], "ax": "left" }, - "left": { "x": [0, 0], "y": [0.27, 0.27], "ax": "right" }, - "lright": { "x": [1, 1], "y": [0.434, 0.434], "ax": "left" } - } - }, - "roundabout": { - "width": 240, - "height": 480, - "core": [0.35, 0.75, 0.09, 0.35], - "nodes": { - "fwd": { "x": [0.5, 0.5], "y": [0.03, 0.03], "ay": "bottom" }, - "right": { "x": [0.9, 0.9], "y": [0.21, 0.21], "ax": "left" }, - "left": { "x": [0.1, 0.1], "y": [0.21, 0.21], "ax": "right" } - } - }, - "water": { - "width": 209, - "height": 19, - "core": [0, 1, 0, 1], - "nodes": { - "name": { "x": [0.5, 0.5], "y": [-0.1, -0.1], "ax": "center", "ay": "bottom" } - } - }, - "spanish": { - "width": 200, - "height": 360, - "core": [0.12, 0.78, 0, 0.65], - "nodes": { - "fwd": { "x": [0.08, 0.72], "y": [0, 0], "ay": "bottom" }, - "left": { "x": [0, 0], "y": [0.22, 0.22], "ax": "right" }, - "right": { "x": [1, 1], "y": [0.22, 0.22], "ax": "left" } - } - } - }, - "symbols": { - "arrow-small": { "width": 48, "height": [48, 192], "default": "left" }, - "exit": { "width": 46, "height": [26, 26] }, - "h1": { "width": 40, "height": [40, 40] }, - "h2": { "width": 40, "height": [40, 40] }, - "h3": { "width": 40, "height": [40, 40] }, - "h4": { "width": 40, "height": [40, 40], "default": "cng" }, - "h5": { "width": 40, "height": [40, 40] }, - "h6": { "width": 40, "height": [40, 40] }, - "h7": { "width": 40, "height": [40, 40] }, - "h8": { "width": 40, "height": [40, 40] }, - "h9": { "width": 40, "height": [40, 40] }, - "h10": { "width": 40, "height": [40, 40] }, - "h11": { "width": 40, "height": [40, 40] }, - "h12": { "width": 40, "height": [40, 40] }, - "h13": { "width": 40, "height": [40, 40] }, - "h14": { "width": 40, "height": [40, 40] }, - "h15": { "width": 40, "height": [40, 40] }, - "h16": { "width": 40, "height": [40, 40] }, - "h17": { "width": 40, "height": [40, 40] }, - "h18": { "width": 40, "height": [40, 40] }, - "h19": { "width": 40, "height": [40, 40] }, - "h20": { "width": 40, "height": [40, 40] }, - "h21": { "width": 40, "height": [40, 40] }, - "h22": { "width": 40, "height": [40, 40] }, - "h24": { "width": 40, "height": [40, 40] }, - "h25": { "width": 40, "height": [40, 40] }, - "h26": { "width": 40, "height": [40, 40] }, - "h27": { "width": 40, "height": [40, 40] }, - "h28": { "width": 40, "height": [40, 40] } - }, - "borderFeatures": { - "bracket": { "paths": [{ "p": "M-${bw/2},0H0L22,27L44,0H${bw/2+w}", "s": 1, "f": 2 }], "w": 44, "h": 27, "cover": false }, - "arrow": { "paths": [{ "p": "M0,0V${h}H${w}V0z", "f": -2, "s": -2 }, { "p": "M0,0L${w/2},${h*17/27}L${w},0z", "f": 2 }, { "p": "M0,-${bw/2}V0L${w/2},${h*17/27}L${w},0V-${bw/2}V0L${w/2},${h*25/27}L0,0z", "s": 1, "f": 1 }], "w": 0, "h": "w*27/44", "cover": true }, - "diag": { - "vars": [["k", "35/60"], ["x1", "1-(k/sqrt((k*k+1)))*bra"], ["xr", "1-(k/sqrt((k*k+1)))*brb"], ["a", "-2*brb+w+xr-x1*k+sqrt((2*bra-x1*x1))-sqrt((2*brb-xr*xr))"], ["margin", "30"]], - "paths": [ - { "p": "M0,0V${-k*x1+sqrt((2*bra-x1*x1))+margin}L${w},${-sqrt((k*k+1))-k+1*bw/2+h}V0z", "f": -2, "s": -2 }, - { "p": "M0,-${bw/2}V${margin}A${bra},${bra},0,0,0,${x1},${sqrt((2*bra-x1*x1))+margin}L${-2*brb+w+xr},${a+sqrt((2*brb-xr*xr))+margin}A${brb},${brb},0,0,0,${w},${a+margin}V-${bw/2}", "s": 1, "f": 2 }, - { "p": "M${w/2-43},0m5,0l-5,7l65,38l-8,14l29,-7l-10,-27l-8,12l-64,-36z", "f": 1 } - ], - "w": 0, - "h": "w-x1*k+sqrt((2*bra-x1*x1))+(sqrt((k*k+1))+k-1*bw/2)+margin", - "cover": true - } - }, - "templates": { - "avfart": (no = "1") => ({ - "type": "skylt", - "properties": { - "padding": 0, - "background": "#aaa", - "color": "black" - }, - "elements": [ - { - "type": "skylt", - "properties": { - "background": "#fd0", - "borderWidth": 4, - "borderRadius": 22, - "padding": [5, 0] - }, - "elements": [ - { - "type": "symbol", - "properties": { "type": "exit" } - }, - { - "type": "text", - "properties": { - "value": no - } - } - ] - } - ] - }), - "vagnr": (no = "000") => ({ - "type": "vagnr", - "properties": { - "value": no - } - }), - "symgroup": (...s: (string | string[])[]) => ({ - "type": "skylt", - "properties": {"padding": 0, "xSpacing": 0, "borderWidth": [3, 0, 0, 0], "borderRadius": 0, "color": "black", "background": "white"}, - "elements": s.map(x => ({"type": "symbol", "properties": {"type": Array.isArray(x) ? x[0] : x, "variant": Array.isArray(x) ? x[1] : undefined , "borderWidth": [0, 3, 3, 3], "padding": 1}})) - }) - } -} - -export default CONFIG; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 1181118..a74c6aa 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,5 @@ -import { SignElement as _SignElement } from "./render.js"; -import { SignElementBaseProperties, SignElementOptions, Vec6, NewDrawingArea, Path2D as _Path2D } from "./typedefs.js"; +import { SignRenderer as _SignRenderer } from "./render.js"; +import { Vec6, NewDrawingArea, Path2D as _Path2D } from "./typedefs.js"; import { createCanvas, Canvas, Path2D, SKRSContext2D } from "@napi-rs/canvas"; import { readFile } from "fs/promises" @@ -66,13 +66,7 @@ class NodeDrawingArea implements NewDrawingArea{ } -export class SignElement extends _SignElement{ - constructor(opt: SignElementOptions, popt: SignElementBaseProperties | null){ - opt = _SignElement.resolveTemplate(opt); - super(opt, popt); - this.addCN(SignElement, opt); - } - +export class SignRenderer extends _SignRenderer{ protected override createCanvas(w?: number, h?: number): NodeDrawingArea { return new NodeDrawingArea(w || 300, h || 150); } diff --git a/src/render.ts b/src/render.ts index 1bd9967..e8d2afd 100644 --- a/src/render.ts +++ b/src/render.ts @@ -1,27 +1,25 @@ -import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea, JSONVec, JSONVecReference } from "./typedefs.js" -import CONFIG from "./config.js"; +import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea, JSONVec, JSONVecReference, ConfigData, BorderFeatureDefinition, UserConfigData, PropertiesDefaults } from "./typedefs.js" import { roundedFill, roundedFrame } from "./graphics.js"; import { mathEval, parseVarStr } from "./utils.js"; -// Priority: -// 1. Specified value -// 2. Value from parent (if property is inherited) or DEFAULTS (if root) -// 3. Default value (from DEFAULT_PROPERTIES) -// 4. Global defaults (GLOBAL_DEFAULTS) - -const GLOBAL_DEFAULTS = CONFIG.properties.globalDefaults; -const DEFAULTS = CONFIG.properties.rootDefaults; -const DEFAULT_PROPERTIES = CONFIG.properties.defaults; - -const SKYLTTYPER = CONFIG.signTypes; -const SYMBOLER = CONFIG.symbols; - -// Samtliga designer sparas i "nedre kant"-form, dvs. -// i en orientering motsvarande klammern i skylt -// F9 (samlingsmärke för vägvisning). -const BORDER_FEATURES = CONFIG.borderFeatures; +const propertiesDefaults: PropertiesDefaults = { + "globalDefaults": { "borderFeatures": {}, "borderWidth": 0, "padding": 0 }, + "rootDefaults": { "background": "#06a", "color": "white", "borderRadius": 8, "font": "sans-serif", "lineHeight": 46, "lineSpacing": 4, "fillCorners": true, "xSpacing": 8 }, + "defaults": { + ".": { "borderWidth": 4, "padding": 8 }, + "skylt": { "padding": 6, "blockDisplay": false, "passAnchor": false, "alignContentsV": "middle" }, + "vagnr": { "value": "123", "borderWidth": 3, "borderRadius": 7, "dashedInset": false, "padding": [14, 2] }, + "text": { "value": "Text" }, + "newline": {}, + "symbol": { "padding": 5, "type": "default", "grow": true } + } +}; -const TEMPLATES = CONFIG.templates; +// Bestämning av värde på elementegenskaper görs enligt följande prioriteringsordning: +// 1. Specificerat värde +// 2. Värde från förälder (om egenskapen kan ärvas) eller från rootDefaults (endast rotelement) +// 3. Typspecifikt standardvärde (från defaults) +// 4. Globalt standardvärde (från globalDefaults) function to4EForm(data: number[] | number): Vec4{ if(!Array.isArray(data)) data = [ data, data ]; @@ -33,29 +31,26 @@ class BorderElement{ env: MathEnv; w: number; h: number; - n: string; - constructor(featureName: string, bw: number, brA: number, brB: number, sideLength: number){ - let w0 = BORDER_FEATURES[featureName].w, - cvr = !!BORDER_FEATURES[featureName].cover; + constructor(feature: BorderFeatureDefinition, bw: number, brA: number, brB: number, sideLength: number){ + let w0 = feature.w, + cvr = !!feature.cover; if(cvr) w0 = sideLength - bw; - this.env = BorderElement.calculateEnv(featureName, bw, brA, brB, w0); + this.env = BorderElement.calculateEnv(feature, bw, brA, brB, w0); - let h0 = mathEval(BORDER_FEATURES[featureName].h, this.env); + let h0 = mathEval(feature.h, this.env); this.env["h"] = h0; this.w = w0 + bw; this.h = h0 + bw; - this.n = featureName; } - static calculateEnv(featureName: string, bw: number, brA: number, brB: number, w0: number): MathEnv{ + static calculateEnv(feature: BorderFeatureDefinition, bw: number, brA: number, brB: number, w0: number): MathEnv{ let env: MathEnv = {bra: brA, brb: brB, bw: bw, w: w0}; - let feature = BORDER_FEATURES[featureName]; if(!Array.isArray(feature.vars)) return env; for(let i = 0; i < feature.vars.length; i++){ @@ -81,24 +76,25 @@ class BorderDimensions{ } } -export abstract class SignElement>{ +export abstract class SignRenderer>{ protected abstract createCanvas(w?: number, h?: number): T; protected abstract getText(url: string): Promise; - private static borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ - let bs = new BorderDimensions(properties.borderWidth); + private borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ + let bs = new BorderDimensions(properties.borderWidth), + bf = properties.borderFeatures; - if(properties.borderFeatures["left"] !== undefined) - bs.set(0, new BorderElement(properties.borderFeatures["left"], properties.borderWidth[0], properties.borderRadius[0], properties.borderRadius[3], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); + if(bf["left"] !== undefined) + bs.set(0, new BorderElement(this.conf.borderFeatures[bf["left"]], properties.borderWidth[0], properties.borderRadius[0], properties.borderRadius[3], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); - if(properties.borderFeatures["right"] !== undefined) - bs.set(2, new BorderElement(properties.borderFeatures["right"], properties.borderWidth[2], properties.borderRadius[2], properties.borderRadius[1], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); + if(bf["right"] !== undefined) + bs.set(2, new BorderElement(this.conf.borderFeatures[bf["right"]], properties.borderWidth[2], properties.borderRadius[2], properties.borderRadius[1], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); - if(properties.borderFeatures["top"] !== undefined) - bs.set(1, new BorderElement(properties.borderFeatures["top"], properties.borderWidth[1], properties.borderRadius[1], properties.borderRadius[0], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); + if(bf["top"] !== undefined) + bs.set(1, new BorderElement(this.conf.borderFeatures[bf["top"]], properties.borderWidth[1], properties.borderRadius[1], properties.borderRadius[0], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); - if(properties.borderFeatures["bottom"] !== undefined) - bs.set(3, new BorderElement(properties.borderFeatures["bottom"], properties.borderWidth[3], properties.borderRadius[3], properties.borderRadius[2], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); + if(bf["bottom"] !== undefined) + bs.set(3, new BorderElement(this.conf.borderFeatures[bf["bottom"]], properties.borderWidth[3], properties.borderRadius[3], properties.borderRadius[2], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); return bs; } @@ -115,17 +111,15 @@ export abstract class SignElement>{ } } - private renderBorderFeature(ctx: NewDrawingArea, x0: number, y0: number, featureName: string, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number){ - let color = this.properties.color, - background = this.properties.background; + private renderBorderFeature(ctx: NewDrawingArea, x0: number, y0: number, feature: BorderFeatureDefinition, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number, prop: SignElementProperties){ + let color = prop.color, + background = prop.background; let lr = (side === "left" || side === "right"); let bri = lr ? (side === "left" ? 0 : 2) : (side === "top" ? 1 : 3); - let bw = this.properties.borderWidth[bri]; - let s = [bs.el[bri]?.w || 0, bs.h[bri]]; - - let feature = BORDER_FEATURES[featureName]; + let bw = prop.borderWidth[bri]; + let s = [bs.el[bri]?.w ?? 0, bs.h[bri]]; let w = lr ? s[1] : s[0], h = lr ? s[0] : s[1]; @@ -168,12 +162,12 @@ export abstract class SignElement>{ if(path.f !== undefined){ ctx.fillStyle = [color, background][Math.abs(path.f)-1]; - if(path.f > 0 || this.properties.fillCorners) ctx.fill(p); + if(path.f > 0 || prop.fillCorners) ctx.fill(p); } if(path.s !== undefined){ ctx.strokeStyle = [color, background][Math.abs(path.s)-1]; - if(path.s > 0 || this.properties.fillCorners) ctx.stroke(p); + if(path.s > 0 || prop.fillCorners) ctx.stroke(p); } }); } @@ -193,7 +187,7 @@ export abstract class SignElement>{ let els: JSONVecReference[]; if(vecImgData.components !== undefined){ - els = vecImgData.core || []; + els = vecImgData.core ?? []; Object.entries(vecImgData.components).filter(e => components.includes(e[0])).forEach(e => els.push(...e[1])); }else{ els = vecImgData.defs.map(function(_: any, i: number): JSONVecReference{ @@ -204,7 +198,7 @@ export abstract class SignElement>{ els.forEach(el => { let def = vecImgData.defs[el.use]; - let tra = el.translate || [0, 0]; + let tra = el.translate ?? [0, 0]; [tm[4], tm[5]] = [tra[0] * xf, tra[1] * yf]; @@ -220,94 +214,85 @@ export abstract class SignElement>{ }); } - private type: string; - private properties: SignElementProperties; - private children: SignElement[]; - private nodes: {[key: string]: {signelement: SignElement, anchor: {x?: string, y?: string}}}; + private conf: ConfigData; - protected static resolveTemplate(data: SignElementOptions): SignElementOptions{ - while(data.type.startsWith("#")){ - let templateName = data.type.slice(1); - if(!TEMPLATES[templateName]){ + protected resolveTemplate(opt: SignElementOptions): SignElementOptions{ + while(opt.type.startsWith("#")){ + let templateName = opt.type.slice(1); + let templ = this.conf.templates[templateName]; + if(!templ){ alert("ERROR: Unknown template \"" + templateName + "\".") break; } - let template = TEMPLATES[templateName](...(data.params || [])); - template.properties = Object.assign(template.properties || {}, data.properties); - data = template; + let template = templ(...(opt.params ?? [])); + + Object.assign(template.properties ??= {}, opt.properties); + opt = template; } - return data; + return opt; + } + + protected constructor(config: UserConfigData){ + this.conf = { + properties: Object.assign({}, propertiesDefaults, config.properties), + signTypes: config.signTypes ?? {}, + symbols: config.symbols ?? {}, + borderFeatures: config.borderFeatures ?? {}, + templates: config.templates ?? {} + }; } - protected constructor(data: SignElementOptions, parentProperties: SignElementBaseProperties | null){ - this.type = data.type; + private static getInhProperties(prop: SignElementProperties): SignElementBaseProperties{ + const { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing } = prop; + return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; + } + + private _render(opt: SignElementOptions, parentProperties: SignElementBaseProperties | null): RenderingResult{ + let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] + + opt = this.resolveTemplate(opt); - let prop = Object.assign( + let prop: SignElementProperties = Object.assign( {}, - GLOBAL_DEFAULTS, - DEFAULT_PROPERTIES[data.type.startsWith(".") ? "." : data.type], - parentProperties === null ? DEFAULTS : parentProperties, - data.properties + this.conf.properties.globalDefaults, + this.conf.properties.defaults[opt.type.startsWith(".") ? "." : opt.type], + parentProperties === null ? this.conf.properties.rootDefaults : parentProperties, + opt.properties ); - this.properties = Object.assign(prop, { + Object.assign(prop, { padding: to4EForm(prop.padding), borderRadius: to4EForm(prop.borderRadius), borderWidth: to4EForm(prop.borderWidth) }); - this.children = []; - this.nodes = {}; - } - - protected addCN>(Cl: new (opt: any, inh: SignElementBaseProperties | null) => X, data: SignElementOptions){ - let inh = this.getInhProperties(); - - this.children = (data.elements || []).map(element => new Cl(element, inh)); - - Object.entries(data.nodes || {}).forEach(e => { - this.nodes[e[0]] = { - signelement: new Cl(e[1].data, inh), - anchor: e[1].anchor - } - }); - } - - private getInhProperties(): SignElementBaseProperties{ - const { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing } = this.properties; - return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; - } - - private _render(): RenderingResult{ - let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] - - let padding = Array.from(this.properties.padding); + let padding = Array.from(prop.padding); let width = 0, height = 0, maxHeight = 0; let renderPromise: (ctx: T, x0: number, y0: number, maxInnerHeight: number) => Promise = () => Promise.resolve(); - if(this.type === "skylt"){ + if(opt.type === "skylt"){ let w = [0], h = [0], j = 0; let totalLineSpacing = 0; - let ch = this.children.map((c, i) => { - let re = c._render(); - let c2 = { isn: c.type === "newline", r: re, bs: re.bs, row: j, x: 0 }; + let ch = (opt.elements ?? []).map((c, i) => { + let re = this._render(c, SignRenderer.getInhProperties(prop)); + let c2 = { isn: c.type === "newline", r: re, bs: re.bs, row: j, x: 0, p: c.properties }; - if(c2.isn || (i > 0 && this.properties.blockDisplay)){ + if(c2.isn || (i > 0 && prop.blockDisplay)){ c2.row = ++j; w.push(0); h.push(0); - totalLineSpacing += (this.properties.blockDisplay ? this.properties.lineSpacing : c.properties.lineSpacing); + totalLineSpacing += (prop.blockDisplay ? prop.lineSpacing : prop.lineSpacing); } if(!c2.isn){ if(w[j] > 0){ - w[j] += this.properties.xSpacing; + w[j] += prop.xSpacing; } c2.x = w[j]; @@ -324,8 +309,8 @@ export abstract class SignElement>{ height = h.reduce((a, b) => a + b, totalLineSpacing); ch = ch.map(c2 => { - if(!c2.isn && !this.properties.blockDisplay){ - c2.x += SignElement.calculateAlignmentOffset(this.properties.alignContents, w[c2.row], width); + if(!c2.isn && !prop.blockDisplay){ + c2.x += SignRenderer.calculateAlignmentOffset(prop.alignContents, w[c2.row], width); } return c2; @@ -340,7 +325,7 @@ export abstract class SignElement>{ height + padding[1] ]; - if(this.properties.passAnchor){ + if(prop.passAnchor){ firstLastCenter[0] += ch[0].r.flc[0]; firstLastCenter[1] += ch[0].bs[1] + ch[0].r.flc[1]; firstLastCenter[2] += ch[ch.length - 1].r.flc[2]; @@ -355,17 +340,17 @@ export abstract class SignElement>{ let y = 0; renderPromise = (ctx, x0, y0, _) => Promise.all(ch.map((c2, i) => { - if(c2.isn || (i > 0 && this.properties.blockDisplay)){ - y += (this.properties.blockDisplay ? this.properties.lineSpacing : this.children[i].properties.lineSpacing); + if(c2.isn || (i > 0 && prop.blockDisplay)){ + y += (prop.blockDisplay ? prop.lineSpacing : (c2.p?.lineSpacing ?? prop.lineSpacing)); y += h[c2.row - 1]; } if(c2.isn) return; - let dx = 0, iw = this.properties.blockDisplay ? (width - c2.bs[0] - c2.bs[2]) : c2.r.w; + let dx = 0, iw = prop.blockDisplay ? (width - c2.bs[0] - c2.bs[2]) : c2.r.w; - if(this.properties.blockDisplay){ - dx += SignElement.calculateAlignmentOffset(this.children[i].properties.alignContents, w[c2.row], iw + c2.bs[0] + c2.bs[2]); + if(prop.blockDisplay){ + dx += SignRenderer.calculateAlignmentOffset(c2.p?.alignContents, w[c2.row], iw + c2.bs[0] + c2.bs[2]); } return c2.r.doRender( @@ -373,61 +358,62 @@ export abstract class SignElement>{ x0 + padding[0] + c2.x, y0 + padding[1] + y, dx, h[c2.row] - c2.bs[1] - c2.bs[3], - this.properties.alignContentsV, + prop.alignContentsV, iw ); })).then(() => {}); - }else if(this.type === "vagnr" || this.type === "text"){ + }else if(opt.type === "vagnr" || opt.type === "text"){ let ctx_temp = this.createCanvas(); - ctx_temp.font = "32px " + this.properties.font; + ctx_temp.font = "32px " + prop.font; - width = Math.floor(ctx_temp.measureText(this.properties.value || "").width); - height = this.properties.lineHeight; + width = Math.floor(ctx_temp.measureText(prop.value ?? "").width); + height = prop.lineHeight; renderPromise = (ctx, x0, y0, _) => new Promise(res => { - if(this.properties.dashedInset){ - let bw = this.properties.borderWidth; + if(prop.dashedInset){ + let bw = prop.borderWidth; roundedFrame( ctx, x0 + 2*bw[0], y0 + 2*bw[1], width + padding[0] + padding[2] - 2*bw[0] - 2*bw[2], height + padding[1] + padding[3] - 2*bw[1] - 2*bw[3], bw, - this.properties.color, - this.properties.borderRadius, + prop.color, + prop.borderRadius, [10, 10] ); } - ctx.font = "32px " + this.properties.font; + ctx.font = "32px " + prop.font; ctx.textBaseline = "middle"; - ctx.fillStyle = this.properties.color; - ctx.fillText(this.properties.value || "", x0 + padding[0], y0 + firstLastCenter[1]); + ctx.fillStyle = prop.color; + ctx.fillText(prop.value ?? "", x0 + padding[0], y0 + firstLastCenter[1]); res(); }); - }else if(this.type === "symbol"){ - let symbolType = SYMBOLER[this.properties.type || ""]; + }else if(opt.type === "symbol"){ + let symbolType = this.conf.symbols[prop.type ?? ""]; width = symbolType.width; [height, maxHeight] = symbolType.height; - let url = "res/symbol/" + (this.properties.type || "") + ".json"; - let v: string | undefined = this.properties.variant || symbolType.default; + let url = "res/symbol/" + (prop.type ?? "default") + ".json"; + let v: string | undefined = prop.variant ?? symbolType.default; renderPromise = (ctx, x0, y0, maxInnerHeight) => this.drawVec( - ctx, url, this.properties.color, v === undefined ? [] : [v], + ctx, url, prop.color, v === undefined ? [] : [v], x0 + padding[0], y0 + padding[1], // dx, dy width, maxInnerHeight - padding[1] - padding[3] // dw=sw, dh=sh ); - }else if(this.type === "newline"){ + }else if(opt.type === "newline"){ width = 0; height = 0; - }else if(this.type.startsWith(".")){ - let t = SKYLTTYPER[this.type.slice(1)]; - let keys = Object.keys(t.nodes).sort().filter(nodeName => !!this.nodes[nodeName]); + }else if(opt.type.startsWith(".") && opt.nodes !== undefined){ + let nodes = opt.nodes; + let t = this.conf.signTypes[opt.type.slice(1)]; + let keys = Object.keys(t.nodes).sort().filter(nodeName => !!nodes[nodeName]); let svgBox = Array.from(t.core); keys.forEach(nodeName => { @@ -446,14 +432,15 @@ export abstract class SignElement>{ // fonts and svg loaded successfully let r = keys.map(nodeName => { - let n = this.nodes[nodeName]; - let s = n.signelement; + let n = nodes[nodeName]; + let s = n.data; let tn = t.nodes[nodeName]; - n.anchor = Object.assign({ "x": tn.ax, "y": tn.ay }, n.anchor); + let ax = n.anchor.x ?? tn.ax, + ay = n.anchor.y ?? tn.ay; - let result = s._render(); + let result = this._render(s, SignRenderer.getInhProperties(prop)); let bs = result.bs; let rse = [ result.w + bs[0] + bs[2], result.h + bs[1] + bs[3] ]; @@ -461,7 +448,7 @@ export abstract class SignElement>{ let lx = tn.x.map(x => x * t.width).map(Math.floor), ty = tn.y.map(y => y * t.height).map(Math.floor); let leftX: number = 0, topY: number = 0; - switch(n.anchor.x){ + switch(ax){ case "right": leftX = lx[1] - rse[0]; break; @@ -478,7 +465,7 @@ export abstract class SignElement>{ leftX = lx[0]; } - switch(n.anchor.y){ + switch(ay){ case "bottom": topY = ty[1] - rse[1]; break; @@ -514,7 +501,7 @@ export abstract class SignElement>{ let dx = 0; - return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.renderPromise.h, this.properties.alignContentsV); + return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.renderPromise.h, prop.alignContentsV); })).then(() => { if(t.width === 0 || t.height === 0) return; @@ -531,9 +518,9 @@ export abstract class SignElement>{ ]; // [x0, y0, w, h] return this.drawVec( - ctx, "res/" + this.type.slice(1) + ".json", this.properties.color, keys, - x0 + this.properties.padding[0] - boundingBox[0] + crop[0], // dx - y0 + this.properties.padding[1] - boundingBox[2] + crop[1], // dy + ctx, "res/" + opt.type.slice(1) + ".json", prop.color, keys, + x0 + prop.padding[0] - boundingBox[0] + crop[0], // dx + y0 + prop.padding[1] - boundingBox[2] + crop[1], // dy crop[2], crop[3], // dw=sw, dh=sh crop[0], crop[1] // sx, sy ); @@ -542,7 +529,7 @@ export abstract class SignElement>{ alert("Fel!"); } - let bs = SignElement.borderSize(width + padding[0] + padding[2], height + padding[1] + padding[3], this.properties); + let bs = this.borderSize(width + padding[0] + padding[2], height + padding[1] + padding[3], prop); if(firstLastCenter.some(isNaN)){ firstLastCenter = [ @@ -565,7 +552,7 @@ export abstract class SignElement>{ const innerWidth = iw === 0 ? (width + padding[0] + padding[2]) : iw; let innerHeight = height + padding[1] + padding[3]; - if(this.properties.grow && innerHeight < maxInnerHeight){ + if(prop.grow && innerHeight < maxInnerHeight){ innerHeight = Math.min(maxInnerHeight, padding[1] + padding[3] + maxHeight); } @@ -580,12 +567,12 @@ export abstract class SignElement>{ // tag bort rundade hörn på sidor med hela kantutsmyckningar let bfs = ["left", "top", "right", "bottom"].map(s => { - let bf = this.properties.borderFeatures[s]; - return bf !== undefined && BORDER_FEATURES[bf].cover; // cover => hel, täcker hela kantens längd + let bf = prop.borderFeatures[s]; + return bf !== undefined && this.conf.borderFeatures[bf].cover; // cover => hel, täcker hela kantens längd }); - let br: Vec4 = [...this.properties.borderRadius], - bw: Vec4 = [...this.properties.borderWidth]; + let br: Vec4 = [...prop.borderRadius], + bw: Vec4 = [...prop.borderWidth]; for(let i = 0; i < 4; i++){ if(bfs[i] || bfs[(i + 1) % 4]) br[i] = 0; @@ -598,8 +585,8 @@ export abstract class SignElement>{ innerWidth, innerHeight, bw, br, - this.properties.background, - !!this.properties.fillCorners + prop.background, + !!prop.fillCorners ); await renderPromise(ctx, x0 + dx + bs.h[0], y0 + dy + bs.h[1], innerHeight); @@ -609,19 +596,19 @@ export abstract class SignElement>{ x0 + bs.h[0], y0 + bs.h[1], innerWidth, innerHeight, bw, - this.properties.color, + prop.color, br ); - Object.entries(this.properties.borderFeatures).forEach(feature => { - this.renderBorderFeature(ctx, x0, y0, feature[1], feature[0], bs, innerWidth, innerHeight); + Object.entries(prop.borderFeatures).forEach(feature => { + this.renderBorderFeature(ctx, x0, y0, this.conf.borderFeatures[feature[1]], feature[0], bs, innerWidth, innerHeight, prop); }); } }; } - public async render(): Promise{ - let r = this._render(); + public async render(data: SignElementOptions): Promise{ + let r = this._render(data, null); let bs = r.bs; let canv = this.createCanvas(r.w + bs[0] + bs[2], r.h + bs[1] + bs[3]); diff --git a/src/typedefs.ts b/src/typedefs.ts index 300910b..f17e37b 100644 --- a/src/typedefs.ts +++ b/src/typedefs.ts @@ -4,7 +4,12 @@ export type Vec2 = [number, number]; export type Vec4 = [number, number, number, number]; export type Vec6 = [number, number, number, number, number, number]; -type BorderFeatureDefinition = { +/** + * Designer sparas i "nedre kant"-form, dvs. + * orienterade på motsvarande sätt som klammern + * i skylt F9 (samlingsmärke för vägvisning). + */ +export type BorderFeatureDefinition = { vars?: string[][]; paths: {p: string, f?: number, s?: number}[]; w: number; @@ -76,7 +81,10 @@ export interface SignElementProperties extends SignElementBaseProperties, SignEl padding: Vec4; }; -export type SignElementAnchor = { x: string; } | { y: string; }; +type SignElementAnchor = { + x?: string; + y?: string; +}; type SignElementNode = { anchor: SignElementAnchor; @@ -93,26 +101,39 @@ export type SignElementOptions = { params?: any[]; } +export type PropertiesDefaults = { + globalDefaults: SignElementUserProperties & SignElementRequiredProperties; + rootDefaults: SignElementBaseProperties & SignElementUserProperties; + defaults: {[key: string]: SignElementUserProperties}; +}; + export type ConfigData = { - properties: { - globalDefaults: SignElementUserProperties & SignElementRequiredProperties; - rootDefaults: SignElementBaseProperties & SignElementUserProperties; - defaults: {[key: string]: SignElementUserProperties}; - }, + // Olika standardegenskaper + properties: PropertiesDefaults, + + // Skylttyper ("symboler med noder") signTypes: { [key: string]: SignTypeDefinition; }, + + // Symboldefinitioner symbols: { [key: string]: SignSymbolDefinition; }, + + // Kantdekorationer borderFeatures: { [key: string]: BorderFeatureDefinition; }, + + // "Dynamiska" mallar (funktioner "parametrar => skyltkonfiguration") templates: { [key: string]: (...args: any[]) => SignElementOptions; } }; +export type UserConfigData = Partial; + export type RenderingResult> = { flc: Vec4; w: number; From 421246688324952c5dd4cd2ad4c393f52bfd8c35 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Fri, 28 Feb 2025 19:02:30 +0100 Subject: [PATCH 09/12] Sortera skyltrendering som ett eget paket --- .gitignore | 7 +++---- .../skyltrendering/package-lock.json | 0 package.json => packages/skyltrendering/package.json | 1 + {src => packages/skyltrendering/src}/browser.ts | 0 {src => packages/skyltrendering/src}/graphics.ts | 0 {src => packages/skyltrendering/src}/main.ts | 0 {src => packages/skyltrendering/src}/render.ts | 0 {src => packages/skyltrendering/src}/typedefs.ts | 0 {src => packages/skyltrendering/src}/utils.ts | 0 tsconfig.json => packages/skyltrendering/tsconfig.json | 0 {utils => packages/skyltrendering/utils}/clean.js | 1 + 11 files changed, 5 insertions(+), 4 deletions(-) rename package-lock.json => packages/skyltrendering/package-lock.json (100%) rename package.json => packages/skyltrendering/package.json (95%) rename {src => packages/skyltrendering/src}/browser.ts (100%) rename {src => packages/skyltrendering/src}/graphics.ts (100%) rename {src => packages/skyltrendering/src}/main.ts (100%) rename {src => packages/skyltrendering/src}/render.ts (100%) rename {src => packages/skyltrendering/src}/typedefs.ts (100%) rename {src => packages/skyltrendering/src}/utils.ts (100%) rename tsconfig.json => packages/skyltrendering/tsconfig.json (100%) rename {utils => packages/skyltrendering/utils}/clean.js (95%) diff --git a/.gitignore b/.gitignore index 9af227b..384c1d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/dist/ -/node_modules/ -*.tsbuildinfo -/index*.js \ No newline at end of file +dist/ +node_modules/ +*.tsbuildinfo \ No newline at end of file diff --git a/package-lock.json b/packages/skyltrendering/package-lock.json similarity index 100% rename from package-lock.json rename to packages/skyltrendering/package-lock.json diff --git a/package.json b/packages/skyltrendering/package.json similarity index 95% rename from package.json rename to packages/skyltrendering/package.json index 3ac454c..fb85a36 100644 --- a/package.json +++ b/packages/skyltrendering/package.json @@ -6,6 +6,7 @@ "browser": "dist/browser/index.esm.js", "scripts": { "clean": "node ./utils/clean.js ./dist/", + "install": "npm run build", "build": "npm run clean && npm run build:node && npm run build:esm", "build:node": "tsc", "build:esm": "esbuild ./src/browser.ts --format=esm --bundle --outfile=./dist/browser/index.esm.js" diff --git a/src/browser.ts b/packages/skyltrendering/src/browser.ts similarity index 100% rename from src/browser.ts rename to packages/skyltrendering/src/browser.ts diff --git a/src/graphics.ts b/packages/skyltrendering/src/graphics.ts similarity index 100% rename from src/graphics.ts rename to packages/skyltrendering/src/graphics.ts diff --git a/src/main.ts b/packages/skyltrendering/src/main.ts similarity index 100% rename from src/main.ts rename to packages/skyltrendering/src/main.ts diff --git a/src/render.ts b/packages/skyltrendering/src/render.ts similarity index 100% rename from src/render.ts rename to packages/skyltrendering/src/render.ts diff --git a/src/typedefs.ts b/packages/skyltrendering/src/typedefs.ts similarity index 100% rename from src/typedefs.ts rename to packages/skyltrendering/src/typedefs.ts diff --git a/src/utils.ts b/packages/skyltrendering/src/utils.ts similarity index 100% rename from src/utils.ts rename to packages/skyltrendering/src/utils.ts diff --git a/tsconfig.json b/packages/skyltrendering/tsconfig.json similarity index 100% rename from tsconfig.json rename to packages/skyltrendering/tsconfig.json diff --git a/utils/clean.js b/packages/skyltrendering/utils/clean.js similarity index 95% rename from utils/clean.js rename to packages/skyltrendering/utils/clean.js index 5f0cddb..e60b971 100644 --- a/utils/clean.js +++ b/packages/skyltrendering/utils/clean.js @@ -22,6 +22,7 @@ } process.argv.slice(2).map(x => { + if(!fs.existsSync(x)) return; if(x.endsWith("/")){ rmDirectory(x, false); }else{ From 7214ae63f040f15ce1378df52fd9a3f68897fc0d Mon Sep 17 00:00:00 2001 From: axelw3 Date: Fri, 28 Feb 2025 21:33:28 +0100 Subject: [PATCH 10/12] =?UTF-8?q?Nytt=20webbgr=C3=A4nssnitt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- font/TRATEXPOSVERSAL-POSVERSAL.otf | Bin 0 -> 11424 bytes font/TratexSvart-Regular.otf | Bin 0 -> 18044 bytes package-lock.json | 39 ++++++ package.json | 14 +++ packages/skyltrendering/src/render.ts | 6 +- packages/skyltrendering/src/typedefs.ts | 2 +- public/css/styles.css | 45 +++++++ public/index.html | 59 ++++++++++ public/render.html | 10 ++ src/config.ts | 133 +++++++++++++++++++++ src/render.ts | 26 ++++ templates.json | 150 ++++++++++++++++++++++++ tsconfig.json | 36 ++++++ 13 files changed, 516 insertions(+), 4 deletions(-) create mode 100644 font/TRATEXPOSVERSAL-POSVERSAL.otf create mode 100644 font/TratexSvart-Regular.otf create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/css/styles.css create mode 100644 public/index.html create mode 100644 public/render.html create mode 100644 src/config.ts create mode 100644 src/render.ts create mode 100644 templates.json create mode 100644 tsconfig.json diff --git a/font/TRATEXPOSVERSAL-POSVERSAL.otf b/font/TRATEXPOSVERSAL-POSVERSAL.otf new file mode 100644 index 0000000000000000000000000000000000000000..60762aa2594096c98e87fd3b47e03b755fa00934 GIT binary patch literal 11424 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 RzjHu;L}7y9r8f$~{{vk0$Xoyb literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f0f3132 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,39 @@ +{ + "name": "skyltprogram", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "skyltprogram", + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "ncp": "^2.0.0", + "typescript": "^5.8.2" + } + }, + "node_modules/ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", + "dev": true, + "bin": { + "ncp": "bin/ncp" + } + }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3bf4d56 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "skyltprogram", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "tsc && ncp public/ dist/" + }, + "author": "axelw3", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "ncp": "^2.0.0", + "typescript": "^5.8.2" + } +} diff --git a/packages/skyltrendering/src/render.ts b/packages/skyltrendering/src/render.ts index e8d2afd..e75a5ad 100644 --- a/packages/skyltrendering/src/render.ts +++ b/packages/skyltrendering/src/render.ts @@ -234,7 +234,7 @@ export abstract class SignRenderer>{ return opt; } - protected constructor(config: UserConfigData){ + public constructor(config: UserConfigData){ this.conf = { properties: Object.assign({}, propertiesDefaults, config.properties), signTypes: config.signTypes ?? {}, @@ -437,8 +437,8 @@ export abstract class SignRenderer>{ let tn = t.nodes[nodeName]; - let ax = n.anchor.x ?? tn.ax, - ay = n.anchor.y ?? tn.ay; + let ax = n.anchor?.x ?? tn.ax, + ay = n.anchor?.y ?? tn.ay; let result = this._render(s, SignRenderer.getInhProperties(prop)); let bs = result.bs; diff --git a/packages/skyltrendering/src/typedefs.ts b/packages/skyltrendering/src/typedefs.ts index f17e37b..7e724a0 100644 --- a/packages/skyltrendering/src/typedefs.ts +++ b/packages/skyltrendering/src/typedefs.ts @@ -87,7 +87,7 @@ type SignElementAnchor = { }; type SignElementNode = { - anchor: SignElementAnchor; + anchor?: SignElementAnchor; data: SignElementOptions; }; diff --git a/public/css/styles.css b/public/css/styles.css new file mode 100644 index 0000000..a141d91 --- /dev/null +++ b/public/css/styles.css @@ -0,0 +1,45 @@ +body, html{ + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; +} + +#left, #right{ + width: 50%; + height: 100%; + float: left; +} + +#input{ + outline: none; + height: calc(100% - 4px); + width: calc(100% - 4px); + padding: 2px; + margin: 0; +} + +#render{ + height: 100%; + width: 100%; +} + +#input, #render{ + border: 0; + resize: none; +} + +#header, #main{ + width: 100%; + float: left; +} + +#header{ + height: 24px; + background: #eee; +} + +#main{ + height: calc(100% - 24px); +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..310d328 --- /dev/null +++ b/public/index.html @@ -0,0 +1,59 @@ + + + + Skyltprogram + + + + + +
+
+ +
+ + + \ No newline at end of file diff --git a/public/render.html b/public/render.html new file mode 100644 index 0000000..f628844 --- /dev/null +++ b/public/render.html @@ -0,0 +1,10 @@ + + + + Skyltprogram (rendering) + + + + + + \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..38d79d9 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,133 @@ +export default { + "signTypes": { + "junction": { + "width": 120, + "height": 240, + "core": [0.4, 0.6, 0.15, 0.44], + "nodes": { + "fwd": { "x": [0.2, 0.8], "y": [0, 0], "ay": "bottom" }, + "right": { "x": [1, 1], "y": [0.27, 0.27], "ax": "left" }, + "left": { "x": [0, 0], "y": [0.27, 0.27], "ax": "right" }, + "lright": { "x": [1, 1], "y": [0.434, 0.434], "ax": "left" } + } + }, + "roundabout": { + "width": 240, + "height": 480, + "core": [0.35, 0.75, 0.09, 0.35], + "nodes": { + "fwd": { "x": [0.5, 0.5], "y": [0.03, 0.03], "ay": "bottom" }, + "right": { "x": [0.9, 0.9], "y": [0.21, 0.21], "ax": "left" }, + "left": { "x": [0.1, 0.1], "y": [0.21, 0.21], "ax": "right" } + } + }, + "water": { + "width": 209, + "height": 19, + "core": [0, 1, 0, 1], + "nodes": { + "name": { "x": [0.5, 0.5], "y": [-0.1, -0.1], "ax": "center", "ay": "bottom" } + } + }, + "spanish": { + "width": 200, + "height": 360, + "core": [0.12, 0.78, 0, 0.65], + "nodes": { + "fwd": { "x": [0.08, 0.72], "y": [0, 0], "ay": "bottom" }, + "left": { "x": [0, 0], "y": [0.22, 0.22], "ax": "right" }, + "right": { "x": [1, 1], "y": [0.22, 0.22], "ax": "left" } + } + } + }, + "symbols": { + "arrow-small": { "width": 48, "height": [48, 192], "default": "left" }, + "exit": { "width": 46, "height": [26, 26] }, + "h1": { "width": 40, "height": [40, 40] }, + "h2": { "width": 40, "height": [40, 40] }, + "h3": { "width": 40, "height": [40, 40] }, + "h4": { "width": 40, "height": [40, 40], "default": "cng" }, + "h5": { "width": 40, "height": [40, 40] }, + "h6": { "width": 40, "height": [40, 40] }, + "h7": { "width": 40, "height": [40, 40] }, + "h8": { "width": 40, "height": [40, 40] }, + "h9": { "width": 40, "height": [40, 40] }, + "h10": { "width": 40, "height": [40, 40] }, + "h11": { "width": 40, "height": [40, 40] }, + "h12": { "width": 40, "height": [40, 40] }, + "h13": { "width": 40, "height": [40, 40] }, + "h14": { "width": 40, "height": [40, 40] }, + "h15": { "width": 40, "height": [40, 40] }, + "h16": { "width": 40, "height": [40, 40] }, + "h17": { "width": 40, "height": [40, 40] }, + "h18": { "width": 40, "height": [40, 40] }, + "h19": { "width": 40, "height": [40, 40] }, + "h20": { "width": 40, "height": [40, 40] }, + "h21": { "width": 40, "height": [40, 40] }, + "h22": { "width": 40, "height": [40, 40] }, + "h24": { "width": 40, "height": [40, 40] }, + "h25": { "width": 40, "height": [40, 40] }, + "h26": { "width": 40, "height": [40, 40] }, + "h27": { "width": 40, "height": [40, 40] }, + "h28": { "width": 40, "height": [40, 40] } + }, + "borderFeatures": { + "bracket": { "paths": [{ "p": "M-${bw/2},0H0L22,27L44,0H${bw/2+w}", "s": 1, "f": 2 }], "w": 44, "h": 27, "cover": false }, + "arrow": { "paths": [{ "p": "M0,0V${h}H${w}V0z", "f": -2, "s": -2 }, { "p": "M0,0L${w/2},${h*17/27}L${w},0z", "f": 2 }, { "p": "M0,-${bw/2}V0L${w/2},${h*17/27}L${w},0V-${bw/2}V0L${w/2},${h*25/27}L0,0z", "s": 1, "f": 1 }], "w": 0, "h": "w*27/44", "cover": true }, + "diag": { + "vars": [["k", "35/60"], ["x1", "1-(k/sqrt((k*k+1)))*bra"], ["xr", "1-(k/sqrt((k*k+1)))*brb"], ["a", "-2*brb+w+xr-x1*k+sqrt((2*bra-x1*x1))-sqrt((2*brb-xr*xr))"], ["margin", "30"]], + "paths": [ + { "p": "M0,0V${-k*x1+sqrt((2*bra-x1*x1))+margin}L${w},${-sqrt((k*k+1))-k+1*bw/2+h}V0z", "f": -2, "s": -2 }, + { "p": "M0,-${bw/2}V${margin}A${bra},${bra},0,0,0,${x1},${sqrt((2*bra-x1*x1))+margin}L${-2*brb+w+xr},${a+sqrt((2*brb-xr*xr))+margin}A${brb},${brb},0,0,0,${w},${a+margin}V-${bw/2}", "s": 1, "f": 2 }, + { "p": "M${w/2-43},0m5,0l-5,7l65,38l-8,14l29,-7l-10,-27l-8,12l-64,-36z", "f": 1 } + ], + "w": 0, + "h": "w-x1*k+sqrt((2*bra-x1*x1))+(sqrt((k*k+1))+k-1*bw/2)+margin", + "cover": true + } + }, + "templates": { + "avfart": (no = "1") => ({ + "type": "skylt", + "properties": { + "padding": 0, + "background": "#aaa", + "color": "black" + }, + "elements": [ + { + "type": "skylt", + "properties": { + "background": "#fd0", + "borderWidth": 4, + "borderRadius": 22, + "padding": [5, 0] + }, + "elements": [ + { + "type": "symbol", + "properties": { "type": "exit" } + }, + { + "type": "text", + "properties": { + "value": no + } + } + ] + } + ] + }), + "vagnr": (no = "000") => ({ + "type": "vagnr", + "properties": { + "value": no + } + }), + "symgroup": (...s: (string | string[])[]) => ({ + "type": "skylt", + "properties": {"padding": 0, "xSpacing": 0, "borderWidth": [3, 0, 0, 0], "borderRadius": 0, "color": "black", "background": "white"}, + "elements": s.map(x => ({"type": "symbol", "properties": {"type": Array.isArray(x) ? x[0] : x, "variant": Array.isArray(x) ? x[1] : undefined , "borderWidth": [0, 3, 3, 3], "padding": 1}})) + }) + } +}; \ No newline at end of file diff --git a/src/render.ts b/src/render.ts new file mode 100644 index 0000000..c5b4529 --- /dev/null +++ b/src/render.ts @@ -0,0 +1,26 @@ +import { SignRenderer } from "../packages/skyltrendering/src/browser.js"; +import CONFIG from "./config.js" + +const tratex = new FontFace( + "Tratex", + "url(font/TratexSvart-Regular.otf)", +); + +const tratexVersal = new FontFace( + "TratexVersal", + "url(font/TRATEXPOSVERSAL-POSVERSAL.otf)", +); + +document.fonts.add(tratex); +document.fonts.add(tratexVersal); + +Promise.all([tratex.load(), tratexVersal.load()]).then(() => { + let url = new URL(window.location.href); + if(!url.searchParams.has("data")) return; + + let data = JSON.parse(url.searchParams.get("data") || ""); + + new SignRenderer(CONFIG).render(data).then((canv: HTMLCanvasElement) => { + document.body.appendChild(canv); + }); +}); \ No newline at end of file diff --git a/templates.json b/templates.json new file mode 100644 index 0000000..a36ad9e --- /dev/null +++ b/templates.json @@ -0,0 +1,150 @@ +[ + { + "name": "F1-1. Orienteringstavla, enkelt exempel", + "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"center-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"vagnr","properties":{"value":"40"}},{"type":"text","properties":{"value":"JÖNKÖPING"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"text","properties":{"value":"HALMSTAD"}},{"type":"newline"},{"type":"text","properties":{"value":"GISLAVED"}}]}}}} + }, + { + "name": "F1-1. Orienteringstavla, exempel", + "json": {"type": ".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"text","properties":{"value":"OSLO"}},{"type":"newline"},{"type":"vagnr","properties":{"value":"66"}},{"type":"text","properties":{"value":"SÄLEN"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"text","properties":{"value":"GÄVLE"}},{"type":"newline"},{"type":"text","properties":{"value":"BORLÄNGE"}}]}}}} + }, + { + "name": "F1-1. Orienteringstavla, mer invecklat exempel", + "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"vagnr","properties":{"value":"26"}},{"type":"vagnr","properties":{"value":"40"}},{"type":"text","properties":{"value":"JÖNKÖPING"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"borderWidth":3,"background":"#097"},"elements":[{"type":"vagnr","properties":{"value":"26","background":"#06a"}},{"type":"text","properties":{"value":"HALMSTAD"}},{"type":"newline"},{"type":"text","properties":{"value":"GISLAVED"}},{"type":"newline"},{"type":"text","properties":{"value":"Sjukhus","font":"\"Tratex\"","color":"black","background":"white"}}]}}}} + }, + { + "name": "F1-1. Orienteringstavla, Transportstyrelsens exempel", + "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"left"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]}},"right":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"LINDESBERG"}}]}}}} + }, + { + "name": "F1-1. Orienteringstavla, exempel med pilar i olika höjd", + "json": {"type":".junction","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"center"},"data":{"type":"skylt","properties":{"xSpacing":0},"elements":[{"type":"vagnr","properties":{"value":"E16","background":"#097"}},{"type":"vagnr","properties":{"value":"66"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"text","properties":{"value":"SKAMHED"}}},"lright":{"anchor":{"y":"middle-first"},"data":{"type":"text","properties":{"value":"SKÅLÖ"}}}}} + }, + { + "name": "F1-2. Orienteringstavla, exempel", + "json": {"type":".roundabout","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"LISTA"}}]}},"fwd":{"anchor":{"x":"center"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"E20","background":"#097"}},{"type":"text","properties":{"value":"GÖTEBORG"}},{"type":"newline"},{"type":"vagnr","properties":{"value":"56"}},{"type":"text","properties":{"value":"NORRKÖPING"}}]}},"right":{"anchor":{"y":"middle"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"TUMBO"}}]}}}} + }, + { + "name": "F1-2. Orienteringstavla, Transportstyrelsens exempel", + "json": {"type":".roundabout","properties":{"borderWidth":4,"font":"\"Tratex\""},"nodes":{"left":{"anchor":{"y":"middle"},"data":{"type":"text","properties":{"value":"KUMLA","font":"\"TratexVersal\""}}},"fwd":{"anchor":{"x":"center"},"data":{"type":"text","properties":{"value":"ÖREBRO","font":"\"TratexVersal\""}}},"right":{"anchor":{"y":"middle"},"data":{"type":"text","properties":{"value":"KATRINEHOLM","font":"\"TratexVersal\""}}}}} + }, + { + "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, Transportstyrelsens exempel", + "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","elements":[{"type":"text","properties":{"value":"BODA"}}]}}}} + }, + { + "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel", + "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"background":"#097","value":"E22"}},{"type":"text","properties":{"value":"KALMAR"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fd0","color":"#c00","borderWidth":3,"font":"\"Tratex\""},"elements":[{"type":"text","properties":{"value":"Saltvik","color":"black"}},{"type":"newline"},{"type":"skylt","properties":{"color":"black","background":"white"},"elements":[{"type":"text","properties":{"value":"Glabo"}},{"type":"newline"},{"type":"text","properties":{"value":"båthamn"}}]}]}}}} + }, + { + "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel med infogad H-skylt", + "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"right"},"data":{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"68"}},{"type":"text","properties":{"value":"GÄVLE"}}]}},"left":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fc0","color":"#c00","borderWidth":4,"font":"\"Tratex\"","lineSpacing":0},"elements":[{"type":"text","properties":{"value":"Övre","color":"black"}},{"type":"newline"},{"type":"text","properties":{"value":"Källfallet","color":"black"}},{"type":"newline"},{"type":"skylt","properties":{"background":"white","color":"black","blockDisplay": true},"elements":[{"type":"text","properties":{"value":"Teater-"}},{"type":"text","properties":{"value":"maskinen"}},{"type":"#symgroup","params":["h19"]}]}]}}}} + }, + { + "name": "F2. Orienteringstavla vid förbjuden sväng i korsning, exempel med högerpil", + "json": {"type":".spanish","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"fwd":{"anchor":{"x":"left"},"data":{"type":"skylt","properties":{"xSpacing":0},"elements":[{"type":"vagnr","properties":{"value":"50"}},{"type":"vagnr","properties":{"value":"68"}}]}},"right":{"anchor":{"y":"middle-first"},"data":{"type":"skylt","properties":{"background":"#fd0","color":"#c00","borderWidth":3,"font":"\"Tratex\""},"elements":[{"type":"text","properties":{"value":"Käpphagen","color":"black"}}]}}}} + }, + { + "name": "F3. Tabellorienteringstavla, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3,"background":"#06a","fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"80"}}]},{"type":"newline"},{"type":"skylt","properties":{"padding":0,"blockDisplay":true,"background":"#06a"},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"vagnr","properties":{"value":"272"}},{"type":"text","properties":{"value":"BOLLNÄS"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"FORSBACKA"}}]},{"type":"skylt","properties":{"borderWidth":3,"alignContents":"center"},"elements":[{"type":"text","properties":{"value":"500 m"}}]}]}]} + }, + { + "name": "F4. Avfartsorienteringstavla, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3,"background":"#06a","fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"50"}}]},{"type":"newline"},{"type":"skylt","properties":{"background":"#06a","borderWidth":3,"fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"exit"}},{"type":"skylt","properties":{"padding":0},"elements":[{"type":"text","properties":{"value":"ORNÄS"}},{"type":"newline"},{"type":"text","properties":{"value":"500 m"}}]}]}]} + }, + { + "name": "F5. Vägvisare, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"borderWidth":3,"borderRadius":7,"borderFeatures":{"right":"arrow"},"padding":6,"font":"\"TratexVersal\""},"elements":[{"type":"text","properties":{"value":"NYKÖPING"}},{"type":"text","properties":{"value":"23","padding":[12,0,0,0]}}]} + }, + { + "name": "F5. Vägvisare, exempel med vägnummer", + "json": {"type":"skylt","properties":{"background":"#097","borderWidth":3,"borderRadius":7,"borderFeatures":{"right":"arrow"},"font":"\"TratexVersal\"","padding":[0,0,5,0]},"elements":[{"type":"text","properties":{"value":"73","borderRadius":0,"borderWidth":[0,0,3,0],"padding":5,"background":"#06a"}},{"type":"text","properties":{"value":"STOCKHOLM"}}]} + }, + { + "name": "F6. Tabellvägvisare, enkelt exempel", + "json": {"type":"skylt","properties":{"padding":0,"blockDisplay":true,"lineSpacing":0,"borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"text","properties":{"value":"STOCKHOLM"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"GÖTEBORG"}}]}]} + }, + { + "name": "F6. Tabellvägvisare, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"padding":0,"blockDisplay":true,"lineSpacing":0,"borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"80"}},{"type":"text","properties":{"value":"GÄVLE"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}},{"type":"vagnr","properties":{"value":"272"}},{"type":"text","properties":{"value":"BOLLNÄS"}}]},{"type":"skylt","properties":{"borderWidth":3},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"right"}},{"type":"text","properties":{"value":"FORSBACKA"}}]}]} + }, + { + "name": "F7. Avfartsvisare, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"borderWidth":4,"borderFeatures":{"right":"diag"},"padding":6,"font":"\"TratexVersal\"","fillCorners":true},"elements":[{"type":"vagnr","properties":{"value":"70"}},{"type":"text","properties":{"value":"MORA"}},{"type":"newline"},{"type":"text","properties":{"value":"ENKÖPING"}}]} + }, + { + "name": "F8. Körfältsvägvisare, exempel med infogade H-skyltar", + "json": {"type":"skylt","properties":{"borderWidth":3,"font":"\"Tratex\"","background":"white","color":"black"},"elements":[{"type":"skylt","properties":{"blockDisplay":true,"padding":0},"elements":[{"type":"text","properties":{"value":"Lindvallen"}},{"type":"#symgroup","params":["h6","h7","h10","h15","h18"]}]},{"type":"symbol","properties":{"type":"arrow-small","variant":"left"}}]} + }, + { + "name": "F8. Körfältsvägvisare, Transportstyrelsens exempel 1/2", + "json": {"type":"skylt","properties":{"borderWidth":4,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"text","properties":{"value":"BODA"}}]} + }, + { + "name": "F8. Körfältsvägvisare, Transportstyrelsens exempel 2/2", + "json": {"type":"skylt","properties":{"borderWidth":4,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"vagnr","properties":{"value":"50"}},{"type":"text","properties":{"value":"FALUN"}}]} + }, + { + "name": "F8. Körfältsvägvisare, komplicerat exempel", + "json": {"type":"skylt","properties":{"padding":0,"lineSpacing":0,"alignContents":"right","background":"transparent","borderWidth":0,"font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"alignContentsV":"top","background":"#097","borderWidth":3,"fillCorners":true},"elements":[{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"skylt","properties":{"padding":0,"alignContents":"center"},"elements":[{"type":"vagnr","properties":{"value":"E4","dashedInset":true}},{"type":"vagnr","properties":{"value":"E18"}},{"type":"newline"},{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"KISTA"}}]},{"type":"symbol","properties":{"type":"arrow-small","variant":"fwd"}},{"type":"skylt","properties":{"padding":0,"alignContents":"center"},"elements":[{"type":"skylt","properties":{"background":"#06a","borderWidth":3,"padding":10},"elements":[{"type":"vagnr","properties":{"value":"279"}},{"type":"text","properties":{"value":"SOLNA"}},{"type":"newline"},{"type":"text","properties":{"value":"SUNDBYBERG"}},{"type":"newline"},{"type":"skylt","properties":{"background":"white","color":"black","padding":[7,0]},"elements":[{"type":"text","properties":{"value":"RINKEBY"}},{"type":"newline"},{"type":"text","properties":{"value":"Bromma","font":"\"Tratex\""}}]}]},{"type":"newline"},{"type":"text","properties":{"value":"100 m"}}]}]},{"type":"newline"},{"type":"#avfart","params":["158"]}]} + }, + { + "name": "F9. Samlingsmärke för vägvisning, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"alignContents":"center","borderWidth":3,"font":"\"TratexVersal\"","padding":10},"elements":[{"type":"skylt","properties":{"borderWidth":3,"borderFeatures":{"bottom":"bracket"},"alignContents":"center"},"elements":[{"type":"text","properties":{"value":"PAJALA"}},{"type":"newline"},{"type":"text","properties":{"value":"ÖVERTORNEÅ"}}]},{"type":"newline"},{"type":"text","properties":{"value":"KIRUNA"}}]} + }, + { + "name": "F10. Platsmärke, Transportstyrelsens exempel", + "json": {"type":"text","properties":{"borderWidth":3,"font":"\"TratexVersal\"","value":"NYKÖPING","padding":8}} + }, + { + "name": "F11. Vägnamn, Transportstyrelsens exempel", + "json": {"type":"text","properties":{"background":"white","color":"black","borderWidth":3,"font":"\"Tratex\"","value":"Hemvägen","padding":8}} + }, + { + "name": "F12. Vattendrag, Transportstyrelsens exempel", + "json": {"type":".water","properties":{"borderWidth":4,"font":"\"TratexVersal\""},"nodes":{"name":{"data":{"type":"text","properties":{"value":"DALÄLVEN"}}}}} + }, + { + "name": "F13. Avståndstavla, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"borderWidth":3,"font":"\"TratexVersal\"","padding":4},"elements":[{"type":"skylt","elements":[{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"SÖDERTÄLJE"}}]},{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"text","properties":{"value":"105"}},{"type":"newline"},{"type":"text","properties":{"value":"71"}}]}]} + }, + { + "name": "F13. Avståndstavla, exempel med vägnummer", + "json": {"type":"skylt","properties":{"padding":4,"alignContents":"center","font":"\"TratexVersal\"","borderWidth":3},"elements":[{"type":"skylt","elements":[{"type":"vagnr","properties":{"value":"123"}}]},{"type":"newline"},{"type":"skylt","elements":[{"type":"text","properties":{"value":"STOCKHOLM"}},{"type":"newline"},{"type":"text","properties":{"value":"SÖDERTÄLJE"}}]},{"type":"skylt","properties":{"alignContents":"right"},"elements":[{"type":"text","properties":{"value":"105"}},{"type":"newline"},{"type":"text","properties":{"value":"71"}}]}]} + }, + { + "name": "F14. Vägnummer, Transportstyrelsens exempel", + "json": {"type":"vagnr","properties":{"background":"#097","value":"E4","font":"\"TratexVersal\""}} + }, + { + "name": "F14-2. Vägnummer, Transportstyrelsens exempel", + "json": {"type":"vagnr","properties":{"background":"#097","value":"E4","dashedInset":true,"font":"\"TratexVersal\""}} + }, + { + "name": "F14-3. Vägnummer, Transportstyrelsens exempel", + "json": {"type":"vagnr","properties":{"background":"#06a","value":"58","font":"\"TratexVersal\""}} + }, + { + "name": "F14-4. Vägnummer, Transportstyrelsens exempel", + "json": {"type":"vagnr","properties":{"background":"#06a","value":"58","dashedInset":true,"font":"\"TratexVersal\""}} + }, + { + "name": "F15. Omledning, Transportstyrelsens exempel", + "json": {"type":"vagnr","properties":{"background":"white","color":"#06a","value":"58","font":"\"TratexVersal\""}} + }, + { + "name": "F27. Trafikplatsnummer, Transportstyrelsens exempel", + "json": {"type":"#avfart","properties":{"font":"\"TratexVersal\""},"params":["75"]} + }, + { + "name": "G3. Radiostation för vägtrafikinformation, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"padding":[17,17,17,2],"borderWidth":3,"alignContents":"center","font":"\"TratexVersal\""},"elements":[{"type":"skylt","properties":{"alignContents":"center","background":"white","color":"black","padding":12},"elements":[{"type":"text","properties":{"value":"Radio","font":"\"Tratex\""}},{"type":"newline"},{"type":"text","properties":{"value":"FM4"}}]},{"type":"newline"},{"type":"text","properties":{"value":"98,7"}}]} + }, + { + "name": "H23. Förberedande upplysning om vägnära service, enkelt exempel", + "json": {"type":"skylt","properties":{"borderWidth":4,"borderRadius":8,"padding":8,"font":"\"Tratex\"","fillCorners":true,"blockDisplay":true},"elements":[{"type":"skylt","properties":{"background":"white","color":"black","padding":8},"elements":[{"type":"#symgroup","params":["h13"]},{"type":"text","properties":{"value":"Strandkanten"}},{"type":"newline"},{"type":"#symgroup","params":["h6","h7","h15"]}]},{"type":"text","properties":{"font":"\"TratexVersal\"","value":"18 km","alignContents":"center"}}]} + }, + { + "name": "J2. Upplysningsmärke, Transportstyrelsens exempel", + "json": {"type":"skylt","properties":{"background":"#fd0","color":"black","borderWidth":4,"font":"\"TratexVersal\"","padding":8,"alignContents":"center","lineSpacing":0},"elements":[{"type":"text","properties":{"value":"VÄGSALTNING"}},{"type":"newline"},{"type":"text","properties":{"value":"UPPHÖR"}}]} + } +] \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..968f2e2 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + /* Language and Environment */ + "target": "es2017", + "noLib": false, + + /* Modules */ + "module": "es6", + "rootDir": ".", + + /* Emit */ + "outDir": "./dist", + "removeComments": true, + + /* Interop Constraints */ + "esModuleInterop": false, + "forceConsistentCasingInFileNames": true, + + /* Type Checking */ + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": false, + "noImplicitOverride": true + }, + "files": ["./packages/skyltrendering/src/browser.ts", "./src/render.ts"], + "include": ["./src/**.ts", "./packages/skyltrendering/src/**.ts"], + "exclude": ["./packages/skyltrendering/src/main.ts"] +} From 17970a505c278bcbdf39b671a081843dc9698299 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Sat, 1 Mar 2025 00:11:01 +0100 Subject: [PATCH 11/12] =?UTF-8?q?G=C3=B6r=20skyltrendering=20till=20en=20s?= =?UTF-8?q?ubmodul?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 3 + packages/skyltrendering | 1 + packages/skyltrendering/package-lock.json | 525 --------------- packages/skyltrendering/package.json | 24 - packages/skyltrendering/src/browser.ts | 81 --- packages/skyltrendering/src/graphics.ts | 129 ---- packages/skyltrendering/src/main.ts | 77 --- packages/skyltrendering/src/render.ts | 621 ------------------ packages/skyltrendering/src/typedefs.ts | 185 ------ packages/skyltrendering/src/utils.ts | 86 --- packages/skyltrendering/tsconfig.json | 38 -- packages/skyltrendering/utils/clean.js | 34 - .../font}/TRATEXPOSVERSAL-POSVERSAL.otf | Bin {font => public/font}/TratexSvart-Regular.otf | Bin public/render.html | 2 +- {res => public/res}/junction.json | 0 {res => public/res}/roundabout.json | 0 {res => public/res}/spanish.json | 0 {res => public/res}/symbol/arrow-small.json | 0 {res => public/res}/symbol/exit.json | 0 {res => public/res}/symbol/h1.json | 0 {res => public/res}/symbol/h10.json | 0 {res => public/res}/symbol/h11.json | 0 {res => public/res}/symbol/h12.json | 0 {res => public/res}/symbol/h13.json | 0 {res => public/res}/symbol/h14.json | 0 {res => public/res}/symbol/h15.json | 0 {res => public/res}/symbol/h16.json | 0 {res => public/res}/symbol/h17.json | 0 {res => public/res}/symbol/h18.json | 0 {res => public/res}/symbol/h19.json | 0 {res => public/res}/symbol/h2.json | 0 {res => public/res}/symbol/h20.json | 0 {res => public/res}/symbol/h21.json | 0 {res => public/res}/symbol/h22.json | 0 {res => public/res}/symbol/h24.json | 0 {res => public/res}/symbol/h25.json | 0 {res => public/res}/symbol/h26.json | 0 {res => public/res}/symbol/h27.json | 0 {res => public/res}/symbol/h28.json | 0 {res => public/res}/symbol/h3.json | 0 {res => public/res}/symbol/h4.json | 0 {res => public/res}/symbol/h5.json | 0 {res => public/res}/symbol/h6.json | 0 {res => public/res}/symbol/h7.json | 0 {res => public/res}/symbol/h8.json | 0 {res => public/res}/symbol/h9.json | 0 {res => public/res}/water.json | 0 48 files changed, 5 insertions(+), 1801 deletions(-) create mode 100644 .gitmodules create mode 160000 packages/skyltrendering delete mode 100644 packages/skyltrendering/package-lock.json delete mode 100644 packages/skyltrendering/package.json delete mode 100644 packages/skyltrendering/src/browser.ts delete mode 100644 packages/skyltrendering/src/graphics.ts delete mode 100644 packages/skyltrendering/src/main.ts delete mode 100644 packages/skyltrendering/src/render.ts delete mode 100644 packages/skyltrendering/src/typedefs.ts delete mode 100644 packages/skyltrendering/src/utils.ts delete mode 100644 packages/skyltrendering/tsconfig.json delete mode 100644 packages/skyltrendering/utils/clean.js rename {font => public/font}/TRATEXPOSVERSAL-POSVERSAL.otf (100%) rename {font => public/font}/TratexSvart-Regular.otf (100%) rename {res => public/res}/junction.json (100%) rename {res => public/res}/roundabout.json (100%) rename {res => public/res}/spanish.json (100%) rename {res => public/res}/symbol/arrow-small.json (100%) rename {res => public/res}/symbol/exit.json (100%) rename {res => public/res}/symbol/h1.json (100%) rename {res => public/res}/symbol/h10.json (100%) rename {res => public/res}/symbol/h11.json (100%) rename {res => public/res}/symbol/h12.json (100%) rename {res => public/res}/symbol/h13.json (100%) rename {res => public/res}/symbol/h14.json (100%) rename {res => public/res}/symbol/h15.json (100%) rename {res => public/res}/symbol/h16.json (100%) rename {res => public/res}/symbol/h17.json (100%) rename {res => public/res}/symbol/h18.json (100%) rename {res => public/res}/symbol/h19.json (100%) rename {res => public/res}/symbol/h2.json (100%) rename {res => public/res}/symbol/h20.json (100%) rename {res => public/res}/symbol/h21.json (100%) rename {res => public/res}/symbol/h22.json (100%) rename {res => public/res}/symbol/h24.json (100%) rename {res => public/res}/symbol/h25.json (100%) rename {res => public/res}/symbol/h26.json (100%) rename {res => public/res}/symbol/h27.json (100%) rename {res => public/res}/symbol/h28.json (100%) rename {res => public/res}/symbol/h3.json (100%) rename {res => public/res}/symbol/h4.json (100%) rename {res => public/res}/symbol/h5.json (100%) rename {res => public/res}/symbol/h6.json (100%) rename {res => public/res}/symbol/h7.json (100%) rename {res => public/res}/symbol/h8.json (100%) rename {res => public/res}/symbol/h9.json (100%) rename {res => public/res}/water.json (100%) diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4cd1699 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "packages/skyltrendering"] + path = packages/skyltrendering + url = https://github.com/axelw3/skyltrendering diff --git a/packages/skyltrendering b/packages/skyltrendering new file mode 160000 index 0000000..303c0ea --- /dev/null +++ b/packages/skyltrendering @@ -0,0 +1 @@ +Subproject commit 303c0ea3d00c4380748b93bd25ff16759cacdb98 diff --git a/packages/skyltrendering/package-lock.json b/packages/skyltrendering/package-lock.json deleted file mode 100644 index c626569..0000000 --- a/packages/skyltrendering/package-lock.json +++ /dev/null @@ -1,525 +0,0 @@ -{ - "name": "skyltrendering", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "skyltrendering", - "version": "1.0.0", - "hasInstallScript": true, - "license": "AGPL-3.0-or-later", - "dependencies": { - "@napi-rs/canvas": "^0.1.67" - }, - "devDependencies": { - "@types/node": "^22.13.5", - "esbuild": "^0.25.0", - "typescript": "^5.7.3" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", - "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", - "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", - "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", - "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", - "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", - "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", - "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", - "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", - "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", - "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", - "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", - "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", - "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", - "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", - "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", - "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", - "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", - "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", - "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", - "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", - "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", - "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", - "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", - "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", - "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.67", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.67.tgz", - "integrity": "sha512-VA4Khm/5Kg2bQGx3jXotTC4MloOG8b1Ung80exafUK0k5u6yJmIz3Q2iXeeWZs5weV+LQOEB+CPKsYwEYaGAjw==", - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.67", - "@napi-rs/canvas-darwin-arm64": "0.1.67", - "@napi-rs/canvas-darwin-x64": "0.1.67", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.67", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.67", - "@napi-rs/canvas-linux-arm64-musl": "0.1.67", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.67", - "@napi-rs/canvas-linux-x64-gnu": "0.1.67", - "@napi-rs/canvas-linux-x64-musl": "0.1.67", - "@napi-rs/canvas-win32-x64-msvc": "0.1.67" - } - }, - "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.67", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.67.tgz", - "integrity": "sha512-K/JmkOFbc4iRZYUqJhj0jwqfHA/wNQEmTiGNsgZ6d59yF/IBNp5T0D5eg3B8ghjI8GxDYCiSJ6DNX8mC3Oh2EQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/node": { - "version": "22.13.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz", - "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", - "dev": true, - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/esbuild": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", - "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.0", - "@esbuild/android-arm": "0.25.0", - "@esbuild/android-arm64": "0.25.0", - "@esbuild/android-x64": "0.25.0", - "@esbuild/darwin-arm64": "0.25.0", - "@esbuild/darwin-x64": "0.25.0", - "@esbuild/freebsd-arm64": "0.25.0", - "@esbuild/freebsd-x64": "0.25.0", - "@esbuild/linux-arm": "0.25.0", - "@esbuild/linux-arm64": "0.25.0", - "@esbuild/linux-ia32": "0.25.0", - "@esbuild/linux-loong64": "0.25.0", - "@esbuild/linux-mips64el": "0.25.0", - "@esbuild/linux-ppc64": "0.25.0", - "@esbuild/linux-riscv64": "0.25.0", - "@esbuild/linux-s390x": "0.25.0", - "@esbuild/linux-x64": "0.25.0", - "@esbuild/netbsd-arm64": "0.25.0", - "@esbuild/netbsd-x64": "0.25.0", - "@esbuild/openbsd-arm64": "0.25.0", - "@esbuild/openbsd-x64": "0.25.0", - "@esbuild/sunos-x64": "0.25.0", - "@esbuild/win32-arm64": "0.25.0", - "@esbuild/win32-ia32": "0.25.0", - "@esbuild/win32-x64": "0.25.0" - } - }, - "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true - } - } -} diff --git a/packages/skyltrendering/package.json b/packages/skyltrendering/package.json deleted file mode 100644 index fb85a36..0000000 --- a/packages/skyltrendering/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "skyltrendering", - "version": "1.0.0", - "description": "", - "main": "dist/node/main.js", - "browser": "dist/browser/index.esm.js", - "scripts": { - "clean": "node ./utils/clean.js ./dist/", - "install": "npm run build", - "build": "npm run clean && npm run build:node && npm run build:esm", - "build:node": "tsc", - "build:esm": "esbuild ./src/browser.ts --format=esm --bundle --outfile=./dist/browser/index.esm.js" - }, - "author": "axelw3", - "license": "AGPL-3.0-or-later", - "devDependencies": { - "@types/node": "^22.13.5", - "typescript": "^5.7.3", - "esbuild": "^0.25.0" - }, - "dependencies": { - "@napi-rs/canvas": "^0.1.67" - } -} diff --git a/packages/skyltrendering/src/browser.ts b/packages/skyltrendering/src/browser.ts deleted file mode 100644 index 13a46ca..0000000 --- a/packages/skyltrendering/src/browser.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { SignRenderer as _SignRenderer } from "./render.js"; -import { Vec6, NewDrawingArea } from "./typedefs.js"; - - -class BrowserDrawingArea implements NewDrawingArea{ - canv: HTMLCanvasElement; - private ctx: CanvasRenderingContext2D; - - constructor(w?: number, h?: number){ - this.canv = Object.assign(document.createElement("canvas"), {width: w || 300, height: h || 150}); - this.ctx = this.canv.getContext("2d") as CanvasRenderingContext2D; - } - - createPath2D(s?: string | undefined, m?: Vec6 | undefined): Path2D { - let p = new window.Path2D(); - let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; - p.addPath(new window.Path2D(s), {a, b, c, d, e, f}); - return p; - } - - measureText(text: string): { width: number; } { - return this.ctx.measureText(text); - } - - set fillStyle(x: string) { - this.ctx.fillStyle = x; - } - - set strokeStyle(x: string) { - this.ctx.strokeStyle = x; - } - - set lineWidth(x: number) { - this.ctx.lineWidth = x; - } - - set font(x: string) { - this.ctx.font = x; - } - - set textBaseline(x: string) { - this.ctx.textBaseline = x as CanvasTextBaseline; - } - - fill(path: Path2D): void { - this.ctx.fill(path); - } - - stroke(path: Path2D): void { - this.ctx.stroke(path); - } - - fillRect(x: number, y: number, w: number, h: number): void { - this.ctx.fillRect(x, y, w, h); - } - - fillText(text: string, x: number, y: number): void { - this.ctx.fillText(text, x, y); - } - - drawImage(image: NewDrawingArea, dx: number, dy: number): void { - this.ctx.drawImage(image.canv, dx, dy); - } -} - -export class SignRenderer extends _SignRenderer{ - protected override createCanvas(w?: number, h?: number): BrowserDrawingArea { - return new BrowserDrawingArea(w, h); - } - - protected override getText(url: string): Promise { - return new Promise(resolve => { - let req = new XMLHttpRequest(); - req.addEventListener("load", () => { - resolve(req.responseText); - }); - req.open("GET", url); - req.send(); - }); - } -}; \ No newline at end of file diff --git a/packages/skyltrendering/src/graphics.ts b/packages/skyltrendering/src/graphics.ts deleted file mode 100644 index e836c21..0000000 --- a/packages/skyltrendering/src/graphics.ts +++ /dev/null @@ -1,129 +0,0 @@ -import type { Vec4, Vec2, NewDrawingArea } from "./typedefs.js"; - -export function roundedFrame(ctx: NewDrawingArea, x0: number, y0: number, innerWidth: number, innerHeight: number, nominalLineWidth: Vec4 = [4, 4, 4, 4], color: string = "#000", borderRadius: Vec4 = [0, 0, 0, 0], lineDash: Vec2 = [1, 0]){ - // lineDash = [längd, mellanrum] - - if(Math.max(...nominalLineWidth) <= 0) return; - - let drawCorner = (cx: number, cy: number, signX: number, signY: number, i: number) => { - let w0 = nominalLineWidth[(Math.ceil(i / 2) * 2) % 4], - w1 = nominalLineWidth[Math.floor(i / 2) * 2 + 1], - br = borderRadius[i]; - - let arx = Math.max(br - w0, 0), - ary = Math.max(br - w1, 0); - - cx -= signX * arx; - cy -= signY * ary; - - let startAngle = ((i - 2) * Math.PI) / 2 + Math.PI/4; - - let v1 = startAngle - signX*signY*Math.PI/4, - v2 = startAngle + signX*signY*Math.PI/4; - - let p = ctx.createPath2D(); - //ctx.moveTo(cx + signX * arx, cy); - p.moveTo(cx + signX*(arx+w0), cy); - p.lineTo(cx + signX*(arx+w0), cy + signY * Math.max(0, w1 - br)); - p.ellipse(cx + signX*Math.max(0, w0 - br), cy + signY * Math.max(0, w1 - br), br, br, 0, v1, v2, signX !== signY); - p.lineTo(cx, cy + signY*(ary+w1)); - p.lineTo(cx, cy + signY*ary); - p.ellipse(cx, cy, arx, ary, 0, v2, v1, signX === signY); - //ctx.closePath(); - - ctx.fillStyle = color; - ctx.fill(p); - }; - - drawCorner(x0, y0, -1, -1, 0); - drawCorner(x0 + innerWidth, y0, 1, -1, 1); - drawCorner(x0 + innerWidth, y0 + innerHeight, 1, 1, 2); - drawCorner(x0, y0 + innerHeight, -1, 1, 3); - - let drawLineDash = (innerLength: number, cb: (z: number, s: number) => void) => { - let actualLineDash = [lineDash[0], lineDash[1]]; - - let r = 0; - while(true){ - r = (innerLength + actualLineDash[1]) % (actualLineDash[0] + actualLineDash[1]); - if(r >= actualLineDash[1]) break; - actualLineDash[0]++; - } - - let z = Math.floor(r / 2); - do{ - cb(z, actualLineDash[0]); - z += actualLineDash[0] + actualLineDash[1]; - }while(z + actualLineDash[0] <= innerLength); - - }; - - ctx.fillStyle = color; - - // Ovanför - drawLineDash( - innerWidth - Math.max(0, borderRadius[0] - nominalLineWidth[0]) - Math.max(0, borderRadius[1] - nominalLineWidth[2]), - (x, w) => ctx.fillRect(x0 + Math.max(0, borderRadius[0] - nominalLineWidth[0]) + x, y0 - nominalLineWidth[1], w, nominalLineWidth[1]) - ); - - // Nedanför - drawLineDash( - innerWidth - Math.max(0, borderRadius[3] - nominalLineWidth[0]) - Math.max(0, borderRadius[2] - nominalLineWidth[2]), - (x, w) => ctx.fillRect(x0 + Math.max(0, borderRadius[3] - nominalLineWidth[0]) + x, y0 + innerHeight, w, nominalLineWidth[3]) - ); - - // Vänster - drawLineDash( - innerHeight - Math.max(0, borderRadius[0] - nominalLineWidth[1]) - Math.max(0, borderRadius[3] - nominalLineWidth[3]), - (y, h) => ctx.fillRect(x0 - nominalLineWidth[0], y0 + Math.max(0, borderRadius[0] - nominalLineWidth[1]) + y, nominalLineWidth[0], h) - ); - - // Höger - drawLineDash( - innerHeight - Math.max(0, borderRadius[1] - nominalLineWidth[1]) - Math.max(0, borderRadius[2] - nominalLineWidth[3]), - (y, h) => ctx.fillRect(x0 + innerWidth, y0 + Math.max(0, borderRadius[1] - nominalLineWidth[1]) + y, nominalLineWidth[2], h) - ); -} - - -export function roundedFill(ctx: NewDrawingArea, x0: number, y0: number, innerWidth: number, innerHeight: number, borderWidth: Vec4 = [4, 4, 4, 4], borderRadius: Vec4 = [0, 0, 0, 0], background: string = "#fff", fillCorners: boolean = false){ - // lineDash = [längd, mellanrum] - - ctx.fillStyle = background; - - if(fillCorners || Math.max(...borderWidth) === 0){ - ctx.fillRect(x0 - borderWidth[0], y0 - borderWidth[1], innerWidth + borderWidth[0] + borderWidth[2], innerHeight + borderWidth[1] + borderWidth[3]); - return; - } - - let p = ctx.createPath2D(); - - let drawCorner = (cx: number, cy: number, signX: number, signY: number, i: number) => { - let arx = borderRadius[i] + borderWidth[(Math.ceil(i / 2) * 2) % 4] / 2, - ary = borderRadius[i] + borderWidth[Math.floor(i / 2) * 2 + 1] / 2; - - let startAngle = ((i - 2) * Math.PI) / 2; - p.ellipse( - cx - signX * borderRadius[i], cy - signY * borderRadius[i], - arx, ary, - 0, - startAngle, startAngle + Math.PI / 2, - false - ); - }; - - drawCorner(x0, y0, -1, -1, 0); - drawCorner(x0 + innerWidth, y0, 1, -1, 1); - drawCorner(x0 + innerWidth, y0 + innerHeight, 1, 1, 2); - drawCorner(x0, y0 + innerHeight, -1, 1, 3); - - ctx.fill(p); - - // mitten - ctx.fillRect( - x0 + Math.max(borderRadius[0], borderRadius[3]), - y0 + Math.max(borderRadius[0], borderRadius[1]), - innerWidth - Math.max(borderRadius[0], borderRadius[3]) - Math.max(borderRadius[1], borderRadius[2]), - innerHeight - Math.max(borderRadius[0], borderRadius[1]) - Math.max(borderRadius[2], borderRadius[3]) - ); -} \ No newline at end of file diff --git a/packages/skyltrendering/src/main.ts b/packages/skyltrendering/src/main.ts deleted file mode 100644 index a74c6aa..0000000 --- a/packages/skyltrendering/src/main.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { SignRenderer as _SignRenderer } from "./render.js"; -import { Vec6, NewDrawingArea, Path2D as _Path2D } from "./typedefs.js"; - -import { createCanvas, Canvas, Path2D, SKRSContext2D } from "@napi-rs/canvas"; -import { readFile } from "fs/promises" - -class NodeDrawingArea implements NewDrawingArea{ - canv: Canvas; - private ctx: SKRSContext2D; - - constructor(w: number, h: number){ - this.canv = createCanvas(w, h); - this.ctx = this.canv.getContext("2d"); - } - - createPath2D(s?: string, m?: Vec6 | undefined): Path2D { - let p = new Path2D(); - let [a, b, c, d, e, f] = m === undefined ? [1, 0, 0, 1, 0, 0] : [...m]; - p.addPath(new Path2D(s), {a, b, c, d, e, f}); - return p; - } - - measureText(text: string): { width: number; } { - return this.ctx.measureText(text); - } - - set fillStyle(x: string) { - this.ctx.fillStyle = x; - } - - set strokeStyle(x: string) { - this.ctx.strokeStyle = x; - } - - set lineWidth(x: number) { - this.ctx.lineWidth = x; - } - - set font(x: string) { - this.ctx.font = x; - } - - set textBaseline(x: string) { - this.ctx.textBaseline = x as CanvasTextBaseline; - } - - fill(path: Path2D): void{ - this.ctx.fill(path); - } - - stroke(path: Path2D): void { - this.ctx.stroke(path); - } - - fillRect(x: number, y: number, w: number, h: number): void { - this.ctx.fillRect(x, y, w, h); - } - - fillText(text: string, x: number, y: number): void { - this.ctx.fillText(text, x, y); - } - - drawImage(image: NewDrawingArea, dx: number, dy: number): void { - this.ctx.drawImage(image.canv, dx, dy); - } -} - - -export class SignRenderer extends _SignRenderer{ - protected override createCanvas(w?: number, h?: number): NodeDrawingArea { - return new NodeDrawingArea(w || 300, h || 150); - } - - protected override getText(url: string): Promise { - return readFile(url, {encoding: "utf8"}); - } -}; \ No newline at end of file diff --git a/packages/skyltrendering/src/render.ts b/packages/skyltrendering/src/render.ts deleted file mode 100644 index e75a5ad..0000000 --- a/packages/skyltrendering/src/render.ts +++ /dev/null @@ -1,621 +0,0 @@ -import type { MathEnv, Vec4, SignElementProperties, SignElementOptions, SignElementBaseProperties, RenderingResult, Vec6, NewDrawingArea, JSONVec, JSONVecReference, ConfigData, BorderFeatureDefinition, UserConfigData, PropertiesDefaults } from "./typedefs.js" -import { roundedFill, roundedFrame } from "./graphics.js"; -import { mathEval, parseVarStr } from "./utils.js"; - -const propertiesDefaults: PropertiesDefaults = { - "globalDefaults": { "borderFeatures": {}, "borderWidth": 0, "padding": 0 }, - "rootDefaults": { "background": "#06a", "color": "white", "borderRadius": 8, "font": "sans-serif", "lineHeight": 46, "lineSpacing": 4, "fillCorners": true, "xSpacing": 8 }, - "defaults": { - ".": { "borderWidth": 4, "padding": 8 }, - "skylt": { "padding": 6, "blockDisplay": false, "passAnchor": false, "alignContentsV": "middle" }, - "vagnr": { "value": "123", "borderWidth": 3, "borderRadius": 7, "dashedInset": false, "padding": [14, 2] }, - "text": { "value": "Text" }, - "newline": {}, - "symbol": { "padding": 5, "type": "default", "grow": true } - } -}; - -// Bestämning av värde på elementegenskaper görs enligt följande prioriteringsordning: -// 1. Specificerat värde -// 2. Värde från förälder (om egenskapen kan ärvas) eller från rootDefaults (endast rotelement) -// 3. Typspecifikt standardvärde (från defaults) -// 4. Globalt standardvärde (från globalDefaults) - -function to4EForm(data: number[] | number): Vec4{ - if(!Array.isArray(data)) data = [ data, data ]; - if(data.length != 4) data = [ data[0], data[1], data[0], data[1] ]; - return [data[0], data[1], data[2], data[3]]; -} - -class BorderElement{ - env: MathEnv; - w: number; - h: number; - - constructor(feature: BorderFeatureDefinition, bw: number, brA: number, brB: number, sideLength: number){ - let w0 = feature.w, - cvr = !!feature.cover; - - if(cvr) w0 = sideLength - bw; - - this.env = BorderElement.calculateEnv(feature, bw, brA, brB, w0); - - let h0 = mathEval(feature.h, this.env); - - this.env["h"] = h0; - - this.w = w0 + bw; - this.h = h0 + bw; - } - - static calculateEnv(feature: BorderFeatureDefinition, bw: number, brA: number, brB: number, w0: number): MathEnv{ - let env: MathEnv = {bra: brA, brb: brB, bw: bw, w: w0}; - - if(!Array.isArray(feature.vars)) return env; - - for(let i = 0; i < feature.vars.length; i++){ - env[feature.vars[i][0]] = mathEval(feature.vars[i][1], env); - } - - return env; - } -} - -class BorderDimensions{ - h: Vec4; - el: (BorderElement | null)[]; - - constructor(heights: Vec4){ - this.h = [...heights]; - this.el = [null, null, null, null]; - } - - set(i: number, el: BorderElement){ - this.el[i] = el; - this.h[i] = Math.floor(el.h); - } -} - -export abstract class SignRenderer>{ - protected abstract createCanvas(w?: number, h?: number): T; - protected abstract getText(url: string): Promise; - - private borderSize(innerWidth: number, innerHeight: number, properties: SignElementProperties){ - let bs = new BorderDimensions(properties.borderWidth), - bf = properties.borderFeatures; - - if(bf["left"] !== undefined) - bs.set(0, new BorderElement(this.conf.borderFeatures[bf["left"]], properties.borderWidth[0], properties.borderRadius[0], properties.borderRadius[3], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); - - if(bf["right"] !== undefined) - bs.set(2, new BorderElement(this.conf.borderFeatures[bf["right"]], properties.borderWidth[2], properties.borderRadius[2], properties.borderRadius[1], innerHeight + properties.borderWidth[1] + properties.borderWidth[3])); - - if(bf["top"] !== undefined) - bs.set(1, new BorderElement(this.conf.borderFeatures[bf["top"]], properties.borderWidth[1], properties.borderRadius[1], properties.borderRadius[0], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); - - if(bf["bottom"] !== undefined) - bs.set(3, new BorderElement(this.conf.borderFeatures[bf["bottom"]], properties.borderWidth[3], properties.borderRadius[3], properties.borderRadius[2], innerWidth + properties.borderWidth[0] + properties.borderWidth[2])); - - return bs; - } - - private static calculateAlignmentOffset(alignMode: string | undefined, innerWidth: number, outerWidth: number){ - switch(alignMode){ - case "center": - return Math.floor((outerWidth - innerWidth) / 2); - case "right": - return outerWidth - innerWidth; - default: - // "left" or unknown value (left-aligned is the default) - return 0; - } - } - - private renderBorderFeature(ctx: NewDrawingArea, x0: number, y0: number, feature: BorderFeatureDefinition, side: string, bs: BorderDimensions, borderBoxInnerW: number, innerHeight: number, prop: SignElementProperties){ - let color = prop.color, - background = prop.background; - - let lr = (side === "left" || side === "right"); - let bri = lr ? (side === "left" ? 0 : 2) : (side === "top" ? 1 : 3); - - let bw = prop.borderWidth[bri]; - let s = [bs.el[bri]?.w ?? 0, bs.h[bri]]; - - let w = lr ? s[1] : s[0], - h = lr ? s[0] : s[1]; - - switch(side){ - case "bottom": - y0 += innerHeight + bs.h[1]; - case "top": - x0 += bs.h[0] + Math.floor((borderBoxInnerW - w) / 2); - break; - case "right": - x0 += borderBoxInnerW + bs.h[0]; - default: - y0 += bs.h[1] + Math.floor((innerHeight - h) / 2); - break; - } - - // left: cos 0 sin -1 - // top: cos -1 sin 0 - // right: cos 0 sin 1 - // bottom: cos 1 sin 0 - - let sr = lr ? (side === "left" ? 1 : (-1)) : 0, cr = lr ? 0 : (side === "top" ? (-1) : 1); - let [a, b] = [(s[0] - bw) / 2, (s[1] - bw) / 2]; - - let tm: Vec6 = [ - cr, sr, -sr, cr, (x0 + w / 2) - a*cr + b*sr, (y0 + h / 2) - a*sr - b*cr - ]; - - //ctx.fillStyle="#000"; - //ctx.fillRect(x0, y0, w, h); - - ctx.fillStyle = background; - ctx.fillRect(x0 + (side === "left" ? (s[1] - bw) : 0) + (lr ? 0 : (bw/2)), y0 + (side === "top" ? (s[1] - bw) : 0) + (lr ? (bw/2) : 0), lr ? bw : (s[0] - bw), lr ? (s[0] - bw) : bw); - - ctx.lineWidth = bw; - - feature.paths.forEach(path => { - let p = ctx.createPath2D(parseVarStr(path.p, bs.el[bri]?.env), tm); - - if(path.f !== undefined){ - ctx.fillStyle = [color, background][Math.abs(path.f)-1]; - if(path.f > 0 || prop.fillCorners) ctx.fill(p); - } - - if(path.s !== undefined){ - ctx.strokeStyle = [color, background][Math.abs(path.s)-1]; - if(path.s > 0 || prop.fillCorners) ctx.stroke(p); - } - }); - } - - private drawVec(ctx: T, href: string, currentColor: string, components: string[], dx: number, dy: number, dw: number, dh: number, sx: number = 0, sy: number = 0, sw: number = dw, sh: number = dh): Promise{ - return this.getText(href).then(rawJson => { - let vecImgData = JSON.parse(rawJson) as JSONVec; - let ctx2: T = this.createCanvas(dw, dh); - - let xf = (dw/sw) * vecImgData.width / vecImgData.vectorSize[0], - yf = (dh/sh) * vecImgData.height / vecImgData.vectorSize[1]; - - let tm: Vec6 = [ - xf, 0, 0, - yf, 0, 0 - ]; - - let els: JSONVecReference[]; - if(vecImgData.components !== undefined){ - els = vecImgData.core ?? []; - Object.entries(vecImgData.components).filter(e => components.includes(e[0])).forEach(e => els.push(...e[1])); - }else{ - els = vecImgData.defs.map(function(_: any, i: number): JSONVecReference{ - return {use: i}; - }); - } - - els.forEach(el => { - let def = vecImgData.defs[el.use]; - - let tra = el.translate ?? [0, 0]; - - [tm[4], tm[5]] = [tra[0] * xf, tra[1] * yf]; - - tm[4] -= sx * dw/sw; - tm[5] -= sy * dh/sh; - - let path = ctx2.createPath2D(def.path, tm); - ctx2.fillStyle = def.fill === "currentColor" ? currentColor : def.fill; - ctx2.fill(path); - }); - - ctx.drawImage(ctx2, dx, dy); - }); - } - - private conf: ConfigData; - - protected resolveTemplate(opt: SignElementOptions): SignElementOptions{ - while(opt.type.startsWith("#")){ - let templateName = opt.type.slice(1); - let templ = this.conf.templates[templateName]; - if(!templ){ - alert("ERROR: Unknown template \"" + templateName + "\".") - break; - } - - let template = templ(...(opt.params ?? [])); - - Object.assign(template.properties ??= {}, opt.properties); - opt = template; - } - - return opt; - } - - public constructor(config: UserConfigData){ - this.conf = { - properties: Object.assign({}, propertiesDefaults, config.properties), - signTypes: config.signTypes ?? {}, - symbols: config.symbols ?? {}, - borderFeatures: config.borderFeatures ?? {}, - templates: config.templates ?? {} - }; - } - - private static getInhProperties(prop: SignElementProperties): SignElementBaseProperties{ - const { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing } = prop; - return { background, borderRadius, color, font, lineHeight, lineSpacing, xSpacing }; - } - - private _render(opt: SignElementOptions, parentProperties: SignElementBaseProperties | null): RenderingResult{ - let firstLastCenter: Vec4 = [NaN, NaN, NaN, NaN]; // [cx_first, cy_firstrow, cx_last, cy_lastrow] - - opt = this.resolveTemplate(opt); - - let prop: SignElementProperties = Object.assign( - {}, - this.conf.properties.globalDefaults, - this.conf.properties.defaults[opt.type.startsWith(".") ? "." : opt.type], - parentProperties === null ? this.conf.properties.rootDefaults : parentProperties, - opt.properties - ); - - Object.assign(prop, { - padding: to4EForm(prop.padding), - borderRadius: to4EForm(prop.borderRadius), - borderWidth: to4EForm(prop.borderWidth) - }); - - let padding = Array.from(prop.padding); - - let width = 0, height = 0, maxHeight = 0; - let renderPromise: (ctx: T, x0: number, y0: number, maxInnerHeight: number) => Promise - = () => Promise.resolve(); - - if(opt.type === "skylt"){ - let w = [0], h = [0], j = 0; - - let totalLineSpacing = 0; - - let ch = (opt.elements ?? []).map((c, i) => { - let re = this._render(c, SignRenderer.getInhProperties(prop)); - let c2 = { isn: c.type === "newline", r: re, bs: re.bs, row: j, x: 0, p: c.properties }; - - if(c2.isn || (i > 0 && prop.blockDisplay)){ - c2.row = ++j; - w.push(0); - h.push(0); - totalLineSpacing += (prop.blockDisplay ? prop.lineSpacing : prop.lineSpacing); - } - - if(!c2.isn){ - if(w[j] > 0){ - w[j] += prop.xSpacing; - } - - c2.x = w[j]; - w[j] += c2.r.w + c2.bs[0] + c2.bs[2]; - - let h0 = c2.r.h + c2.bs[1] + c2.bs[3]; - if(h0 > h[j]) h[j] = h0; - } - - return c2; - }); - - width = Math.max(...w); - height = h.reduce((a, b) => a + b, totalLineSpacing); - - ch = ch.map(c2 => { - if(!c2.isn && !prop.blockDisplay){ - c2.x += SignRenderer.calculateAlignmentOffset(prop.alignContents, w[c2.row], width); - } - - return c2; - }); - - // mitt-x (element), se även if-sats nedan - // mitt-y (rad), se även if-sats nedan - firstLastCenter = [ - padding[0] + ch[0].x + ch[0].bs[0], - padding[1], - padding[0] + ch[ch.length - 1].x + ch[ch.length - 1].bs[0], - height + padding[1] - ]; - - if(prop.passAnchor){ - firstLastCenter[0] += ch[0].r.flc[0]; - firstLastCenter[1] += ch[0].bs[1] + ch[0].r.flc[1]; - firstLastCenter[2] += ch[ch.length - 1].r.flc[2]; - firstLastCenter[3] += ch[ch.length - 1].bs[1] - h[h.length - 1] + ch[ch.length - 1].r.flc[3]; - }else{ - firstLastCenter[0] += Math.floor(ch[0].r.w / 2); - firstLastCenter[1] += Math.floor(h[0] / 2); - firstLastCenter[2] += Math.floor(ch[ch.length - 1].r.w / 2); - firstLastCenter[3] += Math.floor(-h[h.length - 1] / 2); - } - - let y = 0; - - renderPromise = (ctx, x0, y0, _) => Promise.all(ch.map((c2, i) => { - if(c2.isn || (i > 0 && prop.blockDisplay)){ - y += (prop.blockDisplay ? prop.lineSpacing : (c2.p?.lineSpacing ?? prop.lineSpacing)); - y += h[c2.row - 1]; - } - - if(c2.isn) return; - - let dx = 0, iw = prop.blockDisplay ? (width - c2.bs[0] - c2.bs[2]) : c2.r.w; - - if(prop.blockDisplay){ - dx += SignRenderer.calculateAlignmentOffset(c2.p?.alignContents, w[c2.row], iw + c2.bs[0] + c2.bs[2]); - } - - return c2.r.doRender( - ctx, - x0 + padding[0] + c2.x, y0 + padding[1] + y, - dx, - h[c2.row] - c2.bs[1] - c2.bs[3], - prop.alignContentsV, - iw - ); - })).then(() => {}); - }else if(opt.type === "vagnr" || opt.type === "text"){ - let ctx_temp = this.createCanvas(); - - ctx_temp.font = "32px " + prop.font; - - width = Math.floor(ctx_temp.measureText(prop.value ?? "").width); - height = prop.lineHeight; - - renderPromise = (ctx, x0, y0, _) => new Promise(res => { - if(prop.dashedInset){ - let bw = prop.borderWidth; - - roundedFrame( - ctx, - x0 + 2*bw[0], y0 + 2*bw[1], - width + padding[0] + padding[2] - 2*bw[0] - 2*bw[2], height + padding[1] + padding[3] - 2*bw[1] - 2*bw[3], - bw, - prop.color, - prop.borderRadius, - [10, 10] - ); - } - - ctx.font = "32px " + prop.font; - ctx.textBaseline = "middle"; - - ctx.fillStyle = prop.color; - ctx.fillText(prop.value ?? "", x0 + padding[0], y0 + firstLastCenter[1]); - - res(); - }); - }else if(opt.type === "symbol"){ - let symbolType = this.conf.symbols[prop.type ?? ""]; - - width = symbolType.width; - [height, maxHeight] = symbolType.height; - - let url = "res/symbol/" + (prop.type ?? "default") + ".json"; - let v: string | undefined = prop.variant ?? symbolType.default; - - renderPromise = (ctx, x0, y0, maxInnerHeight) => this.drawVec( - ctx, url, prop.color, v === undefined ? [] : [v], - x0 + padding[0], y0 + padding[1], // dx, dy - width, maxInnerHeight - padding[1] - padding[3] // dw=sw, dh=sh - ); - }else if(opt.type === "newline"){ - width = 0; - height = 0; - }else if(opt.type.startsWith(".") && opt.nodes !== undefined){ - let nodes = opt.nodes; - let t = this.conf.signTypes[opt.type.slice(1)]; - let keys = Object.keys(t.nodes).sort().filter(nodeName => !!nodes[nodeName]); - - let svgBox = Array.from(t.core); - keys.forEach(nodeName => { - svgBox[0] = Math.min(svgBox[0], t.nodes[nodeName].x[0]); - svgBox[1] = Math.max(svgBox[1], t.nodes[nodeName].x[1]); - svgBox[2] = Math.min(svgBox[2], t.nodes[nodeName].y[0]); - svgBox[3] = Math.max(svgBox[3], t.nodes[nodeName].y[1]); - }); - - let boundingBox = [ - svgBox[0] * t.width, - svgBox[1] * t.width, - svgBox[2] * t.height, - svgBox[3] * t.height - ].map(Math.floor); - - // fonts and svg loaded successfully - let r = keys.map(nodeName => { - let n = nodes[nodeName]; - let s = n.data; - - let tn = t.nodes[nodeName]; - - let ax = n.anchor?.x ?? tn.ax, - ay = n.anchor?.y ?? tn.ay; - - let result = this._render(s, SignRenderer.getInhProperties(prop)); - let bs = result.bs; - - let rse = [ result.w + bs[0] + bs[2], result.h + bs[1] + bs[3] ]; - - let lx = tn.x.map(x => x * t.width).map(Math.floor), ty = tn.y.map(y => y * t.height).map(Math.floor); - let leftX: number = 0, topY: number = 0; - - switch(ax){ - case "right": - leftX = lx[1] - rse[0]; - break; - case "center": - leftX = Math.floor((lx[0] + lx[1]) / 2 - Math.floor(rse[0] / 2)); - break; - case "center-first": - leftX = Math.floor((lx[0] + lx[1]) / 2) - result.flc[0]; - break; - case "center-last": - leftX = Math.floor((lx[0] + lx[1]) / 2) - result.flc[2]; - break; - default: - leftX = lx[0]; - } - - switch(ay){ - case "bottom": - topY = ty[1] - rse[1]; - break; - case "middle": - topY = Math.floor((ty[0] + ty[1]) / 2) - Math.floor(rse[1] / 2); - break; - case "middle-first": - topY = Math.floor((ty[0] + ty[1]) / 2) - result.flc[1] - bs[1]; - break; - case "middle-last": - topY = Math.floor((ty[0] + ty[1]) / 2) - result.flc[3] - bs[1]; - break; - default: - topY = ty[0]; - } - - boundingBox = [ - Math.min(boundingBox[0], leftX), - Math.max(boundingBox[1], leftX + rse[0]), - Math.min(boundingBox[2], topY), - Math.max(boundingBox[3], topY + rse[1]) - ]; - - return { renderPromise: result, x: leftX, y: topY, p: s.properties }; - }); - - width = boundingBox[1] - boundingBox[0]; - height = boundingBox[3] - boundingBox[2]; - - renderPromise = (ctx, x0, y0, _) => Promise.all(r.map(res => { - let x1 = res.x - boundingBox[0], - y1 = res.y - boundingBox[2]; - - let dx = 0; - - return res.renderPromise.doRender(ctx, x0 + padding[0] + x1, y0 + padding[1] + y1, dx, res.renderPromise.h, prop.alignContentsV); - })).then(() => { - if(t.width === 0 || t.height === 0) return; - - svgBox[0] = Math.min(1, Math.max(0, boundingBox[0] / t.width)); - svgBox[1] = Math.max(0, Math.min(1, boundingBox[1] / t.width)); - svgBox[2] = Math.min(1, Math.max(0, boundingBox[2] / t.height)); - svgBox[3] = Math.max(0, Math.min(1, boundingBox[3] / t.height)); - - let crop = [ - svgBox[0] * t.width, - svgBox[2] * t.height, - (svgBox[1] - svgBox[0]) * t.width, - (svgBox[3] - svgBox[2]) * t.height - ]; // [x0, y0, w, h] - - return this.drawVec( - ctx, "res/" + opt.type.slice(1) + ".json", prop.color, keys, - x0 + prop.padding[0] - boundingBox[0] + crop[0], // dx - y0 + prop.padding[1] - boundingBox[2] + crop[1], // dy - crop[2], crop[3], // dw=sw, dh=sh - crop[0], crop[1] // sx, sy - ); - }); - }else{ - alert("Fel!"); - } - - let bs = this.borderSize(width + padding[0] + padding[2], height + padding[1] + padding[3], prop); - - if(firstLastCenter.some(isNaN)){ - firstLastCenter = [ - Math.floor((width + padding[0] + padding[2]) / 2), - Math.floor((height + padding[1] + padding[3]) / 2), - Math.floor((width + padding[0] + padding[2]) / 2), - Math.floor((height + padding[1] + padding[3]) / 2) - ]; - } - - if(maxHeight < height) maxHeight = height; - - return { - flc: firstLastCenter, - w: width + padding[0] + padding[2], - h: height + padding[1] + padding[3], - bs: bs.h, - doRender: async (ctx: T, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw = 0) => { - const dy = 0; - const innerWidth = iw === 0 ? (width + padding[0] + padding[2]) : iw; - let innerHeight = height + padding[1] + padding[3]; - - if(prop.grow && innerHeight < maxInnerHeight){ - innerHeight = Math.min(maxInnerHeight, padding[1] + padding[3] + maxHeight); - } - - switch (verticalAlign) { - case "middle": - y0 += Math.floor((maxInnerHeight - innerHeight) / 2); - break; - case "bottom": - y0 += maxInnerHeight - innerHeight; - break; - } - - // tag bort rundade hörn på sidor med hela kantutsmyckningar - let bfs = ["left", "top", "right", "bottom"].map(s => { - let bf = prop.borderFeatures[s]; - return bf !== undefined && this.conf.borderFeatures[bf].cover; // cover => hel, täcker hela kantens längd - }); - - let br: Vec4 = [...prop.borderRadius], - bw: Vec4 = [...prop.borderWidth]; - - for(let i = 0; i < 4; i++){ - if(bfs[i] || bfs[(i + 1) % 4]) br[i] = 0; - if(bfs[i]) bw[i] = 0; - } - - roundedFill( - ctx, - x0 + bs.h[0], y0 + bs.h[1], - innerWidth, innerHeight, - bw, - br, - prop.background, - !!prop.fillCorners - ); - - await renderPromise(ctx, x0 + dx + bs.h[0], y0 + dy + bs.h[1], innerHeight); - - roundedFrame( - ctx, - x0 + bs.h[0], y0 + bs.h[1], - innerWidth, innerHeight, - bw, - prop.color, - br - ); - - Object.entries(prop.borderFeatures).forEach(feature => { - this.renderBorderFeature(ctx, x0, y0, this.conf.borderFeatures[feature[1]], feature[0], bs, innerWidth, innerHeight, prop); - }); - } - }; - } - - public async render(data: SignElementOptions): Promise{ - let r = this._render(data, null); - - let bs = r.bs; - let canv = this.createCanvas(r.w + bs[0] + bs[2], r.h + bs[1] + bs[3]); - - if(canv === null) throw new Error("Fel: Kunde inte hitta tvådimensionell renderingskontext."); - - await r.doRender(canv, 0, 0, 0, r.h); - return canv.canv; - } -} \ No newline at end of file diff --git a/packages/skyltrendering/src/typedefs.ts b/packages/skyltrendering/src/typedefs.ts deleted file mode 100644 index 7e724a0..0000000 --- a/packages/skyltrendering/src/typedefs.ts +++ /dev/null @@ -1,185 +0,0 @@ -export type MathEnv = { [key: string]: number}; - -export type Vec2 = [number, number]; -export type Vec4 = [number, number, number, number]; -export type Vec6 = [number, number, number, number, number, number]; - -/** - * Designer sparas i "nedre kant"-form, dvs. - * orienterade på motsvarande sätt som klammern - * i skylt F9 (samlingsmärke för vägvisning). - */ -export type BorderFeatureDefinition = { - vars?: string[][]; - paths: {p: string, f?: number, s?: number}[]; - w: number; - h: number | string; - cover: boolean; -}; - -type SignTypeDefinition = { - nodes: { - [key: string]: { - x: number[]; - y: number[]; - ax?: string; - ay?: string; - } - }; - width: number; - height: number; - core: number[]; -}; - -type SignSymbolDefinition = { - width: number; - height: number[]; - default?: string; -}; - -// properties som ärvs (måste därför specificeras av rootDefaults) -export type SignElementBaseProperties = { - background: string; - borderRadius: number[] | number; - color: string; - font: string; - lineHeight: number; - lineSpacing: number; - xSpacing: number; -}; - -// properties (utöver de i SignElementBaseProperties) som alltid måste finnas -// dessa måste alltså specificeras av globalDefaults -type SignElementRequiredProperties = { - borderFeatures: {[key: string]: string;}; - borderWidth: number[] | number; - padding: number[] | number; -}; - -// properties som inte alltid finns i this.properties (dvs. aldrig obligatoriska) -type SignElementOptionalProperties = { - alignContents: string; - alignContentsV: string; - blockDisplay: boolean; - dashedInset: boolean; - fillCorners: boolean; - grow: boolean; - passAnchor: boolean; - type: string; // symbol - value: string; // text, vagnr - variant: string; // symbol -}; - -// properties som kan specificeras av användaren (inga är obligatoriska) -type SignElementUserProperties = Partial; - -// formatet som this.properties följer -export interface SignElementProperties extends SignElementBaseProperties, SignElementRequiredProperties, Partial{ - borderFeatures: {[key: string]: string}; - borderRadius: Vec4; - borderWidth: Vec4; - padding: Vec4; -}; - -type SignElementAnchor = { - x?: string; - y?: string; -}; - -type SignElementNode = { - anchor?: SignElementAnchor; - data: SignElementOptions; -}; - -// data som ges av användaren -export type SignElementOptions = { - format?: number; // not currently used - type: string; - properties?: SignElementUserProperties; - elements?: SignElementOptions[]; - nodes?: {[key: string]: SignElementNode}; - params?: any[]; -} - -export type PropertiesDefaults = { - globalDefaults: SignElementUserProperties & SignElementRequiredProperties; - rootDefaults: SignElementBaseProperties & SignElementUserProperties; - defaults: {[key: string]: SignElementUserProperties}; -}; - -export type ConfigData = { - // Olika standardegenskaper - properties: PropertiesDefaults, - - // Skylttyper ("symboler med noder") - signTypes: { - [key: string]: SignTypeDefinition; - }, - - // Symboldefinitioner - symbols: { - [key: string]: SignSymbolDefinition; - }, - - // Kantdekorationer - borderFeatures: { - [key: string]: BorderFeatureDefinition; - }, - - // "Dynamiska" mallar (funktioner "parametrar => skyltkonfiguration") - templates: { - [key: string]: (...args: any[]) => SignElementOptions; - } -}; - -export type UserConfigData = Partial; - -export type RenderingResult> = { - flc: Vec4; - w: number; - h: number; - bs: Vec4; - doRender: (ctx: T, x0: number, y0: number, dx: number, maxInnerHeight: number, verticalAlign?: string, iw?: number) => Promise; -}; - -export interface Path2D{ - moveTo(x: number, y: number): void; - lineTo(x: number, y: number): void; - ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise: boolean): void; - closePath(): void; -}; - -type JSONVecElement = {path: string, fill: string}; -export type JSONVecReference = {use: number, translate?: [number, number]}; - -export type JSONVec = { - width: number; - height: number; - vectorSize: [number, number]; - defs: JSONVecElement[]; - core?: JSONVecReference[]; - components?: {[key: string]: JSONVecReference[]}; -}; - -export interface NewDrawingArea{ - canv: T; - - createPath2D(s?: string, m?: Vec6): Path2D; - - measureText(text: string): {width: number}; - - set fillStyle(x: string); - set strokeStyle(x: string); - set lineWidth(x: number); - - set font(x: string); - set textBaseline(x: string); - - fill(path: Path2D): void; - stroke(path: Path2D): void; - - fillRect(x: number, y: number, w: number, h: number): void; - fillText(text: string, x: number, y: number): void; - - drawImage(image: NewDrawingArea, dx: number, dy: number): void; -}; \ No newline at end of file diff --git a/packages/skyltrendering/src/utils.ts b/packages/skyltrendering/src/utils.ts deleted file mode 100644 index ba33dd5..0000000 --- a/packages/skyltrendering/src/utils.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { MathEnv } from "./typedefs.js"; - -export function mathEval(str: string | number, vars: MathEnv = {}): number{ - if(typeof str === "number") return str; - - let v = [0], operators = ["+"], tmp = ""; - - let doOp = (a: number = 0, op: string = "+", b: number = 0): number => { - switch(op){ - case "+": - a += b; - break; - case "-": - a -= b; - break; - case "*": - a *= b; - break; - case "/": - a /= b; - break; - case "sqrt": - a = Math.sqrt(b); - //console.log(a, b); - break; - } - - return a; - }; - - let c; - for(let i = 0; i <= str.length; i++){ - switch(c = str.charAt(i) || "+"){ - case " ": - continue; - case "(": - v.push(0); - if(tmp.length > 0){ - operators.push(tmp); - tmp = ""; - break; - } - operators.push("+"); - break; - case ")": - case "*": - case "/": - case "+": - case "-": - let x0 = tmp.length > 0 ? doOp(v.pop(), operators.pop(), isNaN(parseFloat(tmp)) ? vars[tmp] : parseFloat(tmp)) : v.pop(); - tmp = ""; - - if(c === ")"){ - v[v.length - 1] = doOp(v[v.length - 1], operators.pop(), x0); - break; - } - - v.push(x0 || 0); - operators.push(c); - break; - default: - tmp += c; - } - } - - return v[0]; -} - -export function parseVarStr(str: string, vars = {}): string{ - const EXPRESSION = new RegExp(/\$\{([^\{\}]+)\}/g); - - let result: string[] = []; - - let i = 0; - while(true){ - let match = EXPRESSION.exec(str); - - if(match === null || EXPRESSION.lastIndex === 0) break; - - result.push(str.substring(i, match.index).concat(String(mathEval(match[1], vars)))); - - i = match.index + match[0].length; - } - - return result.join("") + str.substring(i); -} \ No newline at end of file diff --git a/packages/skyltrendering/tsconfig.json b/packages/skyltrendering/tsconfig.json deleted file mode 100644 index 1b75592..0000000 --- a/packages/skyltrendering/tsconfig.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "compilerOptions": { - /* Language and Environment */ - "target": "es2017", - "noLib": false, - - /* Modules */ - "module": "node16", - "rootDir": "./src", - "moduleResolution": "node16", - - /* Emit */ - "declaration": true, - "outDir": "./dist/node", - "removeComments": true, - - /* Interop Constraints */ - "esModuleInterop": false, - "forceConsistentCasingInFileNames": true, - - /* Type Checking */ - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": false, - "noImplicitOverride": true - }, - "files": ["./src/main.ts"], - "include": ["./src/**.ts"], - "exclude": ["./src/browser.ts"] -} diff --git a/packages/skyltrendering/utils/clean.js b/packages/skyltrendering/utils/clean.js deleted file mode 100644 index e60b971..0000000 --- a/packages/skyltrendering/utils/clean.js +++ /dev/null @@ -1,34 +0,0 @@ -(function(){ - const fs = require('fs'); - - function rmFile(path){ - console.log("rm " + path); - fs.rmSync(path); - } - - function rmDirectory(path, rmSelf = true){ - fs.readdirSync(path, {recursive: false, withFileTypes: true}).map(y => { - if(y.isFile()){ - rmFile(path + y.name); - }else if(y.isDirectory()){ - rmDirectory(path + y.name + "/"); - } - }); - - if(!rmSelf) return; - - console.log("rmdir " + path); - fs.rmdirSync(path); - } - - process.argv.slice(2).map(x => { - if(!fs.existsSync(x)) return; - if(x.endsWith("/")){ - rmDirectory(x, false); - }else{ - rmFile(x); - } - }); - - process.exit(0); -})(); \ No newline at end of file diff --git a/font/TRATEXPOSVERSAL-POSVERSAL.otf b/public/font/TRATEXPOSVERSAL-POSVERSAL.otf similarity index 100% rename from font/TRATEXPOSVERSAL-POSVERSAL.otf rename to public/font/TRATEXPOSVERSAL-POSVERSAL.otf diff --git a/font/TratexSvart-Regular.otf b/public/font/TratexSvart-Regular.otf similarity index 100% rename from font/TratexSvart-Regular.otf rename to public/font/TratexSvart-Regular.otf diff --git a/public/render.html b/public/render.html index f628844..37ef042 100644 --- a/public/render.html +++ b/public/render.html @@ -5,6 +5,6 @@ - + \ No newline at end of file diff --git a/res/junction.json b/public/res/junction.json similarity index 100% rename from res/junction.json rename to public/res/junction.json diff --git a/res/roundabout.json b/public/res/roundabout.json similarity index 100% rename from res/roundabout.json rename to public/res/roundabout.json diff --git a/res/spanish.json b/public/res/spanish.json similarity index 100% rename from res/spanish.json rename to public/res/spanish.json diff --git a/res/symbol/arrow-small.json b/public/res/symbol/arrow-small.json similarity index 100% rename from res/symbol/arrow-small.json rename to public/res/symbol/arrow-small.json diff --git a/res/symbol/exit.json b/public/res/symbol/exit.json similarity index 100% rename from res/symbol/exit.json rename to public/res/symbol/exit.json diff --git a/res/symbol/h1.json b/public/res/symbol/h1.json similarity index 100% rename from res/symbol/h1.json rename to public/res/symbol/h1.json diff --git a/res/symbol/h10.json b/public/res/symbol/h10.json similarity index 100% rename from res/symbol/h10.json rename to public/res/symbol/h10.json diff --git a/res/symbol/h11.json b/public/res/symbol/h11.json similarity index 100% rename from res/symbol/h11.json rename to public/res/symbol/h11.json diff --git a/res/symbol/h12.json b/public/res/symbol/h12.json similarity index 100% rename from res/symbol/h12.json rename to public/res/symbol/h12.json diff --git a/res/symbol/h13.json b/public/res/symbol/h13.json similarity index 100% rename from res/symbol/h13.json rename to public/res/symbol/h13.json diff --git a/res/symbol/h14.json b/public/res/symbol/h14.json similarity index 100% rename from res/symbol/h14.json rename to public/res/symbol/h14.json diff --git a/res/symbol/h15.json b/public/res/symbol/h15.json similarity index 100% rename from res/symbol/h15.json rename to public/res/symbol/h15.json diff --git a/res/symbol/h16.json b/public/res/symbol/h16.json similarity index 100% rename from res/symbol/h16.json rename to public/res/symbol/h16.json diff --git a/res/symbol/h17.json b/public/res/symbol/h17.json similarity index 100% rename from res/symbol/h17.json rename to public/res/symbol/h17.json diff --git a/res/symbol/h18.json b/public/res/symbol/h18.json similarity index 100% rename from res/symbol/h18.json rename to public/res/symbol/h18.json diff --git a/res/symbol/h19.json b/public/res/symbol/h19.json similarity index 100% rename from res/symbol/h19.json rename to public/res/symbol/h19.json diff --git a/res/symbol/h2.json b/public/res/symbol/h2.json similarity index 100% rename from res/symbol/h2.json rename to public/res/symbol/h2.json diff --git a/res/symbol/h20.json b/public/res/symbol/h20.json similarity index 100% rename from res/symbol/h20.json rename to public/res/symbol/h20.json diff --git a/res/symbol/h21.json b/public/res/symbol/h21.json similarity index 100% rename from res/symbol/h21.json rename to public/res/symbol/h21.json diff --git a/res/symbol/h22.json b/public/res/symbol/h22.json similarity index 100% rename from res/symbol/h22.json rename to public/res/symbol/h22.json diff --git a/res/symbol/h24.json b/public/res/symbol/h24.json similarity index 100% rename from res/symbol/h24.json rename to public/res/symbol/h24.json diff --git a/res/symbol/h25.json b/public/res/symbol/h25.json similarity index 100% rename from res/symbol/h25.json rename to public/res/symbol/h25.json diff --git a/res/symbol/h26.json b/public/res/symbol/h26.json similarity index 100% rename from res/symbol/h26.json rename to public/res/symbol/h26.json diff --git a/res/symbol/h27.json b/public/res/symbol/h27.json similarity index 100% rename from res/symbol/h27.json rename to public/res/symbol/h27.json diff --git a/res/symbol/h28.json b/public/res/symbol/h28.json similarity index 100% rename from res/symbol/h28.json rename to public/res/symbol/h28.json diff --git a/res/symbol/h3.json b/public/res/symbol/h3.json similarity index 100% rename from res/symbol/h3.json rename to public/res/symbol/h3.json diff --git a/res/symbol/h4.json b/public/res/symbol/h4.json similarity index 100% rename from res/symbol/h4.json rename to public/res/symbol/h4.json diff --git a/res/symbol/h5.json b/public/res/symbol/h5.json similarity index 100% rename from res/symbol/h5.json rename to public/res/symbol/h5.json diff --git a/res/symbol/h6.json b/public/res/symbol/h6.json similarity index 100% rename from res/symbol/h6.json rename to public/res/symbol/h6.json diff --git a/res/symbol/h7.json b/public/res/symbol/h7.json similarity index 100% rename from res/symbol/h7.json rename to public/res/symbol/h7.json diff --git a/res/symbol/h8.json b/public/res/symbol/h8.json similarity index 100% rename from res/symbol/h8.json rename to public/res/symbol/h8.json diff --git a/res/symbol/h9.json b/public/res/symbol/h9.json similarity index 100% rename from res/symbol/h9.json rename to public/res/symbol/h9.json diff --git a/res/water.json b/public/res/water.json similarity index 100% rename from res/water.json rename to public/res/water.json From 44c11394e45444adfba6c23beb7d8619db419e02 Mon Sep 17 00:00:00 2001 From: axelw3 Date: Sat, 1 Mar 2025 00:53:40 +0100 Subject: [PATCH 12/12] =?UTF-8?q?L=C3=A4gg=20till=20arbetsfl=C3=B6de=20f?= =?UTF-8?q?=C3=B6r=20github=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 46 +++++++++++++++++++++++++ public/index.html | 2 +- templates.json => public/templates.json | 0 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/deploy.yml rename templates.json => public/templates.json (100%) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..001d53f --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,46 @@ +name: Build and deploy to pages + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +permissions: + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Use Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: 'npm' + - name: Install dependencies + run: npm ci + - name: Build + run: npm run build + - name: Upload + uses: actions/upload-pages-artifact@v3 + with: + path: dist/ + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + if: github.event_name == 'push' && needs.build.result == 'success' + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + with: + token: ${{ github.token }} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 310d328..ee75ddd 100644 --- a/public/index.html +++ b/public/index.html @@ -3,7 +3,7 @@ Skyltprogram - + diff --git a/templates.json b/public/templates.json similarity index 100% rename from templates.json rename to public/templates.json