How to make Temporary Canvas tiles to start drawing from center?

I have created temporary canvas of tiles, which has tiled images of same set with more images, I am drawing these tiles based on the image's size (width and height). I am using context.fillstyle to repeat the patterns. They draw horizontally or vertically and I want to know if there is a way to draw them from center. So the extra tiles drawn on the image will be splited every corners equally. But right now, they are creating extra spaces on the right side and center of the canvas. I actually want those extra spaces of tiles, because they are the correct measuments of tiles on the wall, it means it varies everytime from the user's input. So it needs to draw (repeat) from center and extra tiles goes top, left, right and bottom.

Please find the image here of the canvas with tiles (temporary canvas) Please find the image here of the canvas with tiles (temporary canvas)

canvas.width = canvas_width * 30;
canvas.height = canvas_height * 30;
var tiledCanvas = document.createElement("canvas");
var tCtx = tiledCanvas.getContext("2d");

tiledCanvas.width = size * 30;
tiledCanvas.height = tile_size_height * 30;
tCtx.drawImage(wallimg, 0, 0, wallimg.width, wallimg.height, 0, 0, size * 30, tile_size_height * 30);


// use getContext to use the canvas for drawing
var ctx = canvas.getContext('2d');
ctx.fillStyle = ctx.createPattern(tiledCanvas, 'repeat');
ctx.beginPath();
ctx.rect(0, rectY, 100400, 100400);
ctx.closePath();

Can I make this patterns to start drawing from center on canvas and repeat around all the areas the extra ones?

Upvotes: 1

Views: 386

Answers (1)

codeanjero
codeanjero

Reputation: 694

In order to achieve that you might need some calculations

you need the size of your image (height and width)

the size of your canvas (height and width)

now to find the center you would divide the height and width of you canvas by 2

to draw the first image you would take the image height and width, divide them by 2 also in order to center it(center point minus half of the image)

then you can draw your other images around this first one by substracting the first image minus its height and width and half height, half width to the canvas height and width

and you do so until the image width is superior to the canvas width and same for the height :

let ctx = mycan.getContext('2d');

base_image = new Image();
  base_image.src = 'https://bilious.alt.org/~paxed/nethack/nhsshot/tileset/nethack-3.4.3-16x16.png';
  base_image.onload = function(){
    const canvasCenterx = Math.floor(mycan.width/2);
    const canvasCentery = Math.floor(mycan.height/2);
    const imgcenterxandy = 16/2;
    
    for(let j = canvasCentery;j>=16;j-=16)
      for(let i = canvasCenterx;i>=16;i-=16)
      {
        ctx.drawImage(base_image, 0, 0, 16, 16, i-imgcenterxandy, j-imgcenterxandy, 16, 16);
        ctx.drawImage(base_image, 0, 0, 16, 16, (canvasCenterx+imgcenterxandy) + -(i-(canvasCenterx - imgcenterxandy))-imgcenterxandy, (canvasCentery+imgcenterxandy) + -(j-(canvasCentery - imgcenterxandy))-imgcenterxandy, 16, 16);
        ctx.drawImage(base_image, 0, 0, 16, 16, i-imgcenterxandy, (canvasCentery+imgcenterxandy) + -(j-(canvasCentery - imgcenterxandy))-imgcenterxandy, 16, 16);
        ctx.drawImage(base_image, 0, 0, 16, 16, (canvasCenterx+imgcenterxandy) + -(i-(canvasCenterx - imgcenterxandy))-imgcenterxandy,j-imgcenterxandy, 16, 16);
        }
    
  }
  
  
<canvas id = "mycan" width=300 height=200>
</canvas>

there are other ways of achieving this, you could for instance resize the image and just draw it as usual but you would get anamorphosis which is not very clean.

or just calculate the number of images you could fit in a canvas by dividing the canvas width and height by the image width and height and then adding half of what's left as a left margin :

let ctx = mycan.getContext('2d');

base_image = new Image();
  base_image.src = 'https://bilious.alt.org/~paxed/nethack/nhsshot/tileset/nethack-3.4.3-16x16.png';
  base_image.onload = ()=>{
    
    for(let j = Math.ceil((mycan.height%16)/2);j<=mycan.height-Math.ceil((mycan.height%16)/2);j+=16)
      for(let i =Math.ceil((mycan.width%16)/2);i<=mycan.width-Math.ceil((mycan.height%16)/2);i+=16)
        ctx.drawImage(base_image, 0, 0, 16, 16, i, j, 16, 16);
    
  }
<canvas id=mycan height=250 width = 500></canvas>

you might even want to add some margin between images and this gets more complicated if you want for instance 16px divided by 100 spaces you would be forced to add one px margin to every image in order for it to be proportionnal

let ctx = mycan.getContext('2d');

base_image = new Image();
  base_image.src = 'https://bilious.alt.org/~paxed/nethack/nhsshot/tileset/nethack-3.4.3-16x16.png';
  base_image.onload = ()=>{
    const numberOfImagesDrawnx = Math.floor(mycan.width/16);
    const numberOfImagesDrawny = Math.floor(mycan.height/16);
    const totalMarginx = numberOfImagesDrawnx*(Math.ceil(numberOfImagesDrawnx/(mycan.width%16)));
    const totalMarginy = numberOfImagesDrawny*(Math.ceil(numberOfImagesDrawny/(mycan.height%16)));
    
    for(let j = Math.ceil((mycan.height%16)/2);j<=mycan.height-Math.floor(mycan.height%(16+Math.ceil(numberOfImagesDrawny/(mycan.height%16))));j+=16+Math.ceil(numberOfImagesDrawny/(mycan.height%16)))
      for(let i =Math.ceil((mycan.width%16)/2);i<=mycan.width-Math.floor(mycan.width%(16+Math.ceil(numberOfImagesDrawnx/(mycan.width%16))));i+=16+Math.ceil(numberOfImagesDrawnx/(mycan.width%16)))
      {
        ctx.drawImage(base_image, 0, 0, 16, 16, i, j , 16+Math.ceil(numberOfImagesDrawnx/(mycan.width%16)), 16+ Math.ceil(numberOfImagesDrawny/(mycan.height%16)));
        }
    
  }
<canvas id=mycan width=500 height= 250></canvas>

Upvotes: 0

Related Questions