tycho-components 0.40.1 → 0.40.2

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.
@@ -0,0 +1,17 @@
1
+ export declare const viewerConfigurations: {
2
+ readonly svgID: "canvas";
3
+ readonly font: "FreeSans, Arial, Helvetica, sans-serif";
4
+ readonly margin: 4;
5
+ readonly nodeFontSize: 16;
6
+ readonly edgeFontSize: 16;
7
+ readonly edgeFontOffset: 8;
8
+ readonly lvlHeight: 40;
9
+ readonly nodeHeight: 48;
10
+ readonly multiSkip: 4;
11
+ readonly multiHeight: 28;
12
+ readonly edgeFontWhiteMargin: 2;
13
+ readonly edgeDrop: 80;
14
+ readonly edgeLblBackground: "white";
15
+ readonly edgeLblOpacity: 0.9;
16
+ readonly nodeTweek: 2;
17
+ };
@@ -0,0 +1,17 @@
1
+ export const viewerConfigurations = {
2
+ svgID: 'canvas',
3
+ font: 'FreeSans, Arial, Helvetica, sans-serif',
4
+ margin: 4,
5
+ nodeFontSize: 16,
6
+ edgeFontSize: 16,
7
+ edgeFontOffset: 8,
8
+ lvlHeight: 40,
9
+ nodeHeight: 48,
10
+ multiSkip: 4,
11
+ multiHeight: 28,
12
+ edgeFontWhiteMargin: 2,
13
+ edgeDrop: 80,
14
+ edgeLblBackground: 'white',
15
+ edgeLblOpacity: 0.9,
16
+ nodeTweek: 2,
17
+ };
@@ -0,0 +1,33 @@
1
+ import { Conllu } from '../../configs/types/Conllu';
2
+ import { ConlluViewerGraph } from './ConlluViewerGraph';
3
+ export declare const calculateTextWidth: (text: string, fontSize: number, bold: boolean) => {
4
+ w: number;
5
+ h: number;
6
+ l: number;
7
+ };
8
+ export declare const throwError: (err: Error, idx: number) => never;
9
+ declare class ConlluViewerConverter {
10
+ private MIN_NODE_WIDTH;
11
+ private NODE_SPACING;
12
+ private MARGIN;
13
+ private NODE_FONT_SIZE;
14
+ private EDGE_FONT_SIZE;
15
+ private EDGE_FONT_OFFSET;
16
+ private LVL_HEIGHT;
17
+ private NODE_HEIGHT;
18
+ private MULTI_SKIP;
19
+ private MULTI_HEIGHT;
20
+ execute: (conllu: Conllu) => ConlluViewerGraph;
21
+ private calculateLower;
22
+ private calculateOffset;
23
+ private calculateHeight;
24
+ private calculateWidth;
25
+ private calculateAnchors;
26
+ private setDependenciesMaxLevel;
27
+ private calculateMaxLevel;
28
+ private calculateDependenciesLevel;
29
+ private relateDependencies;
30
+ private loadDependencies;
31
+ private load;
32
+ }
33
+ export default ConlluViewerConverter;
@@ -0,0 +1,309 @@
1
+ import { fontBaseSize, fontBoldAscent, fontBoldDescent, fontBoldSizes, fontRegularAscent, fontRegularDescent, fontRegularSizes, } from './ConlluFontsizes';
2
+ export const calculateTextWidth = (text, fontSize, bold) => {
3
+ const { sizes, asc, desc } = bold
4
+ ? { sizes: fontBoldSizes, asc: fontBoldAscent, desc: fontBoldDescent }
5
+ : {
6
+ sizes: fontRegularSizes,
7
+ asc: fontRegularAscent,
8
+ desc: fontRegularDescent,
9
+ };
10
+ let w = 0;
11
+ for (const c of text) {
12
+ const i = c.charCodeAt(0);
13
+ let w1;
14
+ if (i >= sizes.length) {
15
+ w1 = fontBaseSize;
16
+ }
17
+ else {
18
+ w1 = sizes[i];
19
+ }
20
+ w += w1;
21
+ }
22
+ return {
23
+ w: Math.round((fontSize * w) / fontBaseSize),
24
+ h: Math.round((fontSize * (asc + desc)) / fontBaseSize),
25
+ l: Math.round((fontSize * asc) / fontBaseSize),
26
+ };
27
+ };
28
+ export const throwError = (err, idx) => {
29
+ console.error({ err, idx });
30
+ throw err;
31
+ };
32
+ class ConlluViewerConverter {
33
+ constructor() {
34
+ this.MIN_NODE_WIDTH = 80;
35
+ this.NODE_SPACING = 8;
36
+ this.MARGIN = 4;
37
+ this.NODE_FONT_SIZE = 16;
38
+ this.EDGE_FONT_SIZE = 16;
39
+ this.EDGE_FONT_OFFSET = 8;
40
+ this.LVL_HEIGHT = 40;
41
+ this.NODE_HEIGHT = 48;
42
+ this.MULTI_SKIP = 4;
43
+ this.MULTI_HEIGHT = 28;
44
+ this.execute = (conllu) => {
45
+ const graph = this.load(conllu);
46
+ this.loadDependencies(graph);
47
+ this.relateDependencies(graph);
48
+ graph.items.sort((a, b) => a.end - b.end);
49
+ this.calculateWidth(graph);
50
+ graph.dependencies.sort((a, b) => a.dist - b.dist);
51
+ this.calculateDependenciesLevel(graph);
52
+ this.calculateMaxLevel(graph);
53
+ this.setDependenciesMaxLevel(graph);
54
+ this.calculateAnchors(graph);
55
+ this.calculateHeight(graph);
56
+ this.calculateOffset(graph);
57
+ this.calculateLower(graph);
58
+ return graph;
59
+ };
60
+ this.calculateLower = (graph) => {
61
+ const { w, h, l: y } = calculateTextWidth('Xg', this.NODE_FONT_SIZE, false);
62
+ graph.lower = y / 2;
63
+ };
64
+ this.calculateOffset = (graph) => {
65
+ graph.offset =
66
+ this.MARGIN +
67
+ this.EDGE_FONT_SIZE +
68
+ this.EDGE_FONT_OFFSET +
69
+ this.LVL_HEIGHT * (graph.maxlvl + 1);
70
+ };
71
+ this.calculateHeight = (graph) => {
72
+ let height = this.MARGIN +
73
+ this.EDGE_FONT_SIZE +
74
+ this.EDGE_FONT_OFFSET +
75
+ this.LVL_HEIGHT * (graph.maxlvl + 1) +
76
+ this.NODE_HEIGHT +
77
+ this.MARGIN;
78
+ if (graph.multis.length > 0) {
79
+ height += this.MULTI_HEIGHT + this.MULTI_SKIP;
80
+ }
81
+ graph.height = height;
82
+ };
83
+ this.calculateWidth = (graph) => {
84
+ let width = this.MARGIN;
85
+ graph.items.forEach((item, i) => {
86
+ if (item.end !== i + 1) {
87
+ throwError(new Error(`Wrong index: ${item.end} != ${i + 1}`), item.lineno);
88
+ }
89
+ item.x1 = width;
90
+ const { w: w1 } = calculateTextWidth(item.postag + ' i', this.NODE_FONT_SIZE, false);
91
+ const { w: w2 } = calculateTextWidth(item.word + ' i', this.NODE_FONT_SIZE, false);
92
+ item.x2 = width + 24 + Math.max(this.MIN_NODE_WIDTH, w1, w2);
93
+ width = item.x2 + this.NODE_SPACING;
94
+ });
95
+ width -= this.NODE_SPACING;
96
+ width += this.MARGIN;
97
+ graph.width = width;
98
+ };
99
+ this.calculateAnchors = (graph) => {
100
+ graph.anchors.forEach((anchor, key) => {
101
+ anchor.forEach((a, i) => {
102
+ if (a.dist === 0) {
103
+ graph.anchors[key][i].level = graph.maxlvl;
104
+ }
105
+ });
106
+ });
107
+ graph.anchors.forEach((anchor) => {
108
+ anchor.sort((a1, a2) => {
109
+ if (a1.dist === 0)
110
+ return a2.dist > 0 ? -1 : 1;
111
+ if (a2.dist === 0)
112
+ return a1.dist < 0 ? -1 : 1;
113
+ if (a1.dist === a2.dist) {
114
+ if (a1.dist < 0)
115
+ return a1.level - a2.level;
116
+ return a2.level - a1.level;
117
+ }
118
+ if (a1.dist < 0) {
119
+ if (a2.dist > 0) {
120
+ return -1;
121
+ }
122
+ return a1.dist < a2.dist ? 1 : -1;
123
+ }
124
+ if (a2.dist < 0) {
125
+ return 1;
126
+ }
127
+ return a1.dist < a2.dist ? 1 : -1;
128
+ });
129
+ });
130
+ };
131
+ this.setDependenciesMaxLevel = (graph) => {
132
+ graph.dependencies.forEach((dep, i) => {
133
+ if (dep.headpos === 0) {
134
+ graph.dependencies[i].lvl = graph.maxlvl;
135
+ }
136
+ });
137
+ };
138
+ this.calculateMaxLevel = (graph) => {
139
+ const maxlvl = graph.dependencies.reduce((max, dep) => Math.max(max, dep.lvl || 0), 0);
140
+ graph.maxlvl = graph.hasEnhanced ? maxlvl + 1 : maxlvl;
141
+ };
142
+ this.calculateDependenciesLevel = (graph) => {
143
+ const anchors = Array.from({ length: graph.items.length }, () => []);
144
+ const grid = Array.from({ length: graph.items.length }, () => Array(2 * graph.items.length).fill(false));
145
+ graph.dependencies.forEach((dep, i) => {
146
+ if (dep.headpos === 0) {
147
+ anchors[dep.end - 1].push({ dist: 0, level: 0 });
148
+ return;
149
+ }
150
+ let i1 = dep.end - 1;
151
+ let i2 = dep.headpos - 1;
152
+ if (i1 > i2) {
153
+ [i1, i2] = [i2, i1];
154
+ }
155
+ let lvl = 0;
156
+ while (true) {
157
+ let ok = true;
158
+ for (let j = i1; j < i2; j++) {
159
+ if (grid[j][lvl]) {
160
+ ok = false;
161
+ break;
162
+ }
163
+ }
164
+ if (ok) {
165
+ for (let j = i1; j < i2; j++) {
166
+ grid[j][lvl] = true;
167
+ }
168
+ break;
169
+ }
170
+ lvl++;
171
+ }
172
+ graph.dependencies[i].lvl = lvl;
173
+ anchors[dep.end - 1].push({ dist: dep.headpos - dep.end, level: lvl });
174
+ anchors[dep.headpos - 1].push({
175
+ dist: dep.end - dep.headpos,
176
+ level: lvl,
177
+ });
178
+ });
179
+ graph.anchors = anchors;
180
+ graph.grid = grid;
181
+ };
182
+ this.relateDependencies = (graph) => {
183
+ for (let i = 0; i < graph.dependencies.length; i++) {
184
+ let d1 = graph.dependencies[i];
185
+ if (d1.rel[0] !== '') {
186
+ for (let j = 0; j < graph.dependencies.length; j++) {
187
+ if (i === j)
188
+ continue;
189
+ let d2 = graph.dependencies[j];
190
+ if (d2.rel[1] !== '' &&
191
+ d1.end === d2.end &&
192
+ d1.headpos === d2.headpos &&
193
+ d1.dist === d2.dist) {
194
+ d1.rel[1] = d2.rel[1];
195
+ graph.dependencies.splice(j, 1);
196
+ if (j < i)
197
+ i--;
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ };
204
+ this.loadDependencies = (graph) => {
205
+ const dependencies = [];
206
+ for (let i = 0; i < graph.items.length; i++) {
207
+ let item = graph.items[i];
208
+ let end = graph.positions[item.here];
209
+ item.end = end;
210
+ if (!item.enhanced) {
211
+ let headpos = graph.positions[item.there];
212
+ if (headpos === undefined) {
213
+ console.error(`Unknown head position ${item.there}`, item.lineno);
214
+ }
215
+ else {
216
+ dependencies.push({
217
+ end,
218
+ headpos,
219
+ rel: [item.rel, ''],
220
+ dist: Math.abs(end - headpos),
221
+ lvl: 0,
222
+ });
223
+ }
224
+ }
225
+ if (item.deps !== '_') {
226
+ const parts = item.deps?.split('|') ?? [];
227
+ parts.forEach((part) => {
228
+ const partsSplits = part.split(':', 2);
229
+ if (partsSplits.length !== 2) {
230
+ throwError(new Error(`Invalid dependency: ${part}`), item.lineno);
231
+ }
232
+ const headpos = graph.positions[partsSplits[0]];
233
+ if (!headpos) {
234
+ throwError(new Error(`Unknown head position ${partsSplits[0]}`), item.lineno);
235
+ }
236
+ dependencies.push({
237
+ end: end,
238
+ headpos: headpos,
239
+ rel: ['', partsSplits[1]],
240
+ dist: Math.abs(end - headpos),
241
+ lvl: 0,
242
+ });
243
+ graph.hasEnhanced = true;
244
+ });
245
+ }
246
+ }
247
+ graph.dependencies = dependencies;
248
+ };
249
+ this.load = (conllu) => {
250
+ const items = [];
251
+ const multis = [];
252
+ const positions = {
253
+ '0': 0,
254
+ };
255
+ let n = 0;
256
+ conllu.tokens.forEach((token, idx) => {
257
+ // TODO: how to calculate nColumns????
258
+ // if (token.id.includes('.') && token.deps === nColumns) {
259
+ if (token.id.includes('.')) {
260
+ return;
261
+ }
262
+ if (token.id.includes('-')) {
263
+ multis.push({
264
+ id: token.id,
265
+ word: token.form,
266
+ lineno: idx,
267
+ });
268
+ return;
269
+ }
270
+ const item = {
271
+ lineno: idx,
272
+ here: token.id,
273
+ word: token.form,
274
+ lemma: token.lemma,
275
+ postag: token.upos,
276
+ xpostag: token.xpos,
277
+ attribs: token.feats !== '_'
278
+ ? token.feats?.replace(/\|/g, ', ').replace(/=/g, ': ')
279
+ : '',
280
+ there: token.head,
281
+ rel: token.deprel,
282
+ deps: token.deps,
283
+ enhanced: token.id.includes('.'),
284
+ end: 0,
285
+ x1: 0,
286
+ x2: 0,
287
+ };
288
+ items.push(item);
289
+ n++;
290
+ positions[token.id] = n;
291
+ });
292
+ return {
293
+ multis,
294
+ items,
295
+ positions,
296
+ hasEnhanced: false,
297
+ dependencies: [],
298
+ anchors: [[]],
299
+ grid: [[]],
300
+ width: 0,
301
+ height: 0,
302
+ maxlvl: 0,
303
+ offset: 0,
304
+ lower: 0,
305
+ };
306
+ };
307
+ }
308
+ }
309
+ export default ConlluViewerConverter;
@@ -0,0 +1,46 @@
1
+ export type ConlluViewerGraph = {
2
+ hasEnhanced: boolean;
3
+ items: ConlluViewerItem[];
4
+ multis: ConlluViewerMulti[];
5
+ dependencies: ConlluViewerDependency[];
6
+ positions: Record<string, number>;
7
+ anchors: ConlluViewerAnchor[][];
8
+ grid: boolean[][];
9
+ width: number;
10
+ height: number;
11
+ maxlvl: number;
12
+ offset: number;
13
+ lower: number;
14
+ };
15
+ export type ConlluViewerItem = {
16
+ lineno: number;
17
+ here: string;
18
+ there: string;
19
+ enhanced: boolean;
20
+ word: string;
21
+ lemma: string;
22
+ postag: string;
23
+ xpostag: string;
24
+ attribs: string;
25
+ rel: string;
26
+ deps: string;
27
+ end: number;
28
+ x1: number;
29
+ x2: number;
30
+ };
31
+ export type ConlluViewerMulti = {
32
+ id: string;
33
+ word: string;
34
+ lineno: number;
35
+ };
36
+ export type ConlluViewerDependency = {
37
+ end: number;
38
+ headpos: number;
39
+ rel: string[];
40
+ dist: number;
41
+ lvl: number;
42
+ };
43
+ export type ConlluViewerAnchor = {
44
+ dist: number;
45
+ level: number;
46
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,6 @@
1
+ export { default as ConlluViewerConverter, calculateTextWidth, throwError, } from './conllu/ConlluViewerConverter';
2
+ export { viewerConfigurations } from './conllu/ConlluViewerConstants';
3
+ export type { ConlluViewerAnchor, ConlluViewerDependency, ConlluViewerGraph, ConlluViewerItem, ConlluViewerMulti, } from './conllu/ConlluViewerGraph';
1
4
  export { default as DateUtils } from './DateUtils';
2
5
  export { default as EditionTierUtils } from './EditionTierUtils';
3
6
  export { normalizeCorpusFromApi } from './normalizeCorpusFromApi';
@@ -1,3 +1,5 @@
1
+ export { default as ConlluViewerConverter, calculateTextWidth, throwError, } from './conllu/ConlluViewerConverter';
2
+ export { viewerConfigurations } from './conllu/ConlluViewerConstants';
1
3
  export { default as DateUtils } from './DateUtils';
2
4
  export { default as EditionTierUtils } from './EditionTierUtils';
3
5
  export { normalizeCorpusFromApi } from './normalizeCorpusFromApi';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tycho-components",
3
3
  "private": false,
4
- "version": "0.40.1",
4
+ "version": "0.40.2",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {