I am new to the world of SVG and D3, learning as I implement. Facing an issue with one of the websites that I am currently working on.
Requirement:
We want to create a custom graph (similar to bar graph) that has a set of bars that represent my data points and certain icons are embedded into these bars based on the type of bar graph data. The graph is representing a person's achievements throughout their career. On hover of the bar we show a custom popup that has a brief description of the bar (see below for an example). Some bars have an additional arrow that represents whether the bar is representing an experience that the user is currently pursuing.
Progress so far:
As you can see my profile under TIMELINE section.
So, whats wrong?
Everything works fine (as you can see from the screenshots) on Chrome. All other browsers render the graph without the icons. You can view my profile on Chrome and Firefox.
I copied d3 generated SVG HTML code and pasted it in jsfiddle to test it out on all browsers and found that all browsers are rendering it: (ignore the colors, I have not applied CSS to it, but the icons show up) http://jsfiddle.net/EbpPG/1/
See JS fiddle link
Check my profile to see the graph. The logic to generate the graph can be found in chart.js file, createTimelineChart() function.
Can someone have a look at it and let me know what's the mistake I am making?
The problem is obviously how you dynamically generate the SVG. The path element is generated in the wrong namespace. This typically happens when you're using something like jQuery's append with a string:
$('svg').append('<path d="m0,0 h100"/>')
This will generate an HTML-namespaced path element, which does not exist. (Interestingly, Chromium is not even showing it in the developer tools.)
Firebug is good at showing you problems of this kind. In the HTML panel, the wrongly namespaced elements are shown in a lighter color. Right-clicking on them in the HTML panel gives you the option to examine in the DOM panel, and there you can see what the namespaceURI property is.
So, use either plain DOM manipulation methods or, if you're already using d3 anyway,
d3.select('svg').append('svg:path').attr('d','m0,0 h100')
Check out with Firefox DOM Inspector and you'll see that the path element that forms the icon is in the HTML namespace rather than the SVG namespace which would be required for it to appear.
Are you passing this data though decodeHTMLEntities, that might be recreating the element in the wrong namespace, you'll need to step though with a debugger to see when it goes wrong.
If you save the d3 generated page then when it's reread by any UA it will pick the right namespace which is why the jsfiddle works.
Related
I want to render a directed graph in d3, and provide it collapsible force layout functionality like we see in this example : https://bl.ocks.org/mbostock/1093130
However, my graph would require bigger nodes with text on it, and my JSON-data is also formatted differently. Here's a working fiddle of my webpage just so you get an idea of what I want my graph to look like(I've also provided the Json-Data I get as input in the javascript section of the fiddle; it is a big graph so you'd have to scroll a bit to see the actual rendering) : https://jsfiddle.net/ashareah/zg42Lvx6/
g.setNode and g.setEdge functions are darge-specific and I run a loop to set them in my webapp using flask. I'm using darge-d3 https://github.com/dagrejs/dagre-d3 to do the rendering mainly because I haven't found how to get this working with d3 directly with the format of data I have.
I'm unable to figure out how to make my graph collapsible as we see in the first example. I'm also open to not using darge-d3 anymore because it's depreciated, if my graph is rendered perfectly and has the collapsible force layout functionality with d3 directly. How do I make my graph collapsible?
I'm following this tutorial on the JavaScript library dc.js and am having an issue with rendering a line chart in the tutorial. I get something to display, but it doesn't look at all the way it should in the tutorial. The D3 and Crossfilter parts of the code seem to be talking to each other since the brushing functionality works, so I'm wondering if I don't have the CSS referenced correctly. You can easily view the code by just viewing the page source. I'm assuming this is something simple that I'm just overlooking due to being fairly new to CSS and JavaScript. Thanks in advance for reading.
Your problem is that the fill attribute on the path svg element is not set, so it's defaulting to black, giving you that black fill in the middle. When I open the developer console in my browser (using IE), I get error messages that say "CSS was ignored due to mime type mismatch." for both dc.css and colorbrewer.css. GitHub is a pain with mime types, so you may want to move these files elsewhere.
The work-around to get the fill to go away (but not addressing your css loading problem) is adding this line of code:
d3.select(".line").attr("fill-opacity", 0);
I hope that helps!
Have looked around the internet, and have not been able to find an answer to this.
I am building yet another custom image slider, but need to be able to handle arbitrary html in the div that is being animated.
Generally, this would be no problem... this certainly isn't the first slider I created, and, in general, if I require the pretty slice and dice effects, I use an empty div with the content as a background image like everyone else. If I do have to allow it to handle arbitrary html, I limit the effects, or simply fade in the html content once the slice-n-dice transition is completed.
In this case, however, I need the pretty effects AND the arbitrary HTML in the same sliders, and at the same time.
My best idea on how to do this was to convert the arbitrary HTML into an image.
I couldn't find a decent, client side solution anywhere... but eventually realized I could stuff the HTML into an SVG element, and can use SVG as a background image for the div.
(Just an FYI, this really only has to be handled by modern browsers, which can handle SVG and DATA-URLS and such)
The first part is actually kinda easy:
arbitraryHTML = "<style>div{padding:10px;border:5px solid red;border-radius:10px;width:500px;height:175px}p{text-align:justify;}img{height:50px;float:left;border-radius:5px;margin:10px;}</style><body><div><img src='steve.png'><h1>Arbitrary HTML</h1><p>This allows arbitrary HTML to be turned into an image, and the image is then able to be stuffed into a canvas. In this case, I will leave this image as an image so that I can set it as a background image of a div that will be visually sliced apart for a slider.</div></body>";
var stuff = document.createElement('svg');
stuff.innerHTML = "<foreignObject>"+arbitraryHTML+"</foreignObject>";
document.body.appendChild(stuff);
This works perfectly fine if I just want to stuff it directly into the DOM... but what I need to do is to use it as a background image for the div that I am slicing and dicing.
Since I already have the SVG code, I should be able to use it as a data uri to feed the image in.
I found an example like this on fiddle, and attempted to use this method on the code sample above to stuff the svg into the background-image...So far, I have completely failed to do so.
Example:
var i = document.createElement('div');
i.setAttribute("style","background-image:url('data:image/svg+xml,<svg>"+stuff.innerHTML+"</svg>);'");
document.body.appendChild(i);
Every time, I get the same problem; there are no errors or warnings thrown by Chrome console, but the div simply shows completely empty.
Using some methods (the code sample above, for example) the console shows the data uri in the code for the div properly, but still fails to show the background.
As part of bug testing, I had both side by side... the actual svg element (which displayed fine), and the div with the same code stuck as a background image (which would not display). Due to this, I am assuming that my problem is something about the way I am casting the svg into the data-url rather than the svg itself.
I really haven't been playing with either inline SVG or Data URL's very much before this... so it is quite possible that I am handling the data URL's or SVG improperly for the way that I am trying to use them.
Not really sure what I am doing wrong, but would really like to solve this.
Is there a better way of converting arbitrary HTML into an image that I missed?
Or is my idea of how to achieve this on the right track, but the implementation screwed up?
Any help would be greatly appreciated.
I guess Chrome still has this webkit bug. What your doing should work in Firefox or Opera 12. Note that IE9/10 doesn't support foreignObject at all, not sure about 11.
I'm wondering how to go about marking up and coding hover effects for a map similar to this image.
When each district (or section) is moused over/touched/clicked I need to change the colour of it without affecting any other section. The boundaries on each section must be representative of the image and shouldn't be squares. The solution can't use canvas since the site I'm working on has to be usable in older browsers (I'm gutted, personally.)
Ideally I want to do this with CSS without using too much JavaScript or loads of images. Has anyone done this before?
Edit: I know people are suggesting the <area> tag, but AFAIK, it doesn't accept the :hover pseudo class.
Edit 2: I might use this: http://www.netzgesta.de/mapper/
Another self answer...
A few months ago I came across a library called Raphael JS - http://raphaeljs.com/. For those of you unfamiliar with it, it's an SVG DOM library first and foremost. If you know a thing or two about SVG, you'll know that IE doesn't support it, but it does support VML. Raphael caters for this as well. Awesome, right?
Anyway, I ended up saving the AI file for the map as an SVG file and importing the paths into a JSON block, basically doing the same thing as this code: http://raphaeljs.com/australia.html
The only issue I came across:
I wanted the map background to be transparent. Setting fill to transparent whilst allowing the section to accept mouseover worked in Firefox, but in IE, it failed. I instead opted for filling the path with white, then setting the opacity to 0.01. After that I duplicated the path and didn't fill it to create the border.
You can use HTML <area> Tag
If you use jQuery you can use the maphilight plugin. documented at http://davidlynch.org/projects/maphilight/docs/ and available from github at https://github.com/kemayo/maphilight
I see what the problem here is: making let's say a world map the usual way is quite a load. If I get it right, what you want is to have a territory map image and put hover effects making hover area match country borders exactly. SVG can be used for the map (the drawing part is already done) but the problem is how to generate HTML area map using SVG map coordinates. There's a solution (I've tried it, looks good at least with the demo provided) which translates SVG into Raphael (generates the coords) using PHP. But again you need raphael.js for that... well if you change your mind: https://github.com/atirip/svg2raphael. And if you're not familiar with Raphael it will take a time to get used to it, documentation is not so good -for me-.
Edit: I can confirm that translation from SVG->rapahel.js works but SVG files needs some tweaks. For what I see in the example SVG provided in svg2raphael the files were made with Adobe Illustrator. I've tried with SVG (plain) from Inkscape and it didn't work properly, but I could manage to fix the issues, for example:
svg2raphael won't translate Inkscape generated <path style="fill:#ff0000" ...></path> (will set fill="none"!!! so the result is invisible, but will translate correctly <path fill="#ff0000" ...></path> Seems like it will ignore everything inside style="".
svg2raphael misreads the alignments from Inkscape SVG, so you need to either move the illustration inside Inkscape or edit the SVG file with text editor and change the M value to M0,0.
svg2raphael can translate multiple svg elements, but looks at the main tag which Inkscape generates to align groups of illustrations, sometimes the whole illustration moves away from the render area and you see nothing. Hope this helps!
Edit 2: You can use Inkscape's style="" for creating CSS rules to apply to the SVG, that works great ang keeps style outside SVG/Raphael!
Does anyone know if I can hack google's visualization ColumnChart api chart somehow, to make a single column stand out with a different color, like so:
I know you can do it with ImageChart, so I don't need that (it fires no events and has no x/y labels).
Can I traverse the result with javascript somehow and change the CSS style, if it is truly rendered in SVG?
A really cheap hack (that works quite well) is the following:
In the Options for your Chart, do: isStacked(true);
Now pass data in two separate series: one that's zero everywhere except at your off-colored bar, and one that's zero only at the off-colored bar. The "stacked" bars yield just the effect your posted in your screenshot.
Well using jQuery I was able to get to my iframe for the graph. It's not pretty, but it works. It's also shorter than using prototype:
$('#google-chart iframe').contents().find("#chartArea g>g>rect")[2].attributes['5'].value = "#eea746";
In the code above attributes['5'] refers to the "fill" attribute of the rect object.
You can traverse the result if you want sure (it's generating inline svg fragments by the looks of it), just open your fave web debugging tool (opera dragonfly, firebug or webkit web inspector) to see what it looks like.
I'm guessing it might be simpler to just use the API to make one bar have a different color, but if you want to traverse the tree and assign some style to it that should work just fine. You can use standard DOM core methods for traversing the tree, just like in HTML, e.g firstChild, nextSibling, parentNode.