How to detect mouse down event on fabric js animated objects - javascript

i was playing with Fabric.js and aim is to detect mouse down event on an animated object. Currently images are being animated from bottom to top, and when i press mouse down it just shows coordinate but does not detect clicking on Object.
I also noticed that, when images start their animation, only then i can click/select them, after that they become non-selectable
here is a jsfiddle demo of code. please check and suggest.
my html is :
<h3>Hello Fabric</h3>
<div class="mainCanvasContainer">
<canvas class="mainCanvas" id="mycanvas" width="500px" height="400px"></canvas>
</div>
<div id='info'>
</div>
now here is my Javascript:
$(document).ready(function () {
var canvas_id = 'mycanvas';
function showInfo(text){
$('#info').append('<div> '+text+' </div>');
}
(function () {
var canvas = this.__canvas = new fabric.Canvas(canvas_id, {selection: false});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
canvas.on('mouse:down', function (options) {
if (options.target) {
showInfo('an object was clicked! ', options.target.type);
}
var cor=options.e.clientX+','+ options.e.clientY;
showInfo(cor);
});
setInterval(function () {
fabric.Image.fromURL('http://www.rashflash.com/fabricjs_animation/img.png', function (img) {
img.scale(0.2);
//img.set('left', fabric.util.getRandomInt(100, 400)).set('top', 450);
//img.movingLeft = !!Math.round(Math.random());
var text = new fabric.Text('hello', {
fontSize: 30,
originX: 'center',
originY: 'center'
});
var group = new fabric.Group([img, text]);
group.set('left', fabric.util.getRandomInt(100, 400)).set('top', 420);
canvas.add(group);
});
}, 1000);
(function animate() {
canvas.forEachObject(function (obj) {
if (!obj) {
return;
}
// obj.left += (obj.movingLeft ? -1 : 1);
obj.top -= 1;
if (obj.left > 500 || obj.top < 0) {
canvas.remove(obj);
}
});
canvas.renderAll();
fabric.util.requestAnimFrame(animate);
})();
})();
});

RashFlash, you are missing setCoords() function when you animate.
Updated function animate:
(function animate() {
canvas.forEachObject(function (obj) {
if (!obj) {
return;
}
// obj.left += (obj.movingLeft ? -1 : 1);
obj.top -= 1;
if (obj.left > 500 || obj.top < 0) {
canvas.remove(obj);
}
obj.setCoords();
});
canvas.renderAll();
fabric.util.requestAnimFrame(animate);
})();
})();
Also, updated fiddle

Related

Fabricjs - Rendering multiple canvases in one document

