UNPKG

@obliczeniowo/elementary

Version:
274 lines (268 loc) 17.8 kB
import * as i1 from '@obliczeniowo/elementary/buttons'; import { ButtonsModule } from '@obliczeniowo/elementary/buttons'; import * as i0 from '@angular/core'; import { input, EventEmitter, effect, HostBinding, ViewChild, Output, Input, Component, Pipe, NgModule } from '@angular/core'; import * as i2 from '@angular/common'; import { CommonModule } from '@angular/common'; import { ElementaryMath } from '@obliczeniowo/elementary/math'; import { Point2D, Dates } from '@obliczeniowo/elementary/classes'; import { DrawingSvgInterface } from '@obliczeniowo/elementary/drawing'; /** * Basic usage of component is to display time as HH:mm:ss format combined with a little dynamic svg * element that display clock pointing time given in input time as Date object or [h, m, s] * * You can set 'interactive' mode by 'display' input set { interactive: true, ... } * In this mode you can change time by clicking on modifying area fields, this will emit * new date every time you click on this areas * * To have easy way of manipulate time size of clock-time must be at least 150px * * In interactive mode you can add own controls buttons: * * @example * * <obl-clock-time [display]="{ time: true; interactive: true }" [column]="true" #clock> * <button (click)="setDate(clock)">OK</button> * <obl-clock-time> */ class ClockTimeComponent { renderer; /** size of clock */ size = input(30); /** switch on/off displaying time text */ display = input({ seconds: true, time: true }); /** font size */ fontSize = input(); /** if display time is set to tru this one will control if clock and time text is displayed in one row or in column */ column = false; /** * set time by Date object or table of [hours, minutes, seconds] */ date = input(new Date(), { transform: (value) => { let date; if (value instanceof Date) { date = value; } else { date = new Date(); date.setHours(value[0]); date.setMinutes(value[1]); date.setSeconds(value[2]); } const h = date.getHours(); const m = date.getMinutes(); const s = date.getSeconds(); this.hAngle = ((h % 12) + m / 60 + s / 3600) * Math.PI / 6; this.mAngle = (m + s / 60) * Math.PI / 30; this.sAngle = s * Math.PI / 30; this.pmAm = date.getHours() / 12 > 1; return date; } }); /** Emit when date is changed */ changed = new EventEmitter(); svg; get noTime() { return !this.display().time; } interactiveTime; dc; hRay = 2; mRay = 3; sRay = 3.5; hAngle = 0; mAngle = 0; sAngle = 0; pmAm = false; mouse = new Point2D(); constructor(renderer) { this.renderer = renderer; effect(() => { this.draw(); }); } ngAfterViewInit() { if (this.svg) { this.dc = new DrawingSvgInterface(this.svg.nativeElement, this.renderer); this.draw(); } } switchPmAm() { this.pmAm = !this.pmAm; this.date().setHours(this.date().getHours() + (this.pmAm ? -12 : 12)); if (this.interactiveTime) { this.interactiveTime = new Date(this.date()); } } clicked(event) { if (!this.display().interactive) { return; } if (this.interactiveTime) { this.date().setSeconds(this.interactiveTime.getSeconds()); this.date().setMinutes(this.interactiveTime.getMinutes()); this.date().setHours(this.interactiveTime.getHours()); this.changed.emit(new Date(this.date())); } } mouseMove(event) { if (!this.display().interactive) { return; } const scale = (this.getBrowserName() === 'firefox' ? 10 : 11) / this.size(); const box = this.dc.svgContainer.getBoundingClientRect(); this.mouse = new Point2D((event.x - box.left) * scale, (event.y - box.top) * scale).subtract(new Point2D(5, 5)); const { hRay, mRay, mouse } = this; const len = mouse.sickLength(); const angle = mouse.angle(); const date = new Date(this.date()); if (len < hRay * hRay) { date.setHours(Math.round(ElementaryMath.fmod(angle + Math.PI * 2.5, 2 * Math.PI) / (2 * Math.PI) * 11 + (this.pmAm ? 12 : 0)) % (12 + (this.pmAm ? 12 : 0))); } else if (len < mRay * mRay) { date.setMinutes(Math.round((angle + Math.PI) / (2 * Math.PI) * 60 + 45) % 60); } this.interactiveTime = date; this.draw(); } draw(dc = this.dc) { if (dc) { const center = new Point2D(5, 5); dc.clear(); dc.drawCircle(center, 4.5, 0.7, 'var(--default-text-color)'); if (this.display().interactive) { dc.drawCircle(center, this.mRay, 0, undefined, undefined, { svgOnly: { classes: ['minutes-area'] } }); dc.drawCircle(center, this.hRay, 0, undefined, undefined, { svgOnly: { classes: ['hours-area'] } }); } dc.drawPolyline([ center.add(new Point2D(this.hRay * Math.sin(this.hAngle), -this.hRay * Math.cos(this.hAngle))), center, center.add(new Point2D(this.mRay * Math.sin(this.mAngle), -this.mRay * Math.cos(this.mAngle))) ], 0.5, 'var(--default-text-color)'); if (this.display().interactive) { if (this.interactiveTime && !Dates.equalToTimeLevel(this.interactiveTime, this.date())) { const h = this.interactiveTime.getHours(); const m = this.interactiveTime.getMinutes(); const hAngle = ((h % 12) + m / 60) * Math.PI / 6; const mAngle = m * Math.PI / 30; dc.drawPolyline([ center.add(new Point2D(this.hRay * Math.sin(hAngle), -this.hRay * Math.cos(hAngle))), center, center.add(new Point2D(this.mRay * Math.sin(mAngle), -this.mRay * Math.cos(mAngle))) ], 0.5, 'var(--obl-clock-time-set-pointer, gray)'); } } if (this.size() > 99) { /** draw seconds pointer */ if (this.display().seconds) { dc.drawLine(center, center.add(new Point2D(this.sRay * Math.sin(this.sAngle), -this.sRay * Math.cos(this.sAngle))), 0.25, 'var(--default-text-color)'); } /** draw scale */ for (let i = 0; i < 12; i++) { const angle = i * Math.PI / 6; dc.drawLine(center.add(new Point2D(this.sRay * Math.sin(angle), -this.sRay * Math.cos(angle))), center.add(new Point2D(1.1 * this.sRay * Math.sin(angle), -(this.sRay * 1.1) * Math.cos(angle))), 0.1, 'var(--default-text-color)'); } } } } getBrowserName() { const agent = window.navigator.userAgent.toLowerCase(); switch (true) { case agent.includes('edge'): return 'edge'; case agent.includes('opr') && !!window.opr: return 'opera'; case agent.includes('chrome') && !!window.chrome: return 'chrome'; case agent.includes('trident'): return 'ie'; case agent.includes('firefox'): return 'firefox'; case agent.includes('safari'): return 'safari'; default: return 'other'; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ClockTimeComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: ClockTimeComponent, isStandalone: false, selector: "obl-clock-time", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, display: { classPropertyName: "display", publicName: "display", isSignal: true, isRequired: false, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: false, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { properties: { "class.column": "this.column", "class.no-time": "this.noTime" } }, viewQueries: [{ propertyName: "svg", first: true, predicate: ["svg"], descendants: true }], ngImport: i0, template: "<svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n viewBox=\"0 0 10 10\"\n (mousemove)=\"mouseMove($event)\"\n (click)=\"clicked($event)\"\n #svg\n></svg>\n\n@if (display().time) {\n <span\n [style.font-size.px]=\"fontSize() || size() * 0.6\"\n [style.line-height.px]=\"fontSize() || size() * 0.6\"\n >\n {{ (interactiveTime ?? date()) | date : (display().seconds ? 'HH:mm:ss' : 'HH:mm') }}\n <ng-content></ng-content>\n </span>\n}\n\n@if (display().interactive) {\n <div class=\"actions\">\n <button oblButton (click)=\"switchPmAm()\"> {{ pmAm && 'PM' || 'AM' }} </button>\n </div>\n}\n", styles: [":root{--obl-primary: #00afaf;--obl-secondary: #008caf;--default-border-color: gray;--default-focus-color: gray;--default-border-outline-color: #080808;--default-disabled-color: gray;--default-background-color: white;--default-hover-color: #eeeeee;--obl-default-error-color: red;--obl-dialog-background: #d3d3d3;--default-radio-color: black;--disabled-color: gray;--default-hex-button-border-color: #008caf;--default-hex-button-hover-border-color: #00afaf;--select-item-background-color: #e4e4e4;--select-item-text-color: #5a5a5a;--default-text-color: black;--obl-default-button-text-color: black;--obl-default-icon-color: black;--equalizer-background-bar-color: #575656;--equalizer-value-bar-color: #e6e6e6;--diagram-3d-background-color: black;--slider-value-container-color: gray;--slider-value-color: #d1d1d1;--slider-hover-value-color: white;--digit-fill-color: #cccccc;--digit-lighted-color: black;--horizontal-progress-bar-value-color: #504f4f;--horizontal-progress-bar-background-pattern-color: #dddddd;--horizontal-progress-bar-value-pattern-color: #b3b3b3;--horizontal-progress-bar-border-rect-color: #cccccc;--temperature-text-color: black;--temperature-path-stroke-color: black;--post-diagram-scale-line-color: #c8c8c8;--volume-channel-secondary-color: gray;--volume-channel-primary-color: #f2f2f2;--arch-progress-secondary-color: #eeeeee;--obl-linear-diagram-greed-color: gray;--obl-rating-selected-color: gold;--obl-rating-color: #cccccc}:host{display:flex;align-items:center;position:relative}:host svg{margin-right:10px}:host svg ::ng-deep .hours-area,:host svg ::ng-deep .minutes-area{opacity:.5}:host svg ::ng-deep .minutes-area{fill:var(--obl-secondary)}:host svg ::ng-deep .hours-area{fill:var(--obl-primary)}:host.no-time svg{margin-right:0}:host.column{flex-direction:column}:host.column svg{margin-right:0;margin-bottom:10px}:host circle{stroke:var(--default-text-color)!important}.actions{position:absolute;right:5px;top:5px}.actions button{font-size:12px;padding:5px;border-radius:10px}\n"], dependencies: [{ kind: "directive", type: i1.ButtonDirective, selector: "oblButton, [oblButton]", inputs: ["oblButton", "icon", "blockWhenLoading", "loading", "toggle", "selected", "link", "target"], exportAs: ["oblButton"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ClockTimeComponent, decorators: [{ type: Component, args: [{ selector: 'obl-clock-time', standalone: false, template: "<svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n viewBox=\"0 0 10 10\"\n (mousemove)=\"mouseMove($event)\"\n (click)=\"clicked($event)\"\n #svg\n></svg>\n\n@if (display().time) {\n <span\n [style.font-size.px]=\"fontSize() || size() * 0.6\"\n [style.line-height.px]=\"fontSize() || size() * 0.6\"\n >\n {{ (interactiveTime ?? date()) | date : (display().seconds ? 'HH:mm:ss' : 'HH:mm') }}\n <ng-content></ng-content>\n </span>\n}\n\n@if (display().interactive) {\n <div class=\"actions\">\n <button oblButton (click)=\"switchPmAm()\"> {{ pmAm && 'PM' || 'AM' }} </button>\n </div>\n}\n", styles: [":root{--obl-primary: #00afaf;--obl-secondary: #008caf;--default-border-color: gray;--default-focus-color: gray;--default-border-outline-color: #080808;--default-disabled-color: gray;--default-background-color: white;--default-hover-color: #eeeeee;--obl-default-error-color: red;--obl-dialog-background: #d3d3d3;--default-radio-color: black;--disabled-color: gray;--default-hex-button-border-color: #008caf;--default-hex-button-hover-border-color: #00afaf;--select-item-background-color: #e4e4e4;--select-item-text-color: #5a5a5a;--default-text-color: black;--obl-default-button-text-color: black;--obl-default-icon-color: black;--equalizer-background-bar-color: #575656;--equalizer-value-bar-color: #e6e6e6;--diagram-3d-background-color: black;--slider-value-container-color: gray;--slider-value-color: #d1d1d1;--slider-hover-value-color: white;--digit-fill-color: #cccccc;--digit-lighted-color: black;--horizontal-progress-bar-value-color: #504f4f;--horizontal-progress-bar-background-pattern-color: #dddddd;--horizontal-progress-bar-value-pattern-color: #b3b3b3;--horizontal-progress-bar-border-rect-color: #cccccc;--temperature-text-color: black;--temperature-path-stroke-color: black;--post-diagram-scale-line-color: #c8c8c8;--volume-channel-secondary-color: gray;--volume-channel-primary-color: #f2f2f2;--arch-progress-secondary-color: #eeeeee;--obl-linear-diagram-greed-color: gray;--obl-rating-selected-color: gold;--obl-rating-color: #cccccc}:host{display:flex;align-items:center;position:relative}:host svg{margin-right:10px}:host svg ::ng-deep .hours-area,:host svg ::ng-deep .minutes-area{opacity:.5}:host svg ::ng-deep .minutes-area{fill:var(--obl-secondary)}:host svg ::ng-deep .hours-area{fill:var(--obl-primary)}:host.no-time svg{margin-right:0}:host.column{flex-direction:column}:host.column svg{margin-right:0;margin-bottom:10px}:host circle{stroke:var(--default-text-color)!important}.actions{position:absolute;right:5px;top:5px}.actions button{font-size:12px;padding:5px;border-radius:10px}\n"] }] }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { column: [{ type: Input }, { type: HostBinding, args: ['class.column'] }], changed: [{ type: Output }], svg: [{ type: ViewChild, args: ['svg'] }], noTime: [{ type: HostBinding, args: ['class.no-time'] }] } }); class TimePipe { transform(time, ...args) { time = Math.ceil(time); const hours = Math.floor(time / 3600); const minutes = Math.floor(time / 60) % 60; const seconds = time % 60; return (hours ? hours + ':' : '') + `0${minutes}`.slice(-2) + ':' + `0${seconds}`.slice(-2); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TimePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: TimePipe, isStandalone: true, name: "time" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TimePipe, decorators: [{ type: Pipe, args: [{ name: 'time', standalone: true }] }] }); class TimeModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TimeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: TimeModule, declarations: [ClockTimeComponent], imports: [CommonModule, ButtonsModule], exports: [ClockTimeComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TimeModule, providers: [ TimePipe ], imports: [CommonModule, ButtonsModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TimeModule, decorators: [{ type: NgModule, args: [{ declarations: [ ClockTimeComponent, ], providers: [ TimePipe ], imports: [ CommonModule, ButtonsModule ], exports: [ ClockTimeComponent, ] }] }] }); /** * Generated bundle index. Do not edit. */ export { ClockTimeComponent, TimeModule, TimePipe }; //# sourceMappingURL=obliczeniowo-elementary-time.mjs.map