Issue
I am having an issue based on selecting the image. I have an array of objects which comes from BE and there each Obj hat it own coordinates which depends on the X and Y of the image. Image has some draws there and includes some numbers. So the property itemNumber on Obj it is the same number what in img will be shown. For example if itemNumber is 1 and then the coordinates are that the number 1 will be bordered on image.
I have achieved something till now but I cannot select the right X and Y everytime it is going somewhere else the border.
I created a Stackblitz
In the stackblitz you can find 2 img's. On the second you will how it should be. I tried many things but unsuccessful
Here is my Obj json.
[
{
"itemNumber": "1",
"partNumber": "4400535240",
"coordinates": [
{
"itemCounter": 0,
"xposition": 970,
"yposition": 375
}
]
},
{
"itemNumber": "2",
"partNumber": "4400541680",
"coordinates": [
{
"itemCounter": 0,
"xposition": 1282,
"yposition": 522
}
]
},
{
"itemNumber": "4",
"partNumber": "4400541390",
"coordinates": [
{
"itemCounter": 0,
"xposition": 445,
"yposition": 307
}
]
},
]`
Here is my TS Code.
showCorner(event: ResponseList) {
console.log(event.coordinates)
const xClientHeight = document.getElementById('imgPath')?.clientHeight as number;
const xClientWidth = document.getElementById('imgPath')?.clientWidth as number;
console.log(xClientHeight);
console.log(xClientWidth);
this.coordinateX = xClientWidth - event.coordinates[0].yposition;
this.coordinateY = xClientHeight - event.coordinates[0].xposition;
(document.getElementById('rec1') as HTMLInputElement).innerHTML = "<img src='../../../assets/rec.gif' style='width:25px; height:25px;'></img>";
}
showImage(imagePath: string) {
return this.environment.endpoints.backendBaseUrl + imagePath; //
imagePath
}
My HTML Code
<table>
<thead>
<tr>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of jsonData">
<td (click)="showCorner(row)">{{ row.name }}</td>
</tr>
</tbody>
</table>
<div class="flex-1 relative">
<div class="relative">
<img id="imgPath" (click.double)="addBorder($event)" style="width: 832px; max-width: fit-content;" [src]="showImage(partListImage.imagePath)">
<div id="rec1" class="absolute" [style]="{'left': coordinateX+ 'px', 'top': coordinateY+ 'px'}">
</div>
</div>
</div>
As you can see in images there are numbers. And each number when you click on table will be selected.
Solution
The problem it is that coordinates are coming from backend which I cannot change them and somehow I need to make it like you did because as you see in img there are around 40 coordinates for 1 image and I have around 100 Img I cannot them manually
the img dimensions which are coming from backend are 1664 × 2344 for all imgs
As provided by the backend, set the original image dimensions (1664x2344) in your component.
Compute the scaling factors based on the current displayed size of the image in the frontend and the original dimensions. Apply Scaling to Coordinates: Use the scaling factors to adjust the coordinates received from the backend.
I have adjusted them in this stackblitz.
Your app.component.ts
would be:
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
@ViewChild('imgPath', { static: false }) imgElementRef!: ElementRef;
coordinateX!: number;
coordinateY!: number;
originalCoordinates: any; // To store original coordinates
columns = [
{
itemNumber: '1',
partNumber: '4400535240',
coordinates: [
{
itemCounter: 0,
xposition: 970,
yposition: 375,
},
],
},
{
itemNumber: '2',
partNumber: '4400541680',
coordinates: [
{
itemCounter: 0,
xposition: 1282,
yposition: 522,
},
],
},
{
itemNumber: '4',
partNumber: '4400541390',
coordinates: [
{
itemCounter: 0,
xposition: 445,
yposition: 307,
},
],
},
];
constructor() {
// Deep copy of original columns to preserve original coordinates
this.originalCoordinates = JSON.parse(JSON.stringify(this.columns));
}
ngAfterViewInit() {
// Calculate and apply scaling when the view is initialized
this.calculateAndApplyScaling();
}
showCorner(event: any) {
// Calculate and apply scaling
this.calculateAndApplyScaling();
// Use the scaled coordinates
this.coordinateX = event.coordinates[0].xposition;
this.coordinateY = event.coordinates[0].yposition + 80;
// Log coordinates to console
console.log('Selected Coordinates:', this.coordinateX, this.coordinateY);
// Update the border element
this.updateBorderElement();
}
private calculateAndApplyScaling() {
const imgElement = this.imgElementRef.nativeElement as HTMLImageElement;
const currentWidth = imgElement.clientWidth;
const currentHeight = imgElement.clientHeight;
console.log(
'Image Current Width:',
currentWidth,
'Current Height:',
currentHeight
);
// Use naturalWidth and naturalHeight properties
const originalWidth = imgElement.naturalWidth;
const originalHeight = imgElement.naturalHeight;
const scaleX = currentWidth / this.originalWidth;
const scaleY = currentHeight / this.originalHeight;
console.log('Scale Factor X:', scaleX, 'Scale Factor Y:', scaleY);
// Apply scale factors to each original coordinate
this.columns.forEach((column, index) => {
column.coordinates.forEach((coordinate, coordIndex) => {
const originalCoordinate =
this.originalCoordinates[index].coordinates[coordIndex];
coordinate.xposition = originalCoordinate.xposition * scaleX;
coordinate.yposition = originalCoordinate.yposition * scaleY;
console.log(
`Original Coordinates: (${originalCoordinate.xposition}, ${originalCoordinate.yposition}), Scaled Coordinates: (${coordinate.xposition}, ${coordinate.yposition})`
);
});
});
}
private updateBorderElement() {
const recElement = document.getElementById('rec1') as HTMLElement;
if (recElement) {
recElement.style.border = '2px solid red';
recElement.style.width = '25px';
recElement.style.height = '25px';
recElement.style.left = this.coordinateX + 'px';
recElement.style.top = this.coordinateY + 'px';
console.log(
'Border Element Updated:',
`Left: ${this.coordinateX}px, Top: ${this.coordinateY}px`
);
}
}
addBorder(event: any) {
console.log('Add Border Event:', event);
const e = event.target.getBoundingClientRect();
console.log('Bounding Client Rect:', e);
const xClientH = event.screenY;
const xClientY = event.screenX;
this.coordinateX = xClientY;
this.coordinateY = xClientH;
console.log(
'Coordinates from Event:',
`X: ${this.coordinateX}, Y: ${this.coordinateY}`
);
const recElement = document.getElementById('rec1') as HTMLInputElement;
if (recElement) {
recElement.innerHTML =
"<img src='../../assets/flow-editor/Image/rec.gif' style='width:25px; height:25px;'></img>";
}
}
}
And your HTML code makes sure the positioning is absolute relative to the parent container of the image.
<table>
<thead>
<tr>
<th scope="col">Name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of columns">
<td (click)="showCorner(row)">{{ row.itemNumber }}</td>
<td (click)="showCorner(row)">{{ row.partNumber }}</td>
</tr>
</tbody>
</table>
<div class="flex-1 relative">
<div class="relative">
<img
#imgPath
(click.double)="addBorder($event)"
style="width: 832px; max-width: fit-content;"
src="../../assets/flow-editor/Image/ev00129014.png"
/>
<div
id="rec1"
class="absolute"
[ngStyle]="{ left: coordinateX + 'px', top: coordinateY + 'px' }"
></div>
</div>
</div>
Note that I had to adjust any assets path from ../assets/...
to ../../assets/...
to make sure the assets images are properly displayed.
Answered By - VonC
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.