I'm having a problem dynamically creating and setting canvas backgrounds.
I want the user to be able to annotate the images with text and shapes, thats why I am doing stuff this way.
I would like to know why is this code producing such output
The idea
Send a get request to an endpoint which returns json data containing
image urls.
Convert that data into a javascript array.
Dynamically create fabric js canvases based on the length of above
array.
Set the canvas backgrounds to the images using their urls. (i.e each canvas will have a different background taken from the url)
The problem
Only the last canvas has a background image.
code
<!DOCTYPE html>
<html>
<head>
<style>
body {
}
</style>
<script
src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous"
></script>
</head>
<body>
<script src="fabric.js"></script>
<!--new start-->
<script>
//procedurally load images from a given source
//endpoint with image links
var end_point = "http://localhost:8080/endpoint.php";
var settings = {
url: "http://localhost:8080/endpoint.php",
method: "GET",
};
//get the images array from end point
$.ajax(settings).done(function (images_json) {
var images = JSON.parse(images_json);
//procedurally create farbric.js canvas for each image element in the html document and set their background as the corresponding image.
//for each item in the images array, create a fabric.js canvas with its background set as the image itself
var canvas_array = [];
for (var i = 0, len = images.length; i < len; i++) {
//console.log(images[i]);
//create canvas and then make it a fabric canvas
document.body.innerHTML += `<canvas
id=${[i]}
width="1000"
height="200"
style="border-style: solid;">
</canvas>`;
//canvases stored in canvas_array
canvas_array[i] = new fabric.Canvas(`${[i]}`);
console.log(canvas_array[i]);
//set canvas background as the image
canvas_array[i].setBackgroundImage(
`${images[i]}`,
canvas_array[i].renderAll.bind(canvas_array[i]),
{
backgroundImageOpacity: 1,
backgroundImageStretch: false,
}
);
}
});
</script>
<!--new end-->
</body>
</html>
result
result
note
The code is generating correct number of canvases. However the background image does not seem to work
Desired result would have 10 canvases with different backgrounds corresponding to the image urls.
I'm new to fabric.js, this may be a dumb mistake.
Using remote source was a strict requirement. I tried several stuff and this finally worked.
code
//c global variable
var n_can_arr = [];
var f_can_arr = [];
var img_arr = [];
//c procedurally load images from a given source
$.ajax({
url: "http://localhost:8080/endpoint.php",
type: "GET",
dataType: "json", //c added data type
success: function (res) {
for (var index = 0; index < res.length; index++) {
//c create canvas
var setHtml = `<canvas
id=${index}
width="1000"
height="800"
style="border-style: solid;">
</canvas>`;
document.body.innerHTML += setHtml;
//c update canvas and image arrays
n_can_arr.push(index);
img_arr.push(res[index]);
}
//c call image set after the loop is over
$(document).trigger("images_set");
},
});
//c on image_set called
$(document).bind("images_set", () => {
//c for each element of normal canvas array, create a fabric js canvas and set its background
for (var i = 0; i < n_can_arr.length; i++) {
create_canvas(i);
}
//c for each element of fabric canvas array, apply the extend canvas function
extend_canvas();
});
function create_canvas(i) {
//c create fabric js canvases with normal canvas id from canvas arrray
var canvas = new fabric.Canvas(`${i}`);
f_can_arr.push(canvas);
//c set canvas background using image array
canvas.setBackgroundImage(img_arr[i], canvas.renderAll.bind(canvas), {
backgroundImageOpacity: 1,
backgroundImageStretch: false,
});
}
function extend_canvas() {
f_can_arr.forEach((canvas) => {
var origX, origY, isDown, mode_rect, mode_uline, mode_free, pointer;
//c setting keypress listener
$(window).on("keypress", (e) => {
console.log(e.key);
//c drawing rectangles
if (e.key == 1) {
var rect;
console.log("Box");
isDown = true;
mode_free = false;
mode_uline = false;
mode_rect = true;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
if (mode_rect) {
pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
console.log(origX + "," + origY);
rect = new fabric.Rect({
left: origX,
top: origY,
originX: "left",
originY: "top",
width: pointer.x - origX,
height: pointer.y - origY,
fill: "red",
angle: 0,
fill: "rgba(255,0,0,0.0)",
stroke: "black",
strokeWidth: 1,
});
canvas.add(rect);
}
});
canvas.on("mouse:move", function (o) {
if (mode_rect) {
if (isDown) {
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({ left: Math.abs(pointer.x) });
}
if (origY > pointer.y) {
rect.set({ top: Math.abs(pointer.y) });
}
rect.set({ width: Math.abs(origX - pointer.x) });
rect.set({ height: Math.abs(origY - pointer.y) });
canvas.renderAll();
}
}
});
}
//c freehand drawing/Highlighter
if (e.key == 2) {
console.log("freehand");
isDown = true;
mode_free = true;
mode_uline = false;
mode_rect = false;
canvas.isDrawingMode = 1;
canvas.freeDrawingBrush.color = "rgba(255,0,0,0.2)";
canvas.freeDrawingBrush.width = 20;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
if (mode_free) {
canvas.renderAll();
}
});
}
//c line mode
if (e.key == 3) {
var line;
console.log("line");
isDown = true;
mode_free = false;
mode_uline = true;
mode_rect = false;
//c canvas event listners
canvas.on("mouse:down", function (o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
if (mode_uline) {
line = new fabric.Line(points, {
strokeWidth: 3,
fill: "red",
stroke: "red",
originX: "center",
originY: "center",
targetFindTolerance: true,
});
canvas.add(line);
}
});
canvas.on("mouse:move", function (o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (mode_uline) {
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
}
});
}
//c deleting a selected shape
if (e.key == 4) {
var activeObject = canvas.getActiveObject();
if (activeObject) {
canvas.remove(activeObject);
}
}
//c cancling freehand drawing mode
if (e.key == "x") {
console.log("freehand mode cancled");
canvas.isDrawingMode = 0;
}
});
//c removing previous event listeners and resetting some global variables
canvas.on("mouse:up", function (o) {
isDown = false;
mode_free = false;
mode_uline = false;
mode_rect = false;
canvas.off("mouse:down");
canvas.off("mouse:move");
});
});
}
function save_canvas() {}
function load_canvas() {}
solution
I setup a custom trigger event after the ajax call is made. When the trigger event is fired, only then I create fabricjs canvases.
(apparently even with promises, the fabric code was not running in correct order. Which was probably due to bad syntax. Custom triggers solve this issue.)
results
-Each image appear separately in its own fabric.js canvas as background.
-Each canvas is independent.
Have create for you just copy code and then use your own images in local to get actual full result in output div( images will generated) .
let CANVAS_LIST = [];
let imageList = [
'https://homepages.cae.wisc.edu/~ece533/images/airplane.png',
'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
'https://homepages.cae.wisc.edu/~ece533/images/baboon.png',
]
imageList.forEach(element => {
let canvasElement = document.createElement("canvas");
canvasElement.width = '300';
canvasElement.height = '300';
$("#canvas_container").append(canvasElement);
let canvas = new fabric.Canvas(canvasElement);
// Adding Example Text here.
canvas.add(new fabric.Text('This text is added', {
fontFamily: 'Delicious_500',
color: 'red',
left: 10,
top: 100
}));
// Setting up Background to dynamic generated Canvas
canvas.setBackgroundImage(
`${element}`,
canvas.renderAll.bind(canvas),
{
backgroundImageOpacity: 1,
backgroundImageStretch: false,
}
);
CANVAS_LIST.push(canvas);
});
setTimeout(() => {
generateOutput();
}, 3000);
function generateOutput() {
$("#output").empty();
CANVAS_LIST.forEach(canvas => {
let image = $("<img>").attr({
width: 200,
height: 200,
src: canvas.toDataURL()
});
image.css({ marginLeft: '20px' });
$("#output").append(image);
})
}
<!DOCTYPE html>
<html>
<head>
<style>
body {}
</style>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div id="canvas_container">
</div>
<button onclick="generateOutput()"> Show output</button>
<div id="output">
</div>
</div>
</body>
</html>
Thanks

