I've been trying to change the width of a single column in a bar chart created using Highcharts. Here is a codepen.
In all the search that I did, I could only find two solutions given in this question.
The problem with that is that since they are set dinamically after initialization, any action that calls the redraw method will revert their width to the calculated one.
Also, I don't understand why they are using series[0].data[5].graphic.attr('width') and how it affects, since I don't see such property in the object (console screenshot)
Finally, in the codepen I'm also changing the color of the same point, but doing it in the initialization function. I wonder if there is a way to do the same for the width.
Am I missing something? Because I didn't find anything in the API docs and I'm clueless as to how these solutions actually work if there is no such property in the object.
Short explanation:
attr method is inherited from Element class. You can see that method in prototype (in console click __proto__). Method attr works in two ways: attr(property_name) is a getter (to get e.g. width) and attr({ property_name: value }) is a setter (to set e.g. width). If you use source files (.src.js), then you would notice that SVGElement class.
width will change on any redraw event, because it is recalculated again (like updating point, or resizing window). In fact you can use chart.events.redraw and there change width. In fact, I would use both, chart.events.redraw and chart.events.load with one function, to update widths.
And to explain, why you can't set width in point, like you did with color: there is not such option on point level, like pointWidth. You can set specific width for all points within one series only (using mentioned pointWidth). There is an idea for Highcharts, to add such feature (to the core or as a plugin). Feel free to vote for it on the UserVoice. Here is interesting example: http://jsfiddle.net/75oucp3b/14/ (works with v4.1.8)
Related
I am using c3.js, AngularJs and bootstrap to render some charts. The setup is as follows:
Bind a variable to <select> form to change between chart types
I have a $watch on the same variable which triggers the chart rendering.
Depending on variable I render multiple charts, different types depending on it's value. I have two charts per row, each one inside a col-XX-6.
Each chart group is hidden/shown using ng-show="myVariable== 'typeX'" depending on the same variable that triggers the render.
So, view and c3 render are acting on the same variable.
The first render is triggered by watch on $viewContentLoaded and everything works fine. After I change the select option, the first chart in the column renders with 100% width, disregarding bootstrap template. My theory is that c3.js renders the chart "too fast", before the view kicks in and sets the proper width. Further investigation:
Adding a $timeout on renderer fixes the problem but this is unacceptable solution
Adding a fixed width on charts works but is not acceptable, it needs to adapt to bootstrap
So far it seems that the only solution is to listen to the actual DOM change to see when the DOM actually becomes visible and only then start the render. But it seems that this technique is highly discouraged.
How do I fix this problem the proper way?
Edit 1: It seems that even if I render all the charts once and never refresh them, they still rarely but randomly oversize when shown.
Edit 2:
Plunkr: http://plnkr.co/edit/mU5m694VoDB5GtXrmPdP
Plunkr works (...) but basically, it happens to me when you'd switch from type2 to type1, the first graph would take 100% width and mess up everything. I'll see if I can find something in Plunkr that would make it break.
Edit 3: Well, perhaps not working that well afterall. I noticed charts sometimes do not render (blank page) and they only appear after I inspect element or fiddle with the screen in some way. Seems like it could be the same problem behind this. You should increase the plunker preview to simulate a wider screen.
You mention that you are having problems with initial size, but actually, there is going to be problems when browser size changes too.
We use d3.js (not c3) extensively in our project, and we found that the best option is to set viewBox attribute of svg element created by d3 to the parent element's size when browser size change event is emitted by window.
viewBox basically translates coordinate system of svg to origin and size defined by it.
I have dynamically generated SVG, and I need to find the current coordinates of one of the elements. According to the SVG documentation, this can be done with the getCMT() function. I have not been able to get this to work in JavaScript. Here is an example code fragment:
thing = document.getElementById("#bx" + myState.myId);
matrix = thing.getCTM();
I correctly select the SVG element, which is a 'g' element, so it has a transform matrix. When I try to get the matrix, it returns a 'null'. This is a simple task, so it is very puzzling that it does not work. I've spent some time looking for examples, but they all seem to use static SVG directly loaded in HTML. What am I missing?
I've also tried this with getBBox() and had the same result. I'm using the current FireFox release.
I found out what the problem was. I was using getElementById in conjunction with the visibility attribute. I was setting visibility to hidden in the root of the SVG structure, and then setting the visibility attribute to visible in a nested g element. The getElementById function returns null when intermediate nodes are not displayed. Calling getElementbyId before changing the visibility made things work.
Here is a reference to where I found this out: https://bugzilla.mozilla.org/show_bug.cgi?id=756985
The specifics have to do with whether the SVG is attached or not. If it is not attached then everything must be visible. If it is attached then it is possible to use hidden/visible.
Thanks to those who responded. In FireFox, it didn't make any difference if there was a "#" at the start of the getElementId argument, but it's good to know the correct syntax. Thanks.
I am facing a very ilogical and odd problem here.
I have defined the width, height and other properties in a seperate CSS file. Now I wan these values on the run time to manipulate them and make my application dynamic.
But when I fetch this value using jQuery, it subtracts one or two from the value.
For example, the width of an element defined in the CSS is 450px, now when I fetch it in jQuery using
$('.programeSectionBox').width();
It will give me 449px. This thing is also happening with height and margin parameters too.
Can somebody please tell me whats happening here, I am badly struct in this problem .
Thanx for all the replies. I have checked the outerWidth() solution but its not working, giving the same issue.
Actually I am creating an application for Samsung Smart TV, they are offering two resolutions 960x540 and 1280x720. For 960x540 everything is working great, but when it comes to 1280x720, the problem is occuring which I have mentioned.
In my application I am using one javascript file and two different CSS files for the two resolutions, the applications checks that on which TV resolution its working and then loads the respective CSS. I cant hardcode the values in JavaScript file because I want to keep it dynamic, if I will hardcode the values, it will obviously work for one resolution.
So if anybody have any other solution, it will be great.
Thanx
Try using outerWidth and see if that works for you:
jQuery("#myElement").outerWidth();
More on outerWidth:
http://api.jquery.com/outerWidth/
Just use parseInt to the value you get it.
After that you will get integer value then you can perform any operation on it.
console.log(parseInt('445px'));
FIDDLE
Since this is happening with several computed values (not only width/height), I would guess that your browser is zoomed. In your case it is probably zoomed out one step, since you seem to be getting lower values than the ones you set via CSS.
Try this example here: http://jsfiddle.net/zsygt/
When the browser zoom is reset to it’s default value (100%), it should print 448. But when I zoom in one step in Chrome, it prints 449.
I'm trying to figure out how to highlight a line (series) in Highcharts from an element that's not related to the Chart object in any way.
I went through the documentation, and don't really see a way of achieving this. I can get into the series elements using the series.get(id).
Seems like there are no methods that can be helpful - http://www.highcharts.com/ref/#series-object
Any ideas if that's even possible?
After a lot of digging and testing, I've managed to get this working - still not sure if this is the best way (probably not).
Chart.series.get(someId).graph.attr('stroke-width', '5')
Unfortunately, this is just getting into the actual DOM element and changing the value of the property of a single element, so if you need to change the stroke width, and the styles of the markers on this line, you'd have to loop through all elements, and apply changes manually.
UPDATE: Ok, there's a better way
But this is using the private API, so if the library changes thins, your code will not work:
Chart.series.get(someId).onMouseOver() and Chart.series.get(someId).onMouseOut().
This actually fires the defined hover-state.
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.