Dragging in Fabric.js - fabricjs

I feel strange that I cannot find the actual dragging-handling code in Fabric.js's demo (for example, this one), but the objects are already draggable "automatically", which is not my case. Here's my code in an external test.js file:
$(function(){
var canvas = new fabric.Canvas('c');
canvas.setWidth(window.innerWidth);
canvas.setHeight(window.innerHeight);
fabric.Image.fromURL('1.png', function(img) {
var group = new fabric.Group([img],
{
hasBorders: false,
hasControls: false,
selectable: true,
evented: true
})
canvas.add(group).setActiveObject(group);
},
{
originX: 'left',
originY: 'top'
});
canvas.renderAll();
});
And here is the test.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>test</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.3.0/fabric.min.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
Am I missing something? Thank you.
UPDATE: solved by using the newest fabricjs (1.3.12) in github.

Related

how to scale image using scalecontroler

I cannot scale the image when moving the scale controller. It shows the following error:
Uncaught TypeError: canvas.requestRenderAll is not a function
Can please anyone help to solve this problem? I want the functionality to be implemented for image please refer to this. Here is my code:
<!DOCTYPE html>
<html>
<head>
<title>Instagram</title>
<script type="text/javascript" src="fabric.js-1.7.21/dist/fabric.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<canvas id="c" width="500px" height="400px"></canvas>
<div id="range">
<input type="range" class="image-scale-lever" step="0.1" max="3" min="0.1" value="1" id="scale-control"></label>
</div>
<script type="text/javascript">
jQuery( document ).ready(function() {
var canvas = this.__canvas = new fabric.Canvas('c');
fabric.Image.fromURL('locket.png', function(oImg) {
oImg.set({
left: 0,
top: 0,
width:500,
height:400
});
canvas.add(oImg);
var scaleControl = $('#scale-control');
scaleControl.oninput = function(x) {
this.val(x);
oImg.scale(parseFloat(x)).setCoords();
canvas.requestRenderAll();
}
function updateControls() {
scaleControl.oninput(oImg.scaleX);
}
canvas.observe("object:scaling", function (e) {
updateControls();
});
});
});
[1]: https://withyoulockets.com/pub/media/catalog/product/cache/image/700x700/e9c3970ab036de70892d86c6d221abfe/k/a/katieopen1100px-min.png
Here is the result. You need to change the scale of the object on onchange event callback.
<!DOCTYPE html>
<html>
<head>
<title>Instagram</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" >
jQuery( document ).ready(function() {
var canvas = this.__canvas = new fabric.Canvas('c');
fabric.Image.fromURL('https://withyoulockets.com/pub/media/catalog/product/cache/image/700x700/e9c3970ab036de70892d86c6d221abfe/k/a/katieopen1100px-min.png', function(oImg) {
oImg.set({
left: 0,
top: 0,
width:500,
height:400
});
canvas.add(oImg);
var scaleControl = $('#scale-control');
scaleControl.on("change",function() {
var newValue = this.value;
oImg.scale(parseFloat(newValue)).setCoords();
canvas.renderAll();
})
function updateControls() {
scaleControl.oninput(oImg.scaleX);
}
canvas.observe("object:scaling", function (e) {
updateControls();
});
});
});
</script>
<body>
<canvas id="c" width="500px" height="400px"></canvas>
<div id="range">
<input type="range" class="image-scale-lever" step="0.1" max="3" min="0.1" value="1" id="scale-control"></label>
</div>
Check here:
https://jsfiddle.net/3mjhxcyn/2/

jQuery mobile app doesn't work on Android app created using PhoneGap [duplicate]

