diff --git a/frontend/src/map/Map.tsx b/frontend/src/map/Map.tsx index f80db12dd5f..ab8e24d83d0 100644 --- a/frontend/src/map/Map.tsx +++ b/frontend/src/map/Map.tsx @@ -18,6 +18,7 @@ import {PinchMoveTouchHandlerEvent} from "./utils/touch_handling/events/PinchMov import {PinchEndTouchHandlerEvent} from "./utils/touch_handling/events/PinchEndTouchHandlerEvent"; import {PointCoordinates} from "./utils/types"; import { create } from "zustand"; +import {considerHiDPI} from "./utils/helpers"; export interface MapProps { rawMap: RawMapData; @@ -100,8 +101,8 @@ abstract class Map extends React.Component

{ return; } - this.canvas.height = this.canvas.clientHeight; - this.canvas.width = this.canvas.clientWidth; + this.canvas.height = considerHiDPI(this.canvas.clientHeight); + this.canvas.width = considerHiDPI(this.canvas.clientWidth); this.ctxWrapper.setTransform(a, b, c, d, e, f); @@ -120,8 +121,8 @@ abstract class Map extends React.Component

{ componentDidMount(): void { this.canvas = this.canvasRef.current!; - this.canvas.height = this.canvas.clientHeight; - this.canvas.width = this.canvas.clientWidth; + this.canvas.height = considerHiDPI(this.canvas.clientHeight); + this.canvas.width = considerHiDPI(this.canvas.clientWidth); this.ctxWrapper = new Canvas2DContextTrackingWrapper(this.canvas.getContext("2d")!); @@ -326,12 +327,13 @@ abstract class Map extends React.Component

{ const transformationMatrixToScreenSpace = this.ctxWrapper.getTransform(); this.ctxWrapper.save(); this.ctxWrapper.setTransform(1, 0, 0, 1, 0, 0); + const scaleFactor = Math.round(this.currentScaleFactor / window.devicePixelRatio); //considerHiDPI this.structureManager.getMapStructures().forEach(s => { s.draw( this.ctxWrapper, transformationMatrixToScreenSpace, - this.currentScaleFactor, + scaleFactor, this.structureManager.getPixelSize() ); }); @@ -340,7 +342,7 @@ abstract class Map extends React.Component

{ s.draw( this.ctxWrapper, transformationMatrixToScreenSpace, - this.currentScaleFactor, + scaleFactor, this.structureManager.getPixelSize() ); }); @@ -430,7 +432,10 @@ abstract class Map extends React.Component

{ factor = 150 / currentScaleFactor; } - const pt = this.ctxWrapper.mapPointToCurrentTransform(evt.offsetX, evt.offsetY); + const pt = this.ctxWrapper.mapPointToCurrentTransform( + considerHiDPI(evt.offsetX), + considerHiDPI(evt.offsetY), + ); this.ctxWrapper.translate(pt.x, pt.y); this.ctxWrapper.scale(factor, factor); this.ctxWrapper.translate(-pt.x, -pt.y); @@ -612,8 +617,8 @@ abstract class Map extends React.Component

{ protected relativeCoordinatesToCanvas(x: number, y:number) : PointCoordinates { const rect = this.canvas.getBoundingClientRect(); return { - x: x - rect.left, - y: y - rect.top + x: Math.round((x - rect.left) * window.devicePixelRatio), + y: Math.round((y - rect.top) * window.devicePixelRatio) }; } diff --git a/frontend/src/map/structures/client_structures/CuttingLineClientStructure.ts b/frontend/src/map/structures/client_structures/CuttingLineClientStructure.ts index d0d8f9a3854..bae8638ed80 100644 --- a/frontend/src/map/structures/client_structures/CuttingLineClientStructure.ts +++ b/frontend/src/map/structures/client_structures/CuttingLineClientStructure.ts @@ -1,4 +1,5 @@ import LineClientStructure from "./LineClientStructure"; +import {considerHiDPI} from "../../utils/helpers"; class CuttingLineClientStructure extends LineClientStructure { public static TYPE = "CuttingLineClientStructure"; @@ -17,11 +18,14 @@ class CuttingLineClientStructure extends LineClientStructure { protected setLineStyle(ctx: CanvasRenderingContext2D) { ctx.strokeStyle = "rgb(255, 255, 255)"; - ctx.lineWidth = 5; + ctx.lineWidth = considerHiDPI(5); ctx.lineCap = "round"; if (this.active) { - ctx.setLineDash([15, 5]); + ctx.setLineDash([ + considerHiDPI(15), + considerHiDPI(5) + ]); } } diff --git a/frontend/src/map/structures/client_structures/GoToTargetClientStructure.ts b/frontend/src/map/structures/client_structures/GoToTargetClientStructure.ts index a05017aba0a..466d00fca51 100644 --- a/frontend/src/map/structures/client_structures/GoToTargetClientStructure.ts +++ b/frontend/src/map/structures/client_structures/GoToTargetClientStructure.ts @@ -1,8 +1,9 @@ import ClientStructure from "./ClientStructure"; import goToTargetIconSVG from "../icons/marker.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = goToTargetIconSVG; class GoToTargetClientStructure extends ClientStructure { @@ -18,8 +19,8 @@ class GoToTargetClientStructure extends ClientStructure { const scaledSize = { - width: Math.max(img.width / (7 / scaleFactor), img.width), - height: Math.max(img.height / (7 / scaleFactor), img.height) + width: Math.max(img.hiDPIAwareWidth / (7 / scaleFactor), img.hiDPIAwareWidth), + height: Math.max(img.hiDPIAwareHeight / (7 / scaleFactor), img.hiDPIAwareHeight) }; ctx.drawImage( diff --git a/frontend/src/map/structures/client_structures/LineClientStructure.ts b/frontend/src/map/structures/client_structures/LineClientStructure.ts index d1efe48aef7..0823bdfff64 100644 --- a/frontend/src/map/structures/client_structures/LineClientStructure.ts +++ b/frontend/src/map/structures/client_structures/LineClientStructure.ts @@ -5,11 +5,12 @@ import {StructureInterceptionHandlerResult} from "../Structure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; import {PointCoordinates} from "../../utils/types"; import {calculateBoxAroundPoint, isInsideBox} from "../../utils/helpers"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img_delete_button = new Image(); +const img_delete_button = new ValetudoMapCanvasImageAsset(); img_delete_button.src = deleteButtonIconSVG; -const img_move_button = new Image(); +const img_move_button = new ValetudoMapCanvasImageAsset(); img_move_button.src = moveButtonIconSVG; const buttonHitboxPadding = 22.5; @@ -82,14 +83,18 @@ abstract class LineClientStructure extends ClientStructure { if (this.active) { ctx.drawImage( img_delete_button, - p0.x - img_delete_button.width / 2, - p0.y - img_delete_button.height / 2 + p0.x - img_delete_button.hiDPIAwareWidth / 2, + p0.y - img_delete_button.hiDPIAwareHeight / 2, + img_delete_button.hiDPIAwareWidth, + img_delete_button.hiDPIAwareHeight ); ctx.drawImage( img_move_button, - p1.x - img_move_button.width / 2, - p1.y - img_move_button.height / 2 + p1.x - img_move_button.hiDPIAwareWidth / 2, + p1.y - img_move_button.hiDPIAwareHeight / 2, + img_move_button.hiDPIAwareWidth, + img_move_button.hiDPIAwareHeight ); } diff --git a/frontend/src/map/structures/client_structures/RestrictedZoneClientStructure.ts b/frontend/src/map/structures/client_structures/RestrictedZoneClientStructure.ts index 7c7cea75bcf..0bdf8c3484f 100644 --- a/frontend/src/map/structures/client_structures/RestrictedZoneClientStructure.ts +++ b/frontend/src/map/structures/client_structures/RestrictedZoneClientStructure.ts @@ -4,12 +4,13 @@ import scaleButtonIconSVG from "../icons/scale_zone.svg"; import {StructureInterceptionHandlerResult} from "../Structure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; import {PointCoordinates} from "../../utils/types"; -import {calculateBoxAroundPoint, isInsideBox} from "../../utils/helpers"; +import {calculateBoxAroundPoint, considerHiDPI, isInsideBox} from "../../utils/helpers"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img_delete_button = new Image(); +const img_delete_button = new ValetudoMapCanvasImageAsset(); img_delete_button.src = deleteButtonIconSVG; -const img_scale_button = new Image(); +const img_scale_button = new ValetudoMapCanvasImageAsset(); img_scale_button.src = scaleButtonIconSVG; const buttonHitboxPadding = 22.5; @@ -63,14 +64,17 @@ abstract class RestrictedZoneClientStructure extends ClientStructure { ctxWrapper.save(); - ctx.lineWidth = 5; + ctx.lineWidth = considerHiDPI(5); ctx.lineCap = "round"; if (!this.active) { ctx.strokeStyle = this.style.stroke; ctx.fillStyle = this.style.fill; } else { - ctx.setLineDash([8, 6]); + ctx.setLineDash([ + considerHiDPI(8), + considerHiDPI(6) + ]); ctx.strokeStyle = this.style.stroke; ctx.fillStyle = this.style.fill; } @@ -85,7 +89,7 @@ abstract class RestrictedZoneClientStructure extends ClientStructure { ctx.fill(); ctx.shadowColor = "rgba(0,0,0, 1)"; - ctx.shadowBlur = 2; + ctx.shadowBlur = considerHiDPI(2); ctx.stroke(); @@ -96,14 +100,18 @@ abstract class RestrictedZoneClientStructure extends ClientStructure { if (this.active) { ctx.drawImage( img_delete_button, - p1.x - img_delete_button.width / 2, - p1.y - img_delete_button.height / 2 + p1.x - img_delete_button.hiDPIAwareWidth / 2, + p1.y - img_delete_button.hiDPIAwareHeight / 2, + img_delete_button.hiDPIAwareWidth, + img_delete_button.hiDPIAwareHeight ); ctx.drawImage( img_scale_button, - p2.x - img_scale_button.width / 2, - p2.y - img_scale_button.height / 2 + p2.x - img_scale_button.hiDPIAwareWidth / 2, + p2.y - img_scale_button.hiDPIAwareHeight / 2, + img_scale_button.hiDPIAwareWidth, + img_scale_button.hiDPIAwareHeight ); } } diff --git a/frontend/src/map/structures/client_structures/VirtualWallClientStructure.ts b/frontend/src/map/structures/client_structures/VirtualWallClientStructure.ts index 10d4281d187..aff77c12458 100644 --- a/frontend/src/map/structures/client_structures/VirtualWallClientStructure.ts +++ b/frontend/src/map/structures/client_structures/VirtualWallClientStructure.ts @@ -1,4 +1,5 @@ import LineClientStructure from "./LineClientStructure"; +import {considerHiDPI} from "../../utils/helpers"; class VirtualWallClientStructure extends LineClientStructure { public static TYPE = "VirtualWallClientStructure"; @@ -17,14 +18,17 @@ class VirtualWallClientStructure extends LineClientStructure { protected setLineStyle(ctx: CanvasRenderingContext2D) { ctx.shadowColor = "rgba(0,0,0, 1)"; - ctx.shadowBlur = 2; + ctx.shadowBlur = considerHiDPI(2); ctx.strokeStyle = "rgb(255, 0, 0)"; - ctx.lineWidth = 5; + ctx.lineWidth = considerHiDPI(5); ctx.lineCap = "round"; if (this.active) { - ctx.setLineDash([15, 5]); + ctx.setLineDash([ + considerHiDPI(15), + considerHiDPI(5) + ]); } } diff --git a/frontend/src/map/structures/client_structures/ZoneClientStructure.ts b/frontend/src/map/structures/client_structures/ZoneClientStructure.ts index 5e1845910b6..4053ce510ab 100644 --- a/frontend/src/map/structures/client_structures/ZoneClientStructure.ts +++ b/frontend/src/map/structures/client_structures/ZoneClientStructure.ts @@ -4,12 +4,13 @@ import scaleButtonIconSVG from "../icons/scale_zone.svg"; import {StructureInterceptionHandlerResult} from "../Structure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; import {PointCoordinates} from "../../utils/types"; -import {calculateBoxAroundPoint, isInsideBox} from "../../utils/helpers"; +import {calculateBoxAroundPoint, considerHiDPI, isInsideBox} from "../../utils/helpers"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img_delete_button = new Image(); +const img_delete_button = new ValetudoMapCanvasImageAsset(); img_delete_button.src = deleteButtonIconSVG; -const img_scale_button = new Image(); +const img_scale_button = new ValetudoMapCanvasImageAsset(); img_scale_button.src = scaleButtonIconSVG; const buttonHitboxPadding = 22.5; @@ -57,16 +58,16 @@ class ZoneClientStructure extends ClientStructure { ctx.strokeStyle = "rgb(255, 255, 255)"; ctx.fillStyle = "rgba(255, 255, 255, 0.4)"; } else { - ctx.setLineDash([15, 5]); + ctx.setLineDash([considerHiDPI(15), considerHiDPI(5)]); ctx.strokeStyle = "rgb(255, 255, 255)"; ctx.fillStyle = "rgba(255, 255, 255, 0)"; } - ctx.lineWidth = 2; + ctx.lineWidth = considerHiDPI(2); ctx.fillRect(p0.x, p0.y, p1.x - p0.x, p1.y - p0.y); ctx.shadowColor = "rgba(0,0,0, 1)"; - ctx.shadowBlur = 2; + ctx.shadowBlur = considerHiDPI(2); ctx.strokeRect(p0.x, p0.y, p1.x - p0.x, p1.y - p0.y); @@ -76,27 +77,31 @@ class ZoneClientStructure extends ClientStructure { ctx.textAlign = "start"; ctx.fillStyle = "rgba(255, 255, 255, 1)"; ctx.strokeStyle = "rgba(18, 18, 18, 1)"; - ctx.font = Math.round(6 * scaleFactor).toString(10) + "px sans-serif"; + ctx.font = `${considerHiDPI(6) * scaleFactor}px sans-serif`; - ctx.lineWidth = 3; - ctx.strokeText(label, p0.x, p0.y - 8); + ctx.lineWidth = considerHiDPI(3); + ctx.strokeText(label, p0.x, p0.y - considerHiDPI(8)); - ctx.lineWidth = 1; - ctx.fillText(label, p0.x, p0.y - 8); + ctx.lineWidth = considerHiDPI(1); + ctx.fillText(label, p0.x, p0.y - considerHiDPI(8)); ctxWrapper.restore(); if (this.active) { ctx.drawImage( img_delete_button, - p1.x - img_delete_button.width / 2, - p0.y - img_delete_button.height / 2 + p1.x - img_delete_button.hiDPIAwareWidth / 2, + p0.y - img_delete_button.hiDPIAwareHeight / 2, + img_delete_button.hiDPIAwareWidth, + img_delete_button.hiDPIAwareHeight ); ctx.drawImage( img_scale_button, - p1.x - img_scale_button.width / 2, - p1.y - img_scale_button.height / 2 + p1.x - img_scale_button.hiDPIAwareWidth / 2, + p1.y - img_scale_button.hiDPIAwareHeight / 2, + img_scale_button.hiDPIAwareWidth, + img_scale_button.hiDPIAwareHeight ); } } diff --git a/frontend/src/map/structures/map_structures/ActiveZoneMapStructure.ts b/frontend/src/map/structures/map_structures/ActiveZoneMapStructure.ts index a06218db3a6..a7889daf73b 100644 --- a/frontend/src/map/structures/map_structures/ActiveZoneMapStructure.ts +++ b/frontend/src/map/structures/map_structures/ActiveZoneMapStructure.ts @@ -1,5 +1,6 @@ import { Canvas2DContextTrackingWrapper } from "../../utils/Canvas2DContextTrackingWrapper"; import MapStructure from "./MapStructure"; +import {considerHiDPI} from "../../utils/helpers"; class ActiveZoneMapStructure extends MapStructure { @@ -41,7 +42,7 @@ class ActiveZoneMapStructure extends MapStructure { ctx.strokeStyle = "rgb(53, 145, 26)"; ctx.fillStyle = "rgba(107, 244, 66, 0.3)"; - ctx.lineWidth = 2; + ctx.lineWidth = considerHiDPI(2); ctx.beginPath(); ctx.moveTo(p0.x, p0.y); diff --git a/frontend/src/map/structures/map_structures/ChargerLocationMapStructure.ts b/frontend/src/map/structures/map_structures/ChargerLocationMapStructure.ts index 08cb669a068..42a50f4ec26 100644 --- a/frontend/src/map/structures/map_structures/ChargerLocationMapStructure.ts +++ b/frontend/src/map/structures/map_structures/ChargerLocationMapStructure.ts @@ -1,8 +1,9 @@ import MapStructure from "./MapStructure"; import chargerIconSVG from "../icons/charger.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = chargerIconSVG; class ChargerLocationMapStructure extends MapStructure { @@ -16,10 +17,9 @@ class ChargerLocationMapStructure extends MapStructure { const ctx = ctxWrapper.getContext(); const p0 = new DOMPoint(this.x0, this.y0).matrixTransform(transformationMatrixToScreenSpace); - const scaledSize = { - width: Math.max(img.width / (4.5 / scaleFactor), img.width), - height: Math.max(img.height / (4.5 / scaleFactor), img.height) + width: Math.max(img.hiDPIAwareWidth / (4.5 / scaleFactor), img.hiDPIAwareWidth), + height: Math.max(img.hiDPIAwareWidth / (4.5 / scaleFactor), img.hiDPIAwareHeight) }; ctx.drawImage( diff --git a/frontend/src/map/structures/map_structures/GoToTargetMapStructure.ts b/frontend/src/map/structures/map_structures/GoToTargetMapStructure.ts index 9b041276ef9..4f48bf062fd 100644 --- a/frontend/src/map/structures/map_structures/GoToTargetMapStructure.ts +++ b/frontend/src/map/structures/map_structures/GoToTargetMapStructure.ts @@ -1,8 +1,9 @@ import MapStructure from "./MapStructure"; import goToTargetIconSVG from "../icons/marker_active.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = goToTargetIconSVG; class GoToTargetMapStructure extends MapStructure { @@ -18,8 +19,8 @@ class GoToTargetMapStructure extends MapStructure { const scaledSize = { - width: Math.max(img.width / (7 / scaleFactor), img.width), - height: Math.max(img.height / (7 / scaleFactor), img.height) + width: Math.max(img.hiDPIAwareWidth / (7 / scaleFactor), img.hiDPIAwareWidth), + height: Math.max(img.hiDPIAwareHeight / (7 / scaleFactor), img.hiDPIAwareHeight) }; ctx.drawImage( diff --git a/frontend/src/map/structures/map_structures/NoGoAreaMapStructure.ts b/frontend/src/map/structures/map_structures/NoGoAreaMapStructure.ts index 92b5b01047d..9af5bd6e3d2 100644 --- a/frontend/src/map/structures/map_structures/NoGoAreaMapStructure.ts +++ b/frontend/src/map/structures/map_structures/NoGoAreaMapStructure.ts @@ -1,5 +1,6 @@ import MapStructure from "./MapStructure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {considerHiDPI} from "../../utils/helpers"; class NoGoAreaMapStructure extends MapStructure { @@ -41,7 +42,7 @@ class NoGoAreaMapStructure extends MapStructure { ctx.strokeStyle = "rgb(255, 0, 0, 0.75)"; ctx.fillStyle = "rgba(255, 0, 0, 0.15)"; - ctx.lineWidth = 2; + ctx.lineWidth = considerHiDPI(2); ctx.beginPath(); ctx.moveTo(p0.x, p0.y); diff --git a/frontend/src/map/structures/map_structures/NoMopAreaMapStructure.ts b/frontend/src/map/structures/map_structures/NoMopAreaMapStructure.ts index be7b646900d..80db1271a42 100644 --- a/frontend/src/map/structures/map_structures/NoMopAreaMapStructure.ts +++ b/frontend/src/map/structures/map_structures/NoMopAreaMapStructure.ts @@ -1,5 +1,6 @@ import MapStructure from "./MapStructure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {considerHiDPI} from "../../utils/helpers"; class NoMopAreaMapStructure extends MapStructure { @@ -41,7 +42,7 @@ class NoMopAreaMapStructure extends MapStructure { ctx.strokeStyle = "rgb(200, 0, 255, 0.6)"; ctx.fillStyle = "rgba(200, 0, 255, 0.15)"; - ctx.lineWidth = 2; + ctx.lineWidth = considerHiDPI(2); ctx.beginPath(); ctx.moveTo(p0.x, p0.y); diff --git a/frontend/src/map/structures/map_structures/ObstacleMapStructure.ts b/frontend/src/map/structures/map_structures/ObstacleMapStructure.ts index 1216b4e8b56..4ac192e91be 100644 --- a/frontend/src/map/structures/map_structures/ObstacleMapStructure.ts +++ b/frontend/src/map/structures/map_structures/ObstacleMapStructure.ts @@ -1,8 +1,10 @@ import MapStructure from "./MapStructure"; import obstacleIconSVG from "../icons/obstacle.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; +import {considerHiDPI} from "../../utils/helpers"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = obstacleIconSVG; class ObstacleMapStructure extends MapStructure { @@ -21,8 +23,8 @@ class ObstacleMapStructure extends MapStructure { const scaledSize = { - width: Math.max(img.width / (8 / scaleFactor), img.width * 0.3), - height: Math.max(img.height / (8 / scaleFactor), img.height * 0.3) + width: Math.max(img.hiDPIAwareWidth / (8 / scaleFactor), img.hiDPIAwareWidth * 0.3), + height: Math.max(img.hiDPIAwareHeight / (8 / scaleFactor), img.hiDPIAwareHeight * 0.3) }; ctx.drawImage( @@ -37,15 +39,15 @@ class ObstacleMapStructure extends MapStructure { ctxWrapper.save(); ctx.textAlign = "center"; - ctx.font = "32px sans-serif"; + ctx.font = `${considerHiDPI(32)}px sans-serif`; ctx.fillStyle = "rgba(255, 255, 255, 1)"; ctx.strokeStyle = "rgba(18, 18, 18, 1)"; - ctx.lineWidth = 2.5; - ctx.strokeText(this.label, p0.x , p0.y + (scaledSize.height/2) + 32); + ctx.lineWidth = considerHiDPI(2.5); + ctx.strokeText(this.label, p0.x , p0.y + (scaledSize.height/2) + considerHiDPI(32)); - ctx.lineWidth = 1; - ctx.fillText(this.label, p0.x , p0.y + (scaledSize.height/2) + 32); + ctx.lineWidth = considerHiDPI(1); + ctx.fillText(this.label, p0.x , p0.y + (scaledSize.height/2) + considerHiDPI(32)); ctxWrapper.restore(); } diff --git a/frontend/src/map/structures/map_structures/RobotPositionMapStructure.ts b/frontend/src/map/structures/map_structures/RobotPositionMapStructure.ts index 74105f9033f..dd794dc0a9d 100644 --- a/frontend/src/map/structures/map_structures/RobotPositionMapStructure.ts +++ b/frontend/src/map/structures/map_structures/RobotPositionMapStructure.ts @@ -1,8 +1,9 @@ import MapStructure from "./MapStructure"; import robotIconSVG from "../icons/robot.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = robotIconSVG; class RobotPositionMapStructure extends MapStructure { @@ -39,8 +40,8 @@ class RobotPositionMapStructure extends MapStructure { }; const scaledSize = { - width: Math.max(img.width / (4.5 / scaleFactor), img.width), - height: Math.max(img.height / (4.5 / scaleFactor), img.height) + width: Math.max(img.hiDPIAwareWidth / (4.5 / scaleFactor), img.hiDPIAwareWidth), + height: Math.max(img.hiDPIAwareHeight / (4.5 / scaleFactor), img.hiDPIAwareHeight) }; ctx.drawImage( diff --git a/frontend/src/map/structures/map_structures/SegmentLabelMapStructure.ts b/frontend/src/map/structures/map_structures/SegmentLabelMapStructure.ts index 617d2dd690c..23b3b4da803 100644 --- a/frontend/src/map/structures/map_structures/SegmentLabelMapStructure.ts +++ b/frontend/src/map/structures/map_structures/SegmentLabelMapStructure.ts @@ -2,11 +2,13 @@ import MapStructure from "./MapStructure"; import segmentIconSVG from "../icons/segment.svg"; import segmentSelectedIconSVG from "../icons/segment_selected.svg"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {ValetudoMapCanvasImageAsset} from "../../utils/ValetudoMapCanvasImageAsset"; +import {considerHiDPI} from "../../utils/helpers"; -const img = new Image(); +const img = new ValetudoMapCanvasImageAsset(); img.src = segmentIconSVG; -const img_selected = new Image(); +const img_selected = new ValetudoMapCanvasImageAsset(); img_selected.src = segmentSelectedIconSVG; @@ -40,12 +42,12 @@ class SegmentLabelMapStructure extends MapStructure { this.scaledIconSize = { width: Math.max( - imageToUse.width * (scaleFactor / 4), - imageToUse.width * 0.8 + imageToUse.hiDPIAwareWidth * (scaleFactor / 4), + imageToUse.hiDPIAwareWidth * 0.8 ), height: Math.max( - imageToUse.height * (scaleFactor / 4), - imageToUse.height * 0.8 + imageToUse.hiDPIAwareHeight * (scaleFactor / 4), + imageToUse.hiDPIAwareHeight * 0.8 ) }; @@ -69,7 +71,7 @@ class SegmentLabelMapStructure extends MapStructure { if (this.topLabel && scaleFactor >= 1.2) { let fontSize; - const yOffset = ((this.scaledIconSize.height/3)*2) + (this.active ? 0 : 10); + const yOffset = ((this.scaledIconSize.height/3)*2) + (this.active ? 0 : considerHiDPI(10)); if (scaleFactor >= 9) { fontSize = 45; @@ -86,14 +88,14 @@ class SegmentLabelMapStructure extends MapStructure { ctxWrapper.save(); ctx.textAlign = "center"; - ctx.font = `${fontSize}px sans-serif`; + ctx.font = `${considerHiDPI(fontSize)}px sans-serif`; ctx.fillStyle = "rgba(255, 255, 255, 1)"; ctx.strokeStyle = "rgba(18, 18, 18, 1)"; - ctx.lineWidth = 2.5; + ctx.lineWidth = considerHiDPI(2.5); ctx.strokeText(this.topLabel, p0.x , p0.y - yOffset); - ctx.lineWidth = 1; + ctx.lineWidth = considerHiDPI(1); ctx.fillText(this.topLabel, p0.x , p0.y - yOffset); ctxWrapper.restore(); @@ -102,29 +104,63 @@ class SegmentLabelMapStructure extends MapStructure { if (scaleFactor >= 7) { ctxWrapper.save(); ctx.textAlign = "center"; - ctx.font = "45px sans-serif"; + ctx.font = `${considerHiDPI(45)}px sans-serif`; ctx.fillStyle = "rgba(255, 255, 255, 1)"; ctx.strokeStyle = "rgba(18, 18, 18, 1)"; if (this.name) { - ctx.lineWidth = 2.5; - ctx.strokeText(this.name, p0.x , p0.y + ((this.scaledIconSize.height/3)*2) + 20 + (this.active ? 25 : 0)); - - ctx.lineWidth = 1; - ctx.fillText(this.name, p0.x , p0.y + ((this.scaledIconSize.height/3)*2) + 20 + (this.active ? 25 : 0)); + ctx.lineWidth = considerHiDPI(2.5); + ctx.strokeText( + this.name, + p0.x , + p0.y + ( + (this.scaledIconSize.height/3)*2 + + considerHiDPI(20) + + (this.active ? considerHiDPI(25) : 0) + ) + ); + + ctx.lineWidth = considerHiDPI(1); + ctx.fillText( + this.name, + p0.x , + p0.y + ( + (this.scaledIconSize.height/3)*2 + + considerHiDPI(20) + + (this.active ? considerHiDPI(25) : 0) + ) + ); } if (scaleFactor >= 11) { let metaString = (this.area / 10000).toPrecision(2) + " m²"; metaString += ` (id=${this.id})`; - ctx.font = "35px sans-serif"; - - ctx.lineWidth = 2.5; - ctx.strokeText(metaString, p0.x , p0.y + ((this.scaledIconSize.height/3)*2) + 20 + (this.active ? 25 : 0) + (this.name ? 45 : 0)); - - ctx.lineWidth = 1; - ctx.fillText(metaString, p0.x , p0.y + ((this.scaledIconSize.height/3)*2) + 20 + (this.active ? 25 : 0) + (this.name ? 45 : 0)); + ctx.font = `${considerHiDPI(35)}px sans-serif`; + + ctx.lineWidth = considerHiDPI(2.5); + ctx.strokeText( + metaString, + p0.x , + p0.y + ( + ((this.scaledIconSize.height/3) *2) + + considerHiDPI(20) + + (this.active ? considerHiDPI(25) : 0) + + (this.name ? considerHiDPI(45) : 0) + ) + ); + + ctx.lineWidth = considerHiDPI(1); + ctx.fillText( + metaString, + p0.x , + p0.y + ( + ((this.scaledIconSize.height/3) *2) + + considerHiDPI(20) + + (this.active ? considerHiDPI(25) : 0) + + (this.name ? considerHiDPI(45) : 0) + ) + ); } diff --git a/frontend/src/map/structures/map_structures/VirtualWallMapStructure.ts b/frontend/src/map/structures/map_structures/VirtualWallMapStructure.ts index 8331795d280..665659554e6 100644 --- a/frontend/src/map/structures/map_structures/VirtualWallMapStructure.ts +++ b/frontend/src/map/structures/map_structures/VirtualWallMapStructure.ts @@ -1,5 +1,6 @@ import MapStructure from "./MapStructure"; import {Canvas2DContextTrackingWrapper} from "../../utils/Canvas2DContextTrackingWrapper"; +import {considerHiDPI} from "../../utils/helpers"; class VirtualWallMapStructure extends MapStructure { @@ -29,7 +30,7 @@ class VirtualWallMapStructure extends MapStructure { ctx.strokeStyle = "rgb(255, 0, 0, 0.75)"; - ctx.lineWidth = 5; + ctx.lineWidth = considerHiDPI(5); ctx.lineCap = "round"; ctx.beginPath(); diff --git a/frontend/src/map/utils/ValetudoMapCanvasImageAsset.ts b/frontend/src/map/utils/ValetudoMapCanvasImageAsset.ts new file mode 100644 index 00000000000..2919bd0c094 --- /dev/null +++ b/frontend/src/map/utils/ValetudoMapCanvasImageAsset.ts @@ -0,0 +1,14 @@ +import {considerHiDPI} from "./helpers"; + +export class ValetudoMapCanvasImageAsset extends HTMLImageElement { + + get hiDPIAwareHeight() { + return considerHiDPI(this.height); + } + + get hiDPIAwareWidth() { + return considerHiDPI(this.width); + } +} + +customElements.define("valetudo-map-canvas-image-asset", ValetudoMapCanvasImageAsset, { extends: "img" }); diff --git a/frontend/src/map/utils/helpers.ts b/frontend/src/map/utils/helpers.ts index f85341a85c2..c7a2d87370a 100644 --- a/frontend/src/map/utils/helpers.ts +++ b/frontend/src/map/utils/helpers.ts @@ -11,6 +11,10 @@ type Box = { } } +export function considerHiDPI(val : number): number { + return Math.round(val * window.devicePixelRatio); +} + export function isInsideBox(point: PointCoordinates, box: Box) { return ( point.x >= box.topLeftBound.x && @@ -21,14 +25,16 @@ export function isInsideBox(point: PointCoordinates, box: Box) { } export function calculateBoxAroundPoint(point: PointCoordinates, boxPadding: number) : Box { + const padding = considerHiDPI(boxPadding); + return { topLeftBound: { - x: point.x - boxPadding, - y: point.y - boxPadding + x: point.x - padding, + y: point.y - padding }, bottomRightBound: { - x: point.x + boxPadding, - y: point.y + boxPadding + x: point.x + padding, + y: point.y + padding } }; }