Fix blur on high DPI screens
This commit is contained in:
1 parent
ebdbb1e979
commit
1c4093481e
4 files changed
+37
-35
No files matched your search
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mapContainer">
|
<div id="mapContainer">
|
||||||
<canvas id="mapCanvas"></canvas>
|
<canvas id="mapCanvas" style="width:100%;height:100%"></canvas>
|
||||||
<div id="tooltip" class="panel" style="display:none"></div>
|
<div id="tooltip" class="panel" style="display:none"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -250,21 +250,22 @@ async function loadPoiData(file){
|
|||||||
let railTrack = {};
|
let railTrack = {};
|
||||||
let curve = {};
|
let curve = {};
|
||||||
function redrawMap(){
|
function redrawMap(){
|
||||||
mapCanvas.width = mapContainer.clientWidth;
|
MapData.view.pixelRatio = window.devicePixelRatio;
|
||||||
mapCanvas.height = mapContainer.clientHeight;
|
mapCanvas.width = mapContainer.clientWidth * MapData.view.pixelRatio;
|
||||||
zoomLevelDisplay.innerHTML = `Zoom: ${MapData.view.scale.toFixed(3)}x / ${(1/MapData.view.scale).toFixed(2)} m/px`;
|
mapCanvas.height = mapContainer.clientHeight * MapData.view.pixelRatio;
|
||||||
|
zoomLevelDisplay.innerHTML = `Zoom: ${(MapData.view.scale*MapData.view.pixelRatio).toFixed(3)}x / ${(1/(MapData.view.scale*MapData.view.pixelRatio)).toFixed(2)} m/px`;
|
||||||
|
|
||||||
if(MapData.layers.terrain){
|
if(MapData.layers.terrain){
|
||||||
mapctx.drawImage(
|
mapctx.drawImage(
|
||||||
mapTerrain,
|
mapTerrain,
|
||||||
MapData.view.convertX(0),
|
MapData.view.convertX(0),
|
||||||
MapData.view.convertY(16384),
|
MapData.view.convertY(16384),
|
||||||
16384 * MapData.view.scale,
|
16384 * MapData.view.scale * MapData.view.pixelRatio,
|
||||||
16384 * MapData.view.scale
|
16384 * MapData.view.scale * MapData.view.pixelRatio
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Game gauge is 1.5 meter
|
// Game gauge is 1.5 meter
|
||||||
const trackWidth = Math.min(Math.max(6, MapData.view.scale * 1.5), MapData.view.scale * 100);
|
const trackWidth = Math.min(Math.max(6, MapData.view.scale * 1.5), MapData.view.scale * 100) * MapData.view.pixelRatio;
|
||||||
mapctx.lineWidth = trackWidth;
|
mapctx.lineWidth = trackWidth;
|
||||||
|
|
||||||
for(const railTrack of MapData.railTracks){
|
for(const railTrack of MapData.railTracks){
|
||||||
@@ -308,7 +309,7 @@ function redrawMap(){
|
|||||||
spriteSize = 30;
|
spriteSize = 30;
|
||||||
mapctx.translate(markerX, markerY);
|
mapctx.translate(markerX, markerY);
|
||||||
mapctx.rotate(marker.rotation);
|
mapctx.rotate(marker.rotation);
|
||||||
mapctx.translate(-0.5*spriteSize, -0.5*spriteSize);
|
mapctx.translate(-0.5*spriteSize * MapData.view.pixelRatio, -0.5*spriteSize * MapData.view.pixelRatio);
|
||||||
mapctx.drawImage(
|
mapctx.drawImage(
|
||||||
Utils.gradeArrows,
|
Utils.gradeArrows,
|
||||||
curSprite.x,
|
curSprite.x,
|
||||||
@@ -317,8 +318,8 @@ function redrawMap(){
|
|||||||
curSprite.height,
|
curSprite.height,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
spriteSize,
|
spriteSize * MapData.view.pixelRatio,
|
||||||
spriteSize
|
spriteSize * MapData.view.pixelRatio
|
||||||
);
|
);
|
||||||
mapctx.resetTransform();
|
mapctx.resetTransform();
|
||||||
curSprite = null;
|
curSprite = null;
|
||||||
@@ -332,7 +333,7 @@ function redrawMap(){
|
|||||||
case 'service':
|
case 'service':
|
||||||
if(!(MapData.layers.services && MapData.layers.poi)) break;
|
if(!(MapData.layers.services && MapData.layers.poi)) break;
|
||||||
marker.visible = true;
|
marker.visible = true;
|
||||||
spriteSize = 30;
|
spriteSize = 30 * MapData.view.pixelRatio;
|
||||||
if(marker.serviceTypes.length == 0) marker.serviceTypes.push('');
|
if(marker.serviceTypes.length == 0) marker.serviceTypes.push('');
|
||||||
if(marker.serviceTypes.length > 1){
|
if(marker.serviceTypes.length > 1){
|
||||||
mapctx.fillStyle = '#239a96';
|
mapctx.fillStyle = '#239a96';
|
||||||
@@ -355,8 +356,8 @@ function redrawMap(){
|
|||||||
}
|
}
|
||||||
if(!marker.tooltipHitzone){
|
if(!marker.tooltipHitzone){
|
||||||
marker.tooltipHitzone = {
|
marker.tooltipHitzone = {
|
||||||
width: spriteSize * marker.serviceTypes.length,
|
width: spriteSize/MapData.view.pixelRatio * marker.serviceTypes.length,
|
||||||
height: spriteSize
|
height: spriteSize/MapData.view.pixelRatio
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
curSprite = null;
|
curSprite = null;
|
||||||
@@ -383,20 +384,20 @@ function redrawMap(){
|
|||||||
mapctx.fillStyle = marker.color;
|
mapctx.fillStyle = marker.color;
|
||||||
mapctx.strokeStyle = '#000';
|
mapctx.strokeStyle = '#000';
|
||||||
mapctx.lineJoin = 'round';
|
mapctx.lineJoin = 'round';
|
||||||
mapctx.lineWidth = 20*MapData.view.scale;
|
mapctx.lineWidth = 20*MapData.view.scale*MapData.view.pixelRatio;
|
||||||
mapctx.font = `bold ${400*MapData.view.scale}px "Noto Sans"`;
|
mapctx.font = `bold ${400*MapData.view.scale*MapData.view.pixelRatio}px "Noto Sans"`;
|
||||||
textMeasure = mapctx.measureText(marker.shorthand);
|
textMeasure = mapctx.measureText(marker.shorthand);
|
||||||
mapctx.strokeText(marker.shorthand, markerX - textMeasure.width * 0.5, markerY);
|
mapctx.strokeText(marker.shorthand, markerX - textMeasure.width * 0.5, markerY);
|
||||||
mapctx.fillText(marker.shorthand, markerX - textMeasure.width * 0.5, markerY);
|
mapctx.fillText(marker.shorthand, markerX - textMeasure.width * 0.5, markerY);
|
||||||
if(!marker.tooltipHitzone) marker.tooltipHitzone = {};
|
if(!marker.tooltipHitzone) marker.tooltipHitzone = {};
|
||||||
marker.tooltipHitzone.width = textMeasure.width;
|
marker.tooltipHitzone.width = textMeasure.width/MapData.view.pixelRatio;
|
||||||
marker.tooltipHitzone.height = textMeasure.actualBoundingBoxAscent;
|
marker.tooltipHitzone.height = textMeasure.actualBoundingBoxAscent/MapData.view.pixelRatio;
|
||||||
marker.tooltipHitzone.offsetY = marker.tooltipHitzone.height * 0.5;
|
marker.tooltipHitzone.offsetY = marker.tooltipHitzone.height * 0.5;
|
||||||
if(MapData.view.scale < 0.14) break;
|
if(MapData.view.scale < 0.14) break;
|
||||||
mapctx.font = `bold ${70*MapData.view.scale}px "Noto Sans"`;
|
mapctx.font = `bold ${70*MapData.view.scale*MapData.view.pixelRatio}px "Noto Sans"`;
|
||||||
textMeasure = mapctx.measureText(marker.nickname ?? marker.name);
|
textMeasure = mapctx.measureText(marker.nickname ?? marker.name);
|
||||||
mapctx.strokeText(marker.nickname ?? marker.name, markerX - textMeasure.width * 0.5, markerY+80*MapData.view.scale);
|
mapctx.strokeText(marker.nickname ?? marker.name, markerX - textMeasure.width * 0.5, markerY+80*MapData.view.scale*MapData.view.pixelRatio);
|
||||||
mapctx.fillText(marker.nickname ?? marker.name, markerX - textMeasure.width * 0.5, markerY+80*MapData.view.scale);
|
mapctx.fillText(marker.nickname ?? marker.name, markerX - textMeasure.width * 0.5, markerY+80*MapData.view.scale*MapData.view.pixelRatio);
|
||||||
break;
|
break;
|
||||||
case 'yardSiding':
|
case 'yardSiding':
|
||||||
case 'yard':
|
case 'yard':
|
||||||
@@ -405,21 +406,21 @@ function redrawMap(){
|
|||||||
mapctx.fillStyle = '#fff';
|
mapctx.fillStyle = '#fff';
|
||||||
mapctx.strokeStyle = '#000';
|
mapctx.strokeStyle = '#000';
|
||||||
mapctx.lineJoin = 'round';
|
mapctx.lineJoin = 'round';
|
||||||
mapctx.lineWidth = 2;
|
mapctx.lineWidth = 2*MapData.view.pixelRatio;
|
||||||
mapctx.font = `14px "Noto Sans Mono"`;
|
mapctx.font = `${14*MapData.view.pixelRatio}px "Noto Sans Mono"`;
|
||||||
textMeasure = mapctx.measureText(marker.name);
|
textMeasure = mapctx.measureText(marker.name);
|
||||||
tempMeasure.width = textMeasure.actualBoundingBoxLeft + textMeasure.actualBoundingBoxRight;
|
tempMeasure.width = textMeasure.actualBoundingBoxLeft + textMeasure.actualBoundingBoxRight;
|
||||||
tempMeasure.height = textMeasure.fontBoundingBoxAscent + textMeasure.fontBoundingBoxDescent;
|
tempMeasure.height = textMeasure.fontBoundingBoxAscent + textMeasure.fontBoundingBoxDescent;
|
||||||
if(!marker.tooltipHitzone){
|
if(!marker.tooltipHitzone){
|
||||||
marker.tooltipHitzone = {
|
marker.tooltipHitzone = {
|
||||||
width: tempMeasure.width + 20,
|
width: (tempMeasure.width + 20)/MapData.view.pixelRatio,
|
||||||
height: tempMeasure.height + 8,
|
height: (tempMeasure.height + 8)/MapData.view.pixelRatio,
|
||||||
offsetY: -tempMeasure.height * 0.5 + 3,
|
offsetY: (-tempMeasure.height * 0.5 + 3)/MapData.view.pixelRatio,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
mapctx.beginPath();
|
mapctx.beginPath();
|
||||||
mapctx.moveTo(markerX, markerY);
|
mapctx.moveTo(markerX, markerY);
|
||||||
mapctx.roundRect(markerX - 0.5*tempMeasure.width - 4, markerY - textMeasure.fontBoundingBoxDescent + 1, tempMeasure.width + 12, tempMeasure.height - 4, 3);
|
mapctx.roundRect(markerX - 0.5*tempMeasure.width - 4*MapData.view.pixelRatio, markerY - textMeasure.fontBoundingBoxDescent + 1*MapData.view.pixelRatio, tempMeasure.width + 12*MapData.view.pixelRatio, tempMeasure.height - 4*MapData.view.pixelRatio, 3*MapData.view.pixelRatio);
|
||||||
mapctx.fill();
|
mapctx.fill();
|
||||||
mapctx.stroke();
|
mapctx.stroke();
|
||||||
mapctx.fillStyle = '#000';
|
mapctx.fillStyle = '#000';
|
||||||
@@ -438,7 +439,7 @@ function redrawMap(){
|
|||||||
marker.tooltipHitzone.radius = marker.radius * MapData.view.scale;
|
marker.tooltipHitzone.radius = marker.radius * MapData.view.scale;
|
||||||
mapctx.beginPath();
|
mapctx.beginPath();
|
||||||
mapctx.moveTo(markerX, markerY);
|
mapctx.moveTo(markerX, markerY);
|
||||||
mapctx.arc(markerX, markerY, marker.radius*MapData.view.scale, 0, Math.PI*2);
|
mapctx.arc(markerX, markerY, marker.radius*MapData.view.scale*MapData.view.pixelRatio, 0, Math.PI*2);
|
||||||
mapctx.fillStyle = '#894b35';
|
mapctx.fillStyle = '#894b35';
|
||||||
mapctx.globalAlpha = 0.65;
|
mapctx.globalAlpha = 0.65;
|
||||||
mapctx.fill();
|
mapctx.fill();
|
||||||
@@ -458,10 +459,10 @@ function redrawMap(){
|
|||||||
curSprite.y,
|
curSprite.y,
|
||||||
curSprite.width,
|
curSprite.width,
|
||||||
curSprite.height,
|
curSprite.height,
|
||||||
markerX-(0.5*spriteSize),
|
markerX-(0.5*spriteSize)*MapData.view.pixelRatio,
|
||||||
markerY-(0.5*spriteSize),
|
markerY-(0.5*spriteSize)*MapData.view.pixelRatio,
|
||||||
spriteSize,
|
spriteSize*MapData.view.pixelRatio,
|
||||||
spriteSize
|
spriteSize*MapData.view.pixelRatio
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -46,8 +46,9 @@ export let view = {
|
|||||||
const mapContainer = document.getElementById('mapContainer');
|
const mapContainer = document.getElementById('mapContainer');
|
||||||
let isLandscape = mapContainer.clientWidth > mapContainer.clientHeight;
|
let isLandscape = mapContainer.clientWidth > mapContainer.clientHeight;
|
||||||
view.scale = Math.min(mapContainer.clientWidth/(matrix.width + Config.defaultMapPadding*2), mapContainer.clientHeight/(matrix.height + Config.defaultMapPadding*2));
|
view.scale = Math.min(mapContainer.clientWidth/(matrix.width + Config.defaultMapPadding*2), mapContainer.clientHeight/(matrix.height + Config.defaultMapPadding*2));
|
||||||
|
view.pixelRatio = window.devicePixelRatio;
|
||||||
if(isLandscape){
|
if(isLandscape){
|
||||||
view.x = mapContainer.clientWidth*0.6 - (matrix.width * 0.5 + matrix.minX)*view.scale;
|
view.x = (mapContainer.clientWidth*0.6 - (matrix.width * 0.5 + matrix.minX)*view.scale);
|
||||||
view.y = (matrix.minY - Config.defaultMapPadding) * view.scale;
|
view.y = (matrix.minY - Config.defaultMapPadding) * view.scale;
|
||||||
}else{
|
}else{
|
||||||
view.x = -(matrix.minX - Config.defaultMapPadding) * view.scale;
|
view.x = -(matrix.minX - Config.defaultMapPadding) * view.scale;
|
||||||
@@ -56,10 +57,10 @@ export let view = {
|
|||||||
view.dirty = false;
|
view.dirty = false;
|
||||||
|
|
||||||
view.convertX = x => {
|
view.convertX = x => {
|
||||||
return x * view.scale + view.x;
|
return x * view.scale * view.pixelRatio + view.x * view.pixelRatio;
|
||||||
}
|
}
|
||||||
view.convertY = y => {
|
view.convertY = y => {
|
||||||
return (matrix.minY+matrix.maxY-y) * view.scale - view.y;
|
return (matrix.minY+matrix.maxY-y) * view.scale * view.pixelRatio - view.y * view.pixelRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
view.unconvertX = x => {
|
view.unconvertX = x => {
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ export const gradeIncrements = [
|
|||||||
0.001
|
0.001
|
||||||
];
|
];
|
||||||
|
|
||||||
const gradeArrowDimensions = 64;
|
const gradeArrowDimensions = 64 * window.devicePixelRatio;
|
||||||
export const gradeArrows = new OffscreenCanvas(11*gradeArrowDimensions, 2*gradeArrowDimensions);
|
export const gradeArrows = new OffscreenCanvas(11*gradeArrowDimensions, 2*gradeArrowDimensions);
|
||||||
|
|
||||||
export function generateGradeArrows(){
|
export function generateGradeArrows(){
|
||||||
|
|||||||
Reference in new issue
Block a user