The default stroke for creating SVG elements with raphaeljs seems to be black 1px. I can manually turn it off every time I create an element, but I rather set it as a default attribute "stroke: none" to the entire paper. Is it possible?
I encountered this problem a little while ago; I believe this is a library default. Whilst you could change this in your library source, doing so would make updating library versions difficult, so you might be better off disabling it in the code that calls Raphael.
If you're worried about this being verbose, you could use a delegate function that hides the 'defaulting hacks' as you build similar shapes.
It depends if this is just for defaults, or trying to cut down repeated code etc. You could create your own shape with defaults you want as a possible alternative is what I was thinking...
var paper = Raphael('mydiv',400,400);
Raphael.fn.myBlueCircle = function (x,y,r) {
this.circle(x,y,r).attr({fill: "#00f", stroke: "none"});
};
paper.myBlueCircle(100,100,100);
paper.myBlueCircle(150,200,100);
jsfiddle
You may also want to do the same for sets if those are to be used with the new elements reference
Related
This is not a: "Do all the work for me!" kind of question. I just wanna know which approach you think would be suitable for this challenge.
I have this map:
As you can see by the blue marker, I've roughly drawned some selections/areas of the map. Theese areas I want to serve as links.
But I don't quite know how to grasp this challenge, since all of the areas have quite odd shapes.
I have looked at cords, but it seems like a huge job with all of the twists and turns that I would need to do.
I would be awesome if I could just slice up the areas in Photoshop and save each of them as .png and just tell my page to ignore the transparent area! But that's just wishfull thinking I suppose.
I hope that one of you have a suggestion that I've overlooked.
Give a try to these -
http://polymaps.org/
http://www.amcharts.com/javascript-maps/
Raphael JS
You can try making an SVG version of your map and then implement it's clickiness with one of these libraries depending on which one you choose.
Here's one tutorial to do this with Raphael JS - http://parall.ax/blog/view/2985/tutorial-creating-an-interactive-svg-map
Make an image for each clickeable zone, like this:
Register to the click event of the img element from the page, this way:
var getAreaFromXY = function(x,y) {
// for each section colored map
// get pixel color on x,y (see http://stackoverflow.com/questions/8751020/how-to-get-a-pixels-x-y-coordinate-color-from-an-image)
// if the color is red, that is the zone
};
$(".post-text img").click(function(e) {
var area = getAreaFromXY(e.offsetX, e.offsetY);
});
When animating one layer in canvas the graphics become choppy if there are other layers present, see fiddle (click RUN to see animation): http://jsfiddle.net/Q97Wn/
If i change this line:
opts.percentageIndicator.clearRect(0, 0, opts.percentageIndicator.width, opts.percentageIndicator.height);
To:
opts.percentageIndicator.clearRect(0, 0, opts.canvas.width, opts.canvas.height);
Then everything goes smoothly, except that this will remove the other layer completely.
I could solve this issue by having both in one canvas each, but i was hoping for structure-purposes that i could avoid that. Any suggestions?
First of all, canvas.getContext() not generating new context, it returning already existing instance, so the lines:
opts.centerCircle = opts.canvas.getContext('2d');
// ...
opts.percentageIndicator = opts.canvas.getContext('2d');
Would mean the same thing.
So I advice you to do like this:
http://jsfiddle.net/Volter9/Q97Wn/2/
What I did I just changed both contexts to one property and after rendering base added:
opts.ctx.strokeStyle = opts.indicatorColor;
Good luck!
I'm working on an application that uses Raphael to draw primitive shapes (rectangles, ellipses, triangles etc) and lines but allows the user to move/resize these objects as well. One of the main requirements is that the face of shapes can have formatted text. The actual text is a subset of Markdown (simple things like bolding, italics, lists) and is rendered as HTML.
FWIW - I'm using Backbone.js views to modularize the shape logic.
Approach 1
My initial thought was to use a combination of foreignObject for SVG and direct HTML with VML for IE. However, IE9 doesn't support foreignObject, and therefore this approach had to be abandoned.
Approach 2
With the beside the canvas object, add divs that contain the actual HTML. Then, position them over the actual shape with a transparent background. I've created a shape view that has references to both the actual Raphael shape and the "overlay" div. There are a couple of problems with this approach:
Using overlay that aren't children of the SVG/VML container feels wrong. Does having this overlay element cause other issues with rendering down the road?
Events that are normally trapped by Raphael (drag, click etc) need to be forwarded from the overlay to the Raphael object. For browsers that support pointer-events, this is easily done:
div.shape-text-overlay {
position: absolute;
background: none;
pointer-events: none;
}
However, other browsers (like IE8 and below) need forwarding of the events:
var forwardedEvents = 'mousemove mousedown mouseup click dblclick mouseover mouseout';
this.$elText.on(forwardedEvents, function(e) {
var original = e.originalEvent;
var event;
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
event.initEvent(e.type, true, true);
}
else {
event = document.createEventObject();
event.eventType = e.type;
}
// FYI - This is the most simplistic approach to event forwarding.
// My real implementation is much larger and uses MouseEvents and UIEvents separately.
event.eventName = e.type;
_.extend(event, original);
if (document.createEvent) {
that.el.node.dispatchEvent(event);
}
else {
that.el.node.fireEvent('on' + event.eventType, event);
}
});
Overlapping shapes cause the text to be overlapped because the text/shapes are on different layers. Although overlapping shapes won't be common, this looks bad:
This approach is what I'm currently using but it just feels like a huge hack.
Approach 3
Almost like Approach 1, but this would involve writing text nodes/VML nodes directly. The biggest problem with this is the amount of manual conversion necessary. Breaking outside of Raphael's API seems like it could cause stability issues with the other Raphael objects.
Question
Has anyone else had to do something similar (rendering HTML inside of SVG/VML)? If so, how did you solve this problem? Were events taken into account?
I built this project (no longer live) using Raphael. What I did is actually abandoned the idea of using HTML inside of SVG because it was just too messy. Instead, I absolutely positioned an HTML layer on top of the SVG layer and moved them around together. When I wanted the HTML to show, I merely faded it in and faded the corresponding SVG object out. If timed and lined up correctly, it's not really noticeable to the untrained eye.
While this may not necessarily be what you're looking for, maybe it will get your mind thinking of new ways to approach your problem! Feel free to look at the JS on that page, as it is unminified ;)
PS, the project is a lead-gathering application. If you just want to see how it works, select "Friend" in the first dropdown and you don't have to provide any info.
Unless another answer can be provided and trump my solution, I have continued with the extra div layer. Forwarding events was the most difficult part (if anyone requires the forwarding events code, I can post it here). Again, the largest downside to this solution is that overlapping shapes will cause their text to overlap above the actual drawn shape.
I've created a 'donut' chart originally from this jsfiddle, using raphael.
I have tweaked this script to suit my needs and currently have this being rendered.
My aim is to animate each slice (at the same time); for example make the blue slice grow to 60%; and the red slice shrink to 40%.
I have been able to redraw the slices by removing the existing one and quickly re-rendering a new one with adjusted values (e.g. 51, 49). But the problem here is that it is instant.
My question is,
(a) Can I animate this without the need to redraw the object (and how)?
(b) If not, how I can animate this effect using a redraw logic?
Yes. There is an example of doing this very thing on the Raphael demos page where you got the pie chart. See the Growing Pie demo.
You should separate the code in which you generate the path into a standalone function so you can use it later to return new paths. In order to use animate(), you'll need to define a function on the customAttributes object; it should return (at least) an object with the path property set to your slice's new path.
Since you have labels, you'll probably want to modify the code such that the pie slices expand/shrink relative to their center, so that you don't have to move the labels, too, since the labels are centered on their slice's "axis."
Update
Here's a JSFiddle with a simple example, pretty much the same as Dmitri's Growing Pie demo, except more like your chart. I export a setValue() method to change slice sizes and call it when the page loads. See his blog post about adding customAttributes, too.
In my last paragraph above, I was off the mark a bit. Your chart wasn't the one with labels; I had them mixed up. Also, it would be harder to keep slices centered, so I didn't do that after all. The animate() function sets each segment to its new starting and ending points on the circle, and Raphael figures out the intermediate points. As you can see, you can pass multiple arguments in an array.
this.customAttributes.slice = function(a0, a1) { /*...*/ }
// ...
chart.push(paper.path().attr({slice:[0, Math.PI/2 ]})
Can't see all the fiddle because I'm on iPod however it sounds like you need to have an animate call inside a function that you will need to write
Use the callback parameter that calls the function it sits inside.
Code your recursively called function so it eventually completes when all the work is done.
Each call to the function will happen at the end of every elapssed time interval you specify...
Is it possible to create Raphael's object but not drawing it on paper?
In example, i want to create circle, do some actions and show it on callback of actions.
You would need what is called an "offscreen canvas", something that is currently not implemented in html5 (some people talk about it).
Maybe you can create a canvas and set the css to display: none or visibility: hidden, and copy the image data from one canvas to the other.
You can use this construct:
var foo = circle(whatever).hide();
and then later use
foo.show();
inside whichever callback. it creates the circle object (you can see it in the dom) but you won't see it on the raphael paper