plotly-print 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.
@@ -0,0 +1,1195 @@
1
+ /**
2
+ * plotly-print Micro-DOM for Plotly.js / D3 v3 static rendering in QuickJS.
3
+ */
4
+ (function() {
5
+ 'use strict';
6
+
7
+ var globalScope = typeof globalThis !== 'undefined' ? globalThis : this;
8
+ if (typeof globalScope.process === 'undefined') {
9
+ globalScope.process = { env: { NODE_ENV: 'production' }, browser: true, version: '' };
10
+ }
11
+
12
+ // --- Helpers ---
13
+ function camelToDashed(str) {
14
+ return str.replace(/[A-Z]/g, function(m) { return '-' + m.toLowerCase(); });
15
+ }
16
+
17
+ // --- CSSStyleDeclaration ---
18
+ function CSSStyleDeclaration() {
19
+ this._properties = {};
20
+ }
21
+ CSSStyleDeclaration.prototype.setProperty = function(name, value, priority) {
22
+ if (value === null || value === undefined || value === '') {
23
+ delete this._properties[name];
24
+ } else {
25
+ this._properties[name] = String(value);
26
+ }
27
+ };
28
+ CSSStyleDeclaration.prototype.getPropertyValue = function(name) {
29
+ return this._properties[name] || '';
30
+ };
31
+ CSSStyleDeclaration.prototype.removeProperty = function(name) {
32
+ var val = this._properties[name] || '';
33
+ delete this._properties[name];
34
+ return val;
35
+ };
36
+ CSSStyleDeclaration.prototype.cssText = function() {
37
+ var parts = [];
38
+ for (var k in this._properties) {
39
+ parts.push(camelToDashed(k) + ': ' + this._properties[k]);
40
+ }
41
+ return parts.join('; ');
42
+ };
43
+
44
+ // Style proxy or property reflection
45
+ function createStyle(element) {
46
+ var decl = new CSSStyleDeclaration();
47
+ decl._element = element;
48
+ // Return a proxy if available, else plain decl with getters/setters for common props
49
+ if (typeof Proxy !== 'undefined') {
50
+ return new Proxy(decl, {
51
+ get: function(target, prop) {
52
+ if (prop in target || typeof prop === 'symbol') {
53
+ return target[prop];
54
+ }
55
+ var dashed = camelToDashed(String(prop));
56
+ return target.getPropertyValue(dashed);
57
+ },
58
+ set: function(target, prop, value) {
59
+ if (prop === '_properties' || prop in target) {
60
+ target[prop] = value;
61
+ } else {
62
+ var dashed = camelToDashed(String(prop));
63
+ target.setProperty(dashed, value);
64
+ }
65
+ return true;
66
+ }
67
+ });
68
+ }
69
+ return decl;
70
+ }
71
+
72
+ // --- DOM Node ---
73
+ function Node() {
74
+ this.childNodes = [];
75
+ this.parentNode = null;
76
+ this._ownerDoc = null;
77
+ this.nodeType = 1;
78
+ this.nodeName = '';
79
+ }
80
+
81
+ Object.defineProperty(Node.prototype, 'ownerDocument', {
82
+ get: function() {
83
+ if (this.nodeType === 9) return null;
84
+ return this._ownerDoc || (globalScope.document || null);
85
+ },
86
+ set: function(v) {
87
+ this._ownerDoc = v;
88
+ }
89
+ });
90
+
91
+ Object.defineProperty(Node.prototype, 'firstChild', {
92
+ get: function() { return this.childNodes[0] || null; }
93
+ });
94
+ Object.defineProperty(Node.prototype, 'lastChild', {
95
+ get: function() { return this.childNodes[this.childNodes.length - 1] || null; }
96
+ });
97
+ Object.defineProperty(Node.prototype, 'nextSibling', {
98
+ get: function() {
99
+ if (!this.parentNode) return null;
100
+ var idx = this.parentNode.childNodes.indexOf(this);
101
+ return (idx !== -1 && idx + 1 < this.parentNode.childNodes.length) ? this.parentNode.childNodes[idx + 1] : null;
102
+ }
103
+ });
104
+ Object.defineProperty(Node.prototype, 'previousSibling', {
105
+ get: function() {
106
+ if (!this.parentNode) return null;
107
+ var idx = this.parentNode.childNodes.indexOf(this);
108
+ return (idx > 0) ? this.parentNode.childNodes[idx - 1] : null;
109
+ }
110
+ });
111
+
112
+ Node.prototype.appendChild = function(child) {
113
+ if (child.nodeType === 11) { // DocumentFragment
114
+ var children = child.childNodes.slice();
115
+ for (var i = 0; i < children.length; i++) {
116
+ this.appendChild(children[i]);
117
+ }
118
+ return child;
119
+ }
120
+ if (child.parentNode) {
121
+ child.parentNode.removeChild(child);
122
+ }
123
+ child.parentNode = this;
124
+ child._ownerDoc = this.nodeType === 9 ? this : (this.ownerDocument || globalScope.document);
125
+ this.childNodes.push(child);
126
+ return child;
127
+ };
128
+
129
+ Node.prototype.removeChild = function(child) {
130
+ var idx = this.childNodes.indexOf(child);
131
+ if (idx !== -1) {
132
+ this.childNodes.splice(idx, 1);
133
+ child.parentNode = null;
134
+ return child;
135
+ }
136
+ return child;
137
+ };
138
+
139
+ Node.prototype.insertBefore = function(newChild, refChild) {
140
+ if (!refChild) return this.appendChild(newChild);
141
+ if (newChild.nodeType === 11) { // DocumentFragment
142
+ var children = newChild.childNodes.slice();
143
+ for (var i = 0; i < children.length; i++) {
144
+ this.insertBefore(children[i], refChild);
145
+ }
146
+ return newChild;
147
+ }
148
+ if (newChild.parentNode) {
149
+ newChild.parentNode.removeChild(newChild);
150
+ }
151
+ var idx = this.childNodes.indexOf(refChild);
152
+ if (idx !== -1) {
153
+ newChild.parentNode = this;
154
+ newChild.ownerDocument = this.ownerDocument || this;
155
+ this.childNodes.splice(idx, 0, newChild);
156
+ return newChild;
157
+ }
158
+ return this.appendChild(newChild);
159
+ };
160
+
161
+ Node.prototype.replaceChild = function(newChild, oldChild) {
162
+ this.insertBefore(newChild, oldChild);
163
+ return this.removeChild(oldChild);
164
+ };
165
+
166
+ Node.prototype.cloneNode = function(deep) {
167
+ var clone;
168
+ if (this.nodeType === 3) {
169
+ clone = new Text(this.nodeValue);
170
+ } else if (this.nodeType === 1) {
171
+ clone = this.namespaceURI
172
+ ? (this.ownerDocument || document).createElementNS(this.namespaceURI, this.tagName.toLowerCase())
173
+ : (this.ownerDocument || document).createElement(this.tagName.toLowerCase());
174
+ for (var k in this._attributes) {
175
+ clone.setAttribute(k, this._attributes[k]);
176
+ }
177
+ for (var prop in this.style._properties) {
178
+ clone.style.setProperty(prop, this.style.getPropertyValue(prop));
179
+ }
180
+ } else {
181
+ clone = new Node();
182
+ }
183
+ if (deep && this.childNodes) {
184
+ for (var i = 0; i < this.childNodes.length; i++) {
185
+ clone.appendChild(this.childNodes[i].cloneNode(true));
186
+ }
187
+ }
188
+ return clone;
189
+ };
190
+
191
+ Object.defineProperty(Node.prototype, 'textContent', {
192
+ get: function() {
193
+ if (this.nodeType === 3) return this.nodeValue;
194
+ var txt = '';
195
+ for (var i = 0; i < this.childNodes.length; i++) {
196
+ txt += this.childNodes[i].textContent || '';
197
+ }
198
+ return txt;
199
+ },
200
+ set: function(val) {
201
+ this.childNodes = [];
202
+ if (val !== null && val !== undefined && val !== '') {
203
+ this.appendChild(new Text(String(val)));
204
+ }
205
+ }
206
+ });
207
+
208
+ // --- Text Node ---
209
+ function Text(text) {
210
+ Node.call(this);
211
+ this.nodeType = 3;
212
+ this.nodeName = '#text';
213
+ this.nodeValue = String(text !== undefined && text !== null ? text : '');
214
+ }
215
+ Text.prototype = Object.create(Node.prototype);
216
+ Object.defineProperty(Text.prototype, 'data', {
217
+ get: function() { return this.nodeValue; },
218
+ set: function(v) { this.nodeValue = String(v); }
219
+ });
220
+
221
+ // --- DocumentFragment ---
222
+ function DocumentFragment() {
223
+ Node.call(this);
224
+ this.nodeType = 11;
225
+ this.nodeName = '#document-fragment';
226
+ }
227
+ DocumentFragment.prototype = Object.create(Node.prototype);
228
+
229
+ // --- Element ---
230
+ function Element(tagName, namespaceURI) {
231
+ Node.call(this);
232
+ this.nodeType = 1;
233
+ this.namespaceURI = namespaceURI || null;
234
+ var tagStr = String(tagName);
235
+ if (this.namespaceURI === 'http://www.w3.org/2000/svg') {
236
+ var lower = tagStr.toLowerCase();
237
+ this.tagName = SVG_CAMEL_TAGS[lower] || lower;
238
+ this.nodeName = this.tagName;
239
+ } else {
240
+ this.tagName = tagStr.toUpperCase();
241
+ this.nodeName = this.tagName;
242
+ }
243
+ this._attributes = {};
244
+ this.style = createStyle(this);
245
+ this.classList = new ClassList(this);
246
+ this._eventListeners = {};
247
+
248
+ // Default dimensions
249
+ this.clientWidth = 0;
250
+ this.clientHeight = 0;
251
+ this.offsetWidth = 0;
252
+ this.offsetHeight = 0;
253
+ }
254
+ Element.prototype = Object.create(Node.prototype);
255
+
256
+ Object.defineProperty(Element.prototype, 'id', {
257
+ get: function() { return this.getAttribute('id') || ''; },
258
+ set: function(v) { this.setAttribute('id', v); }
259
+ });
260
+
261
+ Object.defineProperty(Element.prototype, 'className', {
262
+ get: function() { return this.getAttribute('class') || ''; },
263
+ set: function(v) { this.setAttribute('class', v); }
264
+ });
265
+
266
+ function ClassList(el) { this._el = el; }
267
+ ClassList.prototype.add = function() {
268
+ var current = (this._el.getAttribute('class') || '').split(/\s+/).filter(Boolean);
269
+ for (var i = 0; i < arguments.length; i++) {
270
+ if (current.indexOf(arguments[i]) === -1) current.push(arguments[i]);
271
+ }
272
+ this._el.setAttribute('class', current.join(' '));
273
+ };
274
+ ClassList.prototype.remove = function() {
275
+ var current = (this._el.getAttribute('class') || '').split(/\s+/).filter(Boolean);
276
+ for (var i = 0; i < arguments.length; i++) {
277
+ var idx = current.indexOf(arguments[i]);
278
+ if (idx !== -1) current.splice(idx, 1);
279
+ }
280
+ this._el.setAttribute('class', current.join(' '));
281
+ };
282
+ ClassList.prototype.contains = function(name) {
283
+ var current = (this._el.getAttribute('class') || '').split(/\s+/).filter(Boolean);
284
+ return current.indexOf(name) !== -1;
285
+ };
286
+ ClassList.prototype.toggle = function(name) {
287
+ if (this.contains(name)) { this.remove(name); return false; }
288
+ else { this.add(name); return true; }
289
+ };
290
+
291
+ Element.prototype.setAttribute = function(name, value) {
292
+ this._attributes[name] = String(value);
293
+ };
294
+ Element.prototype.getAttribute = function(name) {
295
+ return this._attributes.hasOwnProperty(name) ? this._attributes[name] : null;
296
+ };
297
+ Element.prototype.hasAttribute = function(name) {
298
+ return this._attributes.hasOwnProperty(name);
299
+ };
300
+ Element.prototype.removeAttribute = function(name) {
301
+ delete this._attributes[name];
302
+ };
303
+ Element.prototype.setAttributeNS = function(ns, name, value) {
304
+ this.setAttribute(name, value);
305
+ if (name === 'href' && ns && String(ns).indexOf('xlink') !== -1) {
306
+ this.setAttribute('xlink:href', value);
307
+ } else if (name === 'xlink:href') {
308
+ this.setAttribute('href', value);
309
+ }
310
+ };
311
+ Element.prototype.getAttributeNS = function(ns, name) {
312
+ return this.getAttribute(name);
313
+ };
314
+ Element.prototype.hasAttributeNS = function(ns, name) {
315
+ return this.hasAttribute(name);
316
+ };
317
+ Element.prototype.removeAttributeNS = function(ns, name) {
318
+ this.removeAttribute(name);
319
+ };
320
+
321
+ // Event listeners
322
+ Element.prototype.addEventListener = function(event, fn) {
323
+ if (!this._eventListeners[event]) this._eventListeners[event] = [];
324
+ this._eventListeners[event].push(fn);
325
+ };
326
+ Element.prototype.removeEventListener = function(event, fn) {
327
+ if (!this._eventListeners[event]) return;
328
+ var idx = this._eventListeners[event].indexOf(fn);
329
+ if (idx !== -1) this._eventListeners[event].splice(idx, 1);
330
+ };
331
+ Element.prototype.dispatchEvent = function(evt) {
332
+ var fns = this._eventListeners[evt.type];
333
+ if (fns) {
334
+ for (var i = 0; i < fns.length; i++) {
335
+ try { fns[i].call(this, evt); } catch(e) {}
336
+ }
337
+ }
338
+ return true;
339
+ };
340
+
341
+ // D3 / Plotly Query Selectors
342
+ Element.prototype.matches = function(selector) {
343
+ if (!selector) return false;
344
+ if (selector === '*') return true;
345
+ if (selector === ':first-child') {
346
+ if (!this.parentNode) return false;
347
+ for (var i = 0; i < this.parentNode.childNodes.length; i++) {
348
+ var ch = this.parentNode.childNodes[i];
349
+ if (ch.nodeType === 1) return ch === this;
350
+ }
351
+ return false;
352
+ }
353
+ if (selector[0] === '#') return this.id === selector.slice(1);
354
+ if (selector[0] === '.') {
355
+ var cls = selector.slice(1);
356
+ return this.classList.contains(cls);
357
+ }
358
+
359
+ // Attribute selector e.g. g[class^="barlayer"], [class^="barlayer"], [id="xyz"]
360
+ var attrMatch = selector.match(/^([a-zA-Z0-9_-]*)\[([a-zA-Z0-9_-]+)([\^$*~|]?=)?(["']?)(.*?)\4\]$/);
361
+ if (attrMatch) {
362
+ var tag = attrMatch[1];
363
+ var attr = attrMatch[2];
364
+ var op = attrMatch[3];
365
+ var val = attrMatch[5];
366
+ if (tag && this.tagName.toLowerCase() !== tag.toLowerCase()) return false;
367
+ if (!this.hasAttribute(attr)) return false;
368
+ if (!op) return true;
369
+ var actual = this.getAttribute(attr) || '';
370
+ if (op === '=') return actual === val;
371
+ if (op === '^=') return actual.indexOf(val) === 0;
372
+ if (op === '$=') return actual.slice(-val.length) === val;
373
+ if (op === '*=') return actual.indexOf(val) !== -1;
374
+ if (op === '~=') return (' ' + actual + ' ').indexOf(' ' + val + ' ') !== -1;
375
+ return false;
376
+ }
377
+
378
+ // Tag with class(es): e.g. svg.main-svg or g.trace.bars
379
+ if (selector.indexOf('.') !== -1) {
380
+ var parts = selector.split('.');
381
+ var tagMatch = !parts[0] || this.tagName.toLowerCase() === parts[0].toLowerCase();
382
+ if (!tagMatch) return false;
383
+ for (var p = 1; p < parts.length; p++) {
384
+ if (!this.classList.contains(parts[p])) return false;
385
+ }
386
+ return true;
387
+ }
388
+ return this.tagName.toLowerCase() === selector.toLowerCase();
389
+ };
390
+
391
+ Element.prototype.querySelector = function(selector) {
392
+ if (selector === ':first-child') {
393
+ for (var i = 0; i < this.childNodes.length; i++) {
394
+ var ch = this.childNodes[i];
395
+ if (ch.nodeType === 1) return ch;
396
+ }
397
+ return null;
398
+ }
399
+ var results = this.querySelectorAll(selector);
400
+ return results.length > 0 ? results[0] : null;
401
+ };
402
+
403
+ function querySelectorAllSimple(root, selector) {
404
+ var matches = [];
405
+ function walk(node) {
406
+ for (var i = 0; i < node.childNodes.length; i++) {
407
+ var child = node.childNodes[i];
408
+ if (child.nodeType === 1) {
409
+ if (child.matches(selector)) matches.push(child);
410
+ walk(child);
411
+ }
412
+ }
413
+ }
414
+ walk(root);
415
+ return matches;
416
+ }
417
+
418
+ function querySelectorAllSingle(root, selector) {
419
+ selector = selector.trim();
420
+ if (!selector) return [];
421
+
422
+ // Handle child combinators: e.g. "a > b > c"
423
+ if (selector.indexOf('>') !== -1) {
424
+ var segments = selector.split('>');
425
+ var current = [root];
426
+ for (var s = 0; s < segments.length; s++) {
427
+ var seg = segments[s].trim();
428
+ var next = [];
429
+ for (var c = 0; c < current.length; c++) {
430
+ var parentNode = current[c];
431
+ if (s === 0) {
432
+ var matched = querySelectorAllSingle(parentNode, seg);
433
+ for (var m = 0; m < matched.length; m++) {
434
+ if (next.indexOf(matched[m]) === -1) next.push(matched[m]);
435
+ }
436
+ } else {
437
+ for (var ch = 0; ch < parentNode.childNodes.length; ch++) {
438
+ var kid = parentNode.childNodes[ch];
439
+ if (kid.nodeType === 1 && kid.matches(seg)) {
440
+ if (next.indexOf(kid) === -1) next.push(kid);
441
+ }
442
+ }
443
+ }
444
+ }
445
+ current = next;
446
+ }
447
+ return current;
448
+ }
449
+
450
+ // Handle space descendant combinators: e.g. "a b c"
451
+ var inBracket = false;
452
+ var hasSpace = false;
453
+ for (var i = 0; i < selector.length; i++) {
454
+ if (selector[i] === '[') inBracket = true;
455
+ else if (selector[i] === ']') inBracket = false;
456
+ else if (selector[i] === ' ' && !inBracket) {
457
+ hasSpace = true;
458
+ break;
459
+ }
460
+ }
461
+ if (hasSpace) {
462
+ var tokens = [];
463
+ var curr = '';
464
+ for (var i = 0; i < selector.length; i++) {
465
+ if (selector[i] === '[') inBracket = true;
466
+ else if (selector[i] === ']') inBracket = false;
467
+ if (selector[i] === ' ' && !inBracket) {
468
+ if (curr.trim()) tokens.push(curr.trim());
469
+ curr = '';
470
+ } else {
471
+ curr += selector[i];
472
+ }
473
+ }
474
+ if (curr.trim()) tokens.push(curr.trim());
475
+
476
+ var current = [root];
477
+ for (var t = 0; t < tokens.length; t++) {
478
+ var tok = tokens[t];
479
+ var next = [];
480
+ for (var c = 0; c < current.length; c++) {
481
+ var descendants = querySelectorAllSimple(current[c], tok);
482
+ for (var d = 0; d < descendants.length; d++) {
483
+ if (next.indexOf(descendants[d]) === -1) next.push(descendants[d]);
484
+ }
485
+ }
486
+ current = next;
487
+ }
488
+ return current;
489
+ }
490
+
491
+ return querySelectorAllSimple(root, selector);
492
+ }
493
+
494
+ Element.prototype.querySelectorAll = function(selector) {
495
+ if (!selector) return [];
496
+ if (selector.indexOf(',') !== -1) {
497
+ var parts = selector.split(',');
498
+ var all = [];
499
+ for (var p = 0; p < parts.length; p++) {
500
+ var res = querySelectorAllSingle(this, parts[p]);
501
+ for (var r = 0; r < res.length; r++) {
502
+ if (all.indexOf(res[r]) === -1) all.push(res[r]);
503
+ }
504
+ }
505
+ return all;
506
+ }
507
+ return querySelectorAllSingle(this, selector);
508
+ };
509
+
510
+ Element.prototype.getElementsByTagName = function(tagName) {
511
+ var target = tagName.toUpperCase();
512
+ var matches = [];
513
+ function walk(node) {
514
+ for (var i = 0; i < node.childNodes.length; i++) {
515
+ var child = node.childNodes[i];
516
+ if (child.nodeType === 1) {
517
+ if (target === '*' || child.tagName === target) matches.push(child);
518
+ walk(child);
519
+ }
520
+ }
521
+ }
522
+ walk(this);
523
+ return matches;
524
+ };
525
+
526
+ Element.prototype.getElementsByClassName = function(className) {
527
+ return this.querySelectorAll('.' + className);
528
+ };
529
+
530
+ // --- Geometry & Font Measurement ---
531
+ Element.prototype.getCTM = function() {
532
+ return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
533
+ };
534
+ Element.prototype.getScreenCTM = function() {
535
+ return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
536
+ };
537
+
538
+ function identityMatrix() {
539
+ return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
540
+ }
541
+
542
+ function multiplyMatrices(m1, m2) {
543
+ // Column-vector convention: result = m1 * m2 (m2 applied first).
544
+ return {
545
+ a: m1.a * m2.a + m1.c * m2.b,
546
+ b: m1.b * m2.a + m1.d * m2.b,
547
+ c: m1.a * m2.c + m1.c * m2.d,
548
+ d: m1.b * m2.c + m1.d * m2.d,
549
+ e: m1.a * m2.e + m1.c * m2.f + m1.e,
550
+ f: m1.b * m2.e + m1.d * m2.f + m1.f
551
+ };
552
+ }
553
+
554
+ function transformPoint(m, x, y) {
555
+ return {
556
+ x: m.a * x + m.c * y + m.e,
557
+ y: m.b * x + m.d * y + m.f
558
+ };
559
+ }
560
+
561
+ function translateMatrix(tx, ty) {
562
+ return { a: 1, b: 0, c: 0, d: 1, e: tx || 0, f: ty || 0 };
563
+ }
564
+
565
+ /**
566
+ * Parse a full SVG transform attribute into a 2D affine matrix.
567
+ * SVG post-multiplies the list left-to-right (M = T1*T2*...*Tn), so the
568
+ * rightmost transform is applied to a point first.
569
+ */
570
+ function parseTransform(transform) {
571
+ if (!transform) return identityMatrix();
572
+ var result = identityMatrix();
573
+ var re = /(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*([^)]*)\s*\)/g;
574
+ var match;
575
+ while ((match = re.exec(String(transform))) !== null) {
576
+ var type = match[1];
577
+ var rawArgs = match[2].trim();
578
+ var args = rawArgs ? rawArgs.split(/[\s,]+/).map(parseFloat) : [];
579
+ var m = identityMatrix();
580
+
581
+ if (type === 'matrix' && args.length >= 6) {
582
+ m = {
583
+ a: args[0], b: args[1], c: args[2],
584
+ d: args[3], e: args[4], f: args[5]
585
+ };
586
+ } else if (type === 'translate') {
587
+ m.e = args[0] || 0;
588
+ m.f = args.length > 1 ? (args[1] || 0) : 0;
589
+ } else if (type === 'scale') {
590
+ var sx = args.length > 0 && !isNaN(args[0]) ? args[0] : 1;
591
+ var sy = args.length > 1 && !isNaN(args[1]) ? args[1] : sx;
592
+ m.a = sx;
593
+ m.d = sy;
594
+ } else if (type === 'rotate') {
595
+ var angle = ((args[0] || 0) * Math.PI) / 180;
596
+ var cos = Math.cos(angle);
597
+ var sin = Math.sin(angle);
598
+ var rot = { a: cos, b: sin, c: -sin, d: cos, e: 0, f: 0 };
599
+ if (args.length >= 3) {
600
+ var cx = args[1] || 0;
601
+ var cy = args[2] || 0;
602
+ // translate(cx,cy) rotate(a) translate(-cx,-cy)
603
+ m = multiplyMatrices(
604
+ translateMatrix(cx, cy),
605
+ multiplyMatrices(rot, translateMatrix(-cx, -cy))
606
+ );
607
+ } else {
608
+ m = rot;
609
+ }
610
+ } else if (type === 'skewX') {
611
+ m.c = Math.tan(((args[0] || 0) * Math.PI) / 180);
612
+ } else if (type === 'skewY') {
613
+ m.b = Math.tan(((args[0] || 0) * Math.PI) / 180);
614
+ }
615
+ result = multiplyMatrices(result, m);
616
+ }
617
+ return result;
618
+ }
619
+
620
+ /** Axis-aligned bounds of a bbox after applying an affine matrix to its corners. */
621
+ function transformBBox(bb, matrix) {
622
+ var corners = [
623
+ transformPoint(matrix, bb.x, bb.y),
624
+ transformPoint(matrix, bb.x + bb.width, bb.y),
625
+ transformPoint(matrix, bb.x, bb.y + bb.height),
626
+ transformPoint(matrix, bb.x + bb.width, bb.y + bb.height)
627
+ ];
628
+ var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
629
+ for (var i = 0; i < 4; i++) {
630
+ var p = corners[i];
631
+ if (p.x < minX) minX = p.x;
632
+ if (p.y < minY) minY = p.y;
633
+ if (p.x > maxX) maxX = p.x;
634
+ if (p.y > maxY) maxY = p.y;
635
+ }
636
+ return {
637
+ x: minX,
638
+ y: minY,
639
+ width: maxX - minX,
640
+ height: maxY - minY,
641
+ left: minX,
642
+ top: minY,
643
+ right: maxX,
644
+ bottom: maxY
645
+ };
646
+ }
647
+
648
+ function getTextAnchor(node) {
649
+ var cur = node;
650
+ while (cur && cur.nodeType === 1) {
651
+ var anchor = cur.style ? (cur.style.getPropertyValue('text-anchor') || cur.getAttribute('text-anchor')) : null;
652
+ if (anchor) return anchor.trim().toLowerCase();
653
+ cur = cur.parentNode;
654
+ }
655
+ return 'start';
656
+ }
657
+
658
+ Element.prototype.getBBox = function() {
659
+ var tag = this.tagName.toLowerCase();
660
+ var x = parseFloat(this.getAttribute('x')) || 0;
661
+ var y = parseFloat(this.getAttribute('y')) || 0;
662
+
663
+ if (tag === 'text') {
664
+ // Check if <text> contains child <tspan> elements (e.g. multi-line text)
665
+ var tspans = [];
666
+ for (var i = 0; i < this.childNodes.length; i++) {
667
+ var ch = this.childNodes[i];
668
+ if (ch.nodeType === 1 && ch.tagName.toLowerCase() === 'tspan') {
669
+ tspans.push(ch);
670
+ }
671
+ }
672
+
673
+ if (tspans.length > 0) {
674
+ var parentFontSize = parseFloat(this.style.getPropertyValue('font-size') || this.getAttribute('font-size')) || 12;
675
+ var parentFontFamily = this.style.getPropertyValue('font-family') || this.getAttribute('font-family') || 'sans-serif';
676
+ var parentFontWeight = this.style.getPropertyValue('font-weight') || this.getAttribute('font-weight') || 'normal';
677
+ var parentAnchor = getTextAnchor(this);
678
+ var baseX = x;
679
+ var baseY = y;
680
+
681
+ var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
682
+ var curY = baseY;
683
+
684
+ for (var j = 0; j < tspans.length; j++) {
685
+ var tsp = tspans[j];
686
+ var tText = tsp.textContent || '';
687
+ var tFontSize = parseFloat(tsp.style.getPropertyValue('font-size') || tsp.getAttribute('font-size')) || parentFontSize;
688
+ var tFontFamily = tsp.style.getPropertyValue('font-family') || tsp.getAttribute('font-family') || parentFontFamily;
689
+ var tFontWeight = tsp.style.getPropertyValue('font-weight') || tsp.getAttribute('font-weight') || parentFontWeight;
690
+ var tAnchor = (tsp.style.getPropertyValue('text-anchor') || tsp.getAttribute('text-anchor') || parentAnchor).trim().toLowerCase();
691
+
692
+ var tx = tsp.hasAttribute('x') ? (parseFloat(tsp.getAttribute('x')) || 0) : baseX;
693
+ if (tsp.hasAttribute('y')) {
694
+ curY = parseFloat(tsp.getAttribute('y')) || 0;
695
+ }
696
+ if (tsp.hasAttribute('dy')) {
697
+ var dyStr = tsp.getAttribute('dy') || '';
698
+ var dyVal = 0;
699
+ if (dyStr.indexOf('em') !== -1) {
700
+ dyVal = parseFloat(dyStr) * tFontSize;
701
+ } else {
702
+ dyVal = parseFloat(dyStr) || 0;
703
+ }
704
+ curY += dyVal;
705
+ }
706
+
707
+ var tw = 0, th = tFontSize * 1.2, ta = tFontSize * 0.8;
708
+ if (typeof globalScope._measureTextRaw === 'function') {
709
+ try {
710
+ var raw = globalScope._measureTextRaw(tText, tFontFamily, String(tFontSize), tFontWeight);
711
+ var parts = raw.split(',');
712
+ tw = parseFloat(parts[0]) || 0;
713
+ th = parseFloat(parts[1]) || (tFontSize * 1.2);
714
+ ta = parseFloat(parts[2]) || (tFontSize * 0.8);
715
+ } catch(e) {
716
+ tw = tText.length * tFontSize * 0.6;
717
+ }
718
+ } else {
719
+ tw = tText.length * tFontSize * 0.6;
720
+ }
721
+
722
+ var tMinX;
723
+ if (tAnchor === 'middle') {
724
+ tMinX = tx - tw / 2;
725
+ } else if (tAnchor === 'end') {
726
+ tMinX = tx - tw;
727
+ } else {
728
+ tMinX = tx;
729
+ }
730
+ var tMaxX = tMinX + tw;
731
+ var tMinY = curY - ta;
732
+ var tMaxY = tMinY + th;
733
+
734
+ if (tMinX < minX) minX = tMinX;
735
+ if (tMinY < minY) minY = tMinY;
736
+ if (tMaxX > maxX) maxX = tMaxX;
737
+ if (tMaxY > maxY) maxY = tMaxY;
738
+ }
739
+
740
+ if (minX !== Infinity) {
741
+ var w = maxX - minX;
742
+ var h = maxY - minY;
743
+ return {
744
+ x: minX,
745
+ y: minY,
746
+ width: w,
747
+ height: h,
748
+ left: minX,
749
+ top: minY,
750
+ right: maxX,
751
+ bottom: maxY
752
+ };
753
+ }
754
+ }
755
+ }
756
+
757
+ if (tag === 'text' || tag === 'tspan') {
758
+ var text = this.textContent || '';
759
+ var fontSize = parseFloat(this.style.getPropertyValue('font-size') || this.getAttribute('font-size')) || 12;
760
+ var fontFamily = this.style.getPropertyValue('font-family') || this.getAttribute('font-family') || 'sans-serif';
761
+ var fontWeight = this.style.getPropertyValue('font-weight') || this.getAttribute('font-weight') || 'normal';
762
+ var anchor = getTextAnchor(this);
763
+
764
+ var w = 0, h = fontSize * 1.2, a = fontSize * 0.8, d = fontSize * 0.2;
765
+ if (typeof globalScope._measureTextRaw === 'function') {
766
+ try {
767
+ var raw = globalScope._measureTextRaw(text, fontFamily, String(fontSize), fontWeight);
768
+ var parts = raw.split(',');
769
+ w = parseFloat(parts[0]) || 0;
770
+ h = parseFloat(parts[1]) || (fontSize * 1.2);
771
+ a = parseFloat(parts[2]) || (fontSize * 0.8);
772
+ d = parseFloat(parts[3]) || (fontSize * 0.2);
773
+ } catch(e) {
774
+ w = text.length * fontSize * 0.6;
775
+ }
776
+ } else {
777
+ w = text.length * fontSize * 0.6;
778
+ }
779
+
780
+ var minX;
781
+ if (anchor === 'middle') {
782
+ minX = x - w / 2;
783
+ } else if (anchor === 'end') {
784
+ minX = x - w;
785
+ } else {
786
+ minX = x;
787
+ }
788
+
789
+ return {
790
+ x: minX,
791
+ y: y - a,
792
+ width: w,
793
+ height: h,
794
+ left: minX,
795
+ top: y - a,
796
+ right: minX + w,
797
+ bottom: y - a + h
798
+ };
799
+ }
800
+
801
+ // For groups (<g>, <svg>), aggregate children bounding boxes.
802
+ // Each child's transform is applied to its bbox corners (SVG getBBox on a
803
+ // group includes child transforms; an element's own transform is NOT part
804
+ // of that element's own getBBox).
805
+ var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
806
+ var hasKids = false;
807
+ for (var i = 0; i < this.childNodes.length; i++) {
808
+ var child = this.childNodes[i];
809
+ if (child.nodeType === 1 && typeof child.getBBox === 'function') {
810
+ var bb = child.getBBox();
811
+ var childMatrix = parseTransform(child.getAttribute('transform'));
812
+ var transformed = transformBBox(bb, childMatrix);
813
+ var cw = transformed.width;
814
+ var ch = transformed.height;
815
+ if (cw > 0 || ch > 0) {
816
+ hasKids = true;
817
+ if (transformed.x < minX) minX = transformed.x;
818
+ if (transformed.y < minY) minY = transformed.y;
819
+ if (transformed.x + cw > maxX) maxX = transformed.x + cw;
820
+ if (transformed.y + ch > maxY) maxY = transformed.y + ch;
821
+ }
822
+ }
823
+ }
824
+ if (!hasKids) {
825
+ return { x: 0, y: 0, width: 0, height: 0, left: 0, top: 0, right: 0, bottom: 0 };
826
+ }
827
+ return {
828
+ x: minX,
829
+ y: minY,
830
+ width: maxX - minX,
831
+ height: maxY - minY,
832
+ left: minX,
833
+ top: minY,
834
+ right: maxX,
835
+ bottom: maxY
836
+ };
837
+ };
838
+
839
+ Element.prototype.getBoundingClientRect = function() {
840
+ var bb = this.getBBox();
841
+ // Compose full ancestor matrices (including this element's transform).
842
+ // Walk self → root so final = T_root * ... * T_parent * T_self.
843
+ var matrix = identityMatrix();
844
+ var cur = this;
845
+ while (cur && cur.nodeType === 1) {
846
+ var local = cur.getAttribute
847
+ ? parseTransform(cur.getAttribute('transform'))
848
+ : identityMatrix();
849
+ var ox = cur.offsetLeft || 0;
850
+ var oy = cur.offsetTop || 0;
851
+ if (ox || oy) {
852
+ local = multiplyMatrices(translateMatrix(ox, oy), local);
853
+ }
854
+ matrix = multiplyMatrices(local, matrix);
855
+ cur = cur.parentNode;
856
+ }
857
+ var transformed = transformBBox(bb, matrix);
858
+ // Prefer explicit layout size when present (HTML elements); otherwise use
859
+ // the transformed SVG bbox so rotations expand width/height correctly.
860
+ var width = this.offsetWidth || this.clientWidth || transformed.width;
861
+ var height = this.offsetHeight || this.clientHeight || transformed.height;
862
+ return {
863
+ left: transformed.x,
864
+ top: transformed.y,
865
+ right: transformed.x + width,
866
+ bottom: transformed.y + height,
867
+ width: width,
868
+ height: height
869
+ };
870
+ };
871
+
872
+ Element.prototype.getComputedTextLength = function() {
873
+ return this.getBBox().width;
874
+ };
875
+
876
+ Element.prototype.getTotalLength = function() {
877
+ var bb = this.getBBox();
878
+ var p = (bb.width + bb.height) * 2;
879
+ return p > 0 ? p : 100;
880
+ };
881
+
882
+ Element.prototype.getPointAtLength = function(len) {
883
+ var bb = this.getBBox();
884
+ return { x: bb.x, y: bb.y };
885
+ };
886
+
887
+ var SVG_CAMEL_TAGS = {
888
+ 'lineargradient': 'linearGradient',
889
+ 'radialgradient': 'radialGradient',
890
+ 'clippath': 'clipPath',
891
+ 'textpath': 'textPath',
892
+ 'foreignobject': 'foreignObject',
893
+ 'animatetransform': 'animateTransform',
894
+ 'fecolormatrix': 'feColorMatrix',
895
+ 'fecomposite': 'feComposite',
896
+ 'fegaussianblur': 'feGaussianBlur',
897
+ 'femerge': 'feMerge',
898
+ 'femergenode': 'feMergeNode',
899
+ 'feoffset': 'feOffset'
900
+ };
901
+
902
+ // Serialization
903
+ function serializeNode(node) {
904
+ if (node.nodeType === 3) {
905
+ return node.nodeValue
906
+ .replace(/&/g, '&amp;')
907
+ .replace(/</g, '&lt;')
908
+ .replace(/>/g, '&gt;');
909
+ }
910
+ if (node.nodeType === 1) {
911
+ var lowerTag = node.tagName.toLowerCase();
912
+ var tag = SVG_CAMEL_TAGS[lowerTag] || lowerTag;
913
+ var out = '<' + tag;
914
+ var css = (node.style && typeof node.style.cssText === 'function') ? node.style.cssText() : '';
915
+ for (var k in node._attributes) {
916
+ if (k === 'style') continue;
917
+ out += ' ' + k + '="' + String(node._attributes[k]).replace(/"/g, '&quot;') + '"';
918
+ }
919
+ if (css) {
920
+ out += ' style="' + css.replace(/"/g, '&quot;') + '"';
921
+ } else if (node._attributes['style']) {
922
+ out += ' style="' + String(node._attributes['style']).replace(/"/g, '&quot;') + '"';
923
+ }
924
+ if (node.childNodes.length === 0) {
925
+ if (['circle', 'path', 'line', 'rect', 'polygon', 'polyline', 'ellipse'].indexOf(lowerTag) !== -1) {
926
+ return out + '/>';
927
+ }
928
+ return out + '></' + tag + '>';
929
+ }
930
+ out += '>';
931
+ for (var i = 0; i < node.childNodes.length; i++) {
932
+ out += serializeNode(node.childNodes[i]);
933
+ }
934
+ out += '</' + tag + '>';
935
+ return out;
936
+ }
937
+ return '';
938
+ }
939
+
940
+ Object.defineProperty(Element.prototype, 'outerHTML', {
941
+ get: function() { return serializeNode(this); }
942
+ });
943
+ Object.defineProperty(Element.prototype, 'innerHTML', {
944
+ get: function() {
945
+ var out = '';
946
+ for (var i = 0; i < this.childNodes.length; i++) {
947
+ out += serializeNode(this.childNodes[i]);
948
+ }
949
+ return out;
950
+ },
951
+ set: function(html) {
952
+ this.childNodes = [];
953
+ // Basic text assignment if no parser needed
954
+ if (html && html.indexOf('<') === -1) {
955
+ this.appendChild(new Text(html));
956
+ }
957
+ }
958
+ });
959
+
960
+ // --- HTML / SVG Specifics ---
961
+ function HTMLElement(tagName) { Element.call(this, tagName, null); }
962
+ HTMLElement.prototype = Object.create(Element.prototype);
963
+
964
+ function SVGElement(tagName) { Element.call(this, tagName, 'http://www.w3.org/2000/svg'); }
965
+ SVGElement.prototype = Object.create(Element.prototype);
966
+
967
+ function HTMLStyleElement() {
968
+ HTMLElement.call(this, 'style');
969
+ this.sheet = {
970
+ insertRule: function(rule, index) {},
971
+ addRule: function(selector, style, index) {},
972
+ cssRules: []
973
+ };
974
+ }
975
+ HTMLStyleElement.prototype = Object.create(HTMLElement.prototype);
976
+
977
+ function HTMLCanvasElement() {
978
+ HTMLElement.call(this, 'canvas');
979
+ this._width = 300;
980
+ this._height = 150;
981
+ this._ctx2d = null;
982
+ }
983
+ HTMLCanvasElement.prototype = Object.create(HTMLElement.prototype);
984
+ Object.defineProperty(HTMLCanvasElement.prototype, 'width', {
985
+ get: function() { return this._width; },
986
+ set: function(v) {
987
+ this._width = parseInt(v, 10) || 0;
988
+ this.setAttribute('width', this._width);
989
+ if (this._ctx2d) { this._ctx2d._commands = []; }
990
+ }
991
+ });
992
+ Object.defineProperty(HTMLCanvasElement.prototype, 'height', {
993
+ get: function() { return this._height; },
994
+ set: function(v) {
995
+ this._height = parseInt(v, 10) || 0;
996
+ this.setAttribute('height', this._height);
997
+ if (this._ctx2d) { this._ctx2d._commands = []; }
998
+ }
999
+ });
1000
+ HTMLCanvasElement.prototype.getContext = function(type) {
1001
+ if (type === '2d') {
1002
+ if (!this._ctx2d) {
1003
+ var self = this;
1004
+ this._ctx2d = {
1005
+ canvas: self,
1006
+ fillStyle: '#000000',
1007
+ strokeStyle: '#000000',
1008
+ lineWidth: 1,
1009
+ _commands: [],
1010
+ fillRect: function(x, y, w, h) {
1011
+ this._commands.push({
1012
+ op: 'fillRect',
1013
+ x: x,
1014
+ y: y,
1015
+ w: w,
1016
+ h: h,
1017
+ fill: this.fillStyle
1018
+ });
1019
+ },
1020
+ clearRect: function(x, y, w, h) {
1021
+ this._commands.push({
1022
+ op: 'clearRect',
1023
+ x: x,
1024
+ y: y,
1025
+ w: w,
1026
+ h: h
1027
+ });
1028
+ },
1029
+ save: function() {},
1030
+ restore: function() {},
1031
+ beginPath: function() {},
1032
+ closePath: function() {},
1033
+ moveTo: function() {},
1034
+ lineTo: function() {},
1035
+ stroke: function() {},
1036
+ fill: function() {}
1037
+ };
1038
+ }
1039
+ return this._ctx2d;
1040
+ }
1041
+ return null;
1042
+ };
1043
+ HTMLCanvasElement.prototype.toDataURL = function(type) {
1044
+ if (typeof globalScope._encodeCanvasToPNG === 'function') {
1045
+ var cmds = this._ctx2d ? this._ctx2d._commands : [];
1046
+ return globalScope._encodeCanvasToPNG(this.width, this.height, JSON.stringify(cmds));
1047
+ }
1048
+ return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1049
+ };
1050
+
1051
+ // --- Document ---
1052
+ function Document() {
1053
+ Node.call(this);
1054
+ this.nodeType = 9;
1055
+ this.nodeName = '#document';
1056
+ this._ownerDoc = null;
1057
+ this.documentElement = new HTMLElement('html');
1058
+ this.documentElement._ownerDoc = this;
1059
+ this.head = new HTMLElement('head');
1060
+ this.head._ownerDoc = this;
1061
+ this.body = new HTMLElement('body');
1062
+ this.body._ownerDoc = this;
1063
+ this.documentElement.appendChild(this.head);
1064
+ this.documentElement.appendChild(this.body);
1065
+ this._elementsById = {};
1066
+ }
1067
+ Document.prototype = Object.create(Node.prototype);
1068
+
1069
+ Document.prototype.createElement = function(tag) {
1070
+ var lower = String(tag).toLowerCase();
1071
+ var el;
1072
+ if (lower === 'style') el = new HTMLStyleElement();
1073
+ else if (lower === 'canvas') el = new HTMLCanvasElement();
1074
+ else el = new HTMLElement(lower);
1075
+ el.ownerDocument = this;
1076
+ return el;
1077
+ };
1078
+
1079
+ Document.prototype.createElementNS = function(ns, tag) {
1080
+ var lower = String(tag).toLowerCase();
1081
+ var el = new SVGElement(lower);
1082
+ el.namespaceURI = ns;
1083
+ el.ownerDocument = this;
1084
+ return el;
1085
+ };
1086
+
1087
+ Document.prototype.createTextNode = function(text) {
1088
+ var t = new Text(text);
1089
+ t.ownerDocument = this;
1090
+ return t;
1091
+ };
1092
+
1093
+ Document.prototype.createDocumentFragment = function() {
1094
+ var frag = new DocumentFragment();
1095
+ frag.ownerDocument = this;
1096
+ return frag;
1097
+ };
1098
+
1099
+ Document.prototype.getElementById = function(id) {
1100
+ return this.documentElement.querySelector('#' + id);
1101
+ };
1102
+
1103
+ Document.prototype.querySelector = function(sel) {
1104
+ return this.documentElement.querySelector(sel);
1105
+ };
1106
+
1107
+ Document.prototype.querySelectorAll = function(sel) {
1108
+ return this.documentElement.querySelectorAll(sel);
1109
+ };
1110
+
1111
+ Document.prototype.getElementsByTagName = function(tag) {
1112
+ return this.documentElement.getElementsByTagName(tag);
1113
+ };
1114
+
1115
+ Document.prototype.getElementsByClassName = function(cls) {
1116
+ return this.documentElement.getElementsByClassName(cls);
1117
+ };
1118
+
1119
+ // --- Global Setup ---
1120
+ globalScope.console = {
1121
+ log: function() {
1122
+ if (typeof globalScope._printLog === 'function') {
1123
+ globalScope._printLog(Array.prototype.slice.call(arguments).map(String).join(' '));
1124
+ }
1125
+ },
1126
+ warn: function() {
1127
+ if (typeof globalScope._printLog === 'function') {
1128
+ globalScope._printLog('[WARN] ' + Array.prototype.slice.call(arguments).map(String).join(' '));
1129
+ }
1130
+ },
1131
+ error: function() {
1132
+ if (typeof globalScope._printLog === 'function') {
1133
+ globalScope._printLog('[ERROR] ' + Array.prototype.slice.call(arguments).map(String).join(' '));
1134
+ }
1135
+ }
1136
+ };
1137
+
1138
+ var doc = new Document();
1139
+ globalScope.window = globalScope;
1140
+ globalScope.self = globalScope;
1141
+ globalScope.document = doc;
1142
+ globalScope.Node = Node;
1143
+ globalScope.Element = Element;
1144
+ globalScope.HTMLElement = HTMLElement;
1145
+ globalScope.HTMLCanvasElement = HTMLCanvasElement;
1146
+ globalScope.SVGElement = SVGElement;
1147
+ globalScope.DocumentFragment = DocumentFragment;
1148
+ globalScope.Text = Text;
1149
+
1150
+ globalScope.Event = function(type) { this.type = type; };
1151
+ globalScope.CustomEvent = function(type, p) { this.type = type; this.detail = p ? p.detail : null; };
1152
+ globalScope.MouseEvent = function(type) { this.type = type; };
1153
+
1154
+ globalScope.DOMParser = function() {};
1155
+ globalScope.DOMParser.prototype.parseFromString = function(str, mime) {
1156
+ var d = new Document();
1157
+ var root = new SVGElement('svg');
1158
+ d.appendChild(root);
1159
+ return d;
1160
+ };
1161
+
1162
+ globalScope.XMLSerializer = function() {};
1163
+ globalScope.XMLSerializer.prototype.serializeToString = function(node) {
1164
+ return serializeNode(node);
1165
+ };
1166
+
1167
+ globalScope.getComputedStyle = function(el) {
1168
+ return el ? el.style : new CSSStyleDeclaration();
1169
+ };
1170
+
1171
+ globalScope.setTimeout = function(fn, ms) { return 1; };
1172
+ globalScope.clearTimeout = function(id) {};
1173
+ globalScope.setInterval = function(fn, ms) { return 1; };
1174
+ globalScope.clearInterval = function(id) {};
1175
+ globalScope.requestAnimationFrame = function(fn) {
1176
+ try { fn(Date.now()); } catch(e) {}
1177
+ return 1;
1178
+ };
1179
+ globalScope.cancelAnimationFrame = function(id) {};
1180
+
1181
+ globalScope.navigator = {
1182
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)",
1183
+ platform: "MacIntel"
1184
+ };
1185
+
1186
+ globalScope.location = {
1187
+ href: "http://localhost/",
1188
+ protocol: "http:",
1189
+ host: "localhost",
1190
+ pathname: "/"
1191
+ };
1192
+
1193
+ globalScope.screen = { width: 1920, height: 1080 };
1194
+
1195
+ })();