fabric.js construct groups on conditions - javascript

I'm trying to create several groups. Each of the group will get a custom attribute to indicate its position. Depending on this attribute I want to set different images as a group members. This part doesn't work and I cannot figure it out. image header.png is added twice and shows in content-footer area. in the header area there is no image at all.
Also when I try to log the output
console.log(JSON.stringify(canvasBuild)
there is no content inside the "objects" property of a group. When I try to log stringified group - it does show the image objects.
This is the simplified code so far
var hasHeader = false;
var hasFooter = false;
// users choice of layout
var customPosition = [];
$(this).siblings('.layoutOptions').children('input:checked').each(function(i)
{
customPosition[i] = $(this).val();
if ( customPosition[i]=='content-header'){
hasHeader = true;
}else if (customPosition[i]=='content-footer'){
hasFooter = true;
}
});
$(this).siblings('.contentOptions').children('input:checked').val();
for (i = 0; i< customPosition.length; i++){
console.log(i);
console.log(customPosition[i]);
var canvField = (canvasBHeight - shadowBVal*2) - strokeBWidth*2;
if (customPosition[i] == 'content-header'){
//header positioning
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: '#ccc',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
//height: canvasBHeight/5 - strokeBWidth,
height: canvField/5,
top: strokeBWidth,
ry: 0,
rx: 20,
//originX: 'center',
//originY: 'center'
});
//add dummy content
fabric.Image.fromURL('image/bordenconfigurator/dummies/header.png', function(oImg) {
oImg.set({
});
group.add(oImg);
console.log('group '+i+' '+customPosition[i]+':');
console.log(JSON.stringify(group));
//console.log(group);
});
}else if(customPosition[i] == 'content-footer') {
console.log(customPosition[i]);
//footer positioning
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: '#ccc',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
//height: canvasBHeight/5 - strokeBWidth,
height: canvField/5,
top: strokeBWidth + canvField*4/5 + 10,
ry: 0,
rx: 20,
//originX: 'center',
//originY: 'center'
});
//add dummy content
fabric.Image.fromURL('image/bordenconfigurator/dummies/footer.png', function(oImg) {
oImg.set({
top: canvasBHeight- strokeBWidth-shadowBVal,
});
group.add(oImg);
canvasBuild.centerObjectH(oImg);
console.log('group '+i+' '+customPosition[i]+':');
console.log(JSON.stringify(group));
});
}else{
console.log(customPosition[i]);
//body positioning
var height,top;
if (hasHeader === true && hasFooter === true){
height = canvField*3/5 + 5;
top = strokeBWidth + canvField/5 + 5;
}else if(hasHeader ===true && hasFooter === false){
height = canvField*4/5 + 5;
top = strokeBWidth + canvField/5 + 5;
}else if(hasHeader ===false && hasFooter === true){
height = canvField*4/5;
top = strokeBWidth + 5;
}
var group = new fabric.Group([],{
left: strokeBWidth + 10,
stroke: '#ddd',
strokeLineJoin: 'round',
strokeWidth: 2,
hasControls: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
selectable: true,
position: posB,
fill: 'rgba(255,255,255,0)',
width: ((canvasBWidth - shadowBVal*2) - strokeBWidth*2 - 10),
height: height,
//top: strokeBWidth + canvField/5 + 5,
top: top,
ry: 20,
rx: 20
});
}
group.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
customPosition: this.customPosition,
label: this.label,
id: this.id
});
};
})(group.toObject);
group.customPosition = customPosition[i];
group.id = posB;
canvasBuild.add(group);
group.length = 0;
posB++;
}
//addOrientationLines();
//canvasBuild.renderAll();
//console.log(JSON.stringify(canvasBuild));
});

Related

Resizing rectangle based on user input

