Line data Source code
1 : // @ts-check
2 : import {
3 : clone, cloneDeep, find, get, identity, isNil, map, padStart,
4 : size, toNumber, toString
5 : } from "lodash";
6 : import { parser } from "@cern/ssvg-engine";
7 : import { getAttribute } from "./element";
8 : import { color, rgb } from "d3-color";
9 : import { BaseLogger as logger } from "@cern/base-vue";
10 :
11 : /**
12 : * @param {Element|null} stateElement
13 : * @param {string} name
14 : * @return {Element|null}
15 : */
16 : export function getPropertyByName(stateElement, name) {
17 1 : return find(get(stateElement, "children"), (c) => {
18 5 : return (c.tagName === "property" || c.tagName === "computed") &&
19 : c.getAttribute("name") === name;
20 : }) || null;
21 : }
22 :
23 : /**
24 : * @param {Element|null} transformElement
25 : */
26 : export function getTransformValues(transformElement) {
27 : // FIXME: support "by" and "to" without "from" ? (requires svg and selector access)
28 0 : try {
29 : /** @type {ssvg.$Transform[][]|null} */
30 0 : let transforms = [];
31 0 : const values = getAttribute(transformElement, "values");
32 0 : if (values) {
33 0 : transforms = parser.parseTTransformRange(values);
34 : }
35 : else {
36 0 : const from = getAttribute(transformElement, "from");
37 0 : if (from) {
38 0 : transforms.push(parser.parseTTransform(from) ?? []);
39 : }
40 0 : const to = getAttribute(transformElement, "to");
41 0 : if (to) {
42 0 : transforms.push(parser.parseTTransform(from) ?? []);
43 : }
44 : }
45 0 : return parser.normalizeTransform(transforms ?? []);
46 : }
47 : catch (err) {
48 : // logger.error(err);
49 0 : return null;
50 : }
51 : }
52 :
53 : /**
54 : * @param {Element|null} relationElement
55 : */
56 : export function getRelationValues(relationElement) {
57 2 : try {
58 2 : const values = getAttribute(relationElement, "values");
59 2 : if (!isNil(values)) {
60 2 : return parser.parseTRange(values);
61 : }
62 0 : const to = getAttribute(relationElement, "to");
63 0 : if (!isNil(to)) {
64 0 : const from = getAttribute(relationElement, "from");
65 0 : if (isNil(from)) {
66 : // FIXME get initial value from store
67 : }
68 0 : return parser.makeRange(
69 : parser.parseTValue(from), parser.parseTValue(to));
70 : }
71 : else {
72 0 : const by = getAttribute(relationElement, "by");
73 0 : if (!isNil(by)) {
74 0 : const current = parser.parseTValue(""); // FIXME get initial value from store
75 0 : const to = parser.parseTValue(getAttribute(relationElement, "by"));
76 : /* @ts-ignore */
77 0 : to.value += current?.value ?? 0;
78 0 : return parser.makeRange(current, to);
79 : }
80 : }
81 : }
82 : catch (err) {
83 0 : logger.error(err);
84 : }
85 0 : return null;
86 : }
87 :
88 : /**
89 : * @param {Element|null} relationElement relation or transform
90 : */
91 : export function getKeyTimes(relationElement) {
92 2 : const keyTimes = getAttribute(relationElement, "key-times");
93 2 : if (!isNil(keyTimes)) {
94 0 : return parser.parseTRange(keyTimes)?.values ?? null;
95 : }
96 2 : return null;
97 : }
98 :
99 1 : const strRe = /([\\"'])/g;
100 : /**
101 : * @param {any} value
102 : * @param {string} type
103 : */
104 : export function tvalueToString(value, type) {
105 6 : const valueString = toString(value);
106 6 : if (type === "string") {
107 6 : return `"${valueString.replace(strRe, "\$1")}"`;
108 : }
109 0 : return valueString;
110 : }
111 :
112 :
113 : /**
114 : * @type {{ [from: string]: { [to: string]: (v: any) => any } }}
115 : */
116 1 : const typeConverter = {
117 : string: {
118 8 : number: (v) => (toNumber(v.slice(1, -1)) || 0),
119 : color: (v) => {
120 4 : v = v.slice(1, -1);
121 4 : return color(v) ? (v) : ("#" + padStart((toNumber(v) || 0).toString(16), 6, "0"));
122 : }
123 : },
124 : number: {
125 6 : string: (v) => `"${v}"`,
126 6 : color: (v) => ("#" + padStart(toNumber(v).toString(16), 6, "0"))
127 : },
128 : color: {
129 4 : string: (v) => `"${(color(v) || rgb(0, 0, 0)).toString()}"`,
130 : number: (v) => {
131 4 : const c = (color(v) || rgb(0, 0, 0)).rgb();
132 4 : return c.b + (c.g << 8) + (c.r << 16);
133 : }
134 : }
135 : };
136 :
137 : /**
138 : * @brief convert a TRange to another type
139 : * @param {ssvg.$TRange} tvalues
140 : * @param {ssvg.$TTypeName} type
141 : * @return {ssvg.$TRange}
142 : */
143 : export function trangeConvert(tvalues, type) {
144 9 : tvalues = cloneDeep(tvalues);
145 9 : const convert = get(typeConverter, [ tvalues.type, type ], identity);
146 32 : tvalues.values = map(tvalues.values, (v) => convert(v));
147 9 : delete tvalues.unit;
148 9 : tvalues.type = type;
149 9 : return tvalues;
150 : }
151 :
152 : /**
153 : * @param {number[]} args
154 : * @param {(string|null)[]} units
155 : * @return {string}
156 : */
157 : export function transformArgsStr(args, units) {
158 : /** @type {any[]} */
159 0 : const ret = clone(args);
160 0 : if (!ret) { return ""; }
161 0 : for (let i = 0; i < size(units); ++i) {
162 0 : if (units[i]) {
163 0 : ret[i] = ret[i] + units[i];
164 : }
165 : }
166 0 : return ret.join(", ");
167 : }
|