Below is an interactive example attempting to implement setStops to a radial gradient. When the 'setStops' button is clicked an error message occurs: "setStops is not a function"
Am I using this correctly?
<!DOCTYPE HTML>
<html>
<head>
<title>Snap.svg setStops</title>
<script type="text/javascript" src="http://svgDiscovery.com/_SNP/snap.svg-min.js"></script>
</head>
<body>
<svg id=mySVG width=400 height=200></svg>
<br><button onClick=stopsSet()>setStops</button>
<script>
var SNPsvg = Snap("#mySVG");
var radialGradient = SNPsvg.gradient("r(.5,.5,.5,.5)#000-#f00-#fff-green");
var circle = SNPsvg.circle(200,100,50).attr({fill: radialGradient});
//---button---
function stopsSet()
{
radialGradient.setStops("#fff-#000-#f00-#fc0");
circle.attr({fill: radialGradient});
}
</script>
</body>
</html>
Seems to be a bug in snap.svg. The code for linearGradient looks like this:
function gradientLinear(defs, x1, y1, x2, y2) {
var el = Snap._.make("linearGradient", defs);
el.stops = Gstops;
el.addStop = GaddStop;
el.getBBox = GgetBBox;
el.setStops = GsetStops;
but for radialGradients it's this:
function gradientRadial(defs, cx, cy, r, fx, fy) {
var el = Snap._.make("radialGradient", defs);
el.stops = Gstops;
el.addStop = GaddStop;
el.getBBox = GgetBBox;
if (cx != null) {
The code to add the setStops function is missing.
I've created a pull request in Snap.svg to fix this so hopefully one of the maintainers will merge it and include it in a subsequent release. In the meantime you could always make the same change to a local copy of Snap.
I think that's because setStops is only available for a linearGradient and not a radialGradient (not sure if that's by design or not).
If you try gradient("L(0, 0, 100, 100)#000-#f00:25-#fff") I think the error will go away. Naturally that's probably not what you want, but I'm just explaining why I think the error is there.
One thing you can always do with Snap if you get stuck, is use a bit of your own markup if it's not supported direct, and add it in. Eg Snap.parse('Some SVG Markup')
var svgMarkup = Snap.parse('<defs><radialGradient id="exampleGradient"><stop offset="10%" stop-color="gold"/><stop offset="95%" stop-color="green"/></radialGradient></defs>');
SNPsvg.append( svgMarkup );
var radialGradient = SNPsvg.select('#exampleGradient')
var circle = SNPsvg.circle(200,100,50).attr({fill: radialGradient});
Example jsfiddle
Related
I'm trying to learn about JavaScript and the html5 canvas, however, it's proving a little confusing and I don't understand why it doesn't seem to work...
I am working on creating a simple map that has some of the capabilities of google maps(drag and drop/zoom in/out/etc). In order to do this, I chose html5 canvas and easeljs for the drag and drop functions.
I have a javascript file (path.js) which contains 2 functions:
pathConstructor() - example function from the easeljs tutorial
drawMap() - copy of the first function slightly modified (and probably wrong right now)
Everything worked fine when I called pathConstructor() from the canvas, however, after I replaced it with drawMap(), everything stopped working. It won't even work if I replace drawMap() with pathContrcutor() right now.
I put some alerts before and after calling the function from the canvas and inside pathConstructor(). The before alert goes off but the others don't so for some reason the function never gets called...
If I use the pathConstructor code as inline code in the canvas then it works just fine, however, I would like to avoid that since I believe it's bad programming. I want it to be neat and each script to have its own file.
Anyone know why this is happening?
HTML
<!Doctype html>
<html>
<head>
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script src="path.js" type="text/javascript"></script>
</head>
<body>
<canvas id="canvas" width="1300px" height="800px"style="border:1px dotted black;">
<script>pathConstructor();</script>
</canvas>
</body>
</html>
Javascript
var stage;
function pathConstructor() {
alert('inside pathConstructor');
stage = new createjs.Stage('canvas');
// this lets our drag continue to track the mouse even when it leaves the canvas:
// play with commenting this out to see the difference.
stage.mouseMoveOutside = true;
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
var label = new createjs.Text("drag me", "bold 14px Arial", "#FFFFFF");
label.textAlign = "center";
label.y = -7;
var dragger = new createjs.Container();
dragger.x = dragger.y = 100;
dragger.addChild(circle, label);
stage.addChild(dragger);
dragger.on("pressmove", function(evt) {
// currentTarget will be the container that the event listener was added to:
evt.currentTarget.x = evt.stageX;
evt.currentTarget.y = evt.stageY;
// make sure to redraw the stage to show the change:
stage.update();
});
stage.update();
}
function drawMap() {
stage = new createjs.Stage('canvas');
var bitMap = new createjs.Bitmap('middle-earth-map.jpg');
stage.mouseMoveOutside = true;
var dragger = new createjs.Container();
dragger.x = dragger.y = 0;
dragger.addChild(bitMap);
stage.addChild(dragger);
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});
stage.update();
}
For me it's working fine, you just have to remove that extra ")" in dragger.on('pressmove', function(evt2)) {;
dragger.on('pressmove', function(evt2)) {
evt2.currentTarget.x = evt2.stageX;
evt2.currentTarget.y = evt2.stageY;
stage.update();
});
I am working on a project using fabric.js and facing this problem.
i have a function fun() and its called on event onclick, so basically i am expecting a circle everytime i click on my screen but as result all i get is a blank screen. alerting the objetcs sure gives me the number of objects with the type circle and is incremented everytime i click on the screen but i cant see the circles on the screen, its like the cirlces are there but not visible.
here is the code:
<html>
<head>
<script type="text/javascript" src="C:\Users\Sunny\Documents\6th Sem Ka Maal\Graph\project\GUI\fabric.js-1.5.0\dist\fabric.js"></script>
<script>
var canvas = new fabric.Canvas('p');
function fun(event){
var x = event.clientX;
var y = event.clientY;
alert(x);
alert(y);
alert(canvas);
var circle= new fabric.Circle({
radius: 50, fill: 'green', left: x, top: y
});
alert(circle);
canvas.add(circle);
}
</script>
</head>
<body>
<canvas id="p" height="993" width="1920" onclick="fun(event)"></canvas>
</body>
</html>
why am i not able to see the circles?
Try wiring up the event in Javascript instead, using Fabric's on() listener.
canvas.on('mouse:up', fun);
Read more about fabric events here:
https://github.com/kangax/fabric.js/wiki/Working-with-events
Last year I was messing around with Fabric for an OU project for point-to-point drawing, you can have a look at it here might give you some ideas.
I am failing at getting a DOM Image onclick event to work.
var context = document.getElementById('canvas').getContext('2d');
var image = new Image();
image.src = "foo.png"
image.onclick = function(e) { console.log("clicked"); }
setInterval(function() {
context.drawImage(image, 100, 100, 50, 50);
};
Why do I not get the log message when i click on the image. In developer tools i can see the onclick function is not null for the image.
Yes, what Musa said...and a few other things.
Some changes to your code
Image.src=”foo.png” should come after the image.onclick function
Context.drawImage should be inside the image.onclick function
setInterval is not needed as far as I can see
Try this:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var context=document.getElementById("canvas").getContext("2d");
var image=new Image();
image.onload=function(){
context.drawImage(image,0,0);
}
image.src="http://i.imgur.com/nJiIJIJ.png";
document.getElementById("canvas").addEventListener("click", function(){console.log("clicked");}, false);
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You cannot set onclick for a particular image added in canvas . You can set onclick for the whole canvas alone so you have to use any third party js or else you should do some calculations which finds that you clicked on the image of the canvas ..
Other users are right.
The image you draw on the canvas is a DOM element but it is rendered in a position which is not stored in the DOM.
This doesn't mean you can access it's position and compare it with the mouse position.
I'm using an external library here, but it does what you need: http://jsfiddle.net/Saturnix/cygUH/
this is the library used.
Since I can't post link to jsfiddles without posting the code, here's the script I've wrote for you.
function demo(g) {
g.ctx.font = "bold 16px Arial";
g.draw = function () {
g.ctx.clearRect(0, 0, g.width, g.height)
var posX = 0;
var posY = 0;
g.ctx.drawImage(image, posX, posY);
if (g.mouseX > posX && g.mouseX < image.width &&
g.mouseY > posY && g.mouseY < image.height &&
g.mousePressed)
g.ctx.fillText("You're clicking the image!", g.mouseX, g.mouseY);
}
}
You can cast a ray (with an onclick on the canvas) into the canvas and manually test your images for intersection with the ray. You should write a
objectsUnderPoint( x, y );
function that returns an array of all the images that intersect with the ray at x, y.
This is the way it is usually done in 3D engines as well. You ofcourse need to keep the image position as a property of the image for intersection testing.
I have problem with display of correct javascript in IE9. Other browsers (Firefox, Opera, Chrome, Safari) work well, but animation in IE is not fluent. For example see this line which can be dragged from left to right (link at the end of the post).
javascript code:
var w = 1250;
var h = 650;
var drawing = Raphael("obrazek",w,h);
var Ax = 50
var Ay = 50
var Ey = 500
var w = 1250;
var h = 650;
var drawing = Raphael("obrazek",w,h);
var Ax = 50
var function onDragMove(dx,dz) {
this.onDragUpdate(dx - (this.deltax || 0), dz - (this.deltaz || 0));
this.deltax = dx;
this.deltaz = dz;
}
function onDragStart() { this.deltax = this.deltaz = 0; }
function onDragStop() { this.onDragStop(); }
// line 1
var Ax
var line = drawing.path([["M",Ax,Ay],["L",Ax,Ey]]).attr({"stroke-width":3})
line.drag(onDragMove,onDragStart)
line.attr({"cursor":"move"})
line.onDragUpdate = function(dx,dz) {
Ax += dx
line.attr({"path":[["M",Ax,Ay],["L",Ax,Ey]]})
}
and corresponding HTML:
<html>
<head>
<script src="raphael.js"></script>
</head>
<body>
<div id="obrazek">
<script src="ietest.js"></script>
</div>
</body>
</html>
or see the problem in IE9 here and compare it with Chrome:
http://mech.fsv.cvut.cz/~stransky/ietest/ietest.html
Thank in advance for any help.
Your page is missing doctype, so it is rendered in quirks mode. IE9 uses VML instead of SVG in quirks mode, which probably results in slower rendering. Just add this on the first line of your html:
<!DOCTYPE html>
However, your code has some other problems:
Missing semicolons. There is a good explanation of how it may be dangerous.
Variable re-declarations and re-definitions.
When handling rapidly repeating events like mousemove or scroll, it is reasonable to use throttling to avoid redrawing/repainting glitches and performance problems. You can read more about it here. Include the plugin from that site and replace your drag binding with the following:
line.drag($.throttle(30, onDragMove), onDragStart);
In fact, even doing this without specifying the doctype can greatly improve the rendering performance, but there's no reason not to specify it altogether.
I'm trying to build an application which, based on various user interactions, allows for various ellipse based visuals to be added to the stage and then animated very simply. I've currently got a basic demo set up where javascript / jquery communicates with processing.js, but it just seems like really inefficient code, because processing relies on running a continuous loop in order to draw to the screen. I'm wondering, one, if the way I'm doing it will be effective on a larger scale, and two, if there's a better technology or method to use. I come from a flash background where nothing on screen is changed or drawn/animated unless a function is triggered telling it to animate, which seems sensible. Anyway, here's my code:
HTML / JS:
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Processing</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
<script src="js/processing-1.3.6.min.js"></script>
<script src="processing/Tween.lib"></script>
</head>
<body>
<canvas id="circles" data-processing-sources="js/drawCircles.js"></canvas>
<div id="clicker">Click</div>
<script>
window.Processing.data = {};
var dataRef = window.Processing.data;
var animInterval;
dataRef.circleArray = new Array();
$('#clicker').click(function(){
var circle = {};
circle.radius = 50;
dataRef.circleArray.push(circle)
var from = {property: 50};
var to = {property: 75};
jQuery(from).animate(to, {
duration: 300,
step: function() {
for (var i in dataRef.circleArray){
circle.radius = this.property;
}
}
});
})
</script>
</body>
</html>
PROCESSING.JS
// Global variables
float radius = 1.0;
int X, Y;
int nX, nY;
int delay = 16;
// Setup the Processing Canvas
void setup(){
// Fill canvas grey
background( 100 );
size( 200, 200 );
strokeWeight( 10 );
frameRate( 15 );
X = width / 2;
Y = width / 2;
nX = X;
nY = Y;
}
// Main draw loop
void draw(){
var dataRef = window.Processing.data;
for (var i in window.Processing.data.circleArray){
radius = dataRef.circleArray[i].radius;
// Set fill-color to blue
fill( 0, 121, 184 );
// Set stroke-color white
stroke(255);
// Draw circle
ellipse( X+(i*10), Y, radius, radius );
}
}
If you want to control when Processing.js draws to the canvas, you have two options. In both cases, the first thing you'll want to do is get access to the Processing instance:
var p = Processing.instances[0];
Now you can make all the Processing API calls you want from JavaScript. You could call noLoop() in your sketch's setup() function, and then inside your jQuery animation loop you could call p.redraw(), which will animate one frame.
In Processing.js we attach all of the functions to the Processing instance. So another option is creating your own function in the sketch, and call it with:
var p = Processing.instances[0];
p.drawEllipses(radius);
You could even pass the data to it in the function parameters, removing the need for windows.Processing.data.
For what you want to do, you might prefer using another library such as paperjs http://paperjs.org/