Positioning y-axis labels in a horizontal Victory bar chart - victory-charts

I'm having issues with the layout in a VictoryChart using horizontal bars. I'm trying to left align the labels on the vertical axis below:
The relevant bits of code I'm using is
<VictoryChart domainPadding={{ x: [20, 20] }}>
<VictoryAxis
dependentAxis={true}
tickValues={[0, 2, 4, 6, 8, 10, 12, 14]}
/>
<VictoryAxis
labelComponent={<VictoryLabel textAnchor="start" />}
style={{
tickLabels: {
fontSize: 10,
textAnchor: "end"
}
}}
/>
<VictoryBar
data={data}
horizontal={true}
domain={{ y: [-10, 15] }}
x="name"
y="value"
/>
</VictoryChart>
And I've created a sandbox here.
I had to add the tickLabels style textAnchor: "end" to get the labels to be visible in the first place but I would very much like them to align to a common left vertical line, not right like they are now. I tried by defining a labelComponent as <VictoryLabel textAnchor="start" /> but this did not have the effect I hoped for. Upon inspecting the generated SVG that seems to control how the text is anchored within it's container element but what I really need to do here is moving the entire container to the left.
I've gone through the API documentation several times but haven't been able to spot anything that looks like it would be useful. VictoryGroup looked promising but the docs specifically tell me not to use it with the axis component.

OK so I was just getting lost in the jungle of props here.
The solution was first to not try to do this using CSS styles, so the tickLabels.textAnchor: "end" style had to go. Secondly, there's more than one label-component and for the labels on the VictoryAxis the relevant property is tickLabelComponent and not labelComponent.
Replacing the second VictoryAxis component with
<VictoryAxis
tickLabelComponent={(
<VictoryLabel
verticalAnchor="middle"
textAnchor="start"
x={0}
/>
)}
style={{
tickLabels: {
fontSize: 10,
}
}}
/>
Fixes my issue.

Related

How to paint primefaces pie charts with huge legends?

I want to paint some pie charts with huge legends, but I can't resize the yellow panel in the background of the pieChart.
Is there any way to resize the yellow panel to put the legend below and not resizing the piechart itself?
Piechart without legend:
Piechart with legend:
Here I let you my piechart code (I am using primefaces 4.0):
<p:panel style="width: 600px; height:500px;">
<p:pieChart value="#{pieModel.value}" title="#{pieModel.key}" showDataLabels="true" extender="pieExtender" legendPosition="s" legendCols="6" />
</p:panel>
I have tried to play with panel styles, but it was useless.
EDIT (after kukeltje comment):
I have searched in jqPlot documentation, but I haven't found anything. What are the jqplot properties for changing this panel size. Or maybe I need an extension?. No idea.Please, show me an example... I just found a way to show labels when moused over, and I figured out it could be something similar, but not come upon the background panel size:
<script type="text/javascript">
function pieExtender() {
this.cfg.highlighter = {
show: true,
tooltipLocation: 'n',
useAxesFormatters: false,
formatString: '%s = %d'
};
}
</script>
I have solved the problem defining the style of the chart, and I have to calculate how big will be the legend, bring the width and height to the pieChart component:
This is not the best solution, because it is quite impossible calculate the exactly panel size to keep the pie chart size as without legend, but at least I can keep the pie visible...

Add data to a legend, with different format? Or should I use a label?

I am experimenting with the legend; trying to get as result, a panel where I display data about the chart.
I am planning to add the last value, and min and max.
Looking for some examples, and I found one that use a function called labelFormatter, altho I am not having luck in understanding how does it works.
I need to have values with different text color and different size, so I am not even sure if I can use the title of the legend for this purpose, or if I should hide the legend and create directly a label (altho the issue then is related to moving and resizing, right? Since the legend update its position if the chart window is resized).
Which is the best way to do what I am planning to do? a label or the legend?
If you are considering adding HTML elements into the chart plot area then you will have to use Highcharts Renderer API.
You can refer this JSFIDDLE working demo
it works like:
var chart = new Highcharts.Chart({
....
.....
......
}, function(chart) { // on complete
chart.renderer.text('This text is <span style="color: red">styled</span> and linked', 150, 80)
.css({
color: '#4572A7',
fontSize: '16px'
})
.add();
});

Draw trending icons inside chart plot