Tinder like function, appcelerator

I tried to re create a Tinder like function.
I found this code :
var win = Titanium.UI.createWindow({
backgroundColor: "#ffffff",
title: "win"
});
// animations
var animateLeft = Ti.UI.createAnimation({
left: -520,
transform: Ti.UI.create2DMatrix({rotate: 60}),
opacity: 0,
duration: 300
});
var animateRight = Ti.UI.createAnimation({
left: 520,
transform: Ti.UI.create2DMatrix({rotate: -60}),
opacity: 0,
duration: 300
});
var curX = 0;
win.addEventListener('touchstart', function (e) {
curX = parseInt(e.x, 10);
});
win.addEventListener('touchmove', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// Subtracting current position to starting horizontal position
var coordinates = parseInt(e.x, 10) - curX;
// Defining coordinates as the final left position
var matrix = Ti.UI.create2DMatrix({rotate: -(coordinates / 10)});
var animate = Ti.UI.createAnimation({
left: coordinates,
transform: matrix,
duration: 20
});
e.source.animate(animate);
e.source.left = coordinates;
});
win.addEventListener('touchend', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// No longer moving the window
if (e.source.left >= 75) {
e.source.animate(animateRight);
} else if (e.source.left <= -75) {
e.source.animate(animateLeft);
} else {
// Repositioning the window to the left
e.source.animate({
left: 0,
transform: Ti.UI.create2DMatrix({rotate: 0}),
duration: 300
});
}
});
for (var i = 0; i < 10; i++) {
var wrap = Ti.UI.createView({
"id": 'oferta',
"width": 320,
"height": 400,
"backgroundColor": (i % 2 == 0 ? "red" : "blue")
});
var text = Ti.UI.createLabel({
text: "row: " + i,
color: "black"
});
wrap.add(text);
win.add(wrap);
}
win.open();
But there's a weird behaviour.
Indeed, When I took the wrap view from the top, everythnig is OK but if I put my finger on the bottom on the wrap view, the image becomes crazy..
Try the code and You will see strange behaviour.
I use Titanium SDK 5.2.2
and iOS 9.3.1 on an iPhone 6.
Here s a video showing the weird thing: http://tinypic.com/player.php?v=x37d5u%3E&s=9#.Vx_zDaOLQb0
(Sorry for the video size)
Thanks for your help
Use this code to convert pxToDp and vice versa:
Put following code in your lib folder and include it
with require("measurement")
instead of require("alloy/measurement")
var dpi = Ti.Platform.displayCaps.dpi, density = Ti.Platform.displayCaps.density;
exports.dpToPX = function(val) {
switch (density) {
case "xxxhigh":
return 5 * val;
case "xxhigh":
return 4 * val;
case "xhigh":
return 3 * val;
case "high":
return 2 * val;
default:
return val;
}
};
exports.pxToDP = function(val) {
switch (density) {
case "xxxhigh":
return 5 / val;
case "xxhigh":
return 4 / val;
case "xhigh":
return val / 3;
case "high":
return val / 2;
default:
return val;
}
};
exports.pointPXToDP = function(pt) {
return {
x: exports.pxToDP(pt.x),
y: exports.pxToDP(pt.y)
};
};
Many thanks to all !!! It works using this code ::
var win = Titanium.UI.createWindow({
backgroundColor: "#ffffff",
title: "win"
});
// animations
var animateLeft = Ti.UI.createAnimation({
left: -520,
transform: Ti.UI.create2DMatrix({rotate: 60}),
opacity: 0,
duration: 300
});
var animateRight = Ti.UI.createAnimation({
left: 520,
transform: Ti.UI.create2DMatrix({rotate: -60}),
opacity: 0,
duration: 300
});
Ti.include('measurement.js');
var curX = 0;
var wrap = [];
var topWrap = 100; //(Titanium.Platform.displayCaps.platformHeight - 400) / 2;
var leftWrap = 50; //(Titanium.Platform.displayCaps.platformWidth - 320) / 2;
for (var i = 0; i < 10; i++) {
wrap[i] = Ti.UI.createView({
"id": 'oferta',
"width": Titanium.Platform.displayCaps.platformWidth - 100,
"height": Titanium.Platform.displayCaps.platformHeight - 300,
image:(i % 2 == 0 ? 'principale.png' : 'principale1.png'),
"backgroundColor": (i % 2 == 0 ? "red" : "blue"),
top:topWrap,
left:leftWrap,
});
wrap[i].addEventListener('touchstart', function (e) {
// curX = parseInt(e.x, 10);
curX = pxToDP(parseInt(e.x, 10));
// curY = pxToDP(parseInt(e.Y, 10));
});
wrap[i].addEventListener('touchmove', function (e) {
// Subtracting current position to starting horizontal position
// var coordinates = parseInt(e.x, 10) - curX;
// Defining coordinates as the final left position
var coordinatesX = pxToDP(parseInt(e.x, 10)) - curX;
//var coordinatesY = pxToDP(parseInt(e.y, 10)) - curY;
var matrix = Ti.UI.create2DMatrix({rotate: -(coordinatesX / 10)});
var animate = Ti.UI.createAnimation({
left: coordinatesX,
// top: coordinatesY,
transform: matrix,
duration: 10
});
e.source.animate(animate);
e.source.left = coordinatesX;
// e.source.top = coordinatesY;
});
wrap[i].addEventListener('touchend', function (e) {
// No longer moving the window
if (e.source.left >= 75) {
e.source.animate(animateRight);
} else if (e.source.left <= -75) {
e.source.animate(animateLeft);
} else {
// Repositioning the window to the left
e.source.animate({
left: leftWrap,
transform: Ti.UI.create2DMatrix({rotate: 0}),
duration: 300
});
}
});
win.add(wrap);
}
win.open();
And the measurement.js file is :
var dpi = Ti.Platform.displayCaps.dpi, density = Ti.Platform.displayCaps.density;
function dpToPX(val) {
switch (density) {
case "xxxhigh":
return 5 * val;
case "xxhigh":
return 4 * val;
case "xhigh":
return 3 * val;
case "high":
return 2 * val;
default:
return val;
}
};
function pxToDP(val) {
switch (density) {
case "xxxhigh":
return 5 / val;
case "xxhigh":
return 4 / val;
case "xhigh":
return val / 3;
case "high":
return val / 2;
default:
return val;
}
};
function pointPXToD(pt) {
return {
x: pxToDP(pt.x),
y: pxToDP(pt.y)
};
};
You have to convert px to dp.
var measurement = require('alloy/measurement');
win.addEventListener('touchstart', function (e) {
curX = measurement.pxToDP(parseInt(e.x, 10));
Ti.API.info("touchstart curX: " + curX);
});
...
win.addEventListener('touchmove', function (e) {
if (!e.source.id || e.source.id !== 'oferta') {
return;
}
// Subtracting current position to starting horizontal position
var coordinates = measurement.pxToDP(parseInt(e.x, 10)) - curX;
...

Fabric.js Sticky Note type text wrap

I am trying to make a sticky note type utility with the fabric canvas. It will help to be used as annotators.
I want the text to wrap by itself at the given rectangle's width.
Can someone update my fiddle work??
Suggestions are appreciated. Regards...
The following is the link to a part of my fiddle:
http://jsfiddle.net/U7E9q/5/
var canvas = new fabric.Canvas('fabric-canvas');
canvas.hoverCursor = 'pointer';
var text = new fabric.IText("Enter Text Here ",{
fontSize: 20,
top: 100,
left: 100,
backgroundColor: '#faa',
lockScalingX: true,
lockScalingY: true,
selectable: true
});
//alert(text.text);
var rect = new fabric.Rect({
text_field: text,
width: 200,
height: 50,
fill: '#faa',
rx: 10,
ry: 10,
top: 100,
left: 100
});
canvas.add(rect);
canvas.add(text);
canvas.on('object:moving', function (event){
canvas.renderAll();
});
createListenersKeyboard();
function createListenersKeyboard() {
document.onkeydown = onKeyDownHandler;
//document.onkeyup = onKeyUpHandler;
}
function onKeyDownHandler(event) {
//event.preventDefault();
var key;
if(window.event){
key = window.event.keyCode;
}
else{
key = event.keyCode;
}
switch(key){
//////////////
// Shortcuts
//////////////
// Copy (Ctrl+C)
case 67: // Ctrl+C
if(ableToShortcut()){
if(event.ctrlKey){
event.preventDefault();
copy();
}
}
break;
// Delete (Ctrl+D)
case 127: // Ctrl+D
if(ableToShortcut()){
if(event.deleteKey){
delet();
}
}
break;
// Paste (Ctrl+V)
case 86: // Ctrl+V
if(ableToShortcut()){
if(event.ctrlKey){
event.preventDefault();
paste();
}
}
break;
default:
// TODO
break;
}
}
function ableToShortcut(){
/*
TODO check all cases for this
if($("textarea").is(":focus")){
return false;
}
if($(":text").is(":focus")){
return false;
}
*/
return true;
}
function copy(){
if(canvas.getActiveGroup()){
for(var i in canvas.getActiveGroup().objects){
var object = fabric.util.object.clone(canvas.getActiveGroup().objects[i]);
object.set("top", object.top+5);
object.set("left", object.left+5);
copiedObjects[i] = object;
}
}
else if(canvas.getActiveObject()){
var object = fabric.util.object.clone(canvas.getActiveObject());
object.set("top", object.top+5);
object.set("left", object.left+5);
copiedObject = object;
copiedObjects = new Array();
}
}
function paste(){
if(copiedObjects.length > 0){
for(var i in copiedObjects){
canvas.add(copiedObjects[i]);
}
}
else if(copiedObject){
canvas.add(copiedObject);
}
canvas.renderAll();
}
function delet(){
var activeObject = canvas.getActiveObject();
canvas.remove(activeObject);
console.log('after remove getActiveObject(): ', canvas.getActiveObject(), activeObject === canvas.getActiveObject());
canvas.renderAll();
}
If you manage the sticky note as a grouped rect and text you can improve the same behavior. When you need to edit the text inside the group, you just ungroup and clone the elements, append the cloned elements to the canvas and set text as editable.
You need to handle an event like double click to handle this behavior and then handle the mousedown or other interactivity with canvas to regroup them.
http://jsfiddle.net/4HE3U/1/
Above is one fiddle that can satisfy you
Basically i have made one group of Text and Rectangle and i have added it to canvas. There is only one change you need to make is that you can take one textbox to get current sticky note text content as we can not edit text of i-text online once we are adding it any group. Currently there is no way for IText to handle the events as they are not handed down to it if it's contained in a group. I think this is also the prefered way to handle that as it would confuse the user - what if he starts to edit multiple texts. This might end up in a mess. Maybe you can rework your script a little to workaround this problems.
I have added Text and Rectangle
var canvas = new fabric.Canvas('fabric-canvas');
canvas.hoverCursor = 'pointer';
var text = new fabric.IText("Enter Text Here ",{
fontSize: 20,
top: 100,
left: 100,
backgroundColor: '#faa',
lockScalingX: true,
lockScalingY: true,
selectable: true
});
//alert(text.text);
var rect = new fabric.Rect({
text_field: text,
width: 200,
height: 50,
fill: '#faa',
rx: 10,
ry: 10,
top: 100,
left: 100
});
var group = new fabric.Group([ rect, text ], {
left: 100,
top: 100,
lockScalingX: true,
lockScalingY: true,
hasRotatingPoint: false,
transparentCorners: false,
cornerSize: 7
});
canvas.add(group);
//canvas.add(text);
canvas.on('object:moving', function (event){
canvas.renderAll();
});
createListenersKeyboard();
function createListenersKeyboard() {
document.onkeydown = onKeyDownHandler;
//document.onkeyup = onKeyUpHandler;
}
function onKeyDownHandler(event) {
//event.preventDefault();
var key;
if(window.event){
key = window.event.keyCode;
}
else{
key = event.keyCode;
}
switch(key){
//////////////
// Shortcuts
//////////////
// Copy (Ctrl+C)
case 67: // Ctrl+C
if(ableToShortcut()){
if(event.ctrlKey){
event.preventDefault();
copy();
}
}
break;
// Delete (Ctrl+D)
case 127: // Ctrl+D
if(ableToShortcut()){
if(event.deleteKey){
delet();
}
}
break;
// Paste (Ctrl+V)
case 86: // Ctrl+V
if(ableToShortcut()){
if(event.ctrlKey){
event.preventDefault();
paste();
}
}
break;
default:
// TODO
break;
}
}
function ableToShortcut(){
/*
TODO check all cases for this
if($("textarea").is(":focus")){
return false;
}
if($(":text").is(":focus")){
return false;
}
*/
return true;
}
function copy(){
if(canvas.getActiveGroup()){
for(var i in canvas.getActiveGroup().objects){
var object = fabric.util.object.clone(canvas.getActiveGroup().objects[i]);
object.set("top", object.top+5);
object.set("left", object.left+5);
copiedObjects[i] = object;
}
}
else if(canvas.getActiveObject()){
var object = fabric.util.object.clone(canvas.getActiveObject());
object.set("top", object.top+5);
object.set("left", object.left+5);
copiedObject = object;
copiedObjects = new Array();
}
}
function paste(){
if(copiedObjects.length > 0){
for(var i in copiedObjects){
canvas.add(copiedObjects[i]);
}
}
else if(copiedObject){
canvas.add(copiedObject);
}
canvas.renderAll();
}
function delet(){
var activeObject = canvas.getActiveObject();
canvas.remove(activeObject);
console.log('after remove getActiveObject(): ', canvas.getActiveObject(), activeObject === canvas.getActiveObject());
canvas.renderAll();
}
<canvas id="fabric-canvas" width="400" height="400"></canvas>
Here is Sticky note functionality. Text wrap working and font size changes w.r.t sticky note width and height. Editing mode activates on double click.
export const createStickyNotes = (canvas, options) => {
fabric.StickyNote = fabric.util.createClass(fabric.Group, {
type: "StickyNote",
initialize: function (options) {
this.set(options);
var height = this.height;
var width = this.width;
this.rectObj = new fabric.Rect({
width: width,
height: height,
fill: this.rectObj?.fill ?? "rgba(251,201,112,1)",
originX: "center",
originY: "center",
objectCaching: false,
stateProperties: ["fill"],
});
this.textObj = new fabric.Textbox(this.textObj?.text ?? "Notes", {
originX: "center",
originY: "center",
textAlign: "center",
width: 100,
hasControls: false,
fontSize: this.textObj?.fontSize ?? 30,
lineHeight: 1,
stateProperties: ["text", "fontSize"],
scaleX: this.textObj?.scaleX ?? 1,
scaleY: this.textObj?.scaleY ?? 1,
objectCaching: false,
breakWords: true,
fontFamily: "Open Sans",
});
this._objects = [this.rectObj, this.textObj];
// this custom _set function will set custom properties value to object when it will load from json.
// at that time loadFromJson function will call this initialize function.
// this._setCustomProperties(this.options);
canvas.renderAll();
//evenet will fire if the object is double clicked by mouse
this.on("mousedblclick", (e) => {
var pasteFlag = false;
var scaling = e.target.getScaledWidth() / 100;
var textForEditing;
canvas.bringToFront(e.target);
e.target.selectable = false;
const [rectObj, textObj] = this.getObjects();
textObj.clone(function (clonedObj) {
clonedObj.set({
left: e.target.left,
top: e.target.top,
lockMovementY: true,
lockMovementX: true,
hasBorders: false,
scaleX: scaling,
scaleY: scaling,
breakWords: true,
width: textObj.width,
stateProperties: [],
});
textForEditing = clonedObj;
});
this.remove(textObj);
canvas.add(textForEditing);
canvas.setActiveObject(textForEditing);
textForEditing.enterEditing();
textForEditing.selectAll();
textForEditing.paste = (function (paste) {
return function (e) {
disableScrolling();
pasteFlag = true;
};
})(textForEditing.paste);
textForEditing.on("changed", function (e) {
var fontSize = textForEditing.fontSize;
var charCount = Math.max(textForEditing._text.length, 1);
var charWR =
(textForEditing.textLines.length * width) / (charCount * fontSize);
if (textForEditing.height < height - 15) {
fontSize = Math.min(
Math.sqrt(
((height - 10 - fontSize) / 1.16) *
(width / (charCount * charWR))
),
30
);
}
if (textForEditing.height > height - 15) {
fontSize = Math.sqrt(
((height - 10) / 1.16) * (width / (charCount * charWR))
);
}
if (pasteFlag) {
pasteFlag = false;
while (
textForEditing.height > height - 15 &&
textForEditing.fontSize > 0
) {
fontSize = textForEditing.fontSize -= 0.2;
canvas.renderAll();
}
}
textForEditing.fontSize = fontSize;
});
textForEditing.on("editing:exited", () => {
enableScrolling();
canvas.setActiveObject(textObj);
textObj.set({
text: textForEditing.text,
fontSize: textForEditing.fontSize,
visible: true,
});
this.add(textObj);
this.selectable = true;
canvas.remove(textForEditing);
canvas.discardActiveObject();
});
});
function disableScrolling() {
var x = window.scrollX;
var y = window.scrollY;
window.onscroll = function () {
window.scrollTo(x, y);
};
}
var _wrapLine = function (_line, lineIndex, desiredWidth, reservedSpace) {
var lineWidth = 0,
splitByGrapheme = this.splitByGrapheme,
graphemeLines = [],
line = [],
// spaces in different languges?
words = splitByGrapheme
? fabric.util.string.graphemeSplit(_line)
: _line.split(this._wordJoiners),
word = "",
offset = 0,
infix = splitByGrapheme ? "" : " ",
wordWidth = 0,
infixWidth = 0,
largestWordWidth = 0,
lineJustStarted = true,
additionalSpace = splitByGrapheme ? 0 : this._getWidthOfCharSpacing();
reservedSpace = reservedSpace || 0;
desiredWidth -= reservedSpace;
for (var i = 0; i < words.length; i++) {
// i would avoid resplitting the graphemes
word = fabric.util.string.graphemeSplit(words[i]);
wordWidth = this._measureWord(word, lineIndex, offset);
offset += word.length;
// Break the line if a word is wider than the set width
if (this.breakWords && wordWidth >= desiredWidth) {
if (!lineJustStarted) {
graphemeLines.push(line);
line = [];
lineWidth = 0;
lineJustStarted = true;
}
this.fontSize *= desiredWidth / (wordWidth + 1);
// Loop through each character in word
for (var w = 0; w < word.length; w++) {
var letter = word[w];
var letterWidth =
(this.getMeasuringContext().measureText(letter).width *
this.fontSize) /
this.CACHE_FONT_SIZE;
line.push(letter);
lineWidth += letterWidth;
}
word = [];
} else {
lineWidth += infixWidth + wordWidth - additionalSpace;
}
if (lineWidth >= desiredWidth && !lineJustStarted) {
graphemeLines.push(line);
line = [];
lineWidth = wordWidth;
lineJustStarted = true;
} else {
lineWidth += additionalSpace;
}
if (!lineJustStarted) {
line.push(infix);
}
line = line.concat(word);
infixWidth = this._measureWord([infix], lineIndex, offset);
offset++;
lineJustStarted = false;
// keep track of largest word
if (wordWidth > largestWordWidth && !this.breakWords) {
largestWordWidth = wordWidth;
}
}
i && graphemeLines.push(line);
if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {
this.dynamicMinWidth =
largestWordWidth - additionalSpace + reservedSpace;
}
return graphemeLines;
};
fabric.util.object.extend(fabric.Textbox.prototype, {
_wrapLine: _wrapLine,
});
function enableScrolling() {
window.onscroll = function () {};
}
},
toObject: function (propertiesToInclude) {
// This function is used for serialize this object. (used for create json)
// not inlclude this.textObj and this.rectObj into json because when object will load from json, init fucntion of this class is called and it will assign this two object textObj and rectObj again.
var obj = this.callSuper(
"toObject",
[
"objectCaching",
"textObj",
"rectObj",
// ... property list that you want to add into json when this object is convert into json using toJSON() function. (serialize)
].concat(propertiesToInclude)
);
// delete objects array from json because then object load from json, Init function will call. which will automatically re-assign object and assign _object array.
delete obj.objects;
return obj;
},
});
fabric.StickyNote.async = true;
fabric.StickyNote.fromObject = function (object, callback) {
// This function is used for deserialize json and convert object json into button object again. (called when we call loadFromJson() fucntion on canvas)
return fabric.Object._fromObject("StickyNote", object, callback);
};
return new fabric.StickyNote(options);
};
//How to use
var options = {
width: 100,
height: 100,
originX: "center",
originY: "center",
};
var notes = StickyNotes(canvas, options);
canvas.add(notes);

How could I progress the sprite animation on scroll?

I am newbie. I can't sprite animation using jquery..
What's the problem?
How can make progressing the sprite animation on the spot loop as scroll??
$(window).scroll('scroll',function(e){
parallaxScroll();
});
function parallaxScroll() {
var ani_data = [0, -120, -240, -480];
var frame_index = 0;
if ( ScrollCount == 3 ) {
ScrollCount = 1;
$('#fatherwalk').css('background-position', ani_data[frame_index] + 'px 0px');
frame_index++;
if ( frame_index >= ani_data.length ) {
frame_index = 0;
}
}
scrollcount++;
}
Why you don't get a shortcut and try SpinJS?
http://fgnass.github.io/spin.js/
It's so easy to implement and works fine.
Here is a Sample that I've made on JSFiddle
Below a quick implementation of the JS:
$.fn.spin = function (opts) {
this.each(function () {
var $this = $(this),
spinner = $this.data('spinner');
if (spinner) spinner.stop();
if (opts !== false) {
opts = $.extend({
color: $this.css('color')
}, opts);
spinner = new Spinner(opts).spin(this);
$this.data('spinner', spinner);
}
});
return this;
};
$(function () {
$(".spinner-link").click(function (e) {
e.preventDefault();
$(this).hide();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
color: '#fff', // #rbg or #rrggbb
speed: 1, // Rounds per second
trail: 66, // Afterglow percentage
shadow: true // Whether to render a shadow
};
$("#spin").show().spin(opts);
});
});
Hope this helps.

Canvas fade in/out functions not working as expected

So I have these functions to fade a canvas in and out that aren't working the way I expect them to. Here's what I'm working with at the moment:
function fade_out ()
{
var canvas = document.getElementById("builder");
var context = canvas.getContext('2d');
console.log(context.globalAlpha);
context.globalAlpha -= 0.01;
if(context.globalAlpha > 0)
{
setTimeout(fade_out, 5);
}
}
function fade_in ()
{
var canvas = document.getElementById("builder");
var context = canvas.getContext('2d');
context.globalAlpha += 0.01;
if(context.globalAlpha < 1)
{
setTimeout(fade_in, 5);
}
}
My intent was to make it a half second fade. What I ended up with was it just blinking in and out in a flash. The console.log in the first function tells me it's not even close to working the way I expect it to. What went wrong here?
EDIT: There seems to be an endless loop going, and the context.globalAlpha is getting into 20 significant digits, even though I didn't use numbers like that.
function fade_in() {
setTimeout( function() {
var cn = document.getElementById("builder");
var ct = cn.getContext('2d').globalAlpha;
ct += 0.02;
if(ct >= 1) {
ct=1;
}
if (ct < 1) {
fade_in();
}
else {
return false;
}
}, 30);
}
function fade_out() {
setTimeout( function() {
var cn = document.getElementById("builder");
var ct = cn.getContext('2d').globalAlpha;
ct -= 0.02;
if(ct <= 0) {
ct=0;
}
if (ct > 0) {
fade_out();
}
else {
return false;
}
}, 30);
}

Categories