inugami-ng 0.0.19 → 0.0.21

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,790 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, viewChild, computed, signal, model, effect, HostListener, Component } from '@angular/core';
3
+ import { InuTemplateRegistryService } from 'inugami-ng/directives';
4
+ import { SVG_BUILDER, SVG_ASSETS, SvgAssetUtils, SVG_MATH, SVG_TRANSFORM, SVG } from 'inugami-ng/services';
5
+ import { InuPointPipe } from 'inugami-ng/pipes';
6
+
7
+ const POINTER = 'cursor-pointer';
8
+ const ASSETS_TOOLS = 'tools';
9
+ class InuSvgIsometricHud {
10
+ //====================================================================================================================
11
+ // ATTRIBUTES
12
+ //====================================================================================================================
13
+ parent;
14
+ height;
15
+ width;
16
+ scale = 0.7;
17
+ toolbarMargin = 1.25;
18
+ option;
19
+ //
20
+ hud = null;
21
+ hudToolbar = null;
22
+ hudToolbarAssets = [];
23
+ hudInspector = null;
24
+ hudSettings = null;
25
+ hudNavigation = null;
26
+ //====================================================================================================================
27
+ // INIT
28
+ //====================================================================================================================
29
+ constructor(option) {
30
+ this.parent = option.parent;
31
+ this.height = option.height;
32
+ this.width = option.width;
33
+ this.option = option;
34
+ this.render();
35
+ }
36
+ //====================================================================================================================
37
+ // RENDERING
38
+ //====================================================================================================================
39
+ render() {
40
+ this.hud = SVG_BUILDER.createGroup(this.parent, { styleClass: `hud` });
41
+ this.hudToolbar = this.renderHudToolbar(this.hud);
42
+ this.hudInspector = this.renderHudInspector(this.hud);
43
+ this.hudSettings = this.renderHudSettings(this.hud);
44
+ this.hudNavigation = this.renderHudNavigation(this.hud);
45
+ }
46
+ renderHudToolbar(parent) {
47
+ const result = SVG_BUILDER.createGroup(this.hud, { styleClass: `toolbar` });
48
+ const buttons = [
49
+ {
50
+ name: 'add-asset',
51
+ icon: 'category',
52
+ onover: (event, node) => this.onOverAsset(node),
53
+ onmouseleave: (event, node) => this.onLeaveAsset(node)
54
+ },
55
+ {
56
+ name: 'download',
57
+ icon: 'download',
58
+ onover: (event, node) => this.onOverAsset(node),
59
+ onmouseleave: (event, node) => this.onLeaveAsset(node),
60
+ onclick: (event) => this.option.onDownload()
61
+ },
62
+ {
63
+ name: 'zoom-div',
64
+ icon: 'div'
65
+ },
66
+ {
67
+ name: 'zoom-plus',
68
+ icon: 'zoom',
69
+ onover: (event, node) => this.onOverAsset(node),
70
+ onmouseleave: (event, node) => this.onLeaveAsset(node),
71
+ onclick: (event) => this.option.onZoomIn(event)
72
+ },
73
+ {
74
+ name: 'zoom-min',
75
+ icon: 'zoom',
76
+ type: 'min',
77
+ onover: (event, node) => this.onOverAsset(node),
78
+ onmouseleave: (event, node) => this.onLeaveAsset(node),
79
+ onclick: (event) => this.option.onZoomOut(event)
80
+ },
81
+ ];
82
+ for (let button of buttons) {
83
+ const buttonAsset = this.createAsset({
84
+ parent: result,
85
+ name: button.name,
86
+ asset: {
87
+ assetSet: ASSETS_TOOLS,
88
+ assetName: button.icon,
89
+ type: button.type ? button.type : 'default',
90
+ state: button.state ? button.state : 'default'
91
+ },
92
+ styleClass: POINTER
93
+ });
94
+ if (!buttonAsset) {
95
+ continue;
96
+ }
97
+ if (button.onover)
98
+ buttonAsset.onover = button.onover;
99
+ if (button.onclick)
100
+ buttonAsset.onclick = button.onclick;
101
+ if (button.onmousedown)
102
+ buttonAsset.onmousedown = button.onmousedown;
103
+ if (button.onmousemove)
104
+ buttonAsset.onmousemove = button.onmousemove;
105
+ if (button.onmouseleave)
106
+ buttonAsset.onmouseleave = button.onmouseleave;
107
+ if (button.ondblclick)
108
+ buttonAsset.ondblclick = button.ondblclick;
109
+ if (button.ondrag)
110
+ buttonAsset.ondrag = button.ondrag;
111
+ if (button.ondrop)
112
+ buttonAsset.ondrop = button.ondrop;
113
+ if (button.ondragend)
114
+ buttonAsset.ondragend = button.ondragend;
115
+ if (button.ondragstart)
116
+ buttonAsset.ondragstart = button.ondragstart;
117
+ if (button.ondragleave)
118
+ buttonAsset.ondragleave = button.ondragleave;
119
+ if (button.ondragover)
120
+ buttonAsset.ondragover = button.ondragover;
121
+ if (button.ondragenter)
122
+ buttonAsset.ondragenter = button.ondragenter;
123
+ this.hudToolbarAssets.push(buttonAsset);
124
+ }
125
+ return result;
126
+ }
127
+ renderHudInspector(parent) {
128
+ const result = SVG_BUILDER.createGroup(this.hud, { styleClass: `layers-inspector` });
129
+ return result;
130
+ }
131
+ renderHudSettings(parent) {
132
+ const result = SVG_BUILDER.createGroup(this.hud, { styleClass: `settings` });
133
+ return result;
134
+ }
135
+ renderHudNavigation(parent) {
136
+ const result = SVG_BUILDER.createGroup(this.hud, { styleClass: `navigation` });
137
+ return result;
138
+ }
139
+ //====================================================================================================================
140
+ // ACTIONS
141
+ //====================================================================================================================
142
+ updatePosition(height, width) {
143
+ this.updatePositionHudToolbar(height, width);
144
+ }
145
+ updatePositionHudToolbar(height, width) {
146
+ if (this.hudToolbarAssets.length == 0) {
147
+ return;
148
+ }
149
+ const size = this.hudToolbarAssets[0].getComponentSize();
150
+ for (let i = 1; i < this.hudToolbarAssets.length; i++) {
151
+ this.hudToolbarAssets[i].move({ x: (i * size.width) * this.toolbarMargin, y: 0 });
152
+ }
153
+ }
154
+ //====================================================================================================================
155
+ // EVENTS
156
+ //====================================================================================================================
157
+ onOverAsset(node) {
158
+ node.addStyleClass('over');
159
+ }
160
+ onLeaveAsset(node) {
161
+ node.removeStyleClass('over');
162
+ }
163
+ //====================================================================================================================
164
+ // TOOLS
165
+ //====================================================================================================================
166
+ createAsset(option) {
167
+ const assetIcon = SVG_ASSETS.getAsset(option.asset.assetSet, option.asset.assetName);
168
+ if (!assetIcon || !parent) {
169
+ return undefined;
170
+ }
171
+ const asset = option.asset;
172
+ asset.x = 0;
173
+ asset.y = 0;
174
+ asset.size = this.scale;
175
+ asset.name = option.name;
176
+ return SvgAssetUtils.createAsset({
177
+ parent: option.parent,
178
+ asset: asset,
179
+ scale: this.scale,
180
+ isometric: false,
181
+ enableHitBox: true
182
+ });
183
+ }
184
+ }
185
+
186
+ class InuSvgIsometric {
187
+ //====================================================================================================================
188
+ // ATTRIBUTES
189
+ //====================================================================================================================
190
+ isometric = input(true, ...(ngDevMode ? [{ debugName: "isometric" }] : []));
191
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
192
+ styleclass = input('', ...(ngDevMode ? [{ debugName: "styleclass" }] : []));
193
+ styleclassheight = input('', ...(ngDevMode ? [{ debugName: "styleclassheight" }] : []));
194
+ //
195
+ component = viewChild('component', ...(ngDevMode ? [{ debugName: "component" }] : []));
196
+ container = viewChild('container', ...(ngDevMode ? [{ debugName: "container" }] : []));
197
+ _styleClass = computed(() => {
198
+ return [
199
+ 'inu-svg',
200
+ 'inu-svg-isometric',
201
+ this.disabled() ? 'disabled' : '',
202
+ this.styleclass() ? this.styleclass() : ''
203
+ ].join(' ');
204
+ }, ...(ngDevMode ? [{ debugName: "_styleClass" }] : []));
205
+ //---
206
+ height = signal(400, ...(ngDevMode ? [{ debugName: "height" }] : []));
207
+ width = signal(600, ...(ngDevMode ? [{ debugName: "width" }] : []));
208
+ viewportSize = computed(() => ({ x: this.height(), y: this.width() }), ...(ngDevMode ? [{ debugName: "viewportSize" }] : []));
209
+ center = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "center" }] : []));
210
+ zoom = signal(50, ...(ngDevMode ? [{ debugName: "zoom" }] : []));
211
+ assetSelected = signal(undefined, ...(ngDevMode ? [{ debugName: "assetSelected" }] : []));
212
+ trackMouseMove = signal(false, ...(ngDevMode ? [{ debugName: "trackMouseMove" }] : []));
213
+ mousePosition = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "mousePosition" }] : []));
214
+ previousMouseMove = signal({ x: 0, y: 0 }, ...(ngDevMode ? [{ debugName: "previousMouseMove" }] : []));
215
+ value = model([], ...(ngDevMode ? [{ debugName: "value" }] : []));
216
+ //---
217
+ defaultSize = 50;
218
+ position = { x: 0, y: 0 };
219
+ //--- SVG components
220
+ scale = 1;
221
+ ratio = 1;
222
+ parent = null;
223
+ hiddenAssetLayer = null;
224
+ locator = null;
225
+ defs = null;
226
+ canvas = null;
227
+ graph = null;
228
+ gridPattern = null;
229
+ patternGroup = null;
230
+ gridPatternRect = null;
231
+ layers = null;
232
+ layersComponents = [];
233
+ hud = undefined;
234
+ //====================================================================================================================
235
+ // INIT
236
+ //====================================================================================================================
237
+ constructor() {
238
+ effect(() => {
239
+ this.updateValues();
240
+ });
241
+ }
242
+ ngAfterViewInit() {
243
+ const component = this.component();
244
+ const container = this.container();
245
+ if (component && container) {
246
+ this.resolveParentSize(component, container);
247
+ this.initializeLayout(container);
248
+ this.updateAfterZoom();
249
+ this.resize();
250
+ }
251
+ }
252
+ //====================================================================================================================
253
+ // RENDERING
254
+ //====================================================================================================================
255
+ resolveParentSize(component, container) {
256
+ if (component?.nativeElement && component?.nativeElement.parentNode && component?.nativeElement.parentNode.parentNode) {
257
+ this.parent = component?.nativeElement.parentNode.parentNode;
258
+ }
259
+ if (this.parent) {
260
+ let parentSize = SVG_MATH.size(this.parent);
261
+ this.height.set(parentSize.height);
262
+ this.width.set(parentSize.width);
263
+ }
264
+ this.center.set({ y: this.width() / 2, x: this.height() / 2 });
265
+ container?.nativeElement
266
+ .setAttribute('style', `display: block; height:${this.height()}px;width:${this.width()}px`);
267
+ }
268
+ initializeLayout(container) {
269
+ this.defs = SVG_BUILDER.createDefs(container?.nativeElement);
270
+ const gridGrp = SVG_BUILDER.createGroup(container?.nativeElement);
271
+ this.hiddenAssetLayer = SVG_BUILDER.createGroup(container?.nativeElement, { styleClass: 'hidden-layer' });
272
+ this.locator = SVG_BUILDER.createGroup(container?.nativeElement, { styleClass: 'locator' });
273
+ this.canvas = SVG_BUILDER.createGroup(this.locator, { styleClass: 'canvas' });
274
+ container.nativeElement.onmousedown = (event) => this.trackMouse(true, event);
275
+ container.nativeElement.onmouseup = (event) => this.trackMouse(false, event);
276
+ container.nativeElement.onmousemove = (event) => this.moveViewport(event);
277
+ if (this.hiddenAssetLayer) {
278
+ this.hiddenAssetLayer.setAttribute('inkscape:label', 'hidden');
279
+ this.hiddenAssetLayer.setAttribute('inkscape:groupmode', 'layer');
280
+ this.hiddenAssetLayer.setAttribute('style', 'display: hidden;');
281
+ }
282
+ if (this.defs) {
283
+ this.createGridDefs(this.defs);
284
+ }
285
+ const filter = SVG_BUILDER.createFilter(this.defs, 'shadow', { style: 'color-interpolation-filters: sRGB;' });
286
+ const gaussian = SVG_BUILDER.createNode('feGaussianBlur', filter);
287
+ if (gaussian) {
288
+ gaussian.setAttribute('stdDeviation', '1');
289
+ }
290
+ if (gridGrp) {
291
+ this.renderGrid(gridGrp);
292
+ }
293
+ if (this.canvas) {
294
+ this.graph = SVG_BUILDER.createGroup(this.canvas, { styleClass: 'graph' });
295
+ }
296
+ if (this.graph) {
297
+ this.renderLayers(this.graph);
298
+ }
299
+ if (container?.nativeElement) {
300
+ this.hud = new InuSvgIsometricHud({
301
+ parent: container?.nativeElement,
302
+ height: this.height(),
303
+ width: this.width(),
304
+ //
305
+ onZoomIn: (e) => this.onZoomIn(e),
306
+ onZoomOut: (e) => this.onZoomOut(e),
307
+ onDownload: () => this.download()
308
+ });
309
+ }
310
+ this.updateValues();
311
+ }
312
+ renderLayers(graph) {
313
+ this.layers = SVG_BUILDER.createGroup(this.graph, { styleClass: 'layers' });
314
+ }
315
+ createLayer(name) {
316
+ if (this.layers) {
317
+ const layer = SVG_BUILDER.createGroup(this.layers, { styleClass: `layer ${name}` });
318
+ if (layer) {
319
+ const result = {
320
+ name: name,
321
+ node: layer,
322
+ assets: []
323
+ };
324
+ this.layersComponents.push(result);
325
+ return result;
326
+ }
327
+ }
328
+ return undefined;
329
+ }
330
+ //--------------------------------------------------------------------------------------------------------------------
331
+ // GRID
332
+ //--------------------------------------------------------------------------------------------------------------------
333
+ createGridDefs(defs) {
334
+ this.gridPattern = SVG_BUILDER.createDefsPattern(defs, 'gridBackground', {
335
+ x: 0,
336
+ y: 0,
337
+ height: SVG_MATH.zoom(1, this.zoom()),
338
+ width: SVG_MATH.zoom(1, this.zoom()),
339
+ patternUnits: "userSpaceOnUse"
340
+ });
341
+ this.patternGroup = SVG_BUILDER.createGroup(this.gridPattern, { styleClass: 'inu-svg-isometric-grid-background' });
342
+ if (this.patternGroup) {
343
+ const isometric = this.isometric();
344
+ if (isometric) {
345
+ SVG_BUILDER.createCurve(this.patternGroup, 'M 0,14.4337 L 25,0 L 50,14.4337 L 25,28.8675 Z');
346
+ }
347
+ else {
348
+ this.gridPatternRect = SVG_BUILDER.createRect(this.patternGroup, {
349
+ height: SVG_MATH.zoom(1, this.zoom()),
350
+ width: SVG_MATH.zoom(1, this.zoom())
351
+ });
352
+ }
353
+ }
354
+ }
355
+ renderGrid(graph) {
356
+ const gridGroup = SVG_BUILDER.createGroup(graph, { styleClass: 'inu-svg-isometric-grid' });
357
+ if (gridGroup) {
358
+ this.renderBackground(gridGroup);
359
+ }
360
+ }
361
+ renderBackground(graph) {
362
+ const result = SVG_BUILDER.createRect(graph, {
363
+ height: this.height(),
364
+ width: this.width(),
365
+ styleClass: 'inu-svg-isometric-border'
366
+ });
367
+ if (result) {
368
+ result.setAttribute('fill', 'url(#gridBackground)');
369
+ }
370
+ return result;
371
+ }
372
+ //====================================================================================================================
373
+ // EVENTS
374
+ //====================================================================================================================
375
+ //--------------------------------------------------------------------------------------------------------------------
376
+ // ZOOM
377
+ //--------------------------------------------------------------------------------------------------------------------
378
+ onResize() {
379
+ const component = this.component();
380
+ const container = this.container();
381
+ if (component && container) {
382
+ this.resolveParentSize(component, container);
383
+ this.resize();
384
+ }
385
+ }
386
+ onMouseWheel(event) {
387
+ event.preventDefault();
388
+ let step = 1;
389
+ if (event.ctrlKey) {
390
+ step = 10;
391
+ }
392
+ if (event.shiftKey) {
393
+ step = 0.1;
394
+ }
395
+ if (event.deltaY > 0) {
396
+ this.zoom.set(this.zoom() - step);
397
+ }
398
+ else {
399
+ this.zoom.set(this.zoom() - step);
400
+ }
401
+ if (this.zoom() <= 0) {
402
+ this.zoom.set(0.001);
403
+ }
404
+ this.updateAfterZoom();
405
+ }
406
+ onMouseDown(event) {
407
+ if (event.button === 1) {
408
+ event.preventDefault();
409
+ let startZoom = this.zoom();
410
+ let endZoom = this.defaultSize;
411
+ let delta = endZoom - startZoom;
412
+ let currentX = 0;
413
+ let currentY = 0;
414
+ let x = 0;
415
+ let y = 0;
416
+ if (this.parent && this.locator) {
417
+ const currentTransfoAttr = this.locator.getAttribute('transform');
418
+ const currentTransfo = SVG_TRANSFORM.extractTransformInformation(this.locator);
419
+ SVG_TRANSFORM.center(this.locator, this.parent, true, true);
420
+ const centerTransfo = SVG_TRANSFORM.extractTransformInformation(this.locator);
421
+ this.locator.setAttribute('transform', currentTransfoAttr);
422
+ currentX = currentTransfo.x;
423
+ currentY = currentTransfo.y;
424
+ x = centerTransfo.x - currentX;
425
+ y = centerTransfo.y - currentY;
426
+ startZoom = currentTransfo.scaleX;
427
+ endZoom = centerTransfo.scaleX;
428
+ delta = endZoom - startZoom;
429
+ }
430
+ SVG.ANIMATION.animate((progress) => {
431
+ const newZoom = startZoom + (delta * progress);
432
+ const newX = currentX + (x * progress);
433
+ const newY = currentY + (y * progress);
434
+ if (this.locator) {
435
+ SVG_TRANSFORM.translateY(this.locator, newY);
436
+ SVG_TRANSFORM.translateX(this.locator, newX);
437
+ SVG_TRANSFORM.scale(this.locator, newZoom, newZoom);
438
+ }
439
+ this.updateGridSize(this.defaultSize * (newZoom));
440
+ }, {
441
+ duration: 2000,
442
+ timer: SVG.ANIMATION.TYPES.easeOutCubic,
443
+ onDone: () => {
444
+ this.zoom.set(this.defaultSize);
445
+ if (this.locator) {
446
+ if (this.parent) {
447
+ SVG_TRANSFORM.center(this.locator, this.parent, true, true);
448
+ const doneTransfo = SVG_TRANSFORM.extractTransformInformation(this.locator);
449
+ this.position.x = doneTransfo.x;
450
+ this.position.y = doneTransfo.y;
451
+ }
452
+ this.updateGridSize(this.zoom());
453
+ }
454
+ }
455
+ });
456
+ }
457
+ }
458
+ updateGridSize(zoom) {
459
+ const width = SVG_MATH.zoom(1, zoom);
460
+ const height = this.isometric() ? width / Math.sqrt(3) : width;
461
+ if (this.patternGroup) {
462
+ const currentZoom = width / this.defaultSize;
463
+ SVG_TRANSFORM.scale(this.patternGroup, currentZoom, currentZoom);
464
+ if (this.gridPattern) {
465
+ this.gridPattern.setAttribute('height', `${height}`);
466
+ this.gridPattern.setAttribute('width', `${width}`);
467
+ }
468
+ }
469
+ }
470
+ onZoomIn(event) {
471
+ const zoom = this.zoom();
472
+ this.zoom.set(zoom + 1);
473
+ this.updateAfterZoom();
474
+ }
475
+ onZoomOut(event) {
476
+ const zoom = this.zoom() - 1;
477
+ this.zoom.set(zoom <= 0 ? 0.001 : zoom);
478
+ this.updateAfterZoom();
479
+ }
480
+ //--------------------------------------------------------------------------------------------------------------------
481
+ // DOWNALOD
482
+ //--------------------------------------------------------------------------------------------------------------------
483
+ download() {
484
+ console.log('download');
485
+ const container = this.container()?.nativeElement;
486
+ if (!container) {
487
+ return;
488
+ }
489
+ const clone = container.cloneNode(true);
490
+ const copyStyles = (source, target) => {
491
+ const computed = window.getComputedStyle(source);
492
+ const svgProps = [
493
+ "fill", "stroke", "stroke-width", "opacity", "display",
494
+ "font-family", "font-size", "font-weight", "text-anchor",
495
+ "transform", "filter", "stop-color", "stop-opacity"
496
+ ];
497
+ svgProps.forEach(prop => {
498
+ target.style[prop] = computed.getPropertyValue(prop);
499
+ });
500
+ for (let i = 0; i < source.children.length; i++) {
501
+ const currentStyleClass = source.children[i].getAttribute('class');
502
+ if (currentStyleClass == 'inu-svg-isometric-grid' || currentStyleClass == 'hud') {
503
+ target.children[i].replaceChildren();
504
+ continue;
505
+ }
506
+ copyStyles(source.children[i], target.children[i]);
507
+ }
508
+ };
509
+ copyStyles(container, clone);
510
+ const realLocator = container.querySelector('.locator');
511
+ const locator = clone.querySelector('.locator');
512
+ let positionGrp = undefined;
513
+ if (locator && clone) {
514
+ const svgLocator = locator;
515
+ clone.replaceChildren();
516
+ positionGrp = SVG_BUILDER.createGroup(clone, { styleClass: 'position' });
517
+ if (positionGrp) {
518
+ positionGrp.appendChild(svgLocator);
519
+ }
520
+ }
521
+ const padding = 20;
522
+ const size = SVG_MATH.size(container);
523
+ const viewBoxValue = `${size.x - padding} ${size.y - padding} ${size.width + padding * 2} ${size.height + padding * 2}`;
524
+ const htmlCloneNode = clone;
525
+ htmlCloneNode.setAttribute('viewBox', viewBoxValue);
526
+ htmlCloneNode.setAttribute('xmlns:inkscape', 'http://www.inkscape.org/namespaces/inkscape');
527
+ htmlCloneNode.setAttribute('xmlns:sodipodi', 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd');
528
+ htmlCloneNode.style.width = `${size.width}px`;
529
+ htmlCloneNode.style.height = `${size.height}px`;
530
+ if (positionGrp && clone && realLocator) {
531
+ const locatorSize = SVG.MATH.size(realLocator);
532
+ const posGrp = SVG.MATH.size(positionGrp);
533
+ const diffSizeX = size.width - locatorSize.width;
534
+ const newPosX = (-posGrp.x) + (diffSizeX / 2);
535
+ const diffSizeY = size.height - locatorSize.height;
536
+ const newPosY = (-posGrp.y) + (diffSizeY / 2);
537
+ SVG.TRANSFORM.translateX(positionGrp, newPosX);
538
+ SVG.TRANSFORM.translateY(positionGrp, newPosY);
539
+ }
540
+ const svgData = new XMLSerializer().serializeToString(clone);
541
+ const svgBlob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
542
+ const svgUrl = URL.createObjectURL(svgBlob);
543
+ const downloadLink = document.createElement("a");
544
+ downloadLink.href = svgUrl;
545
+ downloadLink.download = 'graph.svg';
546
+ document.body.appendChild(downloadLink);
547
+ downloadLink.click();
548
+ document.body.removeChild(downloadLink);
549
+ URL.revokeObjectURL(svgUrl);
550
+ }
551
+ //====================================================================================================================
552
+ // UPDATE VALUES
553
+ //====================================================================================================================
554
+ updateValues() {
555
+ const value = this.value();
556
+ if (value.length == 0) {
557
+ this.clearAllLayers();
558
+ }
559
+ else {
560
+ for (let layer of value) {
561
+ this.updateLayer(layer);
562
+ }
563
+ }
564
+ }
565
+ clearAllLayers() {
566
+ for (let layer of this.layersComponents) {
567
+ for (let asset of layer.assets) {
568
+ asset.remove();
569
+ }
570
+ layer.assets.splice(0, layer.assets.length - 1);
571
+ }
572
+ }
573
+ updateLayer(layer) {
574
+ let currentLayer = this.layersComponents.find(l => layer.name);
575
+ if (!currentLayer) {
576
+ currentLayer = this.createLayer(layer.name);
577
+ }
578
+ if (!currentLayer) {
579
+ return;
580
+ }
581
+ const removedAssets = this.searchAssetsRemoved(layer.asserts, currentLayer.assets);
582
+ removedAssets.forEach(a => a.remove());
583
+ for (let asset of layer.asserts) {
584
+ this.updateOrCreateAsset(asset, currentLayer);
585
+ }
586
+ }
587
+ searchAssetsRemoved(asserts, existingAssets) {
588
+ const result = [];
589
+ for (let existingAsset of existingAssets) {
590
+ const foundAsset = asserts.find(a => a.name == existingAsset.name);
591
+ if (!foundAsset) {
592
+ result.push(existingAsset);
593
+ }
594
+ }
595
+ return result;
596
+ }
597
+ updateOrCreateAsset(asset, layer) {
598
+ const existingAsset = layer.assets.find(a => a.name == asset.name);
599
+ if (existingAsset) {
600
+ existingAsset.update(asset, this.center(), this.scale, this.isometric());
601
+ }
602
+ else {
603
+ const newAsset = SvgAssetUtils.createAsset({
604
+ parent: layer.node,
605
+ asset: asset,
606
+ scale: this.scale,
607
+ center: this.center(),
608
+ isometric: this.isometric(),
609
+ enableHitBox: false
610
+ });
611
+ if (newAsset) {
612
+ layer.assets.push(newAsset);
613
+ }
614
+ }
615
+ }
616
+ updateAfterZoom() {
617
+ const width = SVG_MATH.zoom(1, this.zoom());
618
+ const height = this.isometric() ? width / Math.sqrt(3) : width;
619
+ if (this.patternGroup) {
620
+ const zoom = width / this.defaultSize;
621
+ SVG_TRANSFORM.scale(this.patternGroup, zoom, zoom);
622
+ if (this.layers) {
623
+ SVG_TRANSFORM.scale(this.layers, zoom, zoom);
624
+ }
625
+ if (this.gridPattern) {
626
+ this.gridPattern.setAttribute('height', `${height}`);
627
+ this.gridPattern.setAttribute('width', `${width}`);
628
+ }
629
+ }
630
+ this.computeRatio();
631
+ }
632
+ //====================================================================================================================
633
+ // TOOLS
634
+ //====================================================================================================================
635
+ resize() {
636
+ if (this.locator && this.parent) {
637
+ this.computeRatio();
638
+ SVG_TRANSFORM.center(this.locator, this.parent, true, true);
639
+ const doneTransfo = SVG_TRANSFORM.extractTransformInformation(this.locator);
640
+ this.position.x = doneTransfo.x;
641
+ this.position.y = doneTransfo.y;
642
+ }
643
+ this.hud?.updatePosition(this.height(), this.width());
644
+ }
645
+ computeRatio() {
646
+ if (!this.parent || !this.locator) {
647
+ return;
648
+ }
649
+ const parentSize = SVG_MATH.size(this.parent);
650
+ const locatorSize = SVG_MATH.size(this.locator);
651
+ this.ratio = parentSize.width / locatorSize.width;
652
+ }
653
+ trackMouse(track, event) {
654
+ event.preventDefault();
655
+ this.trackMouseMove.set(track);
656
+ if (track) {
657
+ this.previousMouseMove.set({ x: event.x, y: event.y });
658
+ }
659
+ else {
660
+ this.previousMouseMove.set({ x: 0, y: 0 });
661
+ }
662
+ }
663
+ moveViewport(event) {
664
+ const container = this.container()?.nativeElement;
665
+ if (!container) {
666
+ return;
667
+ }
668
+ this.mousePosition.set({
669
+ x: event.x,
670
+ y: event.y
671
+ });
672
+ const trackMouse = this.trackMouseMove();
673
+ if (!trackMouse) {
674
+ return;
675
+ }
676
+ const currentMove = {
677
+ x: event.x,
678
+ y: event.y
679
+ };
680
+ const previousMouseMove = this.previousMouseMove();
681
+ const delta = {
682
+ x: previousMouseMove.x - currentMove.x,
683
+ y: previousMouseMove.y - currentMove.y
684
+ };
685
+ const asset = this.searchDragComponent();
686
+ if (!asset) {
687
+ event.preventDefault();
688
+ this.position.x = this.position.x - delta.x;
689
+ this.position.y = this.position.y - delta.y;
690
+ if (this.locator) {
691
+ SVG.TRANSFORM.translateY(this.locator, this.position.y);
692
+ SVG.TRANSFORM.translateX(this.locator, this.position.x);
693
+ }
694
+ }
695
+ else {
696
+ asset.moveDrag({
697
+ x: delta.x,
698
+ y: delta.y
699
+ }, this.ratio);
700
+ }
701
+ this.previousMouseMove.set(currentMove);
702
+ }
703
+ searchDragComponent() {
704
+ for (let layer of this.layersComponents) {
705
+ const assert = layer.assets.find(a => a.isDrag());
706
+ if (assert) {
707
+ return assert;
708
+ }
709
+ }
710
+ return undefined;
711
+ }
712
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: InuSvgIsometric, deps: [], target: i0.ɵɵFactoryTarget.Component });
713
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.0.8", type: InuSvgIsometric, isStandalone: true, selector: "inu-svg-isometric", inputs: { isometric: { classPropertyName: "isometric", publicName: "isometric", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, styleclass: { classPropertyName: "styleclass", publicName: "styleclass", isSignal: true, isRequired: false, transformFunction: null }, styleclassheight: { classPropertyName: "styleclassheight", publicName: "styleclassheight", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { listeners: { "window:resize": "onResize()", "wheel": "onMouseWheel($event)", "mousedown": "onMouseDown($event)" } }, providers: [InuTemplateRegistryService], viewQueries: [{ propertyName: "component", first: true, predicate: ["component"], descendants: true, isSignal: true }, { propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: `
714
+ <div class="inu-svg-isometric-debug">
715
+ <div class="inu-svg-isometric-debug-content">
716
+ <dl>
717
+ <dt>viewport size</dt>
718
+ <dd>{{ viewportSize()| inuPipePoint }}</dd>
719
+ <dt>center</dt>
720
+ <dd>{{ center()| inuPipePoint }}</dd>
721
+
722
+ </dl>
723
+ <dl>
724
+ <dt>zoom</dt>
725
+ <dd>{{ zoom() }}</dd>
726
+ <dt>trackMouseMove</dt>
727
+ <dd>{{ trackMouseMove() }}</dd>
728
+ <dt>mousePosition</dt>
729
+ <dd>{{ mousePosition()| inuPipePoint }}</dd>
730
+ <dt>previousMouseMove</dt>
731
+ <dd>{{ previousMouseMove()| inuPipePoint }}</dd>
732
+ </dl>
733
+ </div>
734
+
735
+ </div>
736
+
737
+ <div [class]="_styleClass()" #component>
738
+ <svg #container xmlns="http://www.w3.org/2000/svg"></svg>
739
+ </div>
740
+ `, isInline: true, styles: ["::ng-deep .inu-svg-isometric-grid-background rect{fill:none;stroke-width:1;paint-order:stroke;stroke:var(--neutral-light);stroke-opacity:1}::ng-deep .inu-svg-isometric-grid-background path{fill:none;stroke-width:1;paint-order:stroke;stroke:var(--neutral-light);stroke-opacity:1}::ng-deep .hud .toolbar .inu-svg-asset.over{fill:var(--secondary)}.inu-svg-isometric-debug{display:block}.inu-svg-isometric-debug .inu-svg-isometric-debug-content{display:flex;flex-direction:row;flex-wrap:wrap}.inu-svg-isometric-debug .inu-svg-isometric-debug-content dl{width:33%}\n"], dependencies: [{ kind: "pipe", type: InuPointPipe, name: "inuPipePoint" }] });
741
+ }
742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: InuSvgIsometric, decorators: [{
743
+ type: Component,
744
+ args: [{ selector: 'inu-svg-isometric', standalone: true, providers: [InuTemplateRegistryService], imports: [
745
+ InuPointPipe
746
+ ], template: `
747
+ <div class="inu-svg-isometric-debug">
748
+ <div class="inu-svg-isometric-debug-content">
749
+ <dl>
750
+ <dt>viewport size</dt>
751
+ <dd>{{ viewportSize()| inuPipePoint }}</dd>
752
+ <dt>center</dt>
753
+ <dd>{{ center()| inuPipePoint }}</dd>
754
+
755
+ </dl>
756
+ <dl>
757
+ <dt>zoom</dt>
758
+ <dd>{{ zoom() }}</dd>
759
+ <dt>trackMouseMove</dt>
760
+ <dd>{{ trackMouseMove() }}</dd>
761
+ <dt>mousePosition</dt>
762
+ <dd>{{ mousePosition()| inuPipePoint }}</dd>
763
+ <dt>previousMouseMove</dt>
764
+ <dd>{{ previousMouseMove()| inuPipePoint }}</dd>
765
+ </dl>
766
+ </div>
767
+
768
+ </div>
769
+
770
+ <div [class]="_styleClass()" #component>
771
+ <svg #container xmlns="http://www.w3.org/2000/svg"></svg>
772
+ </div>
773
+ `, styles: ["::ng-deep .inu-svg-isometric-grid-background rect{fill:none;stroke-width:1;paint-order:stroke;stroke:var(--neutral-light);stroke-opacity:1}::ng-deep .inu-svg-isometric-grid-background path{fill:none;stroke-width:1;paint-order:stroke;stroke:var(--neutral-light);stroke-opacity:1}::ng-deep .hud .toolbar .inu-svg-asset.over{fill:var(--secondary)}.inu-svg-isometric-debug{display:block}.inu-svg-isometric-debug .inu-svg-isometric-debug-content{display:flex;flex-direction:row;flex-wrap:wrap}.inu-svg-isometric-debug .inu-svg-isometric-debug-content dl{width:33%}\n"] }]
774
+ }], ctorParameters: () => [], propDecorators: { isometric: [{ type: i0.Input, args: [{ isSignal: true, alias: "isometric", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], styleclass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleclass", required: false }] }], styleclassheight: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleclassheight", required: false }] }], component: [{ type: i0.ViewChild, args: ['component', { isSignal: true }] }], container: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onResize: [{
775
+ type: HostListener,
776
+ args: ['window:resize']
777
+ }], onMouseWheel: [{
778
+ type: HostListener,
779
+ args: ['wheel', ['$event']]
780
+ }], onMouseDown: [{
781
+ type: HostListener,
782
+ args: ['mousedown', ['$event']]
783
+ }] } });
784
+
785
+ /**
786
+ * Generated bundle index. Do not edit.
787
+ */
788
+
789
+ export { InuSvgIsometric };
790
+ //# sourceMappingURL=inugami-ng-components-inu-svg-isometric.mjs.map