Maturutuki
Maturutuki

Reputation: 75

Fabric-js patterns: How create pattern for canvas background from Rects without size depending on Zoom and blured Rects

As end target i need to create classic chess like background for canvas to represent 'transparent' background with option to turn it to real transparent and back (in program, no direct user interaction here) - so I'm open on others ways to do it.

At current state i have created more or less correct pattern and have added it to canvas, but also i have two problems with it to fix:

  1. Transition between two Rects and Rects vs background is blurred instead of sharp.
  2. On adding pattern to canvas it is scaled based on page visual size/zoom on page load instead of programmed size of the pattern and canvas. (To check Zoom then run sipped again)

Code:

// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');

const newTransparent = function() {
    const chessStatic = new fabric.StaticCanvas();
    chessStatic.setHeight(10);
    chessStatic.setWidth(10);
    chessStatic.renderAll();
    chessStatic.setBackgroundColor('lightgrey');
    const greyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 0,
      top: 0,
     // fill: 'grey',
      strokeWidth: 0
    });
    greyRect.set('fill', 'rgba(150, 150, 150, 1)')
    const lightGreyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 5,
      top: 5,
     // fill: 'grey',
      strokeWidth: 0
    });
    lightGreyRect.set('fill', 'rgba(187, 187, 187, 1)')
    
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    const greyRect2 = greyRect;
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    chessStatic.calcOffset();
    chessStatic.renderAll();

    const transparentPattern = new fabric.Pattern({
      source: function() {
        return chessStatic.getElement();
      },
      repeat: 'repeat'
    });
    return transparentPattern;
 }

canvas.setBackgroundColor(newTransparent(), canvas.renderAll.bind(canvas));

fabric.util.addListener(document.getElementById('toggle-repeat'), 'click', function () {

    canvas.setBackgroundColor(newTransparent(), canvas.renderAll.bind(canvas));
const lightGreyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 5,
      top: 5,
     // fill: 'grey',
      strokeWidth: 0
    });
    lightGreyRect.set('fill', 'rgba(187, 187, 187, 1)')
    
    canvas.add(lightGreyRect);
    canvas.renderAll();
});

fabric.util.addListener(document.getElementById('toggle-bgcolor'), 'click', function () {
    if (canvas.backgroundColor instanceof fabric.Pattern) {
        canvas.setBackgroundColor('rgba(0, 225, 64, 0.6)', canvas.renderAll.bind(canvas));
    }
    else {
        canvas.setBackgroundColor({source: 'http://fabricjs.com/assets/escheresque_ste.png'}, canvas.renderAll.bind(canvas));        
    }
});
canvas {
    border: 1px solid #999;
}
button {
    margin-top: 20px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>
<button id="toggle-repeat">Toggle repeat</button>
<button id="toggle-bgcolor">Toggle background</button>

Upvotes: 2

Views: 1794

Answers (2)

Maturutuki
Maturutuki

Reputation: 75

Still i have one more problem with this code - rectangles are blurred.

Tips from other posts: strokeWidth: 0, objectCaching: false are done and they are still blurred. Problem exists both in pattern and in free object rectangle.

(It is small blur but it shouldn't be a case with monocolored straight lines).

// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c', { enableRetinaScaling: false });

const newTransparent = function() {
    const chessStatic = new fabric.StaticCanvas(null, { enableRetinaScaling: false });
    chessStatic.setHeight(40);
    chessStatic.setWidth(40);
    chessStatic.renderAll();
    chessStatic.setBackgroundColor('lightgrey');
    const greyRect = new fabric.Rect({
      width: 20,
      height: 20,
      left: 0,
      top: 0,
      fill: 'grey',
      strokeWidth: 0,
      objectCaching: false
    });
    //greyRect.set('fill', 'rgba(150, 150, 150, 1)')
    const lightGreyRect = new fabric.Rect({
      width: 20,
      height: 20,
      left: 20,
      top: 20,
      fill: 'grey',
      strokeWidth: 0,
      objectCaching: false
    });
    //lightGreyRect.set('fill', 'rgba(187, 187, 187, 1)')
    
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    const greyRect2 = greyRect;
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    chessStatic.calcOffset();
    chessStatic.renderAll();

    const transparentPattern = new fabric.Pattern({
      source: function() {
        return chessStatic.getElement();
      },
      repeat: 'repeat'
    });
    return transparentPattern;
 }

canvas.setBackgroundColor(newTransparent(), canvas.renderAll.bind(canvas));
const GreyRect = new fabric.Rect({
      width: 20,
      height: 20,
      left: 20,
      top: 20,
      fill: 'grey',
      strokeWidth: 0,
      objectCaching: false
    });
canvas.add(GreyRect);
canvas.renderAll();
canvas {
    border: 1px solid #999;
}
button {
    margin-top: 20px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Upvotes: 0

AndreaBogazzi
AndreaBogazzi

Reputation: 14731

The page zoom is stored in the same window variable where the ratio between real pixels and virtual pixels is ( retina for macbook and the hidpis for mobile phones ). So when you want to do something that is not affected by the page zoom level, disable retinaScaling and the canvas will stop considering the value of devicepixelratio. Or you can also set it to the lowest integer before initializing your canvas.

fabric.devicePixelRatio = Math.max(Math.floor(fabric.devicePixelRatio), 1);

// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c', { enableRetinaScaling: false });

const newTransparent = function() {
    const chessStatic = new fabric.StaticCanvas(null, { enableRetinaScaling: false });
    chessStatic.setHeight(10);
    chessStatic.setWidth(10);
    chessStatic.renderAll();
    chessStatic.setBackgroundColor('lightgrey');
    const greyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 0,
      top: 0,
     // fill: 'grey',
      strokeWidth: 0
    });
    greyRect.set('fill', 'rgba(150, 150, 150, 1)')
    const lightGreyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 5,
      top: 5,
     // fill: 'grey',
      strokeWidth: 0
    });
    lightGreyRect.set('fill', 'rgba(187, 187, 187, 1)')
    
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    const greyRect2 = greyRect;
    chessStatic.add(greyRect);
    chessStatic.add(lightGreyRect);
    chessStatic.calcOffset();
    chessStatic.renderAll();

    const transparentPattern = new fabric.Pattern({
      source: function() {
        return chessStatic.getElement();
      },
      repeat: 'repeat'
    });
    return transparentPattern;
 }

canvas.setBackgroundColor(newTransparent(), canvas.renderAll.bind(canvas));

fabric.util.addListener(document.getElementById('toggle-repeat'), 'click', function () {

    canvas.setBackgroundColor(newTransparent(), canvas.renderAll.bind(canvas));
const lightGreyRect = new fabric.Rect({
      width: 5,
      height: 5,
      left: 5,
      top: 5,
     // fill: 'grey',
      strokeWidth: 0
    });
    lightGreyRect.set('fill', 'rgba(187, 187, 187, 1)')
    
    canvas.add(lightGreyRect);
    canvas.renderAll();
});

fabric.util.addListener(document.getElementById('toggle-bgcolor'), 'click', function () {
    if (canvas.backgroundColor instanceof fabric.Pattern) {
        canvas.setBackgroundColor('rgba(0, 225, 64, 0.6)', canvas.renderAll.bind(canvas));
    }
    else {
        canvas.setBackgroundColor({source: 'http://fabricjs.com/assets/escheresque_ste.png'}, canvas.renderAll.bind(canvas));        
    }
});
canvas {
    border: 1px solid #999;
}
button {
    margin-top: 20px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>
<button id="toggle-repeat">Toggle repeat</button>
<button id="toggle-bgcolor">Toggle background</button>

Upvotes: 1

Related Questions