What is the correct way (to this date) to use JQuery Mobile and Phonegap together?
Both frameworks need to load before they can be used. How can I be sure that both are loaded before I can use them?
You can use deferred feature of JQuery.
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
document.addEventListener("deviceReady", deviceReady, false);
function deviceReady() {
deviceReadyDeferred.resolve();
}
$(document).one("mobileinit", function () {
jqmReadyDeferred.resolve();
});
$.when(deviceReadyDeferred, jqmReadyDeferred).then(doWhenBothFrameworksLoaded);
function doWhenBothFrameworksLoaded() {
// TBD
}
Here's how it worked for me, based on the example above
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<title>InforMEA</title>
</head>
<body>
<script type="text/javascript" src="js/jquery-1.8.3.js"></script>
<script type="text/javascript">
var dd = $.Deferred();
var jqd = $.Deferred();
$.when(dd, jqd).done(doInit);
$(document).bind('mobileinit', function () {
jqd.resolve();
});
</script>
<script type="text/javascript" src="js/jquery.mobile-1.2.0.js"></script>
<script type="text/javascript" src="cordova-2.2.0.js"></script>
<script type="text/javascript">
document.addEventListener('deviceready', deviceReady, false);
function deviceReady() {
dd.resolve();
}
function doInit() {
alert('Ready');
}
</script>
</body>
</html>
In order to use phonegap along with jquery mobile, you need to use it like this
<head>
<title>Index Page</title>
<!-- Adding viewport -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no">
<!-- Adding jQuery scripts -->
<script type="text/javascript" src="jquery/jquery-1.7.1.min.js"></script>
<!-- Since jQuery Mobile relies on jQuery core's $.ajax() functionality,
$.support.cors & $.mobile.allowCrossDomainPages must be set to true to tell
$.ajax to load cross-domain pages. -->
<script type="text/javascript">
$(document).bind("mobileinit", function() {
$.support.cors = true;
$.mobile.allowCrossDomainPages = true;
});
</script>
<!-- Adding Phonegap scripts -->
<script type="text/javascript" charset="utf-8"
src="cordova/cordova-1.8.0.js"></script>
<!-- Adding jQuery mobile scripts & CSS -->
<link rel="stylesheet" href="jquerymobile/jquery.mobile-1.1.0.min.css" />
<script type="text/javascript"
src="jquerymobile/jquery.mobile-1.1.0.min.js"></script>
</head>
<script type="text/javascript">
// Listener that will invoke the onDeviceReady() function as soon as phonegap has loaded properly
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
navigator.splashscreen.hide();
document.addEventListener("backbutton", onBackClickEvent, false); // Adding the back button listener
}
</script>
<body>
<div data-role="page" id="something" data-ajax="false">
<script type="text/javascript">
$("#something").on("pageinit", function(e) {
});
$("#something").on("pageshow", function(e) {
});
$("#something").on("pagebeforeshow", function(e) {
});
</script>
<div data-role="header">
</div>
<div data-role="content">
</div>
</div>
</body>
As many people suggested using a deferred is an okay option as long as you don't care what order deviceready and mobileinit happe in. But in my case, I needed a few pageshow events when the application first loaded and mobileinit and by extension those pageshow/pagebeforeshow/etc events were all firing before deviceready finished, so I couldn't bind to them properly using a deferred on them. This race condition was not a good thing.
What I needed to do was make sure 'mobileinit' didn't take place until after 'deviceready' was already fired. Because mobileinit fires immediately when you load JQM I chose to use jQuery.getScript to load it AFTER deviceready was already finished.
<script src="cordova-2.2.0.js"></script>
<script src="js/jquery-1.8.2.min.js"></script>
<script src="js/async.min.js"></script>
<script src="js/app.js"></script>
<script>
document.addEventListener(
'deviceready',
function () {
$('body').css('visibility', 'hidden');
$(document).one("mobileinit", function () {
app.init();
$('body').css('visibility', '');
});
$.getScript('js/jquery.mobile-1.2.0.min.js');
},
false
);
</script>
The reason I'm hiding the body is that a side effect of this method is a half second of visibility of the original HTML document before jquery.mobile loads. In this case hiding it an extra half second of empty space is preferred to seeing the unstyled document.
I believe that it isn't necessary to use the deferred feature. (Maybe this isn't necessary with newer versions of phonegap?) I have this in the head of my index.html file and everything works fine. I do think that the order of including jquery, phonegap and jquery mobile are important.
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<!-- Adding jQuery -->
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<!-- Add Phonegap scripts -->
<script type="text/javascript" src="phonegap.js"></script>
<!-- Add jQuery mobile -->
<link rel="stylesheet" href="css/jquery.mobile-1.3.2.css" />
<script type="text/javascript" src="js/jquery.mobile-1.3.2.min.js"></script>
<title>MY TITLE</title>
</head>
this is work for me. base on dhaval,this sample when I learn using sqlite
<!DOCTYPE html>
<html>
<head>
<title>Cordova Sqlite+Jquery</title>
<script type="text/javascript" charset="utf-8" src="js/jquery-1.8.3.min.js"></script>
<script type="text/javascript" charset="utf-8" src="cordova-2.2.0.js"></script>
<script type="text/javascript" charset="utf-8">`
// Call onDeviceReady when Cordova is loaded.
//
// At this point, the document has loaded but cordova-1.8.0.js has not.
// When Cordova is loaded and talking with the native device,
// it will call the event `deviceready`.
//
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
}
// Populate the database
//
function populateDB(tx) {
tx.executeSql('DROP TABLE IF EXISTS DEMO');
tx.executeSql('CREATE TABLE IF NOT EXISTS DEMO (id unique, data)');
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (1, "First row")');
tx.executeSql('INSERT INTO DEMO (id, data) VALUES (2, "Second row")');
}
// Query the database
//
function queryDB(tx) {
tx.executeSql('SELECT * FROM DEMO', [], querySuccess, errorCB);
}
// Query the success callback
//
function querySuccess(tx, results) {
var len = results.rows.length;
//console.log("DEMO table: " + len + " rows found.");
$('#result').html("DEMO table: " + len + " rows found.");
var listval = '';
for (var i=0; i<len; i++){
//console.log("Row = " + i + " ID = " + results.rows.item(i).id + " Data = " + results.rows.item(i).data);
listval += '<li>'+ results.rows.item(i).data + '[' + results.rows.item(i).id + '] </li>';
}
$('#listItem').html(listval);
}
// Transaction error callback
//
function errorCB(err) {
console.log("Error processing SQL: "+err.code);
}
// Transaction success callback
//
function successCB() {
var db = window.openDatabase("Database", "1.0", "PhoneGap Demo", 200000);
db.transaction(queryDB, errorCB);
}
// Cordova is loaded and it is now safe to make calls Cordova methods
//
function onDeviceReady() {
// Now safe to use the Cordova API
//alert('ready');
var db = window.openDatabase("Database", "1.0", "PhoneGap Demo", 200000);
db.transaction(populateDB, errorCB, successCB);
//$('#result').html('hello');
}
</script>
</head>
<body onload="onLoad()">
<div>result:</div><div id="result"></div>
<ul id="listItem">
</ul>
</body>
</html>
To build on #Jeffrey's answer, I found a much cleaner way which hides the HTML markup until JQM has finished processing the page and renders the first Page element, since I've noticed that 1/2 second flicker of bare markup before JQM renders.
You only need to hide all the markup with css...PageShow() by JQM will toggle the visibility for you.
//snip
<style type="text/css">
.hide {
display:none;
}
</style>
//snip - now the markup notice the hide class
<div id="page1" data-role="page" class="hide">
//all your regular JQM / html form markup
</div>
//snip -- down to the end of /body
<script src="cordova-2.2.0.js"></script>
<script src="js/jquery-1.8.2.min.js"></script>
<script>
document.addEventListener(
'deviceready',
function () {
$(document).one("mobileinit", function () {
//any JQM init methods
});
$.getScript('js/jquery.mobile-1.2.0.min.js');
},
false);
</script>
The following worked for me on PG 2.3 and JQM 1.2, incl. Facebook Connect Plugin:
<head>
<script src="./js/jquery-1.8.2.min.js"></script>
<script>
$.ajaxSetup({
dataType : 'html'
});
var dd = $.Deferred();
var jqd = $.Deferred();
$.when(dd, jqd).done(function() {
FB.init({ appId: auth.fbId, nativeInterface: CDV.FB, useCachedDialogs: false });
});
$(document).bind('mobileinit', function () {
jqd.resolve();
});
</script>
<script src="./js/jquery.mobile-1.2.0.min.js"></script>
<script>
$.mobile.loader.prototype.options.text = "loading";
$.mobile.loader.prototype.options.textVisible = true;
$.mobile.loader.prototype.options.theme = "a";
$.mobile.loader.prototype.options.html = "";
$.mobile.ajaxEnabled = false;
$.mobile.allowCrossDomainPages = true;
$.support.cors = true;
$('[data-role=page]').live('pagecreate', function(event) {
tpl.renderReplace('login', {}, '#content-inner', function() {
auth.init();
});
});
</script>
<script src="./js/cordova-2.3.0.js"></script>
<script src="./js/cdv-plugin-fb-connect.js"></script>
<script src="./js/facebook_js_sdk.js"></script>
<!--some more scripts -->
<script>
document.addEventListener('deviceready', function() {
dd.resolve();
}, false);
</script>
<head>
Loading of PhoneGap is slightly different than loading of jQuery. jQuery works more as a utility library so you include that and it is available for use immediately. On the other hand PhoneGap requires support from native code for proper initialization so it is not ready to use soon after included in the page.
Phonegap suggests to register and wait for deviceready event executing any native specific code.
<!DOCTYPE html>
<html>
<head>
<title>PhoneGap Example</title>
<script type="text/javascript" charset="utf-8" src="lib/jquery.min.js"></script>
<script type="text/javascript">
// jquery code here
</script>
<script type="text/javascript" charset="utf-8" src="lib/android/cordova-1.7.0.js"></script>
<script type="text/javascript" charset="utf-8">
function onLoad(){
document.addEventListener("deviceready", onDeviceReady, false);
}
// Cordova is ready
function onDeviceReady() {
// write code related to phonegap here
}
</script>
</head>
<body onload="onLoad()">
<h1>Phonegap Example</h1>
</body>
</html>
For more info check doc

draw line on mouse drag in raphael js

This is what I have tried:
<!doctype html>
<html>
<head>
<title>Editor</title>
<meta http-equiv="x-ua-compatible" content="ie=9"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/connector.js"></script>
<link rel="stylesheet" href="<%=request.getContextPath()%>/style.css" />
<script type="text/javascript">
window.onload = function ()
{
var paper = new Raphael(Raphael("container", "100%", "100%"));
var line = paper.path();
var start = function (x, y) {
this.ox = this.attr("x");
this.oy = this.attr("y");
var line = paper.path("M", this.ox, this.oy);
},
move = function (dx, dy) {
this.attr({
x: this.ox + dx,
y: this.oy + dy
});
paper.path("L",x,y);
},
up = function () {
this.animate({
opacity: 0
}, 500);
};
paper.set(line).drag(move, start, up);
};
</script>
</head>
<body>
<div id="container">
<div id="header" style="margin-bottom: 0;">
<h1 id="title">Editor</h1>
<div id="footer"></div>
</div>
</div>
</body>
</html>
Here's the live demo: https://jsbin.com/giqufilusu/1/edit?html,output
I don't know why its not working. Is there a syntax problem or I didn't code the correct way. There are some examples on web but most of them use jquery + raphael js to draw line on mouse events but I want to draw with drag() method of raphael. How do I fix this?
I don't know if I got you right.
I guess this is what you want to achieve?
You defined the line variable only in the scope of the start function. To adapt the line you need to make it available to all functions. The jsBin is a quick and dirty approach which should give you a hint how you can do this line drawing with Raphael.

Google Maps: ReferenceError: google is not defined

Whenever i try to load the google maps html code i never get anything to display and i get the following error:
ReferenceError: google is not defined
I can create a hyperlink to google maps but this isn't what i want. I also went ahead and got my own API key and put it into my code. Why isn't google defined? This seems too common of a problem to not have a solution.
Here is my HTML:
<!DOCTYPE html>
<html>
<head>
<title>My first Google Map</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
padding: 0;
}
#map-canvas {
height: 100%;
}
</style>
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDX71YSt1efYJH3MdIsH3SF3kyJNjN-Z78&sensor=false">
</script>
<script type="text/javascript">
function initialize() {
var myLatLng = new google.maps.LatLng(54.124634, -3.237029)
var mapOptions = {
center: myLatLng,
zoom: 17,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
var myMarker = new google.maps.Marker({
position: myLatLng,
map: map,
title: "A place on Earth",
draggable: true,
})
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas" />
</body>
</html>

Coordinates system changed in Fabric.js 1.3.12?

TL; DR: why is the location of the image different?
There seems to be some difference in the coordinate system between 1.3.0 and 1.3.12. Here are the HTML file test.html, working with the newly cloned and built fabric.js by myself ():
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>test</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="./fabric.js/dist/all.min.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
and the JavaScript file test.js:
$(function(){
var canvas = new fabric.Canvas('c');
canvas.setWidth(window.innerWidth);
canvas.setHeight(window.innerHeight);
fabric.Image.fromURL('test.png', function(img) {
var group = new fabric.Group([img],
{
hasBorders: false,
hasControls: false,
selectable: true,
evented: true,
})
canvas.add(group);
});
});
The web page looks like
But if I change fabric.js to the version on the CDN, which is 1.3.0:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>test</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.3.0/fabric.min.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<canvas id="c"></canvas>
</body>
</html>
The web page will look like
The second case makes more sense for me. It puts the center of the image to (0,0). But in the first case it seems to put the image center to (image_width, image_height). So is this a bug? Or a feature of coordinate system for groups?
UPDATE: if simply using
$(function(){
var canvas = new fabric.Canvas('c');
canvas.setWidth(window.innerWidth);
canvas.setHeight(window.innerHeight);
fabric.Image.fromURL('test.png', function(img) {
canvas.add(img);
});
});
, the top left corner of the image will be attached to (0,0).
UPDATE 2: OK, I need to manually set {left: 0, top:0} for the group. But why?
What you're seeing is that originX/originY default values were changed to "left"/"top" from "center"/"center".
This was a very confusing behavior to almost anyone starting with Fabric and we finally got rid of it. You can see this breaking change in a changelog (between unreleased edge/dev version and latest stable 1.3.0)
https://github.com/kangax/fabric.js/blob/master/CHANGELOG.md
originX/originY represent what left/top values of an object are relative to. All objects' left/top used to be relative to their centers; now we're using more common system of left/top corner.

Resources