Is there any way to draw icon/images/triangle anything inside the chart plot?
Like that image, this example, check the green triangle (the red mark is just to show). Is there any way to draw something like that inside?
I tried to using the legends, but it's kind hard to add a new one just for it.
Thanks
Edit:
I tried using the API, but if I resize the page, the chart resize and the the image stays on the same, that's not good at all, I would like the image to remain on the side of the chart. Like the legend.
Does anyone know nice solution for it?
Use either labels or Renderer.
Add the following code at the end:
, function (chart) {
chart.renderer.text('▲', 0, 0)
.attr({
align: 'right',
zIndex: 8
})
.css({
color: '#73903B',
fontSize: '48px'
})
.add()
.align({
align: 'right',
x: -10,
verticalAlign: 'bottom',
y: -40
});
});
DEMO : http://jsfiddle.net/2PNCG/ (Fixed position when resize, bottom right / lower right)
Reference:
http://code.highcharts.com/highcharts.src.js (credits part)
Other possible approaches:
Use chart.plotWidth, chart.plotLeft, chart.plotHeight with marginRight
Use left, top in labels
Related Questions:
Adding a line of words towards the bottom of chart (Bottom Left / Lower left)
How do you add text to the bottom center of legend and bottom center of chart under legend? (Bottom center)
Highcharts - change font size of text on chart (Fixed position)
Move images rendered on highcharts on resize (Fixed position)
This is the kind of thing easily found in the API.

Nesting views deterioriates image quality

I ran in to this problem on a recent project when the guys in the art department noticed deteriorating image quality. I'm not sure what's causing it however we were able to remedy the issue by removing the ScrollView it was nested in. But this is not a viable solution as we will need to nest images within views nested within scrollviews.
My code looked something like:
<View>
<ScrollView>
<View>
<ImageView image="someImage.png" />
</View>
</ScrollView>
</View>
When we removed the ImageView from both the nested ScrollView and it's direct parent view it renders fine. I've created a repo with a simple project illustrating this. The dulling effect is most noticeable on the coloring of the letters, the white drop shadow on the text and the blurring of the grey border.
https://bitbucket.org/bwellons/blurry-images
Is this a bug that needs reporting or is there documentation somewhere that says "don't do it this way" that I don't know of?
Regards
Brant
I think this is caused by not defining bounds (width, height) and anchors (top, left, right, bottom) of views in a consistent manner, for example, if I just change this:
".parent": {
width: '100%',
height : 59,
}
To this:
".parent": {
top : 0,
width: '100%',
height : 59
}
The blurring goes away. I think this is happening because you are mixing relative and absolute view layout techniques (percentages and absolute pixels) in a tightly bound box (the .parent view is the exact same height as the child image view) which is causing the layout calculations underneath to fudge a little when they draw the image inside the parent view.
I say this because this also works to noticeably eliminate the blur, by allowing more room for transformation error:
".parent": {
width: '100%',
height : 62 // Added 3 pixels of padding
}
Here are some other methods that work as well, by either using the same layout mechanism for both width and height, or giving more room for transforms:
".parent": {
width: '100%',
height : '50%' // Dont do this, but shows the point
}
".parent": {
bottom : 0,
width: Ti.UI.FILL, // I use Ti.UI.FILL instead of 100% generally
height : 59
}
So generally, stay away from mixing percentages and absolute values in nesting view chains dimensions, unless you are willing to give some wiggle room in the parent, or define anchors (top, left, right, bottom) to make the drawing transformations work out.
Disclaimer: I only base this statement on about 15-20 different limited layout tests and my own experience (I did not go through native code, yet) so this is by no means science.

Highcharts width exceeds container div on first load

