UNPKG

@obliczeniowo/elementary

Version:
419 lines (410 loc) 33.9 kB
import * as i0 from '@angular/core'; import { input, effect, Component, HostBinding, HostListener, Input, EventEmitter, Output, NgModule } from '@angular/core'; import * as i4 from '@angular/common'; import { CommonModule } from '@angular/common'; import { ElementaryMath } from '@obliczeniowo/elementary/math'; import { DrawingSvgInterface } from '@obliczeniowo/elementary/drawing'; import { Point2D, ColorHSV } from '@obliczeniowo/elementary/classes'; import { firstValueFrom } from 'rxjs'; import * as i1 from '@obliczeniowo/elementary/icons'; class ArchComponent { /** start angle in degrees */ start = input(0); /** end angle in degrees */ end = input(90); /** ray in pixels */ ray = input(10); /** */ x = input(0); /** */ y = input(0); /** arch thickness in pixels */ width = input(10); /** arch stroke color */ background = input('#ff0000'); /** id if required */ pathId = input(); /** reverse for change side of text */ reverse = input(false); /** angle scale */ angleScale = input(1); path; scaledStart = 0; scaledEnd = 0; constructor() { this.recalculatePath(); effect(() => { this.recalculatePath(); }); } recalculatePath() { const start = this.start(); const end = this.end(); const mid = (start + end) / 2; const ray = this.ray(); const length = (end - start) / 2 * this.angleScale(); this.scaledStart = mid - length; this.scaledEnd = mid + length; this.path = DrawingSvgInterface.archPath(new Point2D(this.x(), this.y()), ray, ray, 0, ElementaryMath.degreesToRadians(this.scaledEnd - this.scaledStart), this.reverse()); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ArchComponent, isStandalone: false, selector: "g[obl-arch]", inputs: { start: { classPropertyName: "start", publicName: "start", isSignal: true, isRequired: false, transformFunction: null }, end: { classPropertyName: "end", publicName: "end", isSignal: true, isRequired: false, transformFunction: null }, ray: { classPropertyName: "ray", publicName: "ray", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: false, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, pathId: { classPropertyName: "pathId", publicName: "pathId", isSignal: true, isRequired: false, transformFunction: null }, reverse: { classPropertyName: "reverse", publicName: "reverse", isSignal: true, isRequired: false, transformFunction: null }, angleScale: { classPropertyName: "angleScale", publicName: "angleScale", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (path) {\n <svg:path\n [attr.d]=\"path\"\n [style.strokeWidth]=\"width()\"\n [style.stroke]=\"background()\"\n [attr.transform]=\"(x() || y()) &&\n ('translate(' +\n x() +\n ', ' +\n y() + \n ') rotate(' +\n scaledStart +\n ') translate(' +\n -x() +\n ', ' +\n -y() +\n ')' + (reverse() ? ' scale(-1, 1)' : '')) || 'rotate(' +\n scaledStart +\n ')'\n \"\n [id]=\"pathId()\"\n></svg:path>\n} @else {\n <svg:circle\n [attr.r]=\"ray()\"\n [attr.cx]=\"x()\"\n [attr.cy]=\"y()\"\n [style.strokeWidth]=\"width()\"\n [style.stroke]=\"background()\"\n [id]=\"pathId()\"\n ></svg:circle>\n}\n", styles: ["path,circle{fill:none}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ArchComponent, decorators: [{ type: Component, args: [{ selector: 'g[obl-arch]', standalone: false, template: "@if (path) {\n <svg:path\n [attr.d]=\"path\"\n [style.strokeWidth]=\"width()\"\n [style.stroke]=\"background()\"\n [attr.transform]=\"(x() || y()) &&\n ('translate(' +\n x() +\n ', ' +\n y() + \n ') rotate(' +\n scaledStart +\n ') translate(' +\n -x() +\n ', ' +\n -y() +\n ')' + (reverse() ? ' scale(-1, 1)' : '')) || 'rotate(' +\n scaledStart +\n ')'\n \"\n [id]=\"pathId()\"\n></svg:path>\n} @else {\n <svg:circle\n [attr.r]=\"ray()\"\n [attr.cx]=\"x()\"\n [attr.cy]=\"y()\"\n [style.strokeWidth]=\"width()\"\n [style.stroke]=\"background()\"\n [id]=\"pathId()\"\n ></svg:circle>\n}\n", styles: ["path,circle{fill:none}\n"] }] }], ctorParameters: () => [] }); class MenuItemComponent { /** start angle in degrees */ start = input(0); /** end angle in degrees */ end = input(90); /** ray */ ray = input(100); /** */ x = input(130); /** */ y = input(130); /** thickness of arch */ width = input(25); /** background (thickness) color as string */ background = input('#ff0000'); /** text color */ color = input('#000000'); /** text to display on item */ text = input(''); /** */ angleScale = input(1); shadow = input(false); mouseOver() { this.hover = true; } mouseLeave() { this.hover = false; } hover = false; textPathId; clickable = true; get textRay() { return this.reverse ? this.ray() + 4 : this.ray() - 8; } get reverse() { return Math.abs(this.end() + this.start()) / 2 < 180; } _href = null; get href() { return this._href; } constructor() { this.setId(); } ngOnChanges(changes) { if (changes.x || changes.y || changes.reverse || changes.ray || changes.start || changes.end || changes.angleScale) { setTimeout(() => { this.setId(); }); } } setId() { do { this.textPathId = `textPath${Math.floor(Math.random() * 1000000)}`; } while (document.body.querySelector(`#${this.textPathId}`)); this._href = `#${this.textPathId}`; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: MenuItemComponent, isStandalone: false, selector: "g[obl-menu-item]", inputs: { start: { classPropertyName: "start", publicName: "start", isSignal: true, isRequired: false, transformFunction: null }, end: { classPropertyName: "end", publicName: "end", isSignal: true, isRequired: false, transformFunction: null }, ray: { classPropertyName: "ray", publicName: "ray", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: false, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, angleScale: { classPropertyName: "angleScale", publicName: "angleScale", isSignal: true, isRequired: false, transformFunction: null }, shadow: { classPropertyName: "shadow", publicName: "shadow", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "mouseOver()", "mouseleave": "mouseLeave()" }, properties: { "class.hover": "this.hover", "class.clickable": "this.clickable" } }, usesOnChanges: true, ngImport: i0, template: "<svg:g obl-arch [start]=\"start() + 5\" [end]=\"end() - 5\" [ray]=\"textRay\" [width]=\"0\" [background]=\"'none'\" [x]=\"x()\" [y]=\"y()\"\n [pathId]=\"textPathId\" [reverse]=\"reverse\" [angleScale]=\"angleScale()\"></svg:g>\n\n<svg:g obl-arch [start]=\"start()\" [end]=\"end()\" [ray]=\"ray()\" [x]=\"x()\" [y]=\"y()\" [width]=\"width()\" [background]=\"background()\"\n [angleScale]=\"angleScale()\"></svg:g>\n\n@if (href && angleScale()) {\n <svg:text [class.shadow]=\"shadow()\" [style.fill]=\"color()\">\n <svg:textPath [attr.href]=\"href\" startOffset=\"50%\">\n <tspan>{{ text() }}</tspan>\n </svg:textPath>\n </svg:text>\n}", styles: ["text{font-size:17px;line-height:1.25;font-family:arial;text-align:center;text-anchor:middle}:host{-webkit-tap-highlight-color:transparent}:host.hover{opacity:.8}.shadow{-webkit-filter:drop-shadow(0 0 2px var(--aobl-menu-item-shadow-color, rgb(0, 0, 0)));filter:drop-shadow(0 0 2px var(--aobl-menu-item-shadow-color, rgb(0, 0, 0)))}\n"], dependencies: [{ kind: "component", type: ArchComponent, selector: "g[obl-arch]", inputs: ["start", "end", "ray", "x", "y", "width", "background", "pathId", "reverse", "angleScale"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MenuItemComponent, decorators: [{ type: Component, args: [{ selector: 'g[obl-menu-item]', standalone: false, template: "<svg:g obl-arch [start]=\"start() + 5\" [end]=\"end() - 5\" [ray]=\"textRay\" [width]=\"0\" [background]=\"'none'\" [x]=\"x()\" [y]=\"y()\"\n [pathId]=\"textPathId\" [reverse]=\"reverse\" [angleScale]=\"angleScale()\"></svg:g>\n\n<svg:g obl-arch [start]=\"start()\" [end]=\"end()\" [ray]=\"ray()\" [x]=\"x()\" [y]=\"y()\" [width]=\"width()\" [background]=\"background()\"\n [angleScale]=\"angleScale()\"></svg:g>\n\n@if (href && angleScale()) {\n <svg:text [class.shadow]=\"shadow()\" [style.fill]=\"color()\">\n <svg:textPath [attr.href]=\"href\" startOffset=\"50%\">\n <tspan>{{ text() }}</tspan>\n </svg:textPath>\n </svg:text>\n}", styles: ["text{font-size:17px;line-height:1.25;font-family:arial;text-align:center;text-anchor:middle}:host{-webkit-tap-highlight-color:transparent}:host.hover{opacity:.8}.shadow{-webkit-filter:drop-shadow(0 0 2px var(--aobl-menu-item-shadow-color, rgb(0, 0, 0)));filter:drop-shadow(0 0 2px var(--aobl-menu-item-shadow-color, rgb(0, 0, 0)))}\n"] }] }], ctorParameters: () => [], propDecorators: { mouseOver: [{ type: HostListener, args: ['mouseenter'] }], mouseLeave: [{ type: HostListener, args: ['mouseleave'] }], hover: [{ type: HostBinding, args: ['class.hover'] }], clickable: [{ type: HostBinding, args: ['class.clickable'] }] } }); class SvgIconButtonComponent { icons; elementRef; get iconWidth() { return this._iconWidth; } _ray = 24; get ray() { return this._ray; } k = 0.5; /** icon name */ icon = input(); /** */ disabled; /** */ clickable = true; mouseOver() { this.hover = true; } mouseLeave() { this.hover = false; } hover = false; iconScale = 1; _iconSvg; _iconWidth = 0; constructor(icons, elementRef) { this.icons = icons; this.elementRef = elementRef; effect(() => { const icon = this.icon(); if (icon) { firstValueFrom(this.icons.getIcon(icon)).then((svg) => { this._iconSvg = svg; const icon = this.elementRef.nativeElement.querySelector('g.icon'); if (icon && this._iconSvg) { while (icon.firstChild) { icon.removeChild(icon.firstChild); } icon.innerHTML = this._iconSvg.innerHTML; const viewBox = (this._iconSvg.getAttribute('viewBox') || '').split(' ').map(v => +v); if (viewBox.length) { this._iconWidth = viewBox[2] - viewBox[0]; this.iconScale = this.k * 2 * this.ray / (this._iconWidth || 1); } } }); } }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SvgIconButtonComponent, deps: [{ token: i1.IconResourceService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: SvgIconButtonComponent, isStandalone: false, selector: "g[obl-svg-icon-button]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "mouseOver()", "mouseleave": "mouseLeave()" }, properties: { "class.disabled": "this.disabled", "class.clickable": "this.clickable", "class.hover": "this.hover" } }, ngImport: i0, template: "<svg:circle [attr.r]=\"ray\"></svg:circle>\n\n<svg:g\n class=\"icon clickable\"\n [style.transform]=\"\n 'translate(' +\n -ray * k +\n 'px, ' +\n -ray * k +\n 'px)' +\n 'scale(' +\n iconScale +\n ')'\n \"\n [style.fill]=\"'var(--obl-default-icon-color)'\"\n></svg:g>\n", styles: ["circle{fill:var(--obl-button-background-color)}:host{-webkit-tap-highlight-color:transparent}:host.hover{opacity:.8}\n"] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SvgIconButtonComponent, decorators: [{ type: Component, args: [{ selector: 'g[obl-svg-icon-button]', standalone: false, template: "<svg:circle [attr.r]=\"ray\"></svg:circle>\n\n<svg:g\n class=\"icon clickable\"\n [style.transform]=\"\n 'translate(' +\n -ray * k +\n 'px, ' +\n -ray * k +\n 'px)' +\n 'scale(' +\n iconScale +\n ')'\n \"\n [style.fill]=\"'var(--obl-default-icon-color)'\"\n></svg:g>\n", styles: ["circle{fill:var(--obl-button-background-color)}:host{-webkit-tap-highlight-color:transparent}:host.hover{opacity:.8}\n"] }] }], ctorParameters: () => [{ type: i1.IconResourceService }, { type: i0.ElementRef }], propDecorators: { disabled: [{ type: HostBinding, args: ['class.disabled'] }, { type: Input }], clickable: [{ type: HostBinding, args: ['class.clickable'] }], mouseOver: [{ type: HostListener, args: ['mouseenter'] }], mouseLeave: [{ type: HostListener, args: ['mouseleave'] }], hover: [{ type: HostBinding, args: ['class.hover'] }] } }); class ExtendedMenuItemComponent { /** start angle in degrees */ start = input(0); /** end angle in degrees */ end = input(90); /** ray */ ray = input(100); /** */ x = input(130); /** */ y = input(130); /** thickness of arch */ width = input(40); /** angle scale for animations */ angleScale = input(1); /** */ closeOnClick = input(false); item = input.required(); clicked = new EventEmitter(); mouseOver() { this.hover = true; if (!this.time) { this.time = setInterval(() => this.animate(), 100); } } mouseLeave() { this.hover = false; if (!this.time) { this.time = setInterval(() => this.animate(), 100); } } hover = false; length = 5; time; animation = new Array(this.length).fill(0); startIndex = 0; ngOnDestroy() { if (this.time) { clearInterval(this.time); this.time = undefined; } } itemClicked(item, parent = false) { this.clicked.emit(parent ? item : { ...item, parent: { id: this.item().id, text: this.item().text, data: this.item().data, } }); if (parent) { this.animation = new Array(this.length).fill(1); } else if (this.closeOnClick()) { this.animation = new Array(this.length).fill(0); } } move(move) { this.startIndex = Math.max(Math.min(this.startIndex + move, (this.item().subItems?.length || this.length) - this.length), 0); } animate() { for (let i = 0; i < this.animation.length; i++) { const before = this.animation[i]; this.animation[i] = Math.min(Math.max(this.animation[i] + (this.hover ? 0.2 : -0.2), 0), 1); if (before === (this.hover ? 0 : 1)) { break; } } this.animation = [...this.animation]; const sum = this.animation.reduce((prev, curr) => prev + curr, 0); if (this.hover && sum === 5 || !this.hover && sum === 0) { clearInterval(this.time); this.time = undefined; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ExtendedMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ExtendedMenuItemComponent, isStandalone: false, selector: "g[obl-extended-menu-item]", inputs: { start: { classPropertyName: "start", publicName: "start", isSignal: true, isRequired: false, transformFunction: null }, end: { classPropertyName: "end", publicName: "end", isSignal: true, isRequired: false, transformFunction: null }, ray: { classPropertyName: "ray", publicName: "ray", isSignal: true, isRequired: false, transformFunction: null }, x: { classPropertyName: "x", publicName: "x", isSignal: true, isRequired: false, transformFunction: null }, y: { classPropertyName: "y", publicName: "y", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, angleScale: { classPropertyName: "angleScale", publicName: "angleScale", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { clicked: "clicked" }, host: { listeners: { "mouseenter": "mouseOver()", "mouseleave": "mouseLeave()" }, properties: { "class.hover": "this.hover" } }, ngImport: i0, template: "@if (item()) {\n <svg:g\n obl-menu-item\n [x]=\"x()\"\n [y]=\"y()\"\n [ray]=\"ray()\"\n [width]=\"50\"\n [start]=\"start()\"\n [end]=\"end()\"\n [background]=\"item().background.toString()\"\n [color]=\"item().color.toString()\"\n [text]=\"item().text\"\n [angleScale]=\"angleScale()\"\n (click)=\"itemClicked(item(), true)\"\n ></svg:g>\n\n @if (item().subItems) {\n @for (subItem of item().subItems; track subItem.id) {\n @if (startIndex + length > $index && $index >= startIndex) {\n <svg:g\n obl-menu-item\n [x]=\"x()\"\n [y]=\"y()\"\n [ray]=\"ray() + width() * ($index + 1 - startIndex) + 5\"\n [width]=\"width()\"\n [start]=\"start()\"\n [end]=\"end()\"\n [background]=\"subItem.background.toString()\"\n [color]=\"subItem.color.toString()\"\n [text]=\"subItem.text\"\n [angleScale]=\"animation[$index - startIndex]\"\n (click)=\"itemClicked(subItem)\"\n ></svg:g>\n }\n }\n @if ((item().subItems?.length || 0) > length && !time && hover) {\n <svg:g\n obl-svg-icon-button\n [icon]=\"'left'\"\n [style.transform]=\"\n 'translate(50%, 50%) rotate(' +\n start() +\n 'deg) translate(' +\n (ray() + 50) +\n 'px, 0) scale(0.8)'\n \"\n (click)=\"move(-1)\"\n ></svg:g>\n <svg:g\n obl-svg-icon-button\n [icon]=\"'right'\"\n [style.transform]=\"\n 'translate(50%, 50%) rotate(' +\n start() +\n 'deg) translate(' +\n (ray() + 40 * 5) +\n 'px, 0) scale(0.8)'\n \"\n (click)=\"move(1)\"\n ></svg:g>\n }\n }\n}\n", styles: [":host{-webkit-tap-highlight-color:transparent}\n"], dependencies: [{ kind: "component", type: MenuItemComponent, selector: "g[obl-menu-item]", inputs: ["start", "end", "ray", "x", "y", "width", "background", "color", "text", "angleScale", "shadow"] }, { kind: "component", type: SvgIconButtonComponent, selector: "g[obl-svg-icon-button]", inputs: ["icon", "disabled"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ExtendedMenuItemComponent, decorators: [{ type: Component, args: [{ selector: 'g[obl-extended-menu-item]', standalone: false, template: "@if (item()) {\n <svg:g\n obl-menu-item\n [x]=\"x()\"\n [y]=\"y()\"\n [ray]=\"ray()\"\n [width]=\"50\"\n [start]=\"start()\"\n [end]=\"end()\"\n [background]=\"item().background.toString()\"\n [color]=\"item().color.toString()\"\n [text]=\"item().text\"\n [angleScale]=\"angleScale()\"\n (click)=\"itemClicked(item(), true)\"\n ></svg:g>\n\n @if (item().subItems) {\n @for (subItem of item().subItems; track subItem.id) {\n @if (startIndex + length > $index && $index >= startIndex) {\n <svg:g\n obl-menu-item\n [x]=\"x()\"\n [y]=\"y()\"\n [ray]=\"ray() + width() * ($index + 1 - startIndex) + 5\"\n [width]=\"width()\"\n [start]=\"start()\"\n [end]=\"end()\"\n [background]=\"subItem.background.toString()\"\n [color]=\"subItem.color.toString()\"\n [text]=\"subItem.text\"\n [angleScale]=\"animation[$index - startIndex]\"\n (click)=\"itemClicked(subItem)\"\n ></svg:g>\n }\n }\n @if ((item().subItems?.length || 0) > length && !time && hover) {\n <svg:g\n obl-svg-icon-button\n [icon]=\"'left'\"\n [style.transform]=\"\n 'translate(50%, 50%) rotate(' +\n start() +\n 'deg) translate(' +\n (ray() + 50) +\n 'px, 0) scale(0.8)'\n \"\n (click)=\"move(-1)\"\n ></svg:g>\n <svg:g\n obl-svg-icon-button\n [icon]=\"'right'\"\n [style.transform]=\"\n 'translate(50%, 50%) rotate(' +\n start() +\n 'deg) translate(' +\n (ray() + 40 * 5) +\n 'px, 0) scale(0.8)'\n \"\n (click)=\"move(1)\"\n ></svg:g>\n }\n }\n}\n", styles: [":host{-webkit-tap-highlight-color:transparent}\n"] }] }], propDecorators: { clicked: [{ type: Output }], mouseOver: [{ type: HostListener, args: ['mouseenter'] }], mouseLeave: [{ type: HostListener, args: ['mouseleave'] }], hover: [{ type: HostBinding, args: ['class.hover'] }] } }); class CircleMenuComponent { /** menu items options not optional must be at leas 1 base element, subItems optional */ items = input(new Array(6).fill(0).map((_, index) => ({ id: index, color: ColorHSV.createColorHSV(index * 60, 0.5, 255).convertToRGB(), background: ColorHSV.createColorHSV((index * 60 + 180) % 360, 0.5, 255).convertToRGB(), text: `text to display ${index + 1}` }))); /** menu description */ menu = input('Menu'); /** */ closeOnClick = input(false); clicked = new EventEmitter(); get length() { return this.items().length < 6 && this.items().length || 6; } startIndex = 0; time; animation = 0; get start() { return this.startIndex; } ray = 150; get angle() { return 360 / (this.length || 1); } width = 780; height = 780; get position() { return this.startIndex / (this.items().length - this.length || 1); } ngOnInit() { this.time = setInterval(() => { this.animation = Math.min(Math.max(this.animation + 0.2, 0), 1); if (this.animation === 1) { this.ngOnDestroy(); } }, 100); } move(offset) { if (this.length < this.items().length) { this.startIndex = Math.min(Math.max(this.startIndex + offset, 0), this.items().length - 6); } } itemClicked(item) { this.clicked.emit({ id: item.id, parent: item.parent, text: item.text, data: item.data }); } ngOnDestroy() { if (this.time) { clearInterval(this.time); this.time = undefined; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: CircleMenuComponent, isStandalone: false, selector: "obl-circle-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, menu: { classPropertyName: "menu", publicName: "menu", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<svg\n [attr.width]=\"width\"\n [attr.height]=\"height\"\n [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"\n>\n @if (items().length > 6 && !time) {\n <g\n obl-svg-icon-button\n [icon]=\"'left'\"\n [style.transform]=\"\n 'translate(calc(50% - ' +\n 40 +\n 'px), calc(50% + ' +\n (ray - 70) +\n 'px)) rotate(30deg)'\n \"\n (click)=\"move(-1)\"\n ></g>\n <g\n obl-svg-icon-button\n [icon]=\"'right'\"\n [style.transform]=\"\n 'translate(calc(50% + ' +\n 40 +\n 'px), calc(50% + ' +\n (ray - 70) +\n 'px)) rotate(-30deg)'\n \"\n (click)=\"move(1)\"\n ></g>\n }\n\n @if (position) {\n <g\n obl-arch\n [x]=\"width / 2\"\n [y]=\"height / 2\"\n [ray]=\"ray\"\n [width]=\"60\"\n [start]=\"360 - position * 360 + 270\"\n [end]=\"360 + 270\"\n [background]=\"'#80e2ff'\"\n ></g>\n }\n\n @for (item of items(); track item.id) {\n @if ($index >= start && $index < start + length) {\n <g\n obl-extended-menu-item\n [x]=\"width / 2\"\n [y]=\"height / 2\"\n [ray]=\"ray\"\n [width]=\"40\"\n [start]=\"angle * ($index - start)\"\n [end]=\"angle * ($index - start + 1)\"\n [item]=\"item\"\n [angleScale]=\"animation\"\n [closeOnClick]=\"closeOnClick()\"\n (clicked)=\"itemClicked($event)\"\n ></g>\n }\n }\n\n @if (!time) {\n <text class=\"menu\" [class.more-items]=\"items().length - length === 0\">\n <tspan>{{ menu() }}</tspan>\n </text>\n }\n\n @if (!time && items().length - length) {\n <text class=\"position\">\n <tspan>{{ position * 100 | number : '0.0-0' }} %</tspan>\n </text>\n }\n</svg>\n", styles: ["text.menu{transform:translate(50%,50%);fill:var(--default-text-color);font-size:45px;line-height:1.25;font-family:arial;text-align:center;text-anchor:middle}text.menu.more-items{transform:translate(50%,calc(50% + 10px))}text.position{transform:translate(50%,calc(50% + 35px));text-align:center;text-anchor:middle;fill:var(--default-text-color)}svg{-webkit-tap-highlight-color:transparent}\n"], dependencies: [{ kind: "component", type: ArchComponent, selector: "g[obl-arch]", inputs: ["start", "end", "ray", "x", "y", "width", "background", "pathId", "reverse", "angleScale"] }, { kind: "component", type: SvgIconButtonComponent, selector: "g[obl-svg-icon-button]", inputs: ["icon", "disabled"] }, { kind: "component", type: ExtendedMenuItemComponent, selector: "g[obl-extended-menu-item]", inputs: ["start", "end", "ray", "x", "y", "width", "angleScale", "closeOnClick", "item"], outputs: ["clicked"] }, { kind: "pipe", type: i4.DecimalPipe, name: "number" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuComponent, decorators: [{ type: Component, args: [{ selector: 'obl-circle-menu', standalone: false, template: "<svg\n [attr.width]=\"width\"\n [attr.height]=\"height\"\n [attr.viewBox]=\"'0 0 ' + width + ' ' + height\"\n>\n @if (items().length > 6 && !time) {\n <g\n obl-svg-icon-button\n [icon]=\"'left'\"\n [style.transform]=\"\n 'translate(calc(50% - ' +\n 40 +\n 'px), calc(50% + ' +\n (ray - 70) +\n 'px)) rotate(30deg)'\n \"\n (click)=\"move(-1)\"\n ></g>\n <g\n obl-svg-icon-button\n [icon]=\"'right'\"\n [style.transform]=\"\n 'translate(calc(50% + ' +\n 40 +\n 'px), calc(50% + ' +\n (ray - 70) +\n 'px)) rotate(-30deg)'\n \"\n (click)=\"move(1)\"\n ></g>\n }\n\n @if (position) {\n <g\n obl-arch\n [x]=\"width / 2\"\n [y]=\"height / 2\"\n [ray]=\"ray\"\n [width]=\"60\"\n [start]=\"360 - position * 360 + 270\"\n [end]=\"360 + 270\"\n [background]=\"'#80e2ff'\"\n ></g>\n }\n\n @for (item of items(); track item.id) {\n @if ($index >= start && $index < start + length) {\n <g\n obl-extended-menu-item\n [x]=\"width / 2\"\n [y]=\"height / 2\"\n [ray]=\"ray\"\n [width]=\"40\"\n [start]=\"angle * ($index - start)\"\n [end]=\"angle * ($index - start + 1)\"\n [item]=\"item\"\n [angleScale]=\"animation\"\n [closeOnClick]=\"closeOnClick()\"\n (clicked)=\"itemClicked($event)\"\n ></g>\n }\n }\n\n @if (!time) {\n <text class=\"menu\" [class.more-items]=\"items().length - length === 0\">\n <tspan>{{ menu() }}</tspan>\n </text>\n }\n\n @if (!time && items().length - length) {\n <text class=\"position\">\n <tspan>{{ position * 100 | number : '0.0-0' }} %</tspan>\n </text>\n }\n</svg>\n", styles: ["text.menu{transform:translate(50%,50%);fill:var(--default-text-color);font-size:45px;line-height:1.25;font-family:arial;text-align:center;text-anchor:middle}text.menu.more-items{transform:translate(50%,calc(50% + 10px))}text.position{transform:translate(50%,calc(50% + 35px));text-align:center;text-anchor:middle;fill:var(--default-text-color)}svg{-webkit-tap-highlight-color:transparent}\n"] }] }], propDecorators: { clicked: [{ type: Output }] } }); class CircleMenuModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuModule, declarations: [ArchComponent, MenuItemComponent, CircleMenuComponent, SvgIconButtonComponent, ExtendedMenuItemComponent], imports: [CommonModule], exports: [ArchComponent, MenuItemComponent, CircleMenuComponent, SvgIconButtonComponent, ExtendedMenuItemComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuModule, imports: [CommonModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CircleMenuModule, decorators: [{ type: NgModule, args: [{ declarations: [ ArchComponent, MenuItemComponent, CircleMenuComponent, SvgIconButtonComponent, ExtendedMenuItemComponent, ], imports: [ CommonModule, ], exports: [ ArchComponent, MenuItemComponent, CircleMenuComponent, SvgIconButtonComponent, ExtendedMenuItemComponent ] }] }] }); /** * Generated bundle index. Do not edit. */ export { ArchComponent, CircleMenuComponent, CircleMenuModule, ExtendedMenuItemComponent, MenuItemComponent, SvgIconButtonComponent }; //# sourceMappingURL=obliczeniowo-elementary-circle-menu.mjs.map