0

I made a js High DPI Canvas. But if I make window smaller (browser window, because it calculates from browser window, not in chrome dev tool) - it is going out of initial width and height that I set, it changes its width and height so do not see left or\and down borders. How could I do high DPI flexible canvas that can fit smaller sizes without losing part of the canvas?

 // get pixel ratio
var PIXEL_RATIO = function () {
  var ctx = document.createElement("canvas").getContext("2d");
  var dpr = window.devicePixelRatio || 1;
  var bsr = ctx.webkitBackingStorePixelRatio ||
            ctx.mozBackingStorePixelRatio ||
            ctx.msBackingStorePixelRatio ||
            ctx.oBackingStorePixelRatio ||
            ctx.backingStorePixelRatio || 1;

  return dpr / bsr;
};

// create such a canvas that is not blured on any display size  
var createHiDPICanvas = function(w, h, ratio) {
  if (!ratio) { ratio = PIXEL_RATIO(); }
  var chart_container = document.getElementById("lifespan-chart-content");
  var can = document.createElement("canvas");
  can.width = w * ratio;
  can.height = h * ratio;
  can.style.width = w + "px";
  can.style.height = h + "px";
  can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
  chart_container.appendChild(can);
  return can;
}

// height and width of the canvas
var w    = 500; // should be flexible
var h    = 320;  // should be constant
var text = "Center";
var font = "18px Arial"
var border_width = 50;

//Create canvas & context
canvas = createHiDPICanvas(w, h);
ctx = canvas.getContext("2d");

// create a text
var middle = {x : canvas.width/2, y : canvas.height/2};
var text_width = ctx.measureText(text).width;
ctx.font = font;
ctx.moveTo(middle.x, middle.y);
ctx.fillText("Center", middle.x - text_width / 2, middle.y);

// create left and down borders
createBorders(border_width);

function createBorders(border_width) {
  ctx.save();
  var canv_height = canvas.height;
  var canv_width = canvas.width;
  ctx.moveTo(0,0);
  ctx.lineTo(border_width, 0);
  ctx.lineTo(border_width, canv_height - border_width);
  ctx.lineTo(canv_width, canv_height - border_width);
  ctx.lineTo(canv_width, canv_height);
  ctx.lineTo(0, canv_height);
  ctx.lineTo(0, 0);
  ctx.fill = "black";
  ctx.stroke();
  ctx.restore();
}
canvas {
    background-color:bisque;
}
#lifespan-chart {
    display: flex;
    justify-content: center;
}
#lifespan-chart-content {
    overflow: scroll;
}
<div id="lifespan-chart">
    <div id="lifespan-chart-content"></div>
</div>

PS Ok. Added overflow:scroll; on the container with canvas, now only left part is visible. If user wants he can scroll right, but is there any ways to make left side visible in this case and right overflow hidden without X scrolling (if there is no answer on my question)?

EDIT 1

Answer to my PS question: I needed to add overflow:hidden, it will not show the central part of the canvas if size is smaller. It will start with the left part and hide right part. Taking into account that user is able (in real project canvas) to scroll canvas - it can move right and see all the hidden objects

But this is not the answer on the main proportionally flexible canvas question

WhoAmI
  • 623
  • 5
  • 16

1 Answers1

1

I think you need to use the ratio pretty much everywhere, example:

// get pixel ratio
var PIXEL_RATIO = function () {
  var ctx = document.createElement("canvas").getContext("2d");
  var dpr = window.devicePixelRatio || 1;
  var bsr = ctx.webkitBackingStorePixelRatio ||
            ctx.mozBackingStorePixelRatio ||
            ctx.msBackingStorePixelRatio ||
            ctx.oBackingStorePixelRatio ||
            ctx.backingStorePixelRatio || 1;

  return dpr / bsr;
};

// create such a canvas that is not blured on any display size  
var createHiDPICanvas = function(w, h, ratio) {
  var chart_container = document.getElementById("lifespan-chart-content");
  var can = document.createElement("canvas");
  can.width = w * ratio;
  can.height = h * ratio;
  can.style.width = w + "px";
  can.style.height = h + "px";
  can.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
  chart_container.appendChild(can);
  return can;
}

// height and width of the canvas
var w    = 500; // should be flexible
var h    = 320;  // should be constant
var text = "Center";
var font = "18px Arial"
var border_width = 50;
var ratio = PIXEL_RATIO();

//Create canvas & context
canvas = createHiDPICanvas(w, h, ratio);
ctx = canvas.getContext("2d");

// create a text
var middle = {x : canvas.width / ratio / 2, y : canvas.height / ratio / 2};
var text_width = ctx.measureText(text).width / ratio;
ctx.font = font;
ctx.moveTo(middle.x, middle.y);
ctx.fillText("Center", middle.x - text_width / 2, middle.y);

// create left and down borders
createBorders(border_width);

function createBorders(border_width) {
  ctx.save();
  var canv_height = canvas.height / ratio;
  var canv_width = canvas.width / ratio;
  ctx.moveTo(0,0);
  ctx.lineTo(border_width, 0);
  ctx.lineTo(border_width, canv_height - border_width);
  ctx.lineTo(canv_width, canv_height - border_width);
  ctx.lineTo(canv_width, canv_height);
  ctx.lineTo(0, canv_height);
  ctx.lineTo(0, 0);
  ctx.fill = "black";
  ctx.stroke();
  ctx.restore();
}
Andrea Giammarchi
  • 3,038
  • 15
  • 25
  • I made a little different but giving same result solution : I save my initial canvas sizes in global dict and everywhere I used `canvas.height` or `canvas.width` now I use `initialCanvSize.height`, `initialCanvSize.width`, but as your idea gives same result - I will tick it as an answer, Thank you for alternative solution. – WhoAmI Aug 18 '20 at 12:30
  • 1
    fair ... basically it's about `setTransform` ... if you use it, all coordinates should follow just width and height, those defined as pixels, otherwise you gotta transform everything accordingly with the ratio you've used. thanks for flagging it as answer though – Andrea Giammarchi Aug 18 '20 at 12:40