@datagrok/sequence-translator 1.10.18 → 1.10.19

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.10.18",
4
+ "version": "1.10.19",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-params */
1
2
  /**
2
3
  * Canvas drawing for the OligoNucleotide cell renderer.
3
4
  *
@@ -41,7 +42,7 @@ export interface RenderOpts {
41
42
  scheme?: string;
42
43
  }
43
44
 
44
- const DEFAULT_OPTS: RenderOpts = {showLetters: true, pairAlign: true};
45
+ export const DEFAULT_OPTS: RenderOpts = {showLetters: true, pairAlign: true};
45
46
 
46
47
  /* Visual tuning. */
47
48
  const ASPECT_H_OVER_W = 1.25;
@@ -329,11 +330,11 @@ function fitsInBudget(widths: number[], leadW: number, chipGap: number, budget:
329
330
  export function drawDuplex(
330
331
  g: CanvasRenderingContext2D, cellX: number, cellY: number,
331
332
  cellW: number, cellH: number, model: ParsedDuplex,
332
- opts: Partial<RenderOpts> = {},
333
+ opts: Partial<RenderOpts> = {}, skipDrawing = false,
333
334
  ): DuplexLayout {
334
335
  const o: RenderOpts = {...DEFAULT_OPTS, ...opts};
335
336
  const layout = computeLayout(cellW, cellH, model, o);
336
-
337
+ if (skipDrawing) return layout;
337
338
  g.save();
338
339
  g.beginPath();
339
340
  g.rect(cellX, cellY, cellW, cellH);
@@ -14,7 +14,7 @@
14
14
  import * as DG from 'datagrok-api/dg';
15
15
  import * as ui from 'datagrok-api/ui';
16
16
 
17
- import {drawDuplex, hitTest, DuplexLayout} from './canvas-renderer';
17
+ import {drawDuplex, hitTest, DuplexLayout, RenderOpts, DEFAULT_OPTS} from './canvas-renderer';
18
18
  import {looksLikeHelm, parseHelmDuplex} from './helm-parser';
19
19
  import {ParsedDuplex} from './types';
20
20
  import {showMonomerTooltip} from './tooltip';
@@ -23,9 +23,9 @@ const CELL_TYPE = 'OligoNucleotide';
23
23
 
24
24
  export class OligoNucleotideCellRenderer extends DG.GridCellRenderer {
25
25
  /** WeakMap-by-value cache of parsed HELM. Avoids reparsing on redraw. */
26
- private modelCache = new Map<string, ParsedDuplex>();
26
+ private modelCache = new DG.LruCache<string, ParsedDuplex>();
27
27
  /** Last-rendered layout per cell key, for hit-testing on subsequent moves. */
28
- private layoutCache = new Map<string, DuplexLayout>();
28
+ private layoutCache = new DG.LruCache<string, DuplexLayout>();
29
29
 
30
30
  get name(): string { return CELL_TYPE; }
31
31
  get cellType(): string { return CELL_TYPE; }
@@ -54,11 +54,16 @@ export class OligoNucleotideCellRenderer extends DG.GridCellRenderer {
54
54
  }
55
55
 
56
56
  const model = this.getOrParse(value);
57
+ if (!gridCell.cell?.dart || !gridCell.cell.column) {
58
+ w = g.canvas.width;
59
+ h = g.canvas.height;
60
+ x = 0;
61
+ y = 0;
62
+ // this happens in forms....
63
+ }
57
64
  const layout = drawDuplex(g, x, y, w, h, model);
58
65
  // Cache for hit-test on subsequent mouse moves over the same cell.
59
- this.layoutCache.set(this.cellKey(gridCell), layout);
60
- // Avoid unbounded growth on big tables.
61
- if (this.layoutCache.size > 5000) this.layoutCache.clear();
66
+ this.layoutCache.set(this.cellKey(value, w, h, DEFAULT_OPTS), layout);
62
67
  }
63
68
 
64
69
  override onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
@@ -68,7 +73,11 @@ export class OligoNucleotideCellRenderer extends DG.GridCellRenderer {
68
73
  return;
69
74
  }
70
75
  const model = this.getOrParse(value);
71
- const layout = this.layoutCache.get(this.cellKey(gridCell));
76
+ const layout = this.layoutCache.getOrCreate(
77
+ this.cellKey(value, gridCell.bounds.width, gridCell.bounds.height, DEFAULT_OPTS), (v) => drawDuplex(
78
+ null as unknown as CanvasRenderingContext2D, 0, 0, gridCell.bounds.width, gridCell.bounds.height,
79
+ model, DEFAULT_OPTS, true,
80
+ ));
72
81
  if (!layout) return;
73
82
 
74
83
  const bounds = gridCell.bounds;
@@ -88,24 +97,14 @@ export class OligoNucleotideCellRenderer extends DG.GridCellRenderer {
88
97
  }
89
98
 
90
99
  private getOrParse(helm: string): ParsedDuplex {
91
- let m = this.modelCache.get(helm);
92
- if (!m) {
93
- m = parseHelmDuplex(helm);
94
- // Cap cache to avoid unbounded growth on huge tables.
95
- if (this.modelCache.size > 5000) this.modelCache.clear();
96
- this.modelCache.set(helm, m);
97
- }
98
- return m;
100
+ return this.modelCache.getOrCreate(helm, (h) => parseHelmDuplex(h));
99
101
  }
100
102
 
101
103
  /** Cache key for a cell's layout. Includes the column's `version` so any
102
104
  * edit to the column (which bumps version) orphans previous cache entries
103
105
  * — preventing onMouseMove from hit-testing a stale layout that was cached
104
106
  * before the edit and not yet replaced by a fresh render(). */
105
- private cellKey(gridCell: DG.GridCell): string {
106
- const col = gridCell.tableColumn;
107
- const colName = col?.name ?? gridCell.gridColumn?.name ?? '?';
108
- const ver = col?.version ?? 0;
109
- return `${colName}@${ver}::${gridCell.tableRowIndex ?? -1}`;
107
+ private cellKey(value: string, width: number, height: number, opts: RenderOpts): string {
108
+ return `${value}::${Math.floor(width)}x${Math.floor(height)}::${JSON.stringify(opts)}`;
110
109
  }
111
110
  }