Raphael js: animating path with it's drop shadow - svg

I'm not sure how to fade in and out a path and the drop shadow I've created for it:
var p = "M10,10L810,10L810,190L10,190L10,10";
var s = "M16,16L816,16L816,196L16,196L16,16";
var paper = Raphael(100, 100, 830, 210);
var shadow = paper.path(s);
shadow.attr({stroke: "none", fill: "#999999", opacity:0.1});
shadow.blur(4);
var c = paper.path(p);
c.attr({fill:"#ffffff", stroke:"none"});
Do I have to manually animate c and shadow at the same time? Is there a way I can just tell this particular paper to fade everything inside of it?

put your path and your shadow in a set. apply your animation to the set and it'll affect both.
Here's a really terrible example where I move both at once.

Maybe animating the drop shadow path to match the specification of the other path?
http://www.irunmywebsite.com/raphael/additionalhelp.php?q=fadingdropshadow

the amadan answer is incorrect. please discard it.
If you put elements in a set, the glow will be part of the set but set is logical only.
it means that if you animate the set, your shadow animation will look wierd.
use set only to refer to logical zoning for events for instance.
best is to animate the shadows in // of the other objects.

Related

d3.js geo - rendering svg path

I'd like to create choropleth map of Czech Republic. Inspired by this article http://bl.ocks.org/mbostock/4060606, I have created this
http://jsfiddle.net/1duds8tz/2/
var width = 960;
var height = 500;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
var offset = [width / 2, height / 2];
var projection = d3.geo.mercator().scale(6000).center([15.474, 49.822]).translate(offset);
var path = d3.geo.path().projection(projection);
queue().defer(d3.json, "..map.geojson").await(ready);
function ready(error, reg) {
var group = svg.selectAll("g").data(reg.features).enter().append("g");
group.append("path").attr("d", path).attr("fill", "none").attr("stroke", "#222");
}
When I tried to fill svg path with some color, I ended on this
http://jsfiddle.net/1duds8tz/3/
group.append("path").attr("d", path).attr("fill", "red").attr("stroke", "#222");
There are odd values in path d attribute.
My GeoJSON data must be somehow faulty but I can't figure what is wrong.
Everything looks right here: https://gist.github.com/anonymous/4e51227dd83be8c2311d
Your geoJSON is corrupted and as a result your polygons are being drawn as the interiors of an infinitely bounded polygon. That's why when you attempt to give a fill to the path, it goes beyond the extent of the screen but still displays the border just fine. I tried to reverse the winding order of your coordinates array, and that seemed to fix all of them except for "Brno-venkov", which might be the source of your problems (especially given its administrative shape).
I'd suggest going back to where you created the original GeoJSON and try to re-export it with simplification. If you want to reverse the coordinates on your GeoJSON to correct the winding order, that's pretty simple:
geodata = d3.selectAll("path").data();
for (x in geodata) {geodata[x].geometry.coordinates[0] = geodata[x].geometry.coordinates[0].reverse()}
But this won't fix the problem polygon, nor will not reversing its coordinates.
In case you are familiar with svg manipulation you can try geojson2svg. This allows you manipulate svg in standard way but you have to code a little more. In case your application requires d3 for many other purpose then d3 is best solution.
I've got exactly the same problem with Mapzen's .geojson files.
.reverse()-ing isn't good enough, if you can't make sure all your data has the same winding order.
I solved it with this one:
https://www.npmjs.com/package/geojson-rewind
You'll need to have npm & require available
Install it, and save it to your project
npm i -g geojson-rewind
Import it, to make it useable
var rewind = require('geojson-rewind');
Use it on the data, in this case:
req = rewind(req);
Tip: If you are working with static data, you can do this only once on the console, and you're good to go.

How to right/end align text along an textPath inside an arc using d3.js?

