@stocksharp/diagram 1.1.0 → 1.2.0

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,24 @@
1
+ import { type DiagramScreenshotOptions } from './canvas-renderer.js';
2
+ /**
3
+ * Drawing a diagram where there is no browser -- a server producing a picture for a chat message, an
4
+ * e-mail or a report. The renderer itself never needed one: it draws through a surface, and the SVG
5
+ * surface builds a string. What needed a browser was the control around it, which creates a canvas and
6
+ * listens for pointers; so the few things it reaches for are stood in for here, for the length of one
7
+ * drawing, and taken away again.
8
+ *
9
+ * Text is measured by the SVG surface's own estimate rather than by a real font, so a label's box can sit
10
+ * a pixel or two off where a browser would put it. The alternative is a native canvas dependency on every
11
+ * machine that renders, which is a steep price for that.
12
+ */
13
+ export interface HeadlessRenderOptions extends DiagramScreenshotOptions {
14
+ /** Width of the frame the drawing is laid out in, in CSS pixels. Defaults to 1200. */
15
+ hostWidth?: number;
16
+ /** Height of that frame. Defaults to 800. */
17
+ hostHeight?: number;
18
+ }
19
+ /**
20
+ * Draws a saved diagram and returns the SVG for it. The source is the document as text or as an object;
21
+ * the frame follows the content by default, since a picture made without a viewport has none to crop to.
22
+ */
23
+ export declare function renderDiagramSvg(source: string | unknown, options?: HeadlessRenderOptions): string;
24
+ //# sourceMappingURL=headless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../src/headless.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAG9E;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAsB,SAAQ,wBAAwB;IACnE,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AA6FD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAsBtG"}
@@ -1,4 +1,6 @@
1
1
  export { DiagramDocumentError, cloneDiagramDocument, createDiagramDocument, parseDiagramDocument, serializeDiagramDocument, } from './core/document.js';
2
+ export { renderDiagramSvg } from './headless.js';
3
+ export type { HeadlessRenderOptions } from './headless.js';
2
4
  export { DiagramActionRegistry } from './core/action-registry.js';
3
5
  export type { DiagramAction, DiagramActionState, } from './core/action-registry.js';
4
6
  export { DiagramCommandHistory } from './core/history.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stocksharp/diagram",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Browser strategy-diagram editor for StockSharp with typed ports, palette, canvas rendering, persistence, and a TypeScript API.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": {
