I have seen a lot of frameworks and extensions recently and all for a lot of different things. It is hard for me to do things using just raw JavaScript or raw jQuery. I want to use these JS extensions/frameworks but the problem is that I don't know how to link them to my HTML document.
For Example: <script src="some link of fw/ext" type="text/javascript"></script> I put this in the <head> of my HTML and then write my code in a different file named "script.js" (made using notepad) but the code doesn't seem to work.
I know this is a problem because I don't link it properly.
I want to work with fabric.js on a project related to HTML5 canvas. I think I need to link both, my code and the framework in some way but I'm not sure as to how should I do it.
My HTML code :
<!DOCTYPE html>
<html>
<head>
<title>Code Example</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css"/>
<script type="text/javscript" src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
</head>
<body>
<canvas id="draw" width="250px" height="250px">This if browser doesn't support HTML5
</canvas>
</body>
</html>
My JS Code:
var canvas = new fabric.Canvas('draw');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.width = 100;
canvas.freeDrawingBrush.color = "#ff0000";
Should work somewhat like this : http://jsfiddle.net/MartinThoma/B525t/5/
You need to load fabric.js first at the header and then you need to load your js file order matters.
<script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js'></script>
<script type='text/javascript' src='yourjsfile.js'></script
In case you are not clear on how to add elements to the canvas. Then here is one snippet which could help you.
Also wrap your code inside onload() function so that when the script loads, the #draw element is available
window.onload = function() {
var canvas = new fabric.Canvas('draw');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.width = 5;
canvas.freeDrawingBrush.color = "#ff0000";
// create a rectangle object
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 20,
height: 20
});
// you need to add the object to canvas
canvas.add(rect);
}
Related
I've been hitting wall after wall while following along with almost all of the basic snap.svg tutorials out there. While running their code through jsfiddle or codepen everything works, but when I try the same through my own local editor I've had little luck.
My code:
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="js/snap.svg.js"></script>
</head>
<body>
<svg id="svg" class="svg"></svg>
</body>
</html>
JavaScript
var surface = Snap("#svg");
var circ = surface.circle(100, 100, 50);
circ.attr({
fill: "#addedd",
strokeWidth: 10,
stroke: "#beeeef"
});
CSS
body {
display: block;
width: 200px;
height: 200px;
margin: 50px auto;
}
.svg {
width: 100%;
height: 100%;
}
The main issue I was always presented was a Reference Error for the line:
var surface = Snap("#svg");
I resolved this by including a callback and wrapping the block in a function:
function main(){
var surface = Snap("#svg");
var circ = surface.circle(100, 100, 50);
circ.attr({
fill: "#addedd",
strokeWidth: 10,
stroke: "#beeeef"
});
};
$(document).ready(main);
I feel like these tutorials are skipping something? I'm sure there is a better resolution than what I came up with? What do you think?
I just want to start learning Snap!
Snap has no dependency on jquery.
The problem may be that you are running the script and calling this line.
var surface = Snap("#svg");
Before the svg markup
<svg id="svg" class="svg"></svg>
is loaded into the DOM. So it can't find the element to reference. The issue isn't related to Snap at all, just normal HTML/SVG and JS loading and ordering.
What isn't clear from the original code, is when you are loading your own js code in. You could try putting it after the svg markup, but generally it's preferred to make sure the document is ready first with...
$(document).ready( ... )
As you have already found :).
As you have mentioned, Snap code can only be executed once, jQuery is loaded.
$(document).ready(function(){
var surface = Snap("#svg");
var circ = surface.circle(100, 100, 50);
circ.attr({
fill: "#addedd",
strokeWidth: 10,
stroke: "#beeeef"
});
});
The order of loading js files is important. Since snap has a dependency on jQuery, you can't execute it until jQuery is ready.
More than Snap or any javaScript library, it is important for you to understand the basic of JS first. Smaller files will be loaded faster than a large file even though, they are requested afterwards.
In your case, even before jQuery got downloaded, main function of your js got executed and you got an error. This is why, $(document).ready is always the preferred way of starting your code with jQuery.
EDIT:
As #Ian has pointed out, snap has no dependency on jQuery. The actual issue was of the wrong ordering of the js files. The correct order should be as the following,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="js/snap.svg.js"></script>
</head>
<body>
<svg id="svg" class="svg"></svg>
<!-- custom code should be loaded after the svg markup -->
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
I am trying to pass the canvas HTML element as a parameter, and I thought 'this' would work but I can't quite get it to. Could someone help me use the 'this' keyword to pass the canvas to main() upon page-load, please?
Doesn't work:
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body onload=main(this.firstChild)><canvas></canvas></body>
<script>
function main(canv) {
cntx = canv.getContext("2d");
cntx.rect(10, 10, 100, 100);
cntx.fill();
}
</script>
</html>
Works, but would like to use the 'this' keyword instead:
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body onload=main(document.body.firstChild)><canvas></canvas></body>
<script>
function main(canv) {
cntx = canv.getContext("2d");
cntx.rect(10, 10, 100, 100);
cntx.fill();
}
</script>
</html>
Doesn't work (onload not defined for canvas element):
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body><canvas onload=main(this)></canvas></body>
<script>
function main(canv) {
cntx = canv.getContext("2d");
cntx.rect(10, 10, 100, 100);
cntx.fill();
}
</script>
</html>
Works, and uses 'this', but want the code to run without clicking:
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body><canvas onclick=main(this)></canvas></body>
<script>
function main(canv) {
cntx = canv.getContext("2d");
cntx.rect(10, 10, 100, 100);
cntx.fill();
}
</script>
</html>
I suggest you consider a different approach as you risk complicating the expressiveness of your overall scripting logic if you're mixing it into your HTML tags. More to your point, while you can't use onload in an HTML tag context to get any this beyond the window, you can create JS functions that are defined to execute after window.onload in any fashion you want.
You're already using JavaScript to define your canvas attributes, why not create the canvas in JS at the same time!
You can also see how this could be extended to open up your options on creating/appending more canvasses on the fly.
If this doesn't work for you, let me know if this was an abstracted question for an issue that I might be able to help with more directly.
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body>
<script>
function createCanvasRect(x, y, width, height) {
var canv = document.createElement('canvas'),
cntx = canv.getContext('2d');
cntx.rect(x, y, width, height);
cntx.fill();
return canv;
}
function load() {
var canvas = createCanvasRect(10, 10, 100, 100);
document.body.appendChild(canvas);
}
window.onload = load;
</script>
</body>
</html>
Your problem is with the use of onload.
Typically, a listener attached in-line is called as if wrapped in an outer function with it's this set to the element on which the listener is called. However, that's not the case for onload listeners attached to the body element. Their execution is delayed and they are called with the global / window object set to this.
So you can't use this the way you're trying to do it.
The following demonstrates that a the body's load listener is called with this as the global object, but the div's click listener is called with the div element as this.
<script>
// Reference to global/window object
var global = this;
</script>
<body onload="console.log(this === global)">
<div onclick="console.log(this.tagName)">clickable div</div>
</body>
Try this. I put javascript out from HTML for more cleaner code.
function main() {
console.log(this);
var cntx = this.getContext("2d");
cntx.rect(10, 10, 100, 100);
cntx.fill();
}
window.onload = function() {
main.call(document.getElementById('main'));
}
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body>
<canvas id="main"></canvas>
</body>
</html>
Well so many ways to do things.
Element referencing in Javascript
To access a DOM element you need to id it by giving it a unique id.
<canvas id="myCanvas"></canvas>
Note id Must be unique, if another element has the same id the browser will enter quirks mode (see below)
You can then access it directly using its id as a variable name.
var ctx = myCanvas.getContext("2d");
There are some that prefer to use the slower and more painful.
var ctx = document.getElementById("myCanvas").getContext("2d");
Or others use
var ctx = document.querySelector("#myCanvas").getContext("2d");
Get it in order
All these methods have one problem. When a browser parses a page it adds elements to the DOM one at a time from the top down.
If you add some script above the elements you want to use, the script will not find the elements as they have not yet been created
<canvas id="topCan"></canvas>
<script> // this code is run when the browser finds it
var ctx = topCan.getContext("2d"); // works as the element has been created
var ctx1 = botCan.getContext("2d"); // no work as the element does not yet exist
</script>
<canvas id="botCan"></canvas>
So to make sure you add the script after the elements (and before the closing body tag see quirks mode below)
Sometimes its just plain inconvenient for you to put the script after the content. That is when you would put the code inside a function you call on the load event. The code in the function will not run until all the elements have been added to the page.
How you listen to that event is up to you, see below
Organizing an event
It is considered bad form to assign an event handler directly
myCanvas.onclick = function(){};
and even worse if you do
<canvas onclick = "myFuction(this)"></canvas>
with the road of enlightenment packed with those that say the following way is the way
const canvas = document.querySelector("#myCanvas");
canvas.addEventListener("click",myFunction);
function myFunction(){ /* code */}
All the above methods work, none of them are right or wrong, there are a few other ways as well. What method you use is up to you, I always recommend that you use the method you find easiest to remember and use.
Careful of the quirks
But there are some things you should not do. The reason is that some layouts make the browser think its back in the late 90's early 2000's, and you have not followed the rules (rules that nobody actually knew), to stop it's self looking stupid next to its peers it will switch to quirks mode which is not good and will generally slow everything down.
One of the things that can trigger quirks mode is placing a script tag where it should not be.
So NEVER put a script tag outside the body or head tags
The path to world peace is always put script tags where they belong.
<html>
<head>
<script></script> <!-- browser is your friend -->
</head>
<body>
<script></script> <!-- browser thinks your great -->
<p> some content </p>
<script></script> <!-- and you know everything-->
</body>
</html>
The way to darkness. Putting a script tag anywhere as follows
<script></script> <!-- wrong -->
<html>
<script></script> <!-- wrong -->
<head>
</head>
<script></script> <!-- oh so bad -->
<body>
</body>
<script></script> <!-- oh so bad -->
</html>
<script></script> <!-- just playing with fire -->
One way
How I would do depends on the tide so currently
<html>
<head>
<title>Draw on Canvas</title>
</head>
<body>
<!-- id the canvas with a unique id -->
<canvas id = myCanvas></canvas>
<script> // script after the element you are accessing
const ctx = myCanvas.getContext("2d");
ctx.rect(10, 10, 100, 100);
ctx.fill();
</script> <!-- ensure the script is inside the body tag -->
</body>
</html>
I am trying to convert a div containing some img tags to a png. After some search, it looks like the best way is to use the html2canvas library.
The problem is that it is not working for me and I don't understand why.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="lib/css/bootstrap.min.css">
<script src="lib/js/Blob.js"></script>
<script src="lib/js/canvas-to-blob.min.js"></script>
<script src="lib/js/FileSaver.js"></script>
<script src="lib/js/html2canvas.js"></script>
<script src="lib/js/jquery.min.js"></script>
<script src="lib/js/underscore-min.js"></script>
<title>Tests Only</title>
</head>
<body>
<div id="navigationButtons">
</div>
<div id="sourceScreen" style="width:200px">
<img id="lol" src="tier-icons/base_icons/bronze.png" />
</div>
<div id="targetScreen">
</div>
<script = "text/javascript">
jQuery('#navigationButtons').append('<button type="button" id="makeScreenshot">Screenshot</button>');
jQuery('#makeScreenshot').click(makeScreenshot);
function makeScreenshot(){
html2canvas(jQuery('#sourceScreen'), {
onrendered: function(canvas) {
jQuery('#targetScreen').html(canvas);
}
});
}
</script>
</body>
</html>
Here is a jsFiddle of my code:
https://jsfiddle.net/2vv79ehy/1/
I am trying to get it work with 1 img tag first on this example, the goal is to display the canvas under the real image.
I know there is a problem with cross-domain resources with this library but when I do the test with my real code, the image is hosted on my computer.
Does anyone know how to do it or if there is another way (would be great if it could bypass cross-domain problems too)?
Your JSFiddle works, except for the cross-domain problem. I've played around trying to find a quick hack around it, but the best I could come up with is just drawing onto the canvas that you're given in your onrendered event and I haven't really played with positioning and the z-order would be impossible to implement this way, but maybe this edit to your makeScreenshot function helps you find a solution that works for you:
function makeScreenshot(){
html2canvas(jQuery('#sourceScreen'), {
onrendered: function(canvas) {
var img = jQuery("#cat");
var ctx = canvas.getContext("2d");
var originalPosition = { left: 0, top: 18 };
ctx.drawImage(img[0],originalPosition.left,originalPosition.top);
jQuery('#targetScreen').html(canvas);
}
});
}
My canvas wont show in my browser.
I'm guessing the reason is because of some newbie jquery mistakes.
The codes below are in two separate folders, Game.html and game.js
Game.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<canvas id="gameCanvas">
</canvas>
<script src="Scripts/jquery-2.0.3.js" type="text/javascript"> </script>
<script src="Scripts/game.js" type="text/javascript"> </script>
</body>
</html>
game.js:
var canvasWidth = 800;
var canvasHeight = 600;
$('#gameCanvas').attr('width', canvasWidth);
$('#gameCanvas').attr('height', canvasHeight);
var canvas = $('#gameCanvas')[0].getContext('2d');
canvas.strokeRect(0, 0, canvasWidth, canvasHeight);
Here is tested your code is working perfectly.
Look in your Scripts folder content files jquery-2.0.3.js and game.js.
the only possibility is error path, look at this.
And what browser are you testing? html5 canvas is then only works in some new browsers.
checked here if your browser does have canvas support
Code Equals
working example here
Are you sure your reference to the script file is correct. If both html and script are in two different folders, then the reference might need to be:
<script src="../Scripts/jquery-2.0.3.js" type="text/javascript"> </script>
<script src="../Scripts/game.js" type="text/javascript"> </script>
Here I have a very simple script.
stage = new createjs.Stage("myCanvas");
circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0,0,40);
And my HTML
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="mainStyle.css">
<script src="mainScript.js"></script>
<script src="create.js"></script>
</head>
<body>
<canvas id="myCanvas" width=1000 height=500 ></canvas>
</body>
</html>
Yet it does not work. I get this error:
"createjs is not defined"
But in my HTML it is linked to file. Is there anything else that could be causing this?
<script src="create.js"></script>
<script src="mainScript.js"></script>
Your code needs to execute AFTER including create.js - order matters.
There are a couple problems with your code.
First, and to directly answer the question, you have to load the library which constructs the createjs object before you load your script which instantiates it. Change the order of the script tags you have in your head.
Second, your instantiation will execute before the canvas element is added to the DOM. To fix this you need to listen for the document's onload event. Then execute your code.
Third, to get the red circle object to actually show up you need to append it to the canvas and then call the stages update method.
Ex:
window.onload = function(){
stage = new createjs.Stage("myCanvas");
circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0,0,40);
stage.addChild(circle);
stage.update();
}
For angular projects the above answers might not be sufficient to solve the problem. What I did:
myAngularModule.service('preloadservice', function ($rootScope) {
if (typeof createjs === 'undefined') {
setTimeout(continueAfterWait, 500);
} else {
continueAfterWait();
}
var continueAfterWait = function () {
var queue = new createjs.LoadQueue();
//...
}
}