I'm using Highcharts with jQuery Mobile.
I have an area graph being drawn within a jQM data-role="content" container and within that container I have the following divs:
<div style="padding-top: 5px; padding-bottom: 10px; position: relative; width: 100%;">
<div id="hg_graph" style="width: 100%"></div>
</div>
My highcharts graph is a basic graph taken from one of their examples where I have not set the chart width property.
On the first load the graph exceeds the width of the containing divs, but when I resize the browser it snaps to the appropriate width.
How can I make it so that the width of it is right on first page load and not just on resize?
I've reviewed similar posts on stack overflow and none of the solutions seem to work.
UPDATES
I've identified the problem is that the dynamically generated <rect> tag by Highcharts is taking the full width of the browser window on page load and not taking it from the containiner div width at all. Here's the html generated when I inspect:
<rect rx="5" ry="5" fill="#FFFFFF" x="0" y="0" **width="1920"** height="200"></rect>
I tried to reproduce in JSFiddle, but it seems to work fine there, which really has me stumped. Here's my JSFiddle code: http://jsfiddle.net/meandnotyou/rMXnY
To call chart.reflow() helped me.
Docs: http://api.highcharts.com/highcharts#Chart.reflow
this works like magic
put in your css file following
.highcharts-container {
width:100% !important;
height:100% !important;
}
I have the same problem, in my case had a graph of highchart that it is shown after click a button. I put $(window).resize(); after show event and it solved the problem correctly. I hope you serve.
Set width of the chart. That's the only option that worked for me.
chart: {
type: 'line',
width: 835
},
Define the highcharts inside the document ready:
<div style="width:50%" id="charts">
and the script:
$(document).ready(function(){
$(#chart).highcharts(){
...
});
)};
Hope it works ;)
I had a similar issue with centering the highcharts graph it gave. It would center and size correctly for some resolutions but not all. When it didn't, I had the exact same symptoms you're describing here.
I fixed it by attaching/overriding additional css to the highcharts default.
so in a custom css file, adding
.highcharts-container{
/** Rules it should follow **/
}
should fix your issue. Assuming that your div "hg=graph" has nothing but highcharts.
For those using angular and custom-built components, remember to define a dimensioned display in css (such as block or flex) for the host element.
And when the chart container has padding, you might find this indispensable:
html
<chart (load)="saveInstance($event.context)">
...
</chart>
ts
saveInstance(chartInstance: any) {
this.chart = chartInstance;
setTimeout(() => {
this.chart.reflow();
}, 0);
}
Otherwise the chart will bleed past the container on load and get its correct width only at next browser reflow (eg. when you start to resize window).
The best way is to call chart.reflow in render event function documentation;
Highcharts.stockChart( 'chartContainer', {
chart: {
events: {
render: function() {
this.reflow();
}
},
zoomType: 'x',
...
},
and remember to set min-width to zero and overflow to hidden in chart container.
#chartContainter {
min-width: 0;
overflow: hidden;
}
I just ran into the same problem today - not on mobile, but with a window sized small on first page load. When the page loads, the chart is hidden, then after some selections on the page, we create the chart. We have set a min-width and max-width for the container in css, but not a width.
When the chart is being created, it needs to determine the dimensions to create the SVG . Since the chart is hidden, it cant get the dimensions properly so the code clones the chart container, positions it off-screen and appends it to the body so that it can determine the height/width.
Since the width is not set, the cloned div tries to take as much space as it can - up to the max-width that I had set. The SVG elements are created using that width, but added to the chart container div which currently is smaller (based on the size of the screen). The result is that the chart extends past the container div's boundaries.
After the chart has rendered the first time, the on-screen dimensions are known and the clone function is not called. This means that any window resizes, or reloading of the chart data cause the chart to size correctly.
I got around this initial-load problem by overriding the Highcharts function cloneRenderTo which clones the div to get dimensions:
(function (H) {
// encapsulated variables
var ABSOLUTE = 'absolute';
/**
* override cloneRenderTo to get the first chart display to fit in a smaller container based on the viewport size
*/
H.Chart.prototype.cloneRenderTo = function (revert) {
var clone = this.renderToClone,
container = this.container;
// Destroy the clone and bring the container back to the real renderTo div
if (revert) {
if (clone) {
this.renderTo.appendChild(container);
H.discardElement(clone);
delete this.renderToClone;
}
// Set up the clone
} else {
if (container && container.parentNode === this.renderTo) {
this.renderTo.removeChild(container); // do not clone this
}
this.renderToClone = clone = this.renderTo.cloneNode(0);
H.css(clone, {
position: ABSOLUTE,
top: '-9999px',
display: 'block' // #833
});
if (clone.style.setProperty) { // #2631
clone.style.setProperty('display', 'block', 'important');
}
doc.body.appendChild(clone);
//SA: constrain cloned element to width of parent element
if (clone.clientWidth > this.renderTo.parentElement.clientWidth){
clone.style.width = '' + this.renderTo.parentElement.clientWidth + 'px';
}
if (container) {
clone.appendChild(container);
}
}
}
})(Highcharts);
I saved this function in a separate script file that loads after the Highchart.js script has loaded.
try and encapsulate the highchart generation inside a pageshow event
$(document).on("pageshow", "#hg_graph", function() {...});
I resolved this problem (for my case) by ensuring that the containing UI elements render before the chart, allowing Highcharts to calculate the correct width.
For example:
Before:
var renderChart = function(){
...
};
renderChart();
After:
var renderChart = function(){
...
};
setTimeout(renderChart, 0);
I have been having this issue too, and the .highcharts-container css solution wasn't working for me. I managed to solve it for my case by splitting out an ng-class condition (which was setting different widths for the container div) into separate divs.
eg, this
<div ng-class="condition?'col-12':'col-6'">
<chart></chart>
</div>
into
<div ng-show="condition" class="col-12">
<chart></chart>
</div>
<div ng-show="!condition" class="col-6">
<chart></chart>
</div>
I couldn't really tell you why it worked though. I'm guessing the ng-class takes longer to calculate the container width and so highcharts renders first with an undefined width? Hopefully this helps someone anyway.
I also have the same issue in my app where i am using angular
and i also using ngCloak directive which i have removed as i don't need it
after doing this my problem is solved.
I have just seen that sometimes there are several issues going on at the same time.
If it happens the height exceed the expected heigh:
SCSS style:
.parent_container{
position:relative;
.highcharts-container{position: absolute; width:100% !important;height:100% !important;}
}
If the width exceeds the container (bigger than what's supposed to) or does not resize properly to smaller one:
let element = $("#"+id);
element.highcharts({...});
// For some reason it exceeds the div height.
// Trick done to reflow the graph.
setTimeout(()=>{
element.highcharts().reflow();
}, 100 );
The last one happened to me when destroying the chart and creating a new one... the new one was coming with width extra size.
I have been also bump into this issue. both affected in desktop and mobile view of the chart.
In my case i have a Chart that update the series color depending on min or max.After updating the points, the highcharts width exceeds container div on its first load.
To fix that, what i did is add chart.reflow(); after the update of points.
CODE:
//First declare the chart
var chart = $('#TopPlayer').highcharts();
//Set the min and max
var min = chart.series[0].dataMin; //Top Losser
var max = chart.series[0].dataMax; //Top Winner
for (var i = 0; i < chart.series[0].points.length; i++) {
if (chart.series[0].points[i].y === max) {
chart.series[0].points[i].update({
color: 'GREEN',
});
}
if (chart.series[0].points[i].y === min) {
chart.series[0].points[i].update({
color: 'RED',
});
}
}
// redraw the chart after updating the points
chart.reflow();
Hope this helps to those who has the same issue like me. :)
Here's a solution that worked for me ! The charts were working fine for a while and then after a feature they started exceeding their container. Turns out it was the defer attribute on the script in the head of my application.
Try removing defer on your javascript tags:
<script defer src="script.js"></script>
to
<script src="script.js"></script>
Or moving my stylesheet link higher in the head also seemed to fix it but it's a less reliable solution..
This may have been introduced since the OP in 2013, but you should be able to set height with chart.height (https://api.highcharts.com/highcharts/chart.height)
options: {
chart: {
type: 'bar',
height: window.innerHeight + 'px',
},
title: {
text: 'Top 10 Users',
},
subtitle: {
text: 'by scores',
},
This is a web based solution, but I would expect you could cater it to jQuery.mobile
None of the answers helped me. I dynamically change chart data and the top answer solution ruins the animations and causes a jump in the chart position.
The workaround that I finally came up with was to set some padding for the chart wrapper element (in my case some part of the chart to left was hidden, so I gave some left padding), and then set the chart main element overflow property to visible. It works and the animations are just fine. You may need some experimenting with padding value to get it perfectly displayed.
<div class="chart-wrapper">
<!-- high charts main element here -->
</div>
and the style
.chart-wrapper{
padding-left: 20px;
}
.chart-wrapper > div:first-child{
overflow: visible !important;
}
for me, I set chart width:
$('#container').highcharts({
chart: {
backgroundColor: 'white',
**width:3000**,
..... }
and in html set overflow:auto
<div id="container" style="**width:100%;overflow:auto**;" ></div>
I struggled with this for way too long, and found a solution that works for me. A little bit of background on my setup:
The highcharts chart was loading on a tab on my website that is not visible upon logging into the site.
When switching to that tab, the chart was well outside the div.
So, I attached a unique ID to that particular tab, we'll call it tab5, and then bound a click function that forced - and this is the important part - the <svg> element within the container div to 100% using jQuery:
$('#tab5').bind('click', function() {
$('#container_div svg').width('100%');
});
...and my sanity has been restored. For the moment.
Please add width:100% to chart container.
Hope this will resolve overflow:hidden related issue.
classname{min-height:450px;width: 100%;}

Resources