@@ -0,0 +1,139 @@
1
+ import { Diagram, type DiagramScreenshotOptions } from './canvas-renderer.js';
2
+ import { parseDiagramDocument } from './core/document.js';
3
+
4
+ /**
5
+ * Drawing a diagram where there is no browser -- a server producing a picture for a chat message, an
6
+ * e-mail or a report. The renderer itself never needed one: it draws through a surface, and the SVG
7
+ * surface builds a string. What needed a browser was the control around it, which creates a canvas and
8
+ * listens for pointers; so the few things it reaches for are stood in for here, for the length of one
9
+ * drawing, and taken away again.
10
+ *
11
+ * Text is measured by the SVG surface's own estimate rather than by a real font, so a label's box can sit
12
+ * a pixel or two off where a browser would put it. The alternative is a native canvas dependency on every
13
+ * machine that renders, which is a steep price for that.
14
+ */
15
+ export interface HeadlessRenderOptions extends DiagramScreenshotOptions {
16
+ /** Width of the frame the drawing is laid out in, in CSS pixels. Defaults to 1200. */
17
+ hostWidth?: number;
18
+ /** Height of that frame. Defaults to 800. */
19
+ hostHeight?: number;
20
+ }
21
+
22
+ /** A 2D context that answers every call and remembers nothing: the drawing goes to the SVG surface. */
23
+ function createContext(): CanvasRenderingContext2D {
24
+ const own = {
25
+ globalAlpha: 1,
26
+ measureText: (text: string) => ({ width: text.length * 7 }),
27
+ };
28
+
29
+ return new Proxy(own, {
30
+ get: (target, property) => property in target ? target[property as keyof typeof own] : () => undefined,
31
+ set: (target, property, value) => {
32
+ (target as Record<PropertyKey, unknown>)[property] = value;
33
+ return true;
34
+ },
35
+ }) as unknown as CanvasRenderingContext2D;
36
+ }
37
+
38
+ class StubElement {
39
+ style: Record<string, string> = {};
40
+ className = '';
41
+ tabIndex = 0;
42
+ width = 0;
43
+ height = 0;
44
+ textContent = '';
45
+ readonly children: StubElement[] = [];
46
+ readonly classList = { toggle: () => false, add: () => undefined, remove: () => undefined };
47
+
48
+ private readonly context = createContext();
49
+
50
+ appendChild<T extends StubElement>(child: T): T {
51
+ this.children.push(child);
52
+ return child;
53
+ }
54
+
55
+ removeChild(child: StubElement): StubElement {
56
+ const at = this.children.indexOf(child);
57
+ if (at >= 0) this.children.splice(at, 1);
58
+ return child;
59
+ }
60
+
61
+ remove(): void { /* detached already */ }
62
+ setAttribute(): void { /* nothing reads it here */ }
63
+ focus(): void { /* no focus without a browser */ }
64
+ addEventListener(): void { /* nothing to fire the events */ }
65
+ removeEventListener(): void { /* see above */ }
66
+ getContext(): CanvasRenderingContext2D { return this.context; }
67
+
68
+ getBoundingClientRect(): DOMRect {
69
+ return { left: 0, top: 0, right: this.width, bottom: this.height, width: this.width, height: this.height, x: 0, y: 0, toJSON: () => ({}) } as DOMRect;
70
+ }
71
+
72
+ get clientWidth(): number { return this.width; }
73
+ get clientHeight(): number { return this.height; }
74
+ }
75
+
76
+ const GLOBAL_KEYS = ['window', 'document', 'requestAnimationFrame', 'cancelAnimationFrame', 'Image', 'getComputedStyle', 'performance'] as const;
77
+
78
+ /** Puts the stubs in place, and hands back the function that removes exactly what it added. */
79
+ function installGlobals(): () => void {
80
+ const target = globalThis as Record<string, unknown>;
81
+
82
+ if (target.document !== undefined)
83
+ return () => undefined;
84
+
85
+ const before = new Map<string, unknown>();
86
+ for (const key of GLOBAL_KEYS) before.set(key, target[key]);
87
+
88
+ const stubDocument = Object.assign(new StubElement(), {
89
+ documentElement: new StubElement(),
90
+ createElement: () => new StubElement(),
91
+ });
92
+
93
+ Object.assign(target, {
94
+ window: Object.assign(new StubElement(), { devicePixelRatio: 1 }),
95
+ document: stubDocument,
96
+ requestAnimationFrame: () => 1,
97
+ cancelAnimationFrame: () => undefined,
98
+ Image: class { },
99
+ getComputedStyle: () => ({ getPropertyValue: () => '' }),
100
+ // A host without a browser may have no clock either -- an embedded JS engine has none. The drawing
101
+ // reads it for animation, and a still picture has no animation to advance.
102
+ performance: (globalThis as { performance?: { now(): number } }).performance ?? { now: () => 0 },
103
+ });
104
+
105
+ return () => {
106
+ for (const [key, value] of before) {
107
+ if (value === undefined) delete target[key];
108
+ else target[key] = value;
109
+ }
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Draws a saved diagram and returns the SVG for it. The source is the document as text or as an object;
115
+ * the frame follows the content by default, since a picture made without a viewport has none to crop to.
116
+ */
117
+ export function renderDiagramSvg(source: string | unknown, options: HeadlessRenderOptions = {}): string {
118
+ const { hostWidth = 1200, hostHeight = 800, ...screenshot } = options;
119
+ const restore = installGlobals();
120
+
121
+ try {
122
+ const host = new StubElement();
123
+ host.width = hostWidth;
124
+ host.height = hostHeight;
125
+
126
+ const diagram = new Diagram({ host: host as unknown as HTMLElement });
127
+
128
+ try {
129
+ // Whatever shape it arrived in -- text off the wire, an object already in hand -- the library's
130
+ // own reader decides what a document is.
131
+ diagram.loadDocument(parseDiagramDocument(source));
132
+ return diagram.takeSvg({ scope: 'content', ...screenshot });
133
+ } finally {
134
+ diagram.destroy();
135
+ }
136
+ } finally {
137
+ restore();
138
+ }
139
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,9 @@ export {
6
6
  serializeDiagramDocument,
7
7
  } from './core/document.js';
8
8
 
9
+ export { renderDiagramSvg } from './headless.js';
10
+ export type { HeadlessRenderOptions } from './headless.js';
11
+
9
12
  export { DiagramActionRegistry } from './core/action-registry.js';
10
13
  export type {
11
14
  DiagramAction,