Here's the fiddle: http://jsfiddle.net/DevChefOwen/CZ6Dp/
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
.style("text-anchor","left") // using "end", the entire text disappears
.text("some text");
I've tried a number of different things to no avail. The left align is the easy part. If you did a middle, though, you see only "text" instead of "some text", implying that "some" is just hidden because it went "out of span" for the given arc.
If, however, I added:
.attr("startOffset","39%")
(as in here: http://jsfiddle.net/DevChefOwen/2H99c/)
It would look right aligned, but outside of programmatically trying to get the width/height of the text element and look for sharp changes in width/height (which seems wrong and likely error-prone), I can't seem to find a way to right align the text.
I've also tried using an SVG path (essentially a curved arc line) and the same disappearing act happens with the text when "text-anchor" is set to "left".
Thanks ahead for your time!
The question is somewhat confusing matters. The issue isn't aligning text at the end of the path -- that's easy to do with "text-anchor"="end" and "startOffset"="100%".
However, using those settings with the path created by the d3 arc function, you end up with the text cornering around the end of the inside curve and the left straight edge, to the end of the path as defined by the arc function:
http://jsfiddle.net/CZ6Dp/8/
The real issue is that the path that you want the text to be aligned along (the outside arc of the shape) is only one segment of the path that defines the shape.
(By the way, "left" and "right" are not valid values for the "text-anchor" property, and will just be ignored).
The answer by #defghi1977 gives one way to approach the problem, by figuring out the length of the path segment that you do want to use and adjusting the start offset accordingly.
Another way to approach the problem is to create a separate path (not drawn on screen) that represents only the part of the path that you want to be used for positioning text.
There are a number of possible ways to create a path that only represents the outside arc (some example code here). #defghi1977's approach of grabbing it from the existing path with regular expressions is probably the most efficent for your situation. But instead of just creating a temporary element to calculate a length, I actually have to add the new path to the DOM so it can be used as the reference path for the <textPath> element. (Which I suppose is the downside to this approach -- twice as many DOM elements!)
var path = g.append("svg:path")
.attr("d", arct)
.style("fill","#ccc")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")")
.each(function(d,i) {
var justArc = /(^.+?)L/;
//grab everything up to the first Line statement
var thisSelected = d3.select(this);
var arcD = justArc.exec( thisSelected.attr("d") )[1];
defs.append("path")
.attr("id", "yyy") //normally the id would be based on the data or index
.attr("d", arcD)
.attr("transform", thisSelected.attr("transform") );
//if you can avoid using transforms directly on the path element,
//you'll save yourself having to repeat them for the text paths...
});
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
.style("text-anchor","end")
.attr("startOffset","100%")
.text("some text");
http://jsfiddle.net/CZ6Dp/9/
Again, factoring in the extra DOM load #defghi1977's method is probably slightly preferrable, although this version has the benefit of not being dependent on browser support for getTotalLength. But as far as I know that method is fairly well implemented.
So just consider this an alternate approach for completeness' sake.
This path is constructed by 4(or 5) path segments.
So, this probrem will be solved to get first arc path length.
But I don't know how to get sub path length by using d3.js, thus I use svgdom directly.
I tried to fix your code. If this code is not what you hope, I'm sorry.
path-anchor attribute to end.
define function to get startOffset value.
var path = g.append("svg:path")
.attr("id","yyy")
.attr("d", arct)
.style("fill","#ccc")
.attr("transform", "translate("+cfg.w/2+","+cfg.h/2+")");
var text = g.append("text")
.style("font-size",30)
.style("fill","#000")
.attr("dy",0)
.append("textPath")
.attr("xlink:href","#yyy")
//.style("text-anchor","left") // using "end", the entire text disappears
.attr("text-anchor", "end")
.text("some text")
.attr("startOffset",function(){
var d = document.getElementById("yyy").getAttribute("d");
var tmp = document.createElementNS("http://www.w3.org/2000/svg" ,"path");
//get the arc segment of path
var arc = d.match(/(^.+?)L/)[1];
tmp.setAttribute("d", arc);
//return offset position
return tmp.getTotalLength();
});
I think the confusion comes from the meaning of text-anchor - it's not "relative to where on the parent will I justify" but rather "what part of me should I align to the start".
You're right to try to use startOffset to move the origin. Since the outer radius of your path is longer than the inner radius, the correct start offset is a little more than half of the path (around 53%).
Just a little more twiddling with your settings and you should have it. Here's a fiddle with my interpretation of what you're looking for.

trouble with d3.js - scaling a path shape

I'm trying to scale this speech bubble into existence. I'm not really sure how to do it because the default d3 scale is changing the area where it starts drawing.
var svgHeight = 1000
var svgWidth = 1000
var floatycircleRadius = 30
var textColor = "#FFFFFF"
var svg = d3.select("body").append("svg")
.attr("width", svgHeight)
.attr("height", svgWidth)
var floatycontainer = svg.append("g");
var floatygroup = floatycontainer.append("g")
var floatypath = floatygroup.append("path")
.attr("d", "m125.512,0h-66C26.645,0,0,26.482,0,59.35c0,28.574,20.142,52.312,47,58.029V145l26.283-26.283, l52.229,0.064c32.868,0,59.512-26.563,59.512-59.431S158.38,0,125.512,0z")
.style("fill", "#90C4E4")
floatygroup.attr("transform", "translate(500, 500)")
floatycontainer.attr("transform", "scale(1)");
floatycontainer.transition().duration(2000).attr("transform", "0")
Use transition.attrTween(name, tween) on the <g> or <path> element.
.attrTween("transform", function(d, i, a) {
return d3.interpolateString(a, 'scale(1)');
});
http://jsfiddle.net/Wexcode/2jFP5/
So the problem wasn't that I couldn't get the item to scale. It's that when the item was scaling the "M" attribute was also shifting and the svg element was flying across the page due to mixed relative and absolute points on the path.
After changing the line manually to all relative so I could finish my project I found a javascript script to change all paths to relative. Then I could manually change the "M" attribute to 0 so the scale would work correctly source (Convert SVG Path to Relative Commands).
I modified the script to better suit my needs and build this simple page using gist.github.com and bl.ocks.org so it's a simple site to get the all relative path. It fits my long term use case and I thought I'd share it for those interested. Thanks for your help.
http://bl.ocks.org/TheMcMurder/6393419 (live page to convert)

