Unable to add new canvas element with an existing one - javascript

I am using 2 canvas elements. I am using one element as a main canvas element which has all the elements. I am generating a barcode in a separate canvas and would like to add it to the main canvas. Trying for a long time. Adding an example here fiddle
$(document).ready(function() {
JsBarcode('#barcode', "1234", {
width: 4,
height: 20//displayValue: false
});
var bc = document.getElementById("barcode");
var canvasx = bc.getContext("2d");
var img1 = new Image();
img1.src = bc.toDataURL("image/png");
var c = document.getElementById("labelDesigner");
var canvas = bc.getContext("2d");
c.drawImage(img1);
});
I am using facric.js and JsBarcode. Thanks for the help in advance. If there is any other better way kindly suggest

you can use fabric.Image.fromURL and pass the barcode canvas data as url.
DEMO
$(document).ready(function() {
JsBarcode('#barcode', "1234", {
width: 4,
height: 20 //displayValue: false
});
var canvas = new fabric.Canvas("labelDesigner");
var bc = document.getElementById("barcode");
fabric.Image.fromURL(bc.toDataURL(),function(img){
img.set({
left: 0,
top: 0
})
canvas.add(img);
})
});
canvas[id^=c], div[id=output] {
border: 1px solid red;
}
canvas[id=buffer] {
border: 1px dotted green;
}
#output {
padding: 15px;
}
#output img {
border: 1px dotted blue;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsbarcode/3.9.0/JsBarcode.all.min.js"></script>
<canvas id="barcode"></canvas>
<canvas id="labelDesigner" width="410" height="200" style="border:1px solid #000000;margin-left:200px"></canvas>

The drawImage-function can take another canvas as an argument, so you do not have to convert to an image inbetween. However, it always requires the x and y coordinates as the second and third parameters.
You had also swapped your c and canvas variables:
$(document).ready(function() {
JsBarcode('#barcode', "1234", {
width: 4,
height: 20//displayValue: false
});
var bc = document.getElementById("barcode");
var c = document.getElementById("labelDesigner");
var context = c.getContext("2d");
context.drawImage(bc, 0, 0);
});

Related

Adding Text on the selected canvas in Fabric js

