renderdiff: [viewer] fix magnifier (#9290)
- Fix the magnifier positioning for both compare and standalone mode. Simplified a lot of the logic and streamlined passing of states between components. - Slight css adjustments
This commit is contained in:
@@ -57,11 +57,11 @@ class ExpandedPassedResult extends LitElement {
|
||||
<div>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<label>
|
||||
<input type="checkbox" id="magnifierToggle" checked @change="${this._onMagnifierToggle}">
|
||||
<input type="checkbox" id="magnifierToggle" @change="${this._onMagnifierToggle}">
|
||||
Enable Magnifier
|
||||
</label>
|
||||
</div>
|
||||
<tiff-viewer fileurl="${url}" magnifier-enabled id="passedViewer"></tiff-viewer>
|
||||
<tiff-viewer fileurl="${url}" id="passedViewer"></tiff-viewer>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -91,12 +91,12 @@ class ExpandedFailedResult extends LitElement {
|
||||
}
|
||||
return html`
|
||||
<expanded-comparison-result
|
||||
label-with-type
|
||||
.left=${this.content}
|
||||
.right=${this.content}
|
||||
leftViewType="golden"
|
||||
rightViewType="rendered"
|
||||
.tests=${this.tests}
|
||||
?disableDropdowns=${true}>
|
||||
</expanded-comparison-result>
|
||||
`;
|
||||
}
|
||||
@@ -106,15 +106,15 @@ customElements.define('expanded-failed-result', ExpandedFailedResult);
|
||||
class ExpandedComparisonResult extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
labelWithType: {type: Boolean, attribute: "label-with-type" },
|
||||
left: { type: Object },
|
||||
right: { type: Object },
|
||||
tests: { type: Array },
|
||||
diffResult: { type: Object },
|
||||
showDiff: {type: Boolean },
|
||||
leftViewType: { type: String },
|
||||
rightViewType: { type: String },
|
||||
disableDropdowns: { type: Boolean },
|
||||
magnifierEnabled: { type: Boolean },
|
||||
currentDiffImageData: {type: Object },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,17 +127,6 @@ class ExpandedComparisonResult extends LitElement {
|
||||
.viewer-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
#diffCanvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 22px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.diff-container {
|
||||
position: relative;
|
||||
}
|
||||
.viewer-container {
|
||||
position: relative;
|
||||
}
|
||||
.selector {
|
||||
@@ -147,27 +136,25 @@ class ExpandedComparisonResult extends LitElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.labelWithType = false;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
this.tests = [];
|
||||
this.showDiff = false;
|
||||
this.leftImageLoaded = false;
|
||||
this.rightImageLoaded = false;
|
||||
this.leftViewType = 'golden';
|
||||
this.rightViewType = 'golden';
|
||||
this.disableDropdowns = false;
|
||||
this.magnifierEnabled = true;
|
||||
this.diffCanvasRect = null;
|
||||
this.originalDiffImageData = null;
|
||||
this.globalMousePosition = null;
|
||||
this.currentDiffImageData = null;
|
||||
|
||||
this.addEventListener(
|
||||
'image-loaded',
|
||||
(ev) => {
|
||||
if (ev.detail.name == this.left.name) {
|
||||
if (ev.detail.url == this._getUrl(this.leftViewType, this.left)) {
|
||||
this.leftImageLoaded = true;
|
||||
}
|
||||
if (ev.detail.name == this.right.name) {
|
||||
if (ev.detail.url == this._getUrl(this.rightViewType, this.right)) {
|
||||
this.rightImageLoaded = true;
|
||||
}
|
||||
if (this.leftImageLoaded && this.rightImageLoaded) {
|
||||
@@ -177,13 +164,17 @@ class ExpandedComparisonResult extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
_getUrl(viewType, test) {
|
||||
return viewType == 'rendered' ? getCompUrl(test) : getGoldenUrl(test);
|
||||
}
|
||||
|
||||
_viewer(name, choices, current, viewType) {
|
||||
const url = viewType == 'rendered' ? getCompUrl(current) : getGoldenUrl(current);
|
||||
const url = this._getUrl(viewType, current);
|
||||
const label = this.labelWithType ? viewType : current.name;
|
||||
return html`
|
||||
<div style="flex: 1; margin: 0 5px;">
|
||||
<div>${current.name}</div>
|
||||
<div>${label}</div>
|
||||
<tiff-viewer id="viewer-${name}" class="viewer"
|
||||
name="${current.name}"
|
||||
fileurl="${url}"
|
||||
?magnifier-enabled="${this.magnifierEnabled}"
|
||||
disable-mouse-handlers></tiff-viewer>
|
||||
@@ -210,10 +201,8 @@ class ExpandedComparisonResult extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
const ctxLeft = canvasLeft.getContext('2d');
|
||||
const ctxRight = canvasRight.getContext('2d');
|
||||
const imgLeft = ctxLeft.getImageData(0, 0, canvasLeft.width, canvasLeft.height);
|
||||
const imgRight = ctxRight.getImageData(0, 0, canvasRight.width, canvasRight.height);
|
||||
const imgLeft = tiffViewerLeft.imgdata;
|
||||
const imgRight = tiffViewerRight.imgdata;
|
||||
|
||||
if (imgLeft.width !== imgRight.width || imgLeft.height !== imgRight.height) {
|
||||
console.error("Images have different dimensions");
|
||||
@@ -262,25 +251,19 @@ class ExpandedComparisonResult extends LitElement {
|
||||
const diff = this._computeDiff();
|
||||
if (diff.result == RES_DIFFERENT_PIXELS) {
|
||||
this.diffResult = diff;
|
||||
this.showDiff = true;
|
||||
// Reset original diff data when new diff is computed
|
||||
this.originalDiffImageData = null;
|
||||
}
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
if (this.showDiff && this.diffResult) {
|
||||
const mult = this.shadowRoot.querySelector('#diffMultiplier').value;
|
||||
this._updateDiffCanvas(this.diffResult, mult);
|
||||
const multDiv = this.shadowRoot.querySelector('#diffMultiplier');
|
||||
if (multDiv) {
|
||||
this._updateDiffCanvas(this.diffResult, multDiv.value);
|
||||
}
|
||||
} else {
|
||||
this.diffResult = null;
|
||||
this.currentDiffImageData = null;
|
||||
}
|
||||
}
|
||||
|
||||
_updateDiffCanvas(diffResult, mult) {
|
||||
const diffCanvas = this.shadowRoot.querySelector('#diffCanvas');
|
||||
const diffCtx = diffCanvas.getContext('2d');
|
||||
diffCanvas.width = diffResult.dim.width;
|
||||
diffCanvas.height = diffResult.dim.height;
|
||||
|
||||
// Create a fresh copy of the original diff data to avoid mutation.
|
||||
const diffImgCopy = diffResult.diffImg.slice();
|
||||
|
||||
@@ -294,7 +277,6 @@ class ExpandedComparisonResult extends LitElement {
|
||||
|
||||
// Create the ImageData from the modified copy.
|
||||
const imgData = new ImageData(diffImgCopy, diffResult.dim.width, diffResult.dim.height);
|
||||
diffCtx.putImageData(imgData, 0, 0);
|
||||
|
||||
// Store both original and current diff image data for magnifier
|
||||
if (!this.originalDiffImageData) {
|
||||
@@ -303,124 +285,47 @@ class ExpandedComparisonResult extends LitElement {
|
||||
this.currentDiffImageData = imgData;
|
||||
}
|
||||
|
||||
_onDiffMouseEnter(event) {
|
||||
if (!this.showDiff || !this.currentDiffImageData) return;
|
||||
this.diffCanvasRect = event.target.getBoundingClientRect();
|
||||
}
|
||||
|
||||
_onGlobalMouseLeave(event) {
|
||||
// Hide all magnifiers when mouse leaves the viewer container
|
||||
const leftViewer = this.shadowRoot.querySelector('#viewer-left');
|
||||
const rightViewer = this.shadowRoot.querySelector('#viewer-right');
|
||||
const diffMagnifier = this.shadowRoot.getElementById('diffMagnifier');
|
||||
|
||||
if (leftViewer) {
|
||||
const leftMagnifier = leftViewer.shadowRoot?.getElementById('magnifier');
|
||||
if (leftMagnifier) leftMagnifier.hide();
|
||||
for (const name of ['left', 'right', 'diff']) {
|
||||
const viewer = this.shadowRoot.querySelector('#viewer-' + name);
|
||||
if (viewer) {
|
||||
const mag = viewer.shadowRoot?.getElementById('magnifier');
|
||||
if (mag) {
|
||||
mag.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rightViewer) {
|
||||
const rightMagnifier = rightViewer.shadowRoot?.getElementById('magnifier');
|
||||
if (rightMagnifier) rightMagnifier.hide();
|
||||
}
|
||||
|
||||
if (diffMagnifier) diffMagnifier.hide();
|
||||
}
|
||||
|
||||
_onGlobalMouseMove(event) {
|
||||
this.globalMousePosition = { clientX: event.clientX, clientY: event.clientY };
|
||||
|
||||
// Update all three magnifiers
|
||||
this._updateLeftMagnifier(event);
|
||||
this._updateRightMagnifier(event);
|
||||
this._updateDiffMagnifier(event);
|
||||
}
|
||||
|
||||
_updateLeftMagnifier(event) {
|
||||
if (!this.magnifierEnabled) return;
|
||||
const leftViewer = this.shadowRoot.querySelector('#viewer-left');
|
||||
if (!leftViewer) return;
|
||||
for (const name of ['left', 'right', 'diff']) {
|
||||
const viewer = this.shadowRoot.querySelector('#viewer-' + name);
|
||||
if (!viewer) continue;
|
||||
|
||||
const canvas = leftViewer.shadowRoot?.querySelector('canvas');
|
||||
if (!canvas) return;
|
||||
const canvas = viewer.shadowRoot?.querySelector('canvas');
|
||||
if (!canvas) continue;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const leftMagnifier = leftViewer.shadowRoot?.getElementById('magnifier');
|
||||
// Get image data from the viewer
|
||||
const imageData = viewer.imgdata;
|
||||
const magnifier = viewer.shadowRoot?.getElementById('magnifier');
|
||||
|
||||
if (!leftMagnifier) return;
|
||||
// Check if mouse is over any of the three views (left, , or diff)
|
||||
if (!this._isMouseOverAnyView(event)) {
|
||||
magnifier.hide();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get image data from the viewer
|
||||
const imageData = leftViewer.imageData;
|
||||
if (!imageData) {
|
||||
leftMagnifier.hide();
|
||||
return;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
|
||||
// Calculate the equivalent position on the image
|
||||
const { imageX, imageY, mouseX, mouseY } = this._calculateEquivalentPosition(event, rect, imageData);
|
||||
|
||||
// Position magnifier relative to the canvas within the viewer
|
||||
const origData = name == 'diff' ? this.originalDiffImageData : null;
|
||||
viewer.updateMagnifier(imageX, imageY, origData);
|
||||
}
|
||||
|
||||
// Check if mouse is over any of the three views (left, right, or diff)
|
||||
if (!this._isMouseOverAnyView(event)) {
|
||||
leftMagnifier.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the equivalent position on the left image
|
||||
const { imageX, imageY, mouseX, mouseY } = this._calculateEquivalentPosition(event, rect, imageData);
|
||||
|
||||
// Position magnifier relative to the canvas within the left viewer
|
||||
leftMagnifier.updateMagnifier(imageData, imageX, imageY, mouseX, mouseY, rect);
|
||||
}
|
||||
|
||||
_updateRightMagnifier(event) {
|
||||
if (!this.magnifierEnabled) return;
|
||||
const rightViewer = this.shadowRoot.querySelector('#viewer-right');
|
||||
if (!rightViewer) return;
|
||||
|
||||
const canvas = rightViewer.shadowRoot?.querySelector('canvas');
|
||||
if (!canvas) return;
|
||||
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const rightMagnifier = rightViewer.shadowRoot?.getElementById('magnifier');
|
||||
|
||||
if (!rightMagnifier) return;
|
||||
|
||||
// Get image data from the viewer
|
||||
const imageData = rightViewer.imageData;
|
||||
if (!imageData) {
|
||||
rightMagnifier.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if mouse is over any of the three views (left, right, or diff)
|
||||
if (!this._isMouseOverAnyView(event)) {
|
||||
rightMagnifier.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the equivalent position on the right image
|
||||
const { imageX, imageY, mouseX, mouseY } = this._calculateEquivalentPosition(event, rect, imageData);
|
||||
|
||||
// Position magnifier relative to the canvas within the right viewer
|
||||
rightMagnifier.updateMagnifier(imageData, imageX, imageY, mouseX, mouseY, rect);
|
||||
}
|
||||
|
||||
_updateDiffMagnifier(event) {
|
||||
if (!this.magnifierEnabled || !this.showDiff || !this.currentDiffImageData || !this.diffCanvasRect) return;
|
||||
|
||||
const rect = this.diffCanvasRect;
|
||||
const diffMagnifier = this.shadowRoot.getElementById('diffMagnifier');
|
||||
|
||||
if (!diffMagnifier) return;
|
||||
|
||||
// Check if mouse is over any of the three views (left, right, or diff)
|
||||
if (!this._isMouseOverAnyView(event)) {
|
||||
diffMagnifier.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the equivalent position on the diff image
|
||||
const { imageX, imageY, mouseX, mouseY } = this._calculateEquivalentPosition(event, rect, this.currentDiffImageData);
|
||||
|
||||
// Position magnifier relative to the diff canvas
|
||||
diffMagnifier.updateMagnifier(this.currentDiffImageData, imageX, imageY, mouseX, mouseY, rect, 8, this.originalDiffImageData);
|
||||
}
|
||||
|
||||
_isMouseOverElement(event, rect) {
|
||||
@@ -449,13 +354,14 @@ class ExpandedComparisonResult extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if mouse is over diff canvas
|
||||
if (this.showDiff && this.diffCanvasRect) {
|
||||
if (this._isMouseOverElement(event, this.diffCanvasRect)) {
|
||||
// Check if mouse is over diff viewer
|
||||
const diffViewer = this.shadowRoot.querySelector('#viewer-diff');
|
||||
if (diffViewer) {
|
||||
const diffCanvas = diffViewer.shadowRoot?.querySelector('canvas');
|
||||
if (diffCanvas && this._isMouseOverElement(event, diffCanvas.getBoundingClientRect())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -463,6 +369,7 @@ class ExpandedComparisonResult extends LitElement {
|
||||
// Find which view the mouse is actually over and calculate the equivalent position
|
||||
const leftViewer = this.shadowRoot.querySelector('#viewer-left');
|
||||
const rightViewer = this.shadowRoot.querySelector('#viewer-right');
|
||||
const diffViewer = this.shadowRoot.querySelector('#viewer-diff');
|
||||
|
||||
let sourceRect = null;
|
||||
let sourceImageData = null;
|
||||
@@ -472,7 +379,7 @@ class ExpandedComparisonResult extends LitElement {
|
||||
const leftCanvas = leftViewer.shadowRoot?.querySelector('canvas');
|
||||
if (leftCanvas && this._isMouseOverElement(event, leftCanvas.getBoundingClientRect())) {
|
||||
sourceRect = leftCanvas.getBoundingClientRect();
|
||||
sourceImageData = leftViewer.imageData;
|
||||
sourceImageData = leftViewer.imgdata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,14 +387,15 @@ class ExpandedComparisonResult extends LitElement {
|
||||
const rightCanvas = rightViewer.shadowRoot?.querySelector('canvas');
|
||||
if (rightCanvas && this._isMouseOverElement(event, rightCanvas.getBoundingClientRect())) {
|
||||
sourceRect = rightCanvas.getBoundingClientRect();
|
||||
sourceImageData = rightViewer.imageData;
|
||||
sourceImageData = rightViewer.imgdata;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceRect && this.showDiff && this.diffCanvasRect) {
|
||||
if (this._isMouseOverElement(event, this.diffCanvasRect)) {
|
||||
sourceRect = this.diffCanvasRect;
|
||||
sourceImageData = this.currentDiffImageData;
|
||||
if (!sourceRect && this.diffResult && diffViewer) {
|
||||
const diffCanvas = diffViewer.shadowRoot?.querySelector('canvas');
|
||||
if (diffCanvas && this._isMouseOverElement(event, diffCanvas.getBoundingClientRect())) {
|
||||
sourceRect = diffCanvas.getBoundingClientRect();
|
||||
sourceImageData = diffViewer.imgdata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +432,8 @@ class ExpandedComparisonResult extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const diffStyle = !this.showDiff ? "display:none;" : "display:flex; flex-direction: column;";
|
||||
const showDiff = !!this.diffResult;
|
||||
const diffStyle = !showDiff ? "display:none;" : "display:flex; flex-direction: column; margin: 0 5px;";
|
||||
const v1 = this._viewer("left", this.tests, this.left, this.leftViewType);
|
||||
const v2 = this._viewer("right", this.tests, this.right, this.rightViewType);
|
||||
const onMultiplierChange = (ev) => {
|
||||
@@ -539,9 +448,13 @@ class ExpandedComparisonResult extends LitElement {
|
||||
<div class="main-container">
|
||||
<div class="viewer-container" @mousemove="${this._onGlobalMouseMove}" @mouseleave="${this._onGlobalMouseLeave}">
|
||||
${v1}
|
||||
<div style="flex: 1; ${diffStyle}" class="diff-container">
|
||||
<canvas id="diffCanvas" @mouseenter="${this._onDiffMouseEnter}"></canvas>
|
||||
<image-magnifier id="diffMagnifier"></image-magnifier>
|
||||
<div style="flex: 1; ${diffStyle}" class="viewer-container">
|
||||
<div> </div>
|
||||
<tiff-viewer id="viewer-diff" class="viewer"
|
||||
name="diff"
|
||||
.srcdata="${this.currentDiffImageData}"
|
||||
?magnifier-enabled="${this.magnifierEnabled}"
|
||||
disable-mouse-handlers></tiff-viewer>
|
||||
</div>
|
||||
${v2}
|
||||
</div>
|
||||
@@ -563,9 +476,13 @@ class ExpandedComparisonResult extends LitElement {
|
||||
}
|
||||
customElements.define('expanded-comparison-result', ExpandedComparisonResult);
|
||||
|
||||
|
||||
class App extends LitElement {
|
||||
static styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.test-label {
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
@@ -586,9 +503,9 @@ class App extends LitElement {
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.results {
|
||||
display: flex;
|
||||
|
||||
@@ -45,16 +45,16 @@ class ImageMagnifier extends LitElement {
|
||||
|
||||
.pixel-info {
|
||||
position: absolute;
|
||||
top: -65px;
|
||||
left: 0;
|
||||
top: -40px;
|
||||
left: 15px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
font-size: 9px;
|
||||
white-space: pre-line;
|
||||
max-width: 250px;
|
||||
max-width: 300px;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -76,7 +76,8 @@ class ImageMagnifier extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
updateMagnifier(imageData, imageX, imageY, mouseX, mouseY, canvasRect, zoomFactor = 8, originalImageData = null) {
|
||||
updateMagnifier(imageData, parentRect, imageX, imageY, originalImageData = null) {
|
||||
const zoomFactor = 8;
|
||||
if (!imageData) return;
|
||||
|
||||
if (imageX < 0 || imageX >= imageData.width || imageY < 0 || imageY >= imageData.height) {
|
||||
@@ -90,7 +91,7 @@ class ImageMagnifier extends LitElement {
|
||||
const b = imageData.data[pixelIndex + 2];
|
||||
const a = imageData.data[pixelIndex + 3];
|
||||
|
||||
let pixelInfoText = `RGBA(${r}, ${g}, ${b}, ${a})\n@ (${imageX}, ${imageY})`;
|
||||
let pixelInfoText = `(${r}, ${g}, ${b}, ${a})\n@ (${imageX}, ${imageY})`;
|
||||
|
||||
// If original image data is provided, show the unmultiplied values too
|
||||
if (originalImageData) {
|
||||
@@ -98,9 +99,10 @@ class ImageMagnifier extends LitElement {
|
||||
const origG = originalImageData.data[pixelIndex + 1];
|
||||
const origB = originalImageData.data[pixelIndex + 2];
|
||||
const origA = originalImageData.data[pixelIndex + 3];
|
||||
pixelInfoText = `Diff: RGBA(${origR}, ${origG}, ${origB}, ${origA})\nDisplay: RGBA(${r}, ${g}, ${b}, ${a})\n@ (${imageX}, ${imageY})`;
|
||||
pixelInfoText = `Orig: (${origR}, ${origG}, ${origB}, ${origA})\nMult: (${r}, ${g}, ${b}, ${a})\n@ (${imageX}, ${imageY})`;
|
||||
}
|
||||
|
||||
|
||||
const magnifierSize = 150;
|
||||
const sourceSize = magnifierSize / zoomFactor;
|
||||
const halfSource = sourceSize / 2;
|
||||
@@ -131,19 +133,25 @@ class ImageMagnifier extends LitElement {
|
||||
|
||||
const centerX = magnifierSize / 2;
|
||||
const centerY = magnifierSize / 2;
|
||||
const lineWidth = 1;
|
||||
const boxWidth = zoomFactor + lineWidth;
|
||||
magnifierCtx.strokeStyle = 'red';
|
||||
magnifierCtx.lineWidth = 1;
|
||||
magnifierCtx.lineWidth = lineWidth;
|
||||
magnifierCtx.beginPath();
|
||||
magnifierCtx.moveTo(centerX - 5, centerY);
|
||||
magnifierCtx.lineTo(centerX + 5, centerY);
|
||||
magnifierCtx.moveTo(centerX, centerY - 5);
|
||||
magnifierCtx.lineTo(centerX, centerY + 5);
|
||||
magnifierCtx.moveTo(centerX, centerY);
|
||||
magnifierCtx.lineTo(centerX + boxWidth, centerY);
|
||||
magnifierCtx.lineTo(centerX + boxWidth, centerY + boxWidth);
|
||||
magnifierCtx.lineTo(centerX, centerY + boxWidth);
|
||||
magnifierCtx.lineTo(centerX, centerY);
|
||||
magnifierCtx.stroke();
|
||||
|
||||
// Position relative to the TiffViewer container
|
||||
this.style.left = (mouseX - magnifierSize / 2) + 'px';
|
||||
this.style.top = (mouseY - magnifierSize / 2) + 'px';
|
||||
|
||||
this.style.left = Math.round(-centerX +
|
||||
(imageX / imageData.width) * parentRect.width -
|
||||
boxWidth) + 'px';
|
||||
this.style.top = Math.round(-centerY +
|
||||
(imageY / imageData.height) * parentRect.height -
|
||||
boxWidth) + 'px';
|
||||
pixelInfo.textContent = pixelInfoText;
|
||||
|
||||
this.visible = true;
|
||||
@@ -172,20 +180,20 @@ export class TiffViewer extends LitElement {
|
||||
|
||||
static properties = {
|
||||
fileurl: {type: String, attribute: 'fileurl'},
|
||||
name: {type: String, attribute: 'name'},
|
||||
failedToFetch: {type: Boolean },
|
||||
magnifierEnabled: {type: Boolean, attribute: 'magnifier-enabled'},
|
||||
disableMouseHandlers: {type: Boolean, attribute: 'disable-mouse-handlers'},
|
||||
srcdata: {type: Object, attribute: 'srcdata'},
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.fileurl = null;
|
||||
this.name = null;
|
||||
this.failedToFetch = false;
|
||||
this.magnifierEnabled = false;
|
||||
this.disableMouseHandlers = false;
|
||||
this.imageData = null;
|
||||
this.imgdata = null;
|
||||
this.srcdata = null;
|
||||
this.canvasRect = null;
|
||||
}
|
||||
|
||||
@@ -194,7 +202,11 @@ export class TiffViewer extends LitElement {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<canvas id="tiffCanvas" @mousemove="${this._onMouseMove}" @mouseenter="${this._onMouseEnter}" @mouseleave="${this._onMouseLeave}"></canvas>
|
||||
<canvas id="tiffCanvas"
|
||||
@mousemove="${this._onMouseMove}"
|
||||
@mouseenter="${this._onMouseEnter}"
|
||||
@mouseleave="${this._onMouseLeave}">
|
||||
</canvas>
|
||||
<image-magnifier id="magnifier"></image-magnifier>
|
||||
`;
|
||||
}
|
||||
@@ -202,7 +214,20 @@ export class TiffViewer extends LitElement {
|
||||
updated(props) {
|
||||
if (props.has('fileurl') && this.fileurl) {
|
||||
this._updateImage(this.fileurl);
|
||||
return;
|
||||
}
|
||||
if (props.has('srcdata') && this.srcdata) {
|
||||
this._drawImage(this.srcdata);
|
||||
}
|
||||
}
|
||||
|
||||
_drawImage(imageData) {
|
||||
const canvas = this.shadowRoot.getElementById('tiffCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = imageData.width;
|
||||
canvas.height = imageData.height;
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
this.imgdata = imageData;
|
||||
}
|
||||
|
||||
async _updateImage(fileurl) {
|
||||
@@ -233,9 +258,6 @@ export class TiffViewer extends LitElement {
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
const canvas = this.shadowRoot.getElementById('tiffCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
try {
|
||||
const arrayBuffer = fileblob;
|
||||
const ifds = UTIF.decode(arrayBuffer); // Parse TIFF data
|
||||
@@ -251,6 +273,10 @@ export class TiffViewer extends LitElement {
|
||||
UTIF.decodeImage(arrayBuffer, firstImage, ifds); // Decode the actual pixel data
|
||||
|
||||
const rgba = UTIF.toRGBA8(firstImage); // Convert to RGBA
|
||||
|
||||
// This needs to be present so that the ImageData has the right dimension to begin with
|
||||
// (without initial resizing due to flex's css styling and then resized again in _drawImage()).
|
||||
const canvas = this.shadowRoot.getElementById('tiffCanvas');
|
||||
canvas.width = firstImage.width;
|
||||
canvas.height = firstImage.height;
|
||||
|
||||
@@ -262,18 +288,17 @@ export class TiffViewer extends LitElement {
|
||||
}
|
||||
|
||||
const imageData = new ImageData(new Uint8ClampedArray(rgba), firstImage.width, firstImage.height);
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
|
||||
this.imageData = imageData;
|
||||
this.imgdata = imageData;
|
||||
|
||||
this.dispatchEvent(new CustomEvent('image-loaded', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
name: this.name,
|
||||
url: this.fileurl,
|
||||
img: imageData,
|
||||
}
|
||||
}));
|
||||
this._drawImage(imageData);
|
||||
} catch (error) {
|
||||
console.error('Error processing TIFF file:', error);
|
||||
this._clearCanvas();
|
||||
@@ -289,7 +314,7 @@ export class TiffViewer extends LitElement {
|
||||
}
|
||||
|
||||
_onMouseEnter(event) {
|
||||
if (this.disableMouseHandlers || !this.magnifierEnabled || !this.imageData) return;
|
||||
if (this.disableMouseHandlers || !this.magnifierEnabled || !this.imgdata) return;
|
||||
this.canvasRect = event.target.getBoundingClientRect();
|
||||
}
|
||||
|
||||
@@ -300,11 +325,11 @@ export class TiffViewer extends LitElement {
|
||||
}
|
||||
|
||||
_onMouseMove(event) {
|
||||
if (this.disableMouseHandlers || !this.magnifierEnabled || !this.imageData || !this.canvasRect) return;
|
||||
|
||||
if (this.disableMouseHandlers || !this.canvasRect) return;
|
||||
const rect = this.canvasRect;
|
||||
const scaleX = this.imageData.width / rect.width;
|
||||
const scaleY = this.imageData.height / rect.height;
|
||||
|
||||
const scaleX = this.imgdata.width / rect.width;
|
||||
const scaleY = this.imgdata.height / rect.height;
|
||||
|
||||
const mouseX = event.clientX - rect.left;
|
||||
const mouseY = event.clientY - rect.top;
|
||||
@@ -312,8 +337,18 @@ export class TiffViewer extends LitElement {
|
||||
const imageX = Math.floor(mouseX * scaleX);
|
||||
const imageY = Math.floor(mouseY * scaleY);
|
||||
|
||||
this.updateMagnifier(imageX, imageY);
|
||||
}
|
||||
|
||||
updateMagnifier(imageX, imageY, origData = null) {
|
||||
let rect = null;
|
||||
const canvas = this.shadowRoot.getElementById('tiffCanvas');
|
||||
if (canvas) {
|
||||
rect = canvas.getBoundingClientRect();
|
||||
}
|
||||
if (!this.magnifierEnabled || !this.imgdata || !rect) return;
|
||||
const magnifier = this.shadowRoot.getElementById('magnifier');
|
||||
magnifier.updateMagnifier(this.imageData, imageX, imageY, event.clientX, event.clientY, rect);
|
||||
magnifier.updateMagnifier(this.imgdata, rect, imageX, imageY, origData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user