@obliczeniowo/elementary
Version:
Library made in Angular version 20
419 lines (410 loc) • 33.9 kB
JavaScript
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