quickdbd-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quickdbd_cli/__init__.py +1 -0
- quickdbd_cli/__main__.py +5 -0
- quickdbd_cli/assets/Inter-Bold.ttf +0 -0
- quickdbd_cli/assets/Inter-Bold.woff2 +0 -0
- quickdbd_cli/assets/Inter-LICENSE.txt +92 -0
- quickdbd_cli/assets/Inter-Regular.ttf +0 -0
- quickdbd_cli/assets/Inter-Regular.woff2 +0 -0
- quickdbd_cli/assets/editor.js +244 -0
- quickdbd_cli/assets/elk-LICENSE.md +263 -0
- quickdbd_cli/assets/elk.bundled.js +6605 -0
- quickdbd_cli/assets/font-metrics.json +1 -0
- quickdbd_cli/assets/render.js +230 -0
- quickdbd_cli/assets/style.css +83 -0
- quickdbd_cli/assets/viewer.js +337 -0
- quickdbd_cli/cli.py +169 -0
- quickdbd_cli/export.py +79 -0
- quickdbd_cli/html.py +97 -0
- quickdbd_cli/jsrt.py +77 -0
- quickdbd_cli/layout.py +207 -0
- quickdbd_cli/measure.py +111 -0
- quickdbd_cli/model.py +107 -0
- quickdbd_cli/parser.py +717 -0
- quickdbd_cli/project.py +69 -0
- quickdbd_cli/serve.py +210 -0
- quickdbd_cli-0.1.0.dist-info/METADATA +153 -0
- quickdbd_cli-0.1.0.dist-info/RECORD +32 -0
- quickdbd_cli-0.1.0.dist-info/WHEEL +4 -0
- quickdbd_cli-0.1.0.dist-info/entry_points.txt +2 -0
- quickdbd_cli-0.1.0.dist-info/licenses/LICENSE +201 -0
- quickdbd_cli-0.1.0.dist-info/licenses/NOTICE +19 -0
- quickdbd_cli-0.1.0.dist-info/licenses/src/quickdbd_cli/assets/Inter-LICENSE.txt +92 -0
- quickdbd_cli-0.1.0.dist-info/licenses/src/quickdbd_cli/assets/elk-LICENSE.md +263 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bold": {" ": 0.2368, "!": 0.3379, "\"": 0.5518, "#": 0.6489, "$": 0.6548, "%": 1.0156, "&": 0.6719, "'": 0.3389, "(": 0.377, ")": 0.377, "*": 0.5591, "+": 0.6787, ",": 0.334, "-": 0.4678, ".": 0.334, "/": 0.3882, "0": 0.6743, "1": 0.4312, "2": 0.6299, "3": 0.6455, "4": 0.6763, "5": 0.6221, "6": 0.6494, "7": 0.5815, "8": 0.6509, "9": 0.6494, ":": 0.334, ";": 0.3428, "<": 0.6787, "=": 0.6787, ">": 0.6787, "?": 0.5596, "@": 1.0161, "A": 0.7466, "B": 0.6616, "C": 0.7397, "D": 0.7222, "E": 0.6074, "F": 0.5869, "G": 0.7505, "H": 0.7471, "I": 0.2808, "J": 0.5845, "K": 0.7192, "L": 0.5654, "M": 0.9316, "N": 0.7622, "O": 0.7705, "P": 0.6479, "Q": 0.7769, "R": 0.6567, "S": 0.6548, "T": 0.6675, "U": 0.7319, "V": 0.7466, "W": 1.0376, "X": 0.7383, "Y": 0.731, "Z": 0.6641, "[": 0.377, "\\": 0.3882, "]": 0.377, "^": 0.4868, "_": 0.4761, "`": 0.3652, "a": 0.5806, "b": 0.6304, "c": 0.5884, "d": 0.6304, "e": 0.5957, "f": 0.3979, "g": 0.6318, "h": 0.6226, "i": 0.271, "j": 0.271, "k": 0.5801, "l": 0.271, "m": 0.9126, "n": 0.6226, "o": 0.6133, "p": 0.6304, "q": 0.6304, "r": 0.4072, "s": 0.5601, "t": 0.3662, "u": 0.6226, "v": 0.5996, "w": 0.8501, "x": 0.5801, "y": 0.6021, "z": 0.5728, "{": 0.4688, "|": 0.3716, "}": 0.4688, "~": 0.6787, " ": 0.2368, "¡": 0.3379, "¢": 0.5884, "£": 0.6387, "¤": 0.7617, "¥": 0.5703, "¦": 0.3389, "§": 0.5684, "¨": 0.6226, "©": 0.9141, "ª": 0.4639, "«": 0.6602, "¬": 0.6787, "®": 0.6621, "¯": 0.439, "°": 0.4595, "±": 0.6787, "²": 0.46, "³": 0.4717, "´": 0.3652, "µ": 0.6279, "¶": 0.5986, "·": 0.334, "¸": 0.3643, "¹": 0.333, "º": 0.4897, "»": 0.6602, "¼": 0.8457, "½": 0.8813, "¾": 0.9199, "¿": 0.5596, "À": 0.7466, "Á": 0.7466, "Â": 0.7466, "Ã": 0.7466, "Ä": 0.7466, "Å": 0.7466, "Æ": 1.0225, "Ç": 0.7397, "È": 0.6074, "É": 0.6074, "Ê": 0.6074, "Ë": 0.6074, "Ì": 0.2808, "Í": 0.2808, "Î": 0.2808, "Ï": 0.2808, "Ð": 0.7598, "Ñ": 0.7622, "Ò": 0.7705, "Ó": 0.7705, "Ô": 0.7705, "Õ": 0.7705, "Ö": 0.7705, "×": 0.6787, "Ø": 0.7705, "Ù": 0.7319, "Ú": 0.7319, "Û": 0.7319, "Ü": 0.7319, "Ý": 0.731, "Þ": 0.6689, "ß": 0.6572, "à": 0.5806, "á": 0.5806, "â": 0.5806, "ã": 0.5806, "ä": 0.5806, "å": 0.5806, "æ": 0.9102, "ç": 0.5884, "è": 0.5957, "é": 0.5957, "ê": 0.5957, "ë": 0.5957, "ì": 0.271, "í": 0.271, "î": 0.271, "ï": 0.271, "ð": 0.5991, "ñ": 0.6226, "ò": 0.6133, "ó": 0.6133, "ô": 0.6133, "õ": 0.6133, "ö": 0.6133, "÷": 0.6787, "ø": 0.6133, "ù": 0.6226, "ú": 0.6226, "û": 0.6226, "ü": 0.6226, "ý": 0.6021, "þ": 0.6304, "ÿ": 0.6021, "Ā": 0.7466, "ā": 0.5806, "Ă": 0.7466, "ă": 0.5806, "Ą": 0.7466, "ą": 0.5806, "Ć": 0.7397, "ć": 0.5884, "Ĉ": 0.7397, "ĉ": 0.5884, "Ċ": 0.7397, "ċ": 0.5884, "Č": 0.7397, "č": 0.5884, "Ď": 0.7222, "ď": 0.7544, "Đ": 0.7598, "đ": 0.6304, "Ē": 0.6074, "ē": 0.5957, "Ĕ": 0.6074, "ĕ": 0.5957, "Ė": 0.6074, "ė": 0.5957, "Ę": 0.6074, "ę": 0.5957, "Ě": 0.6074, "ě": 0.5957, "Ĝ": 0.7505, "ĝ": 0.6318, "Ğ": 0.7505, "ğ": 0.6318, "Ġ": 0.7505, "ġ": 0.6318, "Ģ": 0.7505, "ģ": 0.6318, "Ĥ": 0.7471, "ĥ": 0.6226, "Ħ": 0.8071, "ħ": 0.6226, "Ĩ": 0.2808, "ĩ": 0.271, "Ī": 0.2808, "ī": 0.271, "Ĭ": 0.2808, "ĭ": 0.271, "Į": 0.2808, "į": 0.271, "İ": 0.2808, "ı": 0.271, "IJ": 0.8647, "ij": 0.5425, "Ĵ": 0.5845, "ĵ": 0.271, "Ķ": 0.7192, "ķ": 0.5801, "ĸ": 0.5864, "Ĺ": 0.5654, "ĺ": 0.271, "Ļ": 0.5654, "ļ": 0.271, "Ľ": 0.5654, "ľ": 0.395, "Ŀ": 0.5776, "ŀ": 0.4492, "Ł": 0.6055, "ł": 0.271, "Ń": 0.7622, "ń": 0.6226, "Ņ": 0.7622, "ņ": 0.6226, "Ň": 0.7622, "ň": 0.6226, "Ŋ": 0.7622, "ŋ": 0.6226, "Ō": 0.7705, "ō": 0.6133, "Ŏ": 0.7705, "ŏ": 0.6133, "Ő": 0.7705, "ő": 0.6133, "Œ": 1.0176, "œ": 0.9878, "Ŕ": 0.6567, "ŕ": 0.4072, "Ŗ": 0.6567, "ŗ": 0.4072, "Ř": 0.6567, "ř": 0.4072, "Ś": 0.6548, "ś": 0.5601, "Ŝ": 0.6548, "ŝ": 0.5601, "Ş": 0.6548, "ş": 0.5601, "Š": 0.6548, "š": 0.5601, "Ţ": 0.6675, "ţ": 0.3662, "Ť": 0.6675, "ť": 0.4414, "Ŧ": 0.6675, "ŧ": 0.3662, "Ũ": 0.7319, "ũ": 0.6226, "Ū": 0.7319, "ū": 0.6226, "Ŭ": 0.7319, "ŭ": 0.6226, "Ů": 0.7319, "ů": 0.6226, "Ű": 0.7319, "ű": 0.6226, "Ų": 0.7319, "ų": 0.6226, "Ŵ": 1.0376, "ŵ": 0.8501, "Ŷ": 0.731, "ŷ": 0.6021, "Ÿ": 0.731, "Ź": 0.6641, "ź": 0.5728, "Ż": 0.6641, "ż": 0.5728, "Ž": 0.6641, "ž": 0.5728, "ſ": 0.3447}, "regular": {" ": 0.2812, "!": 0.2876, "\"": 0.4658, "#": 0.6333, "$": 0.6416, "%": 0.9819, "&": 0.644, "'": 0.2998, "(": 0.3647, ")": 0.3647, "*": 0.501, "+": 0.6616, ",": 0.2881, "-": 0.46, ".": 0.2881, "/": 0.3604, "0": 0.6309, "1": 0.4067, "2": 0.6099, "3": 0.6177, "4": 0.646, "5": 0.5933, "6": 0.6201, "7": 0.5659, "8": 0.6187, "9": 0.6201, ":": 0.2881, ";": 0.3018, "<": 0.6616, "=": 0.6616, ">": 0.6616, "?": 0.5112, "@": 0.9658, "A": 0.6899, "B": 0.6543, "C": 0.7305, "D": 0.7217, "E": 0.6011, "F": 0.5903, "G": 0.7461, "H": 0.7432, "I": 0.2686, "J": 0.5708, "K": 0.6719, "L": 0.5654, "M": 0.9033, "N": 0.7534, "O": 0.7646, "P": 0.6387, "Q": 0.7646, "R": 0.6436, "S": 0.6416, "T": 0.6455, "U": 0.7441, "V": 0.6899, "W": 0.9854, "X": 0.6821, "Y": 0.6787, "Z": 0.6289, "[": 0.3647, "\\": 0.3604, "]": 0.3647, "^": 0.4712, "_": 0.4561, "`": 0.3228, "a": 0.5615, "b": 0.6123, "c": 0.5713, "d": 0.6123, "e": 0.583, "f": 0.3701, "g": 0.6133, "h": 0.5913, "i": 0.2422, "j": 0.2422, "k": 0.5488, "l": 0.2422, "m": 0.876, "n": 0.5908, "o": 0.5996, "p": 0.6123, "q": 0.6123, "r": 0.3765, "s": 0.5278, "t": 0.3271, "u": 0.5913, "v": 0.562, "w": 0.8184, "x": 0.5459, "y": 0.562, "z": 0.5522, "{": 0.4263, "|": 0.3325, "}": 0.4263, "~": 0.6616, " ": 0.2812, "¡": 0.2876, "¢": 0.5713, "£": 0.6108, "¤": 0.7246, "¥": 0.5498, "¦": 0.27, "§": 0.5684, "¨": 0.5908, "©": 0.9141, "ª": 0.4536, "«": 0.5825, "¬": 0.6616, "®": 0.666, "¯": 0.4775, "°": 0.4556, "±": 0.6616, "²": 0.4419, "³": 0.4458, "´": 0.3228, "µ": 0.5859, "¶": 0.6025, "·": 0.2881, "¸": 0.2681, "¹": 0.3042, "º": 0.4824, "»": 0.5825, "¼": 0.8022, "½": 0.8472, "¾": 0.8818, "¿": 0.5112, "À": 0.6899, "Á": 0.6899, "Â": 0.6899, "Ã": 0.6899, "Ä": 0.6899, "Å": 0.6899, "Æ": 0.9937, "Ç": 0.7305, "È": 0.6011, "É": 0.6011, "Ê": 0.6011, "Ë": 0.6011, "Ì": 0.2686, "Í": 0.2686, "Î": 0.2686, "Ï": 0.2686, "Ð": 0.7349, "Ñ": 0.7534, "Ò": 0.7646, "Ó": 0.7646, "Ô": 0.7646, "Õ": 0.7646, "Ö": 0.7646, "×": 0.6616, "Ø": 0.7646, "Ù": 0.7441, "Ú": 0.7441, "Û": 0.7441, "Ü": 0.7441, "Ý": 0.6787, "Þ": 0.6357, "ß": 0.6162, "à": 0.5615, "á": 0.5615, "â": 0.5615, "ã": 0.5615, "ä": 0.5615, "å": 0.5615, "æ": 0.9175, "ç": 0.5713, "è": 0.583, "é": 0.583, "ê": 0.583, "ë": 0.583, "ì": 0.2422, "í": 0.2422, "î": 0.2422, "ï": 0.2422, "ð": 0.5825, "ñ": 0.5908, "ò": 0.5996, "ó": 0.5996, "ô": 0.5996, "õ": 0.5996, "ö": 0.5996, "÷": 0.6616, "ø": 0.5996, "ù": 0.5913, "ú": 0.5913, "û": 0.5913, "ü": 0.5913, "ý": 0.562, "þ": 0.6123, "ÿ": 0.562, "Ā": 0.6899, "ā": 0.5615, "Ă": 0.6899, "ă": 0.5615, "Ą": 0.6899, "ą": 0.5615, "Ć": 0.7305, "ć": 0.5713, "Ĉ": 0.7305, "ĉ": 0.5713, "Ċ": 0.7305, "ċ": 0.5713, "Č": 0.7305, "č": 0.5713, "Ď": 0.7217, "ď": 0.71, "Đ": 0.7349, "đ": 0.6123, "Ē": 0.6011, "ē": 0.583, "Ĕ": 0.6011, "ĕ": 0.583, "Ė": 0.6011, "ė": 0.583, "Ę": 0.6011, "ę": 0.583, "Ě": 0.6011, "ě": 0.583, "Ĝ": 0.7461, "ĝ": 0.6133, "Ğ": 0.7461, "ğ": 0.6133, "Ġ": 0.7461, "ġ": 0.6133, "Ģ": 0.7461, "ģ": 0.6133, "Ĥ": 0.7432, "ĥ": 0.5913, "Ħ": 0.7764, "ħ": 0.5913, "Ĩ": 0.2686, "ĩ": 0.2422, "Ī": 0.2686, "ī": 0.2422, "Ĭ": 0.2686, "ĭ": 0.2422, "Į": 0.2686, "į": 0.2422, "İ": 0.2686, "ı": 0.2422, "IJ": 0.8394, "ij": 0.4844, "Ĵ": 0.5708, "ĵ": 0.2422, "Ķ": 0.6719, "ķ": 0.5488, "ĸ": 0.5254, "Ĺ": 0.5654, "ĺ": 0.2422, "Ļ": 0.5654, "ļ": 0.2422, "Ľ": 0.5654, "ľ": 0.3398, "Ŀ": 0.5625, "ŀ": 0.3594, "Ł": 0.5947, "ł": 0.2422, "Ń": 0.7534, "ń": 0.5908, "Ņ": 0.7534, "ņ": 0.5908, "Ň": 0.7534, "ň": 0.5908, "Ŋ": 0.7534, "ŋ": 0.5908, "Ō": 0.7646, "ō": 0.5996, "Ŏ": 0.7646, "ŏ": 0.5996, "Ő": 0.7646, "ő": 0.5996, "Œ": 1.0049, "œ": 0.9995, "Ŕ": 0.6436, "ŕ": 0.3765, "Ŗ": 0.6436, "ŗ": 0.3765, "Ř": 0.6436, "ř": 0.3765, "Ś": 0.6416, "ś": 0.5278, "Ŝ": 0.6416, "ŝ": 0.5278, "Ş": 0.6416, "ş": 0.5278, "Š": 0.6416, "š": 0.5278, "Ţ": 0.6455, "ţ": 0.3271, "Ť": 0.6455, "ť": 0.376, "Ŧ": 0.6455, "ŧ": 0.3271, "Ũ": 0.7441, "ũ": 0.5913, "Ū": 0.7441, "ū": 0.5913, "Ŭ": 0.7441, "ŭ": 0.5913, "Ů": 0.7441, "ů": 0.5913, "Ű": 0.7441, "ű": 0.5913, "Ų": 0.7441, "ų": 0.5913, "Ŵ": 0.9854, "ŵ": 0.8184, "Ŷ": 0.6787, "ŷ": 0.562, "Ÿ": 0.6787, "Ź": 0.6289, "ź": 0.5522, "Ż": 0.6289, "ż": 0.5522, "Ž": 0.6289, "ž": 0.5522, "ſ": 0.3145}}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/* qdbd renderer: pure functions, model + positions -> SVG markup.
|
|
2
|
+
* Runs in the browser (viewer) and inside V8 from Python (CLI export), so the page,
|
|
3
|
+
* the SVG and the PNG are drawn by the same code. No DOM access here. */
|
|
4
|
+
(function (root) {
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
var C = {
|
|
8
|
+
bg: "#f4f5f4",
|
|
9
|
+
header: "#2b5797",
|
|
10
|
+
headerText: "#ffffff",
|
|
11
|
+
body: "#ffffff",
|
|
12
|
+
border: "#dfe3e8",
|
|
13
|
+
text: "#333333",
|
|
14
|
+
pk: "#2b5797",
|
|
15
|
+
fk: "#222222",
|
|
16
|
+
type: "#9a9a9a",
|
|
17
|
+
key: "#b0b0b0",
|
|
18
|
+
badgeBg: "#eef1f5",
|
|
19
|
+
badgeText: "#7a8899",
|
|
20
|
+
edge: "#b8bcc2",
|
|
21
|
+
};
|
|
22
|
+
var FONT = "Inter, 'Helvetica Neue', Helvetica, Arial, sans-serif";
|
|
23
|
+
|
|
24
|
+
function esc(s) {
|
|
25
|
+
return String(s == null ? "" : s)
|
|
26
|
+
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
27
|
+
.replace(/"/g, """).replace(/'/g, "'");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function n(v) { return Math.round(v * 100) / 100; }
|
|
31
|
+
|
|
32
|
+
function relatedColumns(model) {
|
|
33
|
+
var set = {};
|
|
34
|
+
model.rels.forEach(function (r) {
|
|
35
|
+
set[r.a.t + "\u0000" + r.a.c] = true;
|
|
36
|
+
set[r.b.t + "\u0000" + r.b.c] = true;
|
|
37
|
+
});
|
|
38
|
+
return set;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Visible columns of each table for a collapse mode: "full" | "keys" | "header". */
|
|
42
|
+
function geometry(model, mode) {
|
|
43
|
+
var st = model.style, rel = mode === "keys" ? relatedColumns(model) : null, out = {};
|
|
44
|
+
model.tables.forEach(function (t) {
|
|
45
|
+
var cols = [];
|
|
46
|
+
if (mode !== "header") {
|
|
47
|
+
t.cols.forEach(function (c) {
|
|
48
|
+
if (mode === "full" || c.pk || c.fk || rel[t.id + "\u0000" + c.id]) cols.push(c);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
var rows = {};
|
|
52
|
+
cols.forEach(function (c, i) { rows[c.id] = i; });
|
|
53
|
+
out[t.id] = {
|
|
54
|
+
cols: cols,
|
|
55
|
+
rows: rows,
|
|
56
|
+
w: t.w,
|
|
57
|
+
h: st.headerH + cols.length * st.rowH + (cols.length ? st.bottomPad : 0),
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function keyIcon(x, cy) {
|
|
64
|
+
return '<g stroke="' + C.key + '" stroke-width="1.5" fill="none">' +
|
|
65
|
+
'<circle cx="' + n(x + 3.5) + '" cy="' + n(cy) + '" r="3"/>' +
|
|
66
|
+
'<path d="M' + n(x + 6.5) + " " + n(cy) + "h7m-2 0v3m-2.5-3v2" + '"/></g>';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function renderTable(model, t, g, p) {
|
|
70
|
+
var st = model.style, w = g.w, h = g.h, out = [];
|
|
71
|
+
out.push('<g class="t" data-id="' + esc(t.id) + '" transform="translate(' + n(p[0]) + "," + n(p[1]) + ')">');
|
|
72
|
+
out.push('<rect class="tb" width="' + w + '" height="' + h + '" rx="2" fill="' + C.body + '" stroke="' + C.border + '"/>');
|
|
73
|
+
out.push('<path class="th" d="M0 2a2 2 0 0 1 2-2h' + (w - 4) + "a2 2 0 0 1 2 2v" + (st.headerH - 2) + "h-" + w + 'z" fill="' + C.header + '"/>');
|
|
74
|
+
out.push('<text x="' + st.padX + '" y="' + n(st.headerH / 2 + st.headerSize * 0.36) + '" fill="' + C.headerText +
|
|
75
|
+
'" font-family="' + FONT + '" font-size="' + st.headerSize + '">' + esc(t.name) + "</text>");
|
|
76
|
+
g.cols.forEach(function (c, i) {
|
|
77
|
+
var y = st.headerH + i * st.rowH, cy = y + st.rowH / 2, base = n(cy + st.rowSize * 0.36);
|
|
78
|
+
var weight = c.pk || c.fk ? ' font-weight="bold"' : "";
|
|
79
|
+
var color = c.pk ? C.pk : c.fk ? C.fk : C.text;
|
|
80
|
+
out.push('<g class="r" data-c="' + esc(c.id) + '">');
|
|
81
|
+
out.push('<rect class="rb" y="' + y + '" width="' + w + '" height="' + st.rowH + '" fill="' + C.body + '" fill-opacity="0"/>');
|
|
82
|
+
out.push('<text x="' + st.padX + '" y="' + base + '" fill="' + color + '" font-family="' + FONT + '" font-size="' +
|
|
83
|
+
st.rowSize + '"' + weight + ">" + esc(c.name) + "</text>");
|
|
84
|
+
var bx = st.padX + c.nameW + 6;
|
|
85
|
+
c.badges.forEach(function (b) {
|
|
86
|
+
var bh = st.badgeSize + 5;
|
|
87
|
+
out.push('<rect x="' + n(bx) + '" y="' + n(cy - bh / 2) + '" width="' + n(b.w) + '" height="' + bh + '" rx="3" fill="' + C.badgeBg + '"/>');
|
|
88
|
+
out.push('<text x="' + n(bx + st.badgePad) + '" y="' + n(cy + st.badgeSize * 0.36) + '" fill="' + C.badgeText +
|
|
89
|
+
'" font-family="' + FONT + '" font-size="' + st.badgeSize + '">' + esc(b.t) + "</text>");
|
|
90
|
+
bx += b.w + st.badgeGap;
|
|
91
|
+
});
|
|
92
|
+
if (c.pk) out.push(keyIcon(w - st.padX - c.typeW - st.keyW + 1, cy));
|
|
93
|
+
out.push('<text x="' + (w - st.padX) + '" y="' + base + '" text-anchor="end" fill="' + C.type + '" font-family="' + FONT +
|
|
94
|
+
'" font-size="' + st.rowSize + '">' + esc(c.type) + "</text>");
|
|
95
|
+
out.push("</g>");
|
|
96
|
+
});
|
|
97
|
+
out.push("</g>");
|
|
98
|
+
return out.join("");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function anchorY(model, g, p, colId) {
|
|
102
|
+
var st = model.style, i = g.rows[colId];
|
|
103
|
+
if (i === undefined) return p[1] + st.headerH / 2;
|
|
104
|
+
return p[1] + st.headerH + i * st.rowH + st.rowH / 2;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Pick sides: facing sides when tables are apart horizontally, both right when stacked. */
|
|
108
|
+
function edgeGeom(model, geo, pos, r) {
|
|
109
|
+
var ga = geo[r.a.t], gb = geo[r.b.t], pa = pos[r.a.t], pb = pos[r.b.t];
|
|
110
|
+
if (!ga || !gb || !pa || !pb) return null;
|
|
111
|
+
var ya = anchorY(model, ga, pa, r.a.c), yb = anchorY(model, gb, pb, r.b.c);
|
|
112
|
+
var da, db;
|
|
113
|
+
var overlap = pa[0] < pb[0] + gb.w + 30 && pb[0] < pa[0] + ga.w + 30;
|
|
114
|
+
if (r.a.t === r.b.t || overlap) { da = 1; db = 1; }
|
|
115
|
+
else if (pa[0] + ga.w / 2 < pb[0] + gb.w / 2) { da = 1; db = -1; }
|
|
116
|
+
else { da = -1; db = 1; }
|
|
117
|
+
var xa = da > 0 ? pa[0] + ga.w : pa[0], xb = db > 0 ? pb[0] + gb.w : pb[0];
|
|
118
|
+
var off;
|
|
119
|
+
if (da === db) off = 40 + Math.min(160, Math.abs(ya - yb) * 0.25) + Math.max(0, (da > 0 ? Math.max(xa, xb) - Math.min(xa, xb) : 0));
|
|
120
|
+
else off = Math.max(40, Math.abs(xb - xa) / 2);
|
|
121
|
+
var offA = off, offB = off;
|
|
122
|
+
if (da === db && da > 0) { offA = off - (Math.max(xa, xb) - xa); offB = off - (Math.max(xa, xb) - xb); offA = Math.max(offA, 40); offB = Math.max(offB, 40); }
|
|
123
|
+
var d = "M" + n(xa) + " " + n(ya) + "C" + n(xa + da * offA) + " " + n(ya) + " " + n(xb + db * offB) + " " + n(yb) + " " + n(xb) + " " + n(yb);
|
|
124
|
+
return { d: d, xa: xa, ya: ya, da: da, xb: xb, yb: yb, db: db };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function marker(card, x, y, dir) {
|
|
128
|
+
var s = [], st = ' stroke="' + C.edge + '" stroke-width="1.2" fill="none"';
|
|
129
|
+
function bar(o) { s.push('<path d="M' + n(x + dir * o) + " " + n(y - 6) + "v12" + '"' + st + "/>"); }
|
|
130
|
+
function crow() {
|
|
131
|
+
s.push('<path d="M' + n(x + dir * 11) + " " + n(y) + "L" + n(x) + " " + n(y - 6) + "M" + n(x + dir * 11) + " " + n(y) + "L" + n(x) + " " + n(y + 6) + '"' + st + "/>");
|
|
132
|
+
}
|
|
133
|
+
function circle(o) {
|
|
134
|
+
s.push('<circle cx="' + n(x + dir * o) + '" cy="' + n(y) + '" r="3.5" fill="' + C.bg + '" stroke="' + C.edge + '" stroke-width="1.2"/>');
|
|
135
|
+
}
|
|
136
|
+
if (card === "one") { bar(7); }
|
|
137
|
+
else if (card === "many") { crow(); }
|
|
138
|
+
else if (card === "zeroOne") { bar(6); circle(14); }
|
|
139
|
+
else if (card === "zeroMany") { crow(); circle(16); }
|
|
140
|
+
return s.join("");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function renderEdge(model, geo, pos, r) {
|
|
144
|
+
var e = edgeGeom(model, geo, pos, r);
|
|
145
|
+
if (!e) return "";
|
|
146
|
+
return '<g class="e" data-a="' + esc(r.a.t) + '" data-ac="' + esc(r.a.c) + '" data-b="' + esc(r.b.t) + '" data-bc="' + esc(r.b.c) + '">' +
|
|
147
|
+
'<path class="ep" d="' + e.d + '" stroke="' + C.edge + '" stroke-width="1.2" fill="none"/>' +
|
|
148
|
+
marker(r.a.card, e.xa, e.ya, e.da) + marker(r.b.card, e.xb, e.yb, e.db) + "</g>";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function subset(model, only) {
|
|
152
|
+
if (!only) return model;
|
|
153
|
+
var keep = {};
|
|
154
|
+
only.forEach(function (id) { keep[id] = true; });
|
|
155
|
+
return {
|
|
156
|
+
style: model.style,
|
|
157
|
+
tables: model.tables.filter(function (t) { return keep[t.id]; }),
|
|
158
|
+
rels: model.rels.filter(function (r) { return keep[r.a.t] && keep[r.b.t]; }),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function renderEdges(model, pos, mode, geo) {
|
|
163
|
+
geo = geo || geometry(model, mode);
|
|
164
|
+
return model.rels.map(function (r) { return renderEdge(model, geo, pos, r); }).join("");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function renderInner(model, pos, mode) {
|
|
168
|
+
var geo = geometry(model, mode);
|
|
169
|
+
var tables = model.tables.map(function (t) { return pos[t.id] ? renderTable(model, t, geo[t.id], pos[t.id]) : ""; }).join("");
|
|
170
|
+
return '<g class="edges">' + renderEdges(model, pos, mode, geo) + '</g><g class="tables">' + tables + "</g>";
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function bounds(model, pos, mode) {
|
|
174
|
+
var geo = geometry(model, mode), b = null;
|
|
175
|
+
model.tables.forEach(function (t) {
|
|
176
|
+
var p = pos[t.id];
|
|
177
|
+
if (!p) return;
|
|
178
|
+
var g = geo[t.id];
|
|
179
|
+
if (!b) b = [p[0], p[1], p[0] + g.w, p[1] + g.h];
|
|
180
|
+
else b = [Math.min(b[0], p[0]), Math.min(b[1], p[1]), Math.max(b[2], p[0] + g.w), Math.max(b[3], p[1] + g.h)];
|
|
181
|
+
});
|
|
182
|
+
return b || [0, 0, 100, 100];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Standalone SVG document. opts: {mode, only: [ids], fontCss, pad} */
|
|
186
|
+
function renderSvg(model, pos, opts) {
|
|
187
|
+
opts = opts || {};
|
|
188
|
+
var mode = opts.mode || "full", m = subset(model, opts.only), pad = opts.pad == null ? 40 : opts.pad;
|
|
189
|
+
var edgePad = 60;
|
|
190
|
+
var b = bounds(m, pos, mode);
|
|
191
|
+
var x0 = b[0] - pad - edgePad, y0 = b[1] - pad, w = b[2] - b[0] + 2 * (pad + edgePad), h = b[3] - b[1] + 2 * pad;
|
|
192
|
+
var style = opts.fontCss ? "<style>" + opts.fontCss + "</style>" : "";
|
|
193
|
+
return '<svg xmlns="http://www.w3.org/2000/svg" width="' + n(w) + '" height="' + n(h) + '" viewBox="' + n(x0) + " " + n(y0) + " " + n(w) + " " + n(h) + '">' +
|
|
194
|
+
style + '<rect x="' + n(x0) + '" y="' + n(y0) + '" width="' + n(w) + '" height="' + n(h) + '" fill="' + C.bg + '"/>' +
|
|
195
|
+
renderInner(m, pos, mode) + "</svg>";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Tables within `depth` relationship hops of `focus`. */
|
|
199
|
+
function neighbourhood(model, focus, depth) {
|
|
200
|
+
var adj = {};
|
|
201
|
+
model.rels.forEach(function (r) {
|
|
202
|
+
(adj[r.a.t] = adj[r.a.t] || []).push(r.b.t);
|
|
203
|
+
(adj[r.b.t] = adj[r.b.t] || []).push(r.a.t);
|
|
204
|
+
});
|
|
205
|
+
var seen = {}, frontier = [focus], out = [focus];
|
|
206
|
+
seen[focus] = true;
|
|
207
|
+
for (var d = 0; d < depth; d++) {
|
|
208
|
+
var next = [];
|
|
209
|
+
frontier.forEach(function (id) {
|
|
210
|
+
(adj[id] || []).forEach(function (o) { if (!seen[o]) { seen[o] = true; next.push(o); out.push(o); } });
|
|
211
|
+
});
|
|
212
|
+
frontier = next;
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
root.qdbd = {
|
|
218
|
+
colors: C,
|
|
219
|
+
geometry: geometry,
|
|
220
|
+
renderTable: renderTable,
|
|
221
|
+
renderEdges: renderEdges,
|
|
222
|
+
renderInner: renderInner,
|
|
223
|
+
renderSvg: renderSvg,
|
|
224
|
+
bounds: bounds,
|
|
225
|
+
neighbourhood: neighbourhood,
|
|
226
|
+
esc: esc,
|
|
227
|
+
};
|
|
228
|
+
root.qdbdRenderSvg = renderSvg;
|
|
229
|
+
root.qdbdNeighbourhood = neighbourhood;
|
|
230
|
+
})(typeof window !== "undefined" ? window : globalThis);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #f4f5f4;
|
|
3
|
+
--blue: #2b5797;
|
|
4
|
+
--ink: #333;
|
|
5
|
+
--muted: #8a8f96;
|
|
6
|
+
--panel: #ffffff;
|
|
7
|
+
--line: #dfe3e8;
|
|
8
|
+
}
|
|
9
|
+
* { box-sizing: border-box; }
|
|
10
|
+
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--ink);
|
|
11
|
+
font-family: Inter, "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; overflow: hidden; }
|
|
12
|
+
#app { position: fixed; inset: 0; display: flex; }
|
|
13
|
+
#stage { position: relative; flex: 1; overflow: hidden; }
|
|
14
|
+
#canvas { width: 100%; height: 100%; display: block; cursor: grab; touch-action: none; user-select: none; }
|
|
15
|
+
#canvas.panning { cursor: grabbing; }
|
|
16
|
+
|
|
17
|
+
/* states */
|
|
18
|
+
.t, .e { transition: opacity .15s; }
|
|
19
|
+
.focus .t.dim, .focus .e.dim { opacity: .12; }
|
|
20
|
+
.e.hl .ep { stroke: var(--blue); stroke-width: 2.2; }
|
|
21
|
+
.e.hl path, .e.hl circle { stroke: var(--blue); }
|
|
22
|
+
.r.hl .rb { fill: #dbe6f6; fill-opacity: 1; }
|
|
23
|
+
.r:hover .rb { fill: #eef3fa; fill-opacity: 1; }
|
|
24
|
+
.t.flash .tb { stroke: #f0a020; stroke-width: 3; }
|
|
25
|
+
.t { cursor: pointer; }
|
|
26
|
+
.serve .t { cursor: move; }
|
|
27
|
+
|
|
28
|
+
/* toolbar (top right, like QuickDBD's zoom controls) */
|
|
29
|
+
.bar { position: absolute; top: 14px; right: 16px; display: flex; gap: 6px; align-items: center; }
|
|
30
|
+
.bar button, .seg button { border: 0; background: transparent; color: #555; font: inherit; cursor: pointer;
|
|
31
|
+
padding: 6px 9px; border-radius: 4px; }
|
|
32
|
+
.bar button:hover, .seg button:hover { background: #e4e7ea; }
|
|
33
|
+
.zoomval { min-width: 48px; text-align: center; color: #666; font-variant-numeric: tabular-nums; }
|
|
34
|
+
.seg { display: flex; background: #e9ecee; border-radius: 6px; padding: 2px; }
|
|
35
|
+
.seg button.on { background: #fff; color: var(--blue); box-shadow: 0 1px 2px rgba(0,0,0,.12); }
|
|
36
|
+
.sep { width: 1px; height: 20px; background: #d5d9dd; margin: 0 4px; }
|
|
37
|
+
|
|
38
|
+
/* search (top left) */
|
|
39
|
+
.search { position: absolute; top: 14px; left: 16px; width: 260px; }
|
|
40
|
+
.search input { width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: 6px; font: inherit;
|
|
41
|
+
background: #fff; outline: none; }
|
|
42
|
+
.search input:focus { border-color: var(--blue); }
|
|
43
|
+
.results { margin-top: 4px; background: #fff; border: 1px solid var(--line); border-radius: 6px; max-height: 300px;
|
|
44
|
+
overflow: auto; display: none; box-shadow: 0 4px 14px rgba(0,0,0,.08); }
|
|
45
|
+
.results.open { display: block; }
|
|
46
|
+
.results div { padding: 6px 10px; cursor: pointer; }
|
|
47
|
+
.results div.sel, .results div:hover { background: #eef3fa; }
|
|
48
|
+
.results small { color: var(--muted); margin-left: 6px; }
|
|
49
|
+
|
|
50
|
+
/* minimap (bottom right) */
|
|
51
|
+
.minimap { position: absolute; right: 16px; bottom: 16px; width: 200px; height: 140px; background: rgba(255,255,255,.9);
|
|
52
|
+
border: 1px solid var(--line); border-radius: 6px; overflow: hidden; cursor: pointer; }
|
|
53
|
+
.minimap svg { width: 100%; height: 100%; display: block; }
|
|
54
|
+
.minimap .vpr { fill: rgba(43,87,151,.12); stroke: var(--blue); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
|
|
55
|
+
|
|
56
|
+
.hint { position: absolute; left: 16px; bottom: 14px; color: var(--muted); font-size: 12px; }
|
|
57
|
+
|
|
58
|
+
/* serve: editor pane */
|
|
59
|
+
#side { width: 420px; display: flex; flex-direction: column; background: #343a40; color: #ddd; border-right: 1px solid #222; }
|
|
60
|
+
#side.hidden { display: none; }
|
|
61
|
+
.tabs { display: flex; overflow-x: auto; background: #2b3035; flex: none; }
|
|
62
|
+
.tabs button { background: transparent; color: #aab; border: 0; padding: 8px 12px; font: inherit; cursor: pointer; white-space: nowrap; }
|
|
63
|
+
.tabs button.on { color: #fff; background: #343a40; }
|
|
64
|
+
.tabs button .dirty { color: #f0a020; }
|
|
65
|
+
#editor { flex: 1; min-height: 0; position: relative; }
|
|
66
|
+
#editor .CodeMirror, #editor textarea { position: absolute; inset: 0; height: 100%; width: 100%; font-size: 13px;
|
|
67
|
+
font-family: Menlo, Consolas, monospace; background: #343a40; color: #ddd; border: 0; padding: 6px; resize: none; }
|
|
68
|
+
#problems { height: 140px; flex: none; overflow: auto; border-top: 2px solid #4caf50; padding: 8px 10px;
|
|
69
|
+
font-family: Menlo, Consolas, monospace; font-size: 12px; color: #ccc; }
|
|
70
|
+
#problems.bad { border-top-color: #e57373; }
|
|
71
|
+
#problems .err { color: #ff9b9b; cursor: pointer; }
|
|
72
|
+
#problems .warn { color: #f0c674; cursor: pointer; }
|
|
73
|
+
.banner { background: #f0a020; color: #222; padding: 6px 10px; font-size: 12px; display: none; }
|
|
74
|
+
.banner.open { display: block; }
|
|
75
|
+
.banner button { margin-left: 8px; }
|
|
76
|
+
.cm-qdbd-op { color: #f0a020; }
|
|
77
|
+
.cm-qdbd-kw { color: #8fbcff; }
|
|
78
|
+
.CodeMirror-gutters { background: #2f353a !important; border-right: 0 !important; }
|
|
79
|
+
.cm-s-default .cm-comment { color: #7f8c8d; }
|
|
80
|
+
.cm-s-default .cm-header { color: #6fc3df; }
|
|
81
|
+
.CodeMirror-cursor { border-left-color: #fff !important; }
|
|
82
|
+
.CodeMirror-selected { background: #4a525a !important; }
|
|
83
|
+
.lineerr { background: rgba(229,115,115,.18); }
|