| /** |
| * @module module/image-compare-sk |
| * @description <h2><code>image-compare-sk</code></h2> |
| * |
| * Shows a side by side comparison of two images. If there's nothing to compare against, it will |
| * only display one. |
| * |
| */ |
| import { define } from 'elements-sk/define'; |
| import { html } from 'lit-html'; |
| import dialogPolyfill from 'dialog-polyfill'; |
| import { ElementSk } from '../../../infra-sk/modules/ElementSk'; |
| import { MultiZoomSk } from '../multi-zoom-sk/multi-zoom-sk'; |
| |
| import 'elements-sk/icon/open-in-new-icon-sk'; |
| import 'elements-sk/styles/buttons'; |
| import { digestDiffImagePath, digestImagePath } from '../common'; |
| |
| import '../multi-zoom-sk'; |
| |
| export interface ImageComparisonData { |
| digest: string; |
| title: string; |
| detail: string; |
| } |
| |
| export class ImageCompareSk extends ElementSk { |
| private static template = (ele: ImageCompareSk) => html` |
| <div class=comparison_bar> |
| <figure> |
| <img class="thumbnail ${ele._fullSizeLeftImage ? 'fullsize' : ''}" |
| alt="left image" |
| src=${digestImagePath(ele.left.digest)} |
| @click=${ele.toggleFullSizeLeftImage}> |
| <figcaption> |
| <span class=legend_dot></span> |
| <a target=_blank rel=noopener href=${ele.left.detail}>${ele.left.title}</a> |
| </figcaption> |
| </figure> |
| <a target=_blank rel=noopener href=${digestImagePath(ele.left.digest)}> |
| <open-in-new-icon-sk></open-in-new-icon-sk> |
| </a> |
| ${ImageCompareSk.comparison(ele)} |
| </div> |
| |
| <button class=zoom_btn ?hidden=${!ele.right} @click=${ele.openZoomWindow}>Zoom</button> |
| <dialog class=zoom_dialog @close=${ele.closeEvent}))}> |
| <button class=close_btn @click=${ele.closeDialog}>Close</button> |
| </dialog> |
| `; |
| |
| private static comparison = (ele: ImageCompareSk) => { |
| if (!ele.right) { |
| if (ele.isComputingDiffs) { |
| return html`<div class=computing title="Check back later"> |
| Computing closest positive and negative image. Check back later.</div>`; |
| } |
| return html`<div class=no_compare>No other images to compare against.</div>`; |
| } |
| const diffSrc = digestDiffImagePath(ele.left.digest, ele.right.digest); |
| return html` |
| <img class="thumbnail diff ${ele._fullSizeDiffImage ? 'fullsize' : ''}" |
| alt="diff between left and right image" |
| src=${diffSrc} |
| @click=${ele.toggleFullSizeDiffImage}> |
| <a target=_blank rel=noopener href=${diffSrc}> |
| <open-in-new-icon-sk></open-in-new-icon-sk> |
| </a> |
| |
| <figure> |
| <img class="thumbnail ${ele._fullSizeRightImage ? 'fullsize' : ''}" |
| alt="right image" |
| src=${digestImagePath(ele.right.digest)} |
| @click=${ele.toggleFullSizeRightImage}> |
| <figcaption> |
| <a target=_blank rel=noopener href=${ele.right.detail}>${ele.right.title}</a> |
| </figcaption> |
| </figure> |
| <a target=_blank rel=noopener href=${digestImagePath(ele.right.digest)}> |
| <open-in-new-icon-sk></open-in-new-icon-sk> |
| </a> |
| `; |
| }; |
| |
| private _left: ImageComparisonData = { |
| digest: '', |
| title: '', |
| // We can't derive the detail url w/o also passing down changelistID, crs etc, so we have |
| // the caller compute those URLs and pass them into this element. |
| detail: '', |
| } |
| |
| private _right: ImageComparisonData | null = null; |
| |
| private computingDiffs = false; |
| |
| private _fullSizeImages = false; |
| |
| private _fullSizeLeftImage = false; |
| |
| private _fullSizeDiffImage = false; |
| |
| private _fullSizeRightImage = false; |
| |
| constructor() { |
| super(ImageCompareSk.template); |
| } |
| |
| connectedCallback(): void { |
| super.connectedCallback(); |
| this._render(); |
| dialogPolyfill.registerDialog(this.querySelector('dialog.zoom_dialog')!); |
| } |
| |
| get isComputingDiffs(): boolean { return this.computingDiffs; } |
| |
| set isComputingDiffs(b: boolean) { |
| this.computingDiffs = b; |
| this._render(); |
| } |
| |
| get left(): ImageComparisonData { return this._left; } |
| |
| set left(img: ImageComparisonData) { |
| this._left = img; |
| this._render(); |
| } |
| |
| get right(): ImageComparisonData | null { return this._right; } |
| |
| set right(img: ImageComparisonData | null) { |
| this._right = img; |
| this._render(); |
| } |
| |
| /** Whether to show thumbnails or full size images. */ |
| get fullSizeImages(): boolean { |
| return this._fullSizeImages; |
| } |
| |
| set fullSizeImages(val: boolean) { |
| this._fullSizeImages = val; |
| this._fullSizeLeftImage = val; |
| this._fullSizeDiffImage = val; |
| this._fullSizeRightImage = val; |
| this._render(); |
| } |
| |
| private closeDialog() { |
| // This will fire a close event. |
| this.querySelector<HTMLDialogElement>('dialog.zoom_dialog')?.close(); |
| } |
| |
| private closeEvent() { |
| // We clean up both when the user clicks the close button as well if they hit escape by waiting |
| // for the close event (instead of handling this in closeDialog(). |
| const dialog = this.querySelector<HTMLDialogElement>('dialog.zoom_dialog'); |
| const zoom = this.querySelector<MultiZoomSk>('dialog multi-zoom-sk'); |
| if (dialog && zoom) { |
| // Removing the element from the dom removes the keybinding handlers and lets the browser |
| // free up the image resources. |
| dialog.removeChild(zoom); |
| } |
| } |
| |
| openZoomWindow(): void { |
| const ele = new MultiZoomSk(); |
| ele.details = { |
| leftImageSrc: digestImagePath(this.left.digest), |
| rightImageSrc: digestImagePath(this.right!.digest), |
| diffImageSrc: digestDiffImagePath(this.left.digest, this.right!.digest), |
| leftLabel: this.left.title, |
| rightLabel: this.right!.title, |
| }; |
| const dialog = this.querySelector<HTMLDialogElement>('dialog.zoom_dialog')!; |
| // put the dialog before the button |
| dialog.insertBefore(ele, dialog.childNodes[0]); |
| dialog.showModal(); |
| } |
| |
| private toggleFullSizeLeftImage(): void { |
| this._fullSizeLeftImage = !this._fullSizeLeftImage; |
| this._render(); |
| } |
| |
| private toggleFullSizeDiffImage(): void { |
| this._fullSizeDiffImage = !this._fullSizeDiffImage; |
| this._render(); |
| } |
| |
| private toggleFullSizeRightImage(): void { |
| this._fullSizeRightImage = !this._fullSizeRightImage; |
| this._render(); |
| } |
| } |
| |
| define('image-compare-sk', ImageCompareSk); |