Integrating Poilu raphael boolean operations(union,substraction) with SVG-edit

I am doing a modification of svg-edit, more specifically Mark McKays Method draw: https://github.com/duopixel/Method-Draw.
I want to use this Raphael library i found: https://github.com/poilu/raphael-boolean that allows me to perform boolean(set) operations on paths within my canvas.
Now i have implemented a button within the editor that fires up a function:
var paper = Raphael("canvas", 250, 250);
var path = paper.path("M 43,53 183,85 C 194,113 179,136 167,161 122,159 98,195 70,188 z");
path.attr({fill: "#a00", stroke: "none"});
var ellipse = paper.ellipse(170, 160, 40, 35);
ellipse.attr({fill: "#0a0", stroke: "none"});
var newPathStr = paper.union(path, ellipse);
//draw a new path element using that string
var newPath = paper.path(newPathStr);
newPath.attr({fill: "#666"});
// as they aren't needed anymore remove the other elements
path.remove();
ellipse.remove();
Okay, upon clicking the button isnt the editor supposed to return a unioned(welded) path with an ellipse?
or am i getting this wrong?
i am figuring that something must change with the var paper = Raphael("canvas", 250, 250); line since svg-edit is using a different name for the canvas but i have no idea how to go about it.
Any help will be deeply appreciated as i have been struggling for sometime with this.
UPDATE: This library is unable to handle multi-object welding, self intersections and many other cases. It is only working if we want to perform operations on 2 simple objects. This might not be immediately relevant to the question at hand but i thought it is wise to mention it anyway.
Refer to this question if you are looking for Boolean Operations on SVG elements: Boolean Operations on SVG paths
The code you posted works in isolation, as shown here: http://jsfiddle.net/5SaR3/
You should be able to change the Raphael constructor line to something like:
var paper = Raphael(canvas);
where canvas is an object reference to the SVG element used by svg-edit.

(RaphaelJS) - How to Fill the inside of a path?

I have a path for the RaphaelJS library, I can't seem to get the fill to change its color.
var mypage = ScaleRaphael('mainContainer', 1000, 1000);
mypage.setStart();
mypath.path('M794.33,21.5l152.3-0.76L946,21.5v-0.22l1.39,0.01l-1.17,206.61l-0.04,0.3l-0.15,0.27l-0.04,0.07l-0.18,0.35l-0.34,0.2 L786.4,321.59l-159.22,92.27l-2.12,1.18l-0.07-2.36v-1v-0.28l0.18-0.26l42.1-97.5l42.26-97.43l21.13-48.71l21.21-48.68 L794.33,21.5z M794.33,21.5l-41.46,97.76l-20.76,48.87l-20.84,48.83l-41.68,97.67l-41.78,97.59l0.18-0.54v1l-2.11-1.18 l159.08-92.46l159.23-92.21l-0.52,0.54l0.03-0.07l-0.14,0.57l2.04-206.6l1.39,0.01v0.22l0.13,0.77l-0.69,0L794.33,21.5z')
.attr({"type":"path","stroke":"none","fill":"blue"});
The path is created correctly but the fill attribute only makes the stroke blue and not the filling, what am i doing wrong?
Your path is shaped like a stroke, to make it fill modify the path by removing everything starting from the second M:
var stage = Raphael('stage',1000, 1000);
var path = stage.path('M794.33,21.5l152.3-0.76L946,21.5v-0.22l1.39,0.01l-1.17,206.61l-0.04,0.3l-0.15,0.27l-0.04,0.07l-0.18,0.35l-0.34,0.2 L786.4,321.59l-159.22,92.27l-2.12,1.18l-0.07-2.36v-1v-0.28l0.18-0.26l42.1-97.5l42.26-97.43l21.13-48.71l21.21-48.68 L794.33,21.5z')
.attr({"type":"path","stroke":"none","fill":"blue"});​
http://jsfiddle.net/YzMCG/
There is quite a nice explanation here that suggests adding a transparent fill to the CSS in order to hide the coloured fill and make it look like a path only:
Raphael Js can't fill path with Image

Resources