I'm new to angular, html, javascript and I didn't figure out how to create a fiddle to explain my problem (sorry), so I uploaded to my dropbox: https://www.dropbox.com/s/60efg5vo3qql29c/image_canvas.zip?dl=0
So what I'm trying to do is upload an image from my database to a canvas and then draw one to many rectangles using fabricjs with a text in it, but when I do it, the image disappears and only appears the new drawn rectangle, what I'm doing wrong?
thanks in advance.
[EDIT]
This is my angular file
$scope.addRectangleToCanvas = function () {
try {
var c = document.getElementById('canvas');
var colorPicker = $('#btnColor');
var fontPicker = $('#bntfontsize');
var canvas = new fabric.Canvas('canvas', { selection: true });
var selText = $('#txtCustomComments').val();
var color = new fabric.Color(colorPicker.val()).toRgb();
var fontSize = fontPicker.val();
commentText = new fabric.IText(selText, {
fontSize: fontSize,
hasControls: false,
hasBorders: true,
originX: 'center',
backgroundColor: 'rgba(0,0,0,0)',
borderColor: color,
opacity: 0.6,
fill: color,
fontFamily: "helvetica"
});
var commentRectange = new fabric.Rect({
originX: 'center',
top: 30,
width: 300,
height: 200,
fill: 'rgba(0,0,0,0)',
stroke: color,
strokeWidth: 4
});
var group = new fabric.Group([commentText, commentRectange], {
left: 100,
top: 150
});
canvas.add(group);
canvas.bringForward(group);
} catch (exception) {
alert(exception);
console.log(exception);
}
};
$scope.GetNextNodes = function () {
var commentRectange, commentText;
var canvas = new fabric.Canvas('canvas', {
selection: true
});
var colorPicker = $('#btnColor');
var fontPicker = $('#bntfontsize');
var image = new Image();
var imageComp;
image.crossOrigin = "Anonymous";
image.onload = function () {
//imageComp = fabric.Image('https://upload.wikimedia.org/wikipedia/commons/0/0e/American_Black_Bear_%283405475634%29.jpg', function (img) {
imageComp = fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/commons/0/0e/American_Black_Bear_%283405475634%29.jpg', function (img) {
var oImg = img.set({
angle: 0,
cornersize: 10,
hoverCursor: "default",
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
hasRotatingPoint: true,
hasControls: false,
hasBorders: false,
lockScalingFlip: true,
lockScalingX: true,
lockScalingY: true,
lockSkewingX: true,
lockSkewingY: true,
height: image.naturalHeight,
width: image.naturalWidth
});
canvas.add(oImg).setActiveObject(oImg);
canvas.moveTo(oImg, window.objectIndex);
}, { crossOrigin: 'Anonymous' });
canvas.setHeight(image.naturalHeight);
canvas.setWidth(image.naturalWidth);
};
image.src = "https://upload.wikimedia.org/wikipedia/commons/0/0e/American_Black_Bear_%283405475634%29.jpg";
};
$scope.GetNextNodes();
This is my Html
<div id="page-wrapper">
<div class="main-dropdown">
<span>Nombre:</span>
<input id="txtCustomComments" name="Comment" value="zona" placeholder="Custom comments here" class="pls-select-comments" type="text">
<button name="btn-apply" id="btnApplyComments" value="apply" class="comment-apply-btn" ng-click="addRectangleToCanvas()">
Agregar
</button>
</div>
<div class="font-setting">
<div class="row">
<div class="color-picker">
<span>Font Color:</span>
<input id="btnColor" class="wmc-font-color" name="favcolor" value="#FF0000" type="color">
</div>
<div class="main-font-size">
<span>Font Size:</span>
<input id="bntfontsize" class="wmc-font-size" min="6" max="72" step="2" value="20" type="number">
</div>
</div>
</div>
<br />
<br/>
<canvas id="canvas" style="border:1px solid #d3d3d3;" />
</div>
You seem to be redeclaring the canvas in addRectangleToCanvas function with the
var canvas = new fabric.Canvas('canvas', { selection: true });
line. Try retaining the reference the getNextNodes function and then acting upon that
var canvas;
$scope.GetNextNodes = function () {
canvas = new fabric.Canvas('canvas');
//...
}
$scope.addRectangleToCanvas = function () {
canvas.add... // Do whatnot here with the canvas w/o redeclaring
}
Declaring the variables under $scope helped.
$scope.commentRectange;
$scope.commentText;
$scope.canvas = new fabric.Canvas('wmcCanvas', {
selection: true
});
$scope.colorPicker = $('#btnColor');
$scope.fontPicker = $('#bntfontsize');
$scope.image = new Image();
$scope.imageComp;
$scope.oImg;
$scope.group;
Related
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>
I am trying to stop or pause the animation of a rectangle using FabricJs. However i tried to google a documentation, there is no much information on how to achieve it. I would appreciate any help
const canvas = new fabric.Canvas('c', {
selection: false
});
var hasAnimationStarted = false;
document.getElementById('button').onclick = startAnimation;
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: "#FF0000",
stroke: "#000",
width: 50,
height: 50,
});
canvas.add(rect);
function startAnimation() {
if (hasAnimationStarted === false) {
hasAnimationStarted === true;
document.getElementById('button').innerText = 'Stop Animation';
rect.animate({
left: 250,
}, {
onChange: canvas.renderAll.bind(canvas),
duration: 6000,
onComplete: function() {
hasAnimationStarted === false;
document.getElementById('button').innerText = 'Start Animation';
},
abort: function() {
}
});
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
<canvas id="c" width="300" height="300" style="border: 2px solid green;"></canvas>
<button id="button">
Start Animation
</button>
Return a truthy value from abort method of animation, it will stop the animation.
DEMO
const canvas = new fabric.Canvas('c', {
selection: false
});
let hasAnimationStarted = false;
document.getElementById('startAnim').onclick = startAnimation;
const rect = new fabric.Rect({
left: 10,
top: 10,
fill: "#FF0000",
stroke: "#000",
width: 50,
height: 50,
});
canvas.add(rect);
function startAnimation() {
if (hasAnimationStarted) {
stopAnimation();
} else {
hasAnimationStarted = true;
document.getElementById('startAnim').innerText = 'Stop Animation';
rect.animate({
left: 250,
}, {
onChange: canvas.requestRenderAll.bind(canvas),
duration: 6000,
onComplete: stopAnimation,
abort: () => !hasAnimationStarted
});
}
}
function stopAnimation() {
hasAnimationStarted = false;
document.getElementById('startAnim').innerText = 'Start Animation';
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
<canvas id="c" width="300" height="300" style="border: 2px solid green;"></canvas>
<button id="startAnim">
Start Animation
</button>
I've got some text on my canvas and I'm trying to use buttons to align the text to the left, center, and right in it's my fabricjs canvas. I saw this example but would prefer to use buttons over a select box. I've tried a bunch and am feeling pretty lost.
var $ = function(id){return document.getElementById(id)};
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(300);
document.getElementById('text-align').onclick = function() {
canvas.getActiveObject().setTextAlign(this.value);
canvas.renderAll();
};
var text = new fabric.IText('Some demo\nText', {
left: 10,
top: 10,
fontSize: 22,
hasBorders: true,
hasControls: true,
cornerStyle: 'circle',
lockRotation: true,
hasControls: true,
lockUniScaling: true,
hasRotatingPoint: false,
})
canvas.add(text);
canvas {
border: 1px solid #dddddd;
margin-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<button id="text-align" value="left">Left</button>
<button id="text-align" value="center">Center</button>
<button id="text-align" value="right">Right</button>
<canvas id="c"></canvas>
The issue is not in the fabric code. Rather it was because you were using the same id for all the buttons. document.getElementById returns only the first instance and therefore your click listener was getting added to the 'left' button only
var $ = function(id) {
return document.getElementById(id)
};
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(300);
document.querySelectorAll('.text-align').forEach(function(btn) {
btn.onclick = function() {
canvas.getActiveObject().setTextAlign(this.value);
canvas.renderAll();
};
})
var text = new fabric.IText('Some demo\nText', {
left: 10,
top: 10,
fontSize: 22,
hasBorders: true,
hasControls: true,
cornerStyle: 'circle',
lockRotation: true,
hasControls: true,
lockUniScaling: true,
hasRotatingPoint: false,
})
canvas.add(text);
canvas {
border: 1px solid #dddddd;
margin-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<button class="text-align" value="left">Left</button>
<button class="text-align" value="center">Center</button>
<button class="text-align" value="right">Right</button>
<canvas id="c"></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>
I have view with countdown timer
here is code of countdown timer in View
<div class="timer-div-one"; id="countdown" style="height: 20px; width: 20px;">
</div>
Here is js code for timer
$("#countdown").countdown360({
radius: 40.5,
seconds: 30,
strokeWidth: 7,
fillStyle: '#ffffff',
strokeStyle: '#ffcf00',
fontSize: 30,
fontColor: '#000000',
autostart: false,
onComplete: function() { alert(); }
}).start();
I need to start it when i click "Запись" button
Here is button in view.
<button id="record" class="btn btn-default" style="background: #ffcf00; color: black; height: 40px;text-shadow: none">Запись</button>
I try to write code like this. But it not works
$("#record").click(function (){
$("#countdown").countdown360({
radius: 40.5,
seconds: 30,
strokeWidth: 7,
fillStyle: '#ffffff',
strokeStyle: '#ffcf00',
fontSize: 30,
fontColor: '#000000',
autostart: false,
onComplete: function() { alert(); }
}).start();});
Where is my fault?
UPDATE
$(function() {
$("#record").click(function (){
$("#countdown").countdown360({
radius: 40.5,
seconds: 30,
strokeWidth: 7,
fillStyle: '#ffffff',
strokeStyle: '#ffcf00',
fontSize: 30,
fontColor: '#000000',
autostart: false,
onComplete: function() { alert(); }
}).start();});
});
Not works and counter not visible.
If I write code like this I will see counter and it works and show alert.
Here is code.
$("#countdown").countdown360({
radius: 40.5,
seconds: 30,
strokeWidth: 7,
fillStyle: '#ffffff',
strokeStyle: '#ffcf00',
fontSize: 30,
fontColor: '#000000',
autostart: false,
onComplete: function() { alert(); }
}).start();
As Jeremy Thille write about click, Yes I have several clicks on "Запись" and "Остановить" buttons.
Here is code:
record.onclick = function () {
record.disabled = true;
navigator.getUserMedia({
audio: true,
video: true
}, function (stream) {
preview.src = window.URL.createObjectURL(stream);
preview.play();
// var legalBufferValues = [256, 512, 1024, 2048, 4096, 8192, 16384];
// sample-rates in at least the range 22050 to 96000.
recordAudio = RecordRTC(stream, {
//bufferSize: 16384,
//sampleRate: 45000,
onAudioProcessStarted: function () {
if (!isFirefox) {
recordVideo.startRecording();
}
}
});
if (isFirefox) {
recordAudio.startRecording();
}
if (!isFirefox) {
recordVideo = RecordRTC(stream, {
type: 'video'
});
recordAudio.startRecording();
}
stop.disabled = false;
}, function (error) {
alert(JSON.stringify(error, null, '\t'));
});
};
var fileName;
stop.onclick = function () {
record.disabled = false;
stop.disabled = true;
window.onbeforeunload = null; //Solve trouble with deleting video
preview.src = '';
fileName = Math.round(Math.random() * 99999999) + 99999999;
console.log(fileName);
if (!isFirefox) {
recordAudio.stopRecording(function () {
PostBlob(recordAudio.getBlob(), 'audio', fileName + '.wav');
});
} else {
recordAudio.stopRecording(function (url) {
preview.src = url;
PostBlob(recordAudio.getBlob(), 'video', fileName + '.webm');
});
}
if (!isFirefox) {
recordVideo.stopRecording(function () {
PostBlob(recordVideo.getBlob(), 'video', fileName + '.webm');
});
}
deleteFiles.disabled = false;
};
I try to paste counter inside Record click, but it not works
Where is my fault?
UPDATE2
Uncaught TypeError: Cannot set property 'onclick' of null
at Recording:250
Yes it reference to another button, i deleted it.
But I don't see timer anyway.
I solved my problem.
Here is how it need to be done
var countdown = $("#countdown").countdown360({
radius: 40.5,
seconds: 30,
strokeWidth: 7,
fillStyle: '#ffffff',
strokeStyle: '#ffcf00',
fontSize: 30,
fontColor: '#000000',
autostart: false,
onComplete: function () {
console.log('done');
}
});
$('#record').click(function () {
countdown.start();
});
$('#stop').click(function () {
countdown.stop();
});