I am trying to resize a rectangle based on the user input, but i get an error saying: Cannot read property 'addEventListener' of null. Do i need to change something in the HTML? I tried moving the script below the body but it didn't work. Seems like everything is alright but it doesn't work.
https://jsfiddle.net/sbLk9zvd/2/
var rect = new fabric.Rect({
fill: "red",
width: 300,
height: 400,
stroke: "gray",
strokeWidth: 30,
fill: "lightgray",
centeredRotation: true,
centeredScaling: true,
});
canvas.add(rect);
var Length = document.getElementById("Length");
var Width = document.getElementById("Width");
Length.addEventListener("input", Modify_Length);
Width.addEventListener("input", Modify_Width);
function Modify_Length() {
var rect = new fabric.Rect({
fill: "red",
width: parseFloat(Width.value) || 300,
height: 400 || parseFloat(Length.value),
stroke: "gray",
strokeWidth: 30,
fill: "lightgray",
centeredRotation: true,
centeredScaling: true,
});
}
function Modify_Width() {
var rect = new fabric.Rect({
fill: "red",
width: parseFloat(Width.value) || 300,
height: parseFloat(Length.value) || 400,
stroke: "gray",
strokeWidth: 30,
fill: "lightgray",
centeredRotation: true,
centeredScaling: true,
});
}
canvas.renderAll();
There is no need for a separate listener for each element. Just share a single callback function. Also, don't forget to rerender.
const canvas = new fabric.Canvas("c");
const rect = new fabric.Rect({
fill: "red",
width: 200,
height: 80,
stroke: "gray",
strokeWidth: 1,
fill: "lightgray",
centeredRotation: true,
centeredScaling: true,
});
canvas.on("object:scaling", function() {
var obj = canvas.getActiveObject(),
width = obj.width,
height = obj.height,
scaleX = obj.scaleX,
scaleY = obj.scaleY;
obj.set({
width: width * scaleX,
height: height * scaleY,
scaleX: 1,
scaleY: 1,
});
});
rect.setControlsVisibility({
mt: false,
mb: false,
ml: false,
mr: false,
bl: false,
br: false,
tl: false,
tr: false,
mtr: false,
});
canvas.add(rect);
canvas.centerObject(rect);
canvas.setActiveObject(rect);
canvas.item(0).lockMovementX = true;
canvas.item(0).lockMovementY = true;
const width = document.getElementById('width');
const height = document.getElementById('height');
const adjust = (e) => {
Object.assign(rect, {
width: parseFloat(width.value) || 300,
height: parseFloat(height.value) || 400,
});
canvas.renderAll();
};
width.addEventListener('input', adjust);
height.addEventListener('input', adjust);
canvas.renderAll();
label, input {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/451/fabric.min.js"></script>
<canvas id="c" width="250" height="120"></canvas>
<div id="user-input">
<label for="width">Width:</label>
<input type="number" id="width" name="width" value="200" />
<label for="height">Height:</label>
<input type="number" id="height" name="height" value="80" />
</div>

Fabric.js svg elements to pop up on click to be edited and then return to its previous size/position

I am developing an app in html5 and I'm using fabric.js to manipulate some graphics. I need to make some of the paths to pop up when clicked in order to be edited on a closer view as their real size is quite small and the app will be display on mobile screens. This is what I have done until now:
canvas = new fabric.Canvas('c', { preserveObjectStacking: true });
canvas.selection = false;
fabric.Object.prototype.borderColor = 'transparent';
fabric.Object.prototype.cornerColor = '#d50000';
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.cornerStyle = 'circle';
canvas.hoverCursor = 'pointer';
// delete icon
var deleteIcon = "data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Cpath style='fill:%23d50000;' d='m 146.8759,307.20476 38.95015,0 114.10246,100.31923 114.10245,-100.31923 38.95016,0 -120.53144,131.86736 120.53144,131.86889 -38.95016,0 -114.10245,-100.31924 -114.10246,100.31924 -38.95015,0 L 267.29322,439.07212 146.8759,307.20476 Z'/%3E%3C/svg%3E";
var img = document.createElement('img');
img.src = deleteIcon;
fabric.Object.prototype.controls.deleteControl = new fabric.Control({
x: 0.5,
y: -0.5,
offsetY: 76,
offsetX: -15,
cursorStyle: 'pointer',
mouseUpHandler: deleteObject,
render: renderIcon,
cornerSize: 24
});
function deleteObject(eventData, transform) {
var target = transform.target;
var canvas = target.canvas;
canvas.remove(target);
canvas.requestRenderAll();
}
function renderIcon(ctx, left, top, styleOverride, fabricObject) {
var size = this.cornerSize;
ctx.save();
ctx.translate(left, top);
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
ctx.drawImage(img, -size/2, -size/2, size, size);
ctx.restore();
}
// bg
canvas.backgroundColor= "#ccc";
//* 31
var v31 = new fabric.Path('m 305.16587,542.07107 9.80091,-0.98571 7.18636,10.09881 c -5.31084,6.69609 -15.03687,7.83521 -21.68907,2.48023 z');
v31.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1});
canvas.add(v31);
v31.set('selectable', false);
p31 = new fabric.Path('m 305.16587,542.07107 -4.70183,11.59335 c -6.69611,-5.31031 -7.83714,-15.03769 -2.48451,-21.69214 z');
p31.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(p31);
p31.set('selectable', false);
var l31 = new fabric.Path('m 314.96678,541.08536 -9.80091,0.98571 -7.31191,-9.93775 c 5.22415,-6.76398 14.93463,-8.02848 21.6553,-2.7598 z');
l31.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(l31);
l31.set('selectable', false);
var d31 = new fabric.Path('m 314.96678,541.08536 4.70184,-11.59338 c 6.6961,5.31032 7.83714,15.0377 2.48451,21.69215 z');
d31.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(d31);
d31.set('selectable', false);
var group31 = new fabric.Group([ v31, l31, p31, d31 ], {left: 210, top: 386, opacity: 1});
// 41
var v41 = new fabric.Path('m 265.11576,542.24785 -9.80091,-0.98571 -7.18636,10.09881 c 5.31083,6.69609 15.03687,7.83521 21.68907,2.48023 z');
v41.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1});
canvas.add(v41);
v41.set('selectable', false);
var p41 = new fabric.Path('m 265.11576,542.24785 4.70182,11.59335 c 6.69612,-5.31031 7.83715,-15.03769 2.48452,-21.69214 z');
p41.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(p41);
p41.set('selectable', false);
var l41 = new fabric.Path('m 255.31485,541.26214 9.80091,0.98571 7.31191,-9.93775 c -5.22416,-6.76398 -14.93462,-8.02848 -21.6553,-2.7598 z');
l41.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(l41);
l41.set('selectable', false);
var d41 = new fabric.Path('m 255.31485,541.26214 -4.70184,-11.59337 c -6.6961,5.31032 -7.83715,15.03769 -2.48451,21.69214 z');
d41.set({fill: '#fff', stroke: '#1a1a1a', strokeWidth: 1.5, opacity: 1 });
canvas.add(d41);
d41.set('selectable', false);
var group41 = new fabric.Group([ v41, l41, p41, d41 ], {left: 173.5, top: 386, opacity: 1});
// create grid
function createGrid() {
canvas.add(new fabric.Path('m 0,49.54498 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,56.08866 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,68.942311 416,0"', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,87.171121 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,110.7751 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,116.61767 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,126.90059 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,137.88462 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,146.08928 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,168.96708 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,172.70632 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,203.08768 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,205.191 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,246.08898 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,247.7249 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,278.57366 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,281.3781 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,304.98207 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,313.39537 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,324.1457 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,334.42862 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,340.50489 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,363.40776 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,382.10398 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,395.19133 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 0,401.73501 416,0', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 32.485,0 -3.19e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 39.963,0 1.69e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 54.453,0 -2.61e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 73.383,0 -3.39e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 97.454,0 4.3e-5,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 99.557,0 3.68e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 111.009,0 -2e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 125.498,0 3.7e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 131.341,0 -6e-5,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 156.581,0 -1.6e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 158.45,0 4.6e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 190,0 3.3e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 225.991,0 -4.5e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 257.54,0 4.2e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 259.17583,0 3.4e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 284.65,0 -6e-5,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 290.726,0 2.1e-4,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 304.74837,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 316.43351,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 318.77054,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 343.07562,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 361.77184,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 376.02771,0 0,441.23077', { opacity: '0', selectable: false }));
canvas.add(new fabric.Path('m 383.7399,0 0,441.23077', { opacity: '0', selectable: false }));
}
// call this to actually create grids
createGrid();
// menu
var redbtn = new fabric.Path('m 536.95273,607.72242 c 10e-6,9.21831 -7.47292,16.69124 -16.69123,16.69123 -9.21831,1e-5 -16.69123,-7.47292 -16.69123,-16.69123 2e-5,-9.2183 7.47293,-16.6912 16.69123,-16.6912 9.2183,0 16.69123,7.4729 16.69123,16.6912 z');
redbtn.set({fill: '#d50000', stroke: '#1a1a1a', strokeWidth: 2, opacity: 1, left:363, top:454, hoverCursor: 'pointer' });
canvas.add(redbtn);
redbtn.set('selectable', false);
var badrbtn = new fabric.Path('m 444.06184,672.53045 c -1.15491,3.93506 1.09854,8.06136 5.03317,9.21638 3.93466,1.15501 8.06055,-1.09864 9.21545,-5.0337 1.1549,-3.93505 -1.09853,-8.06135 -5.03318,-9.21637 -3.93466,-1.15501 -8.06054,1.09865 -9.21544,5.03369 z m -0.38452,1.80161 c 0.008,4.13284 3.325,7.52008 7.4597,7.56212 l -0.0905,9.21705 c -9.21992,-0.11093 -16.61428,-7.65898 -16.43826,-16.87185 z m 7.56106,7.70446 c 4.13199,-0.0601 7.47657,-3.4204 7.46616,-7.55577 l 9.21652,-0.0262 c 0.006,9.22152 -7.44695,16.71174 -16.66036,16.65255 z m 7.61272,-7.45432 c -0.008,-4.13282 -3.32498,-7.52008 -7.45971,-7.56213 l 0.0905,-9.21704 c 9.21993,0.11092 16.61428,7.65899 16.43826,16.87186 z m -7.46384,-7.70858 c -4.13241,0.006 -7.52004,3.32371 -7.56298,7.45881 l -9.21608,-0.0931 c 0.11285,-9.22081 7.66177,-16.61429 16.87371,-16.43626 z');
badrbtn.set({fill: '#007aff', stroke: '#d50000', strokeWidth: 2, opacity: 1, left:315, top:514, hoverCursor: 'pointer' });
canvas.add(badrbtn);
badrbtn.set('selectable', false);
var oligo = new fabric.Path('m 258.83096,607.64956 a 15.904878,15.904878 0 0 1 -15.90488,15.90489 15.904878,15.904878 0 0 1 -15.9049,-15.90489 15.904878,15.904878 0 0 1 15.9049,-15.90488 15.904878,15.904878 0 0 1 15.90488,15.90488 z');
oligo.set({fill: '#fff', stroke: '#0d47a1', strokeWidth: 2, opacity: 1, left:172, top:471, lockRotation: 'true', originX: 'center', originY: 'center'});
canvas.add(oligo);
oligo.setControlsVisibility({ mt: false, mb: false, ml: false, mr: false, bl: false, br: false, tl: false, tr: false, mtr: false, });
var rtnd = new fabric.Path('m 258.6723,674.6758 c 10e-6,8.78402 -7.12086,15.9049 -15.90488,15.9049 -8.78403,10e-6 -15.90491,-7.12087 -15.9049,-15.9049 0,-8.78402 7.12088,-15.90489 15.9049,-15.90488 8.78402,0 15.90488,7.12086 15.90488,15.90488 z');
rtnd.set({fill: '#fff', stroke: '#d50000', strokeWidth: 2, opacity: 1, left:172, top:531, lockRotation: 'true', originX: 'center', originY: 'center'});
canvas.add(rtnd);
rtnd.setControlsVisibility({ mt: false, mb: false, ml: false, mr: false, bl: false, br: false, tl: false, tr: false, mtr: false, });
// snap to grid
canvas.on('object:moving', function(options) {
const horizontalSnappingPoints = options.target.canvas._objects
.filter((el, index) => options.target.canvas._objects
.some((sameTopEl, sameTopElIndex) => sameTopEl.top === el.top && sameTopElIndex !== index)).map(item => item.left);
const verticalSnappingPoints = options.target.canvas._objects
.filter((el, index) => options.target.canvas._objects
.some((sameLeftEl, sameLeftElIndex) => sameLeftEl.left === el.left && sameLeftElIndex !== index)).map(item => item.top)
options.target.set({
left: horizontalSnappingPoints.reduce(function (prev, curr) {
return (Math.abs(curr - options.target.left) < Math.abs(prev - options.target.left) ? curr : prev);
}),
top: verticalSnappingPoints.reduce(function (prev, curr) {
return (Math.abs(curr - options.target.top) < Math.abs(prev - options.target.top) ? curr : prev);
}),
});
});
function saveCanvas(save){
localStorage.setItem("draw", JSON.stringify(canvas.toObject()));
}
if (newCanvas){
var newCanvas = JSON.parse(localStorage.getItem("draw"));
canvas.loadFromJSON()
} else {
canvas = new fabric.Canvas('c', { preserveObjectStacking: true });
canvas.selection = false;
fabric.Object.prototype.borderColor = 'transparent';
fabric.Object.prototype.cornerColor = '#d50000';
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.cornerStyle = 'circle';
canvas.hoverCursor = 'pointer';
}
.controls {
display: flex;justify-content:center;
}
.wrapper {
width:100%;height:auto;
position: relative;
display:flex;
justify-content:center;
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js" type="text/javascript"></script>
</head>
<body>
<div class="wrapper">
<div>
<canvas id="c" width="416" height="570" style="text-align:center;"></canvas>
<div>
<div class="controls">
<button id="save" onClick="saveCanvas()">Save canvas</button>
</div>
</div>
</body>
Then what I need is:
The 4 elements at the bottom will function as helpers or buttons inside the canvas. The red and blue ones should be color pickers where the user will take the fill color and the stroke color with a click/tap and then pass them to one of the areas on the two upper elements. Each area of the upper elements should be colored independet of the rest of the group.
The other two elements at tthe bottom will function as draggable objects which should be placed on top of the upper elements. (this part is working ok)
The upper elements, as there will be many more of them and the app will be displayed on mobile screens, need to be colored using one of the bottom color pickers. But as the tip of a finger is much bigger than the area to tap it will be necessary to make those upper elements to pop up on a triggering action, which should be fired by a mouse click/touch-screen event. Then they will be colored in an easy way.
The elements when pop up should fill the whole superior half of the screen no matter the position they were before, and, after being edited, should be returned to theier initial position by another triggering action (maybe a tiny close button appended to the pop up). The trigering action should be located in the element itself and not in any external button.
I have added the fabric.js serialization and deserialization in order to save the canvas to the localStorage and later retrieve it from it to go on editing. The problem here is that, if I place the JSON.parse(localStorage.getItem("draw")) and the if else at the beginnig, rigth after the canvas initiation the draggable elements stop working, but if I place it at the bottom, then the draggable items still work but theier final position is not saved and when reloaded the canvas is displayed as if the user have not moved/changed anything. Then I need to:
Use the Save button to store only the colored and the dragged elements according to the user's choices and later return them to the exact position, with the exact colors they were saved. I enhanced the word only because, if all the elements are to be saved, it will be and enourmous and unnecesary amount of info to be stored once and again, mainly if we take into account that every user should edit and store a lot of this graphics.
NOTE:There will be a lot of this upper items on the canvas and almost
16 items at the bottom menu. I just placed two of each as a sample.
If someone knows how to solve it, or at least a part of it, I will be very thankfull.

Replacing functions without clearing the whole canvas?

I'm trying to replace text with functions, without clearing all drawn text. Right now I can replace a function but only by clearing the whole canvas. I'd like it to be a little bit more dynamic so that a third function (for example) would remain.
Here's what I've got so far; note how the original text is cleared:
var $ = function(id) {
return document.getElementById(id)
};
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(500);
function textOne() {
canvas.clear();
canvas.add(new fabric.IText('One', {
left: 50,
top: 100,
fontFamily: 'arial',
fill: '#333',
fontSize: 50
}));
}
// Text that should stay
canvas.add(new fabric.IText('This Should Stay The Same\nEdited Or Not', {
left: 300,
top: 45,
fontFamily: 'Monsieur La Doulaise',
fontSize: 27,
hasBorders: false,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
function textTwo() {
canvas.clear();
canvas.add(new fabric.IText('Two', {
left: 200,
top: 100,
fontFamily: 'arial black',
fill: '#333',
fontSize: 50
}));
}
canvas {
border: 1px solid #dddddd;
border-radius: 3px;
margin-top: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<button onclick="textOne()">One</button>
<button onclick="textTwo()">Two</button>
<canvas id="c"></canvas>
Thanks in advance!
You just have to add an empty text inside your canvas and update it inside the corresponding functions. then execute canvas.renderAll after the updates. FYI, I have ZERO experience with fabric.js.
var $ = function(id) {
return document.getElementById(id)
};
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(500);
var dynamicText = new fabric.IText('', {
left: 50,
top: 100,
fontFamily: 'arial',
fill: '#333',
fontSize: 50
})
canvas.add(dynamicText);
function textOne() {
dynamicText.setText('ONE');
canvas.renderAll();
}
// Text that should stay
canvas.add(new fabric.IText('This Should Stay The Same\nEdited Or Not', {
left: 300,
top: 45,
fontFamily: 'Monsieur La Doulaise',
fontSize: 27,
hasBorders: false,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
function textTwo() {
dynamicText.setText('TWO');
canvas.renderAll();
}
canvas {
border: 1px solid #dddddd;
border-radius: 3px;
margin-top: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<button onclick="textOne()">One</button>
<button onclick="textTwo()">Two</button>
<canvas id="c"></canvas>

Modifying Grid Height/Width

I am working on a project that is a world planner/builder for a game that I enjoy. I want to make the grid 100 * 54. I have been messing around with some code on JSFiddle and I can't seem to get what I want. I would like the size of the grid squares to be 16*16
var canvas = new fabric.Canvas('c', {
selection: false
});
var grid = 50;
// create grid
for (var i = 0; i < (600 / grid); i++) {
canvas.add(new fabric.Line([i * grid, 0, i * grid, 600], {
stroke: '#ccc',
selectable: false
}));
canvas.add(new fabric.Line([0, i * grid, 600, i * grid], {
stroke: '#ccc',
selectable: false
}))
}
// add objects
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa',
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
originX: 'left',
originY: 'top',
centeredRotation: true,
hasControls: false
}));
// snap to grid
canvas.on('object:moving', function(options) {
options.target.set({
left: Math.round(options.target.left / grid) * grid,
top: Math.round(options.target.top / grid) * grid
});
});
canvas {
border: 1px solid #ccc;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
The way this works:
Grid is how big your grid will be in pixels.
You need two for loops to indicate how many lines for each.
The for loops generate the grid based on how many loops it goes through. (so 54 means 54 lines.)
The 2000 indicates how long the line will be in pixels.
Working code:
var canvas = new fabric.Canvas('c', {
selection: false
});
var grid = 16;
// create grid
for (var i = 0; i < 100; i++) {
canvas.add(new fabric.Line([i * grid, 0, i * grid, 2000], {
stroke: '#ccc',
selectable: false
})); // horizontal
}
for (var i = 0; i < 54; i++) {
canvas.add(new fabric.Line([0, i * grid, 2000, i * grid], {
stroke: '#ccc',
selectable: false
})); // vertical
}
// add objects
canvas.add(new fabric.Rect({
left: 16,
top: 16,
width: 16,
height: 16,
fill: '#faa',
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
originX: 'left',
originY: 'top',
centeredRotation: true,
hasControls: false
}));
// add objects
canvas.add(new fabric.Rect({
left: 16,
top: 16,
width: 16,
height: 16,
fill: '#faa',
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
originX: 'left',
originY: 'top',
centeredRotation: true,
hasControls: false
}));
// snap to grid
canvas.on('object:moving', function(options) {
options.target.set({
left: Math.round(options.target.left / grid) * grid,
top: Math.round(options.target.top / grid) * grid
});
});
canvas {
border: 1px solid #ccc;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="1600px" height="865px" ></canvas>

Fabric.js : How to set a custom size to Text or IText?

I am using the excellent Fabric.js to draw some text in a canvas. When I specify a custom size ( let's say a 200x200 rectangle) to my IText Object, it seems that Farbric.js force the width and the height of the object to fit around the text.
var t = new fabric.IText("Hello world !", {
top: 100,
left: 100,
width: 200,
height:200,
backgroundColor: '#FFFFFF',
fill: '#000000',
fontSize: 12,
lockScalingX: true,
lockScalingY: true,
hasRotatingPoint: false,
transparentCorners: false,
cornerSize: 7
});
Here is a Fiddle with my problem : http://jsfiddle.net/K52jG/4/
In this example, I want the "Hello World!" text to be in a 200x200 box. Is it possible to do that, and how ?
OK, so because it is not possible, the best way I found to is to nest the IText box in a Rectangle object, using a Group
var r = new fabric.Rect({
width: 200,
height: 200,
fill: '#FFFFFF',
});
// create a rectangle object
var t = new fabric.IText("Hello world !", {
backgroundColor: '#FFFFFF',
fill: '#000000',
fontSize: 12,
top : 3,
});
var group = new fabric.Group([ r, t ], {
left: 100,
top: 100,
lockScalingX: true,
lockScalingY: true,
hasRotatingPoint: false,
transparentCorners: false,
cornerSize: 7
});
Example in this Fiddle : http://jsfiddle.net/4HE3U/1/
Note : I have to set a "top" value to the text because it goes out of the box. The value seem to be : fontSize / 4

Categories