I have fabric js multiple canvases and I would like to add Text on the selected canvas, instead of the last item of the array.
If a user creates multiple canvases then I need an option to add the text on the selected canvas.
Please run the code snippet or see the codepen demo of the current approach...
Thank you!
//================== Create Canvas start =================
var createCanvas = document.getElementById("createCanvas");
var canvasInstances = [];
createCanvas.addEventListener('click',function(){
var canvasContainer = document.getElementById("canvasContainer");
var newcanvas = document.createElement("canvas");
//newcanvas.classList.add("active");
canvasContainer.append(newcanvas);
var fabricCanvasObj = new fabric.Canvas(newcanvas, {
height: 400,
width: 400,
backgroundColor: '#ffffff',
});
canvasInstances.push(fabricCanvasObj);
console.log(canvasInstances);
})
//================== Create Canvas End =================
//================== Add Text ================
var addText = document.getElementById("addText");
addText.addEventListener('click',function(){
canvasInstances.forEach(function(current,id,array){
if(id === array.length - 1){
const converText = new fabric.IText(`Type Text`,{
type: 'text',
width: 200,
fontSize: 20,
left: 20,
top: 20,
fill: '#444'
});
current.add(converText);
current.renderAll();
return false;
}
})
})
//================== Add End =================
*{
box-sizing: border-box;
}
body{
background:#ccc;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 200px;
}
.canvas-container{
margin-bottom:10px;
}
.add-text{
margin: 20px;
width: 400px;
text-align: center;
border:1px dashed red;
padding: 15px;
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>
<div class="add-text" id="addText">Add Text</div>
<div id="canvasContainer">
</div>
<button id="createCanvas">Create Canvas</button>
Declare canvasobject globally, you can try below code
<script type="text/javascript">
var canvasobject;
window.onload = function () {
canvasobject = new fabric.Canvas('myCanvas');
canvasobject.backgroundColor = '#0056d6';
canvasobject.renderAll();
//
function addtext() {
var textvalue = "Type here";
var fontcolor = "#333";
var fontFamily = "Baloo 2";
var myfont = new FontFaceObserver(fontFamily);
myfont.load()
.then(function () {
// when font is loaded, use it.
var text = new fabric.Text(textvalue, {
left: 100,
top: 100,
fontFamily: fontFamily,
fill: fontcolor,
});
canvasobject.add(text);
canvasobject.renderAll();
}).catch(function (e) {
//console.log(e);
console.log('font loading failed ' + fontFamily);
});
}
}

How to pan in PaperJS without using PaperScript

Referring to
How to pan using paperjs
I was trying to implement the pan.
This however only works for me when I use PaperScript and stops to work when I do it in regular JavaScript.
var canvas = document.querySelector('#myCanvas');
paper.install(window);
window.onload = function() {
paper.setup(canvas);
var myCircle = new Path.Circle(new Point(100, 70), 50);
myCircle.fillColor = 'black';
var toolPan = new paper.Tool();
toolPan.onMouseDrag = function (event) {
var offset = event.downPoint - event.point;
// console.log(offset);
paper.view.center = paper.view.center + offset;
};
view.draw();
}
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
canvas[resize] {
width: 100%;
height: 100%;
}
<canvas id="myCanvas" resize></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.11/paper-full.min.js"></script>
Logging out offset to the console tells me it can’t substract the points. In PaperScript the exact same works well, however I have to make it work in regular JavaScript for my Project.
In PaperScript, you can use mathematical operators on Point instances but you can't do this in JavaScript so you have to use the corresponding methods instead.
point1 + point2 => point1.add(point2), etc...
Here is the corrected code:
var canvas = document.querySelector('#myCanvas');
paper.install(window);
window.onload = function() {
paper.setup(canvas);
var myCircle = new Path.Circle(new Point(100, 70), 50);
myCircle.fillColor = 'black';
var toolPan = new paper.Tool();
toolPan.onMouseDrag = function (event) {
var offset = event.downPoint.subtract(event.point);
// console.log(offset);
paper.view.center = paper.view.center.add(offset);
};
view.draw();
}
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
canvas[resize] {
width: 100%;
height: 100%;
}
<canvas id="myCanvas" resize></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.11/paper-full.min.js"></script>

How to display another canvas without zoom in fabricjs

In short, I am developing a project in which there are two canvases: a canvas that supports zoom and drawing, a second canvas - a duplicate of the first canvas, which should display a general view without zoom. Unfortunately, I do not understand how to implement this, since the second canvas also displays a picture with a zoom. Please, help!
Here is a small example of what I have:
var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");
var canvas = this.__canvas = new fabric.Canvas(c1, {
isDrawingMode: true
});
var ctx1 = c1.getContext("2d");
var ctx2 = c2.getContext("2d");
function copy() {
var imgData = ctx1.getImageData(0, 0, 512, 512);
ctx2.putImageData(imgData, 0, 0);
}
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
},
{
crossOrigin: "Annoymous"
}
);
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom + delta/200;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
setInterval(() => {
copy();
}, 10)
canvas {
border: 1px solid black;
}
#static {
position: relative;
top: -300px;
left: 500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"> </script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static"width="300" height="300"></canvas>
There is not a perfect solution because fabricJS does not support rendering on more targets.
There is a toCanvasElement method here that creates a copy to another canvas, but it does not let you specify the canvas you want to draw on.
So here what i m doing is, at some point:
reset the zoom to 1
render to a new canvas
put back the zoom to what it was
copy that canvas on the static canvas
There is an extra copy, that is fast on modern hardware, to the point that you do not care, but would be nicer to add a canvas argument to that toCanvasElement method in order to get the drawing happening on the specified canvas immediately
Then apart from that there is the quesiton on when firing that copy.
'after:render' is not a great idea, it will loop forever and it will also redraw on zoom changes, that is not what you want.
For now i use object:added, you can add also object:modified, and maybe something else but ideally you will call a copy manually when needed when you run some code that will change some of the drawing properties.
var c1 = document.getElementById("scale");
var c2 = document.getElementById("static");
var canvas = this.__canvas = new fabric.Canvas(c1, {
isDrawingMode: true
});
var ctx2 = c2.getContext("2d");
function copy(copiedCanvas) {
ctx2.drawImage(copiedCanvas,0,0);
}
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
},
{
crossOrigin: "Annoymous"
}
);
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom + delta/200;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
function afterRender() {
var originalVP = canvas.viewportTransform;
canvas.viewportTransform = [1, 0, 0, 1, 0, 0];
copy(canvas.toCanvasElement());
canvas.viewportTransform = originalVP;
}
canvas.on('object:added', afterRender);
canvas.on('object:modified', afterRender);
canvas {
border: 1px solid black;
}
#static {
position: relative;
top: -300px;
left: 500px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js"> </script>
This is interactive canvas
<canvas id="scale" width="300" height="300"></canvas>
<canvas id="static"width="300" height="300"></canvas>
Your issue is that you are getting the "ImageData" from the context
but you should be using the fabric.Canvas object...
The context only gives you what you see, so those two canvases will be a mirror image, you have to get the data from the fabric.Canvas that is the one that has the "big picture" with all the edits.
In my prototype I'm using canvas.toJSON to get the data then to draw that data I use loadFromJSON, but I did notice some flickering the new image is loaded so I decided to use an image instead of the static canvas, that way the transition is seamless
see my simple prototype below:
var c1 = document.getElementById("scale");
var static = document.getElementById("img");
var canvas = new fabric.Canvas(c1, {isDrawingMode: true});
function copy() {
var data = canvas.toObject();
var c = new fabric.Canvas();
c.loadFromJSON(data, function() {
static.src = c.toDataURL({ format: 'png' });
});
}
fabric.Image.fromURL(
"https://cdn-images-1.medium.com/max/1800/1*sg-uLNm73whmdOgKlrQdZA.jpeg",
img => {
img.scaleToWidth(canvas.width);
canvas.setBackgroundImage(img);
canvas.requestRenderAll();
}, { crossOrigin: "anonymous" }
);
canvas.on('mouse:wheel', function(opt) {
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom() + opt.e.deltaY / 200;
if (zoom > 20) zoom = 20;
if (zoom < 0.01) zoom = 0.01;
canvas.zoomToPoint({
x: opt.e.offsetX,
y: opt.e.offsetY
}, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
setInterval(copy, 200)
canvas {
border: 2px solid black;
}
img {
border: 2px solid red;
position: absolute;
top: 5px; right: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.1/fabric.min.js">
</script>
<canvas id="scale" width="300" height="150"></canvas>
<br><img id="img" width="300" height="150">
Unless we get some browser compatibility issue (I only tested chrome), the result should look like:

How to use the same functions on canvases that have different background images on different pages?

I'm using fabric.js to manipulate different canvases with their own dimensions and background images. My problem is that I'm not sure how to continue using the below functions with new canvases with different background images (I'm stuck with one background image). I've tried creating new canvases with the following for example and controlling their backgrounds with CSS but it breaks the app on the second page:
var canvas = new fabric.Canvas('d');
I'm still learning how to work with different canvases so wasn't sure how to handle this. Thanks in advance.
The Details:
Right now I have 2 pages, one with:
<canvas width="500" height="500" id="c"></canvas>
and the other with:
<canvas width="700" height="700" id="c"></canvas>
They're both using this the following JavaScript and CSS:
var canvas = new fabric.Canvas('c');
// Upload image
document.getElementById('file').addEventListener("change", function(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(f) {
var data = f.target.result;
fabric.Image.fromURL(data, function(img) {
//create shadow
var shadow = {
color: '#888888',
blur: 70,
offsetX: 45,
offsetY: 45,
opacity: 0.8
}
var oImg = img.set({
left: 0,
top: 0,
angle: 0,
stroke: '#fffcf7',
strokeWidth: 20
}).scale(1);
oImg.setShadow(shadow); //set shadow
canvas.add(oImg).renderAll();
var dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
});
};
reader.readAsDataURL(file);
});
// Add text
function Addtext() {
canvas.add(new fabric.IText('Tap and Type', {
// left: 0,
// top: 0,
fontFamily: 'helvetica neue',
fill: '#000',
stroke: '#000',
strokeWidth: .2,
fontSize: 45
}));
}
// Delete selected object
window.deleteObject = function() {
var activeGroup = canvas.getActiveGroup();
if (activeGroup) {
var activeObjects = activeGroup.getObjects();
for (let i in activeObjects) {
canvas.remove(activeObjects[i]);
}
canvas.discardActiveGroup();
canvas.renderAll();
} else canvas.getActiveObject().remove();
}
// Send selected object to front or back
var selectedObject;
canvas.on('object:selected', function(event) {
selectedObject = event.target;
});
var sendtoback = function() {
canvas.sendToBack(selectedObject);
}
var sendtofront = function() {
canvas.bringToFront(selectedObject);
}
fabric.Object.prototype.set({
transparentCorners: true,
lockUniScaling: true,
cornerColor: '#22A7F0',
borderColor: '#22A7F0',
cornerSize: 12,
padding: 5
});
#c {
background: url(http://i.imgur.com/RkNFWSY.jpg);
}
.myFile {
position: relative;
overflow: hidden;
float: left;
clear: left;
}
.myFile input[type="file"] {
display: block;
position: absolute;
top: 0;
right: 0;
opacity: 0;
font-size: 30px;
filter: alpha(opacity=0);
}
first
Give your canvas (that is on the second page) a different id , for instance d ...
<canvas width="700" height="700" id="d"></canvas>
second
Initiate your new fabric canvas instance as such ...
var id = document.getElementById('c') && c ||
document.getElementById('d') && d;
var canvas = new fabric.Canvas(id);
this will ensure that the appropriate canvas is present on the page
third
Now, set different background image for each canvas (by their id) in your css, like so ...
#c {
background: url(http://i.imgur.com/RkNFWSY.jpg);
}
#d {
background: url(http://i.imgur.com/GYpod56.jpg);
}

HTML attributes (width, height) of canvas change independently

I have some script on JS, it change width and height of canvas element:
function RefreshSizes (canvas) {
var temp_width = 320;
var temp_height = 240;
document.getElementById(canvas).setAttribute('width', temp_width);
document.getElementById(canvas).setAttribute('height', temp_height);
}
this functions calling right after canvas initializing.
It works fine on Chrome.
But in FireFox 49 I see that:
What could it be?
UPD#1 Tested code of BukkitmanPlays MCPE
UPD#2
Full CSS for canvas:
element {
width: 320px;
height: 240px;
}
.canvas {
border: 3px solid #E0E0E0;
z-index: 0;
position: relative;
}
html {
font: 10px/10px arial;
}
some code on one browser isn't the same on another browser, so in this case, what I would do:
function RefreshSizes (canv) {
var temp_width = 320;
var temp_height = 240;
var canvas = canv;
canvas.width = temp_width;
canvas.height = temp_height;
}
I'm sure this will work

Categories