Highcharts sticky labels for big values goes out of chart - javascript

I have two issue to request for help,
Have an issue with the highcharts, it looks like some calculation needs to be done for the chart, but could not ale to figure out the actual thing.
please look at this Fiddle , In this the label at the right hand side $500 is at the correct position that is ok, but when the value is big/large, lets say $555555555555, then the
chart label goes out of chart. Have a look at this fiddle now
Fiddle having Issue
Error:
what should happen is that the $555555555555 should be inside the chart only, having the same position as show in the first fiddle.
What I tried.
Adding/subtracting the length of the string (point.y) with + 30
var chart = new Highcharts.Chart({
...
....
/*********RIGHT SIDE CPM*******************/
var point = chart.series[0].data[7];
var text = chart.renderer.text(
'$'+point.y,
point.plotX + chart.plotLeft - 30,
// point.plotX + chart.plotLeft - ( ((point.y).toString().length) + 30 ), //My change
...
});
But this point.plotX + chart.plotLeft - ( ((point.y).toString().length) + 30 ), did not support when the value again changes from $555555555555 to $5
so Basically the position should not vary when the length of the label is big/small.
My next question, The chart is starting with a small displacement at both sides.
have a look at the image below
As you can see the gap between the two red lines, at both the corners in the image, I need to remove that, It may be a padding issue, but I could not able to figure it out.
Please help me in this two issues.
Thanks for helping in advance.

Issue: Aligning rendered text
So from reading your code I think you are trying to adjust the position of the text and box from the length of the content. Problem here is you have a font that has variable width characters while subtracting a constant value per character. Also, the renderer.text method always anchors in the bottom left, which isn't in your favor.
What I would do here is leverage that the text.getBBox knows the exact bounding box of the text Element. You might be able to get this to look a bit better, but here's a crude example:
/*********RIGHT SIDE CPM*******************/
var point = chart.series[0].data[7];
// Draw dummy text, just to get bounding box
var text = chart.renderer.text('$'+point.y, 0, 0)
.attr({
zIndex: 5
}).add();
// Get bounding box
var box = text.getBBox();
// Destroy dummy text
text.destroy();
// Draw actual text based on bounding box
text = chart.renderer.text(
'$'+point.y,
point.plotX + chart.plotLeft - box.width + 2 ,
point.plotY + chart.plotTop - 10
).attr({
zIndex: 5
}).add();
// Get actual box
box = text.getBBox();
// Draw actual box
chart.renderer.rect(box.x - 5, box.y - 5, box.width + 10, box.height + 10, 5)
.attr({
fill: '#FFFFEF',
stroke: 'gray',
'stroke-width': 1,
zIndex: 4
})
.add();
And a JFiddle example (I only bothered to fix your right side CPM, but you get the point).
Issue: Spacing on sides of graph
Set the min and max of your x-axis to specific values, as shown in the JFiddle example, with the code:
xAxis: {
...,
min: 1,
max: 8
}

Related

Data label not rendered on sapui5 viz dual y-axis graph when line and column intersect

I have a requirement to show data labels of two graphs on the same axes.
Only when they intersect, one of the two labels won't show. This can be demonstrated below:
As you can see on the 2nd, 5th and 6th columns from the left with values 0%, 7% and 8% respectively
only the orange line values are shown but the blue column values are missing.
This is the final html of the graph after rendering:
So data-datapoint-id 142, 145 and 146 are missing from the html.
I tried using the plotArea.dataLabel.renderer function as a manipulation of what was proposed here but nothing changed, still not rendering.
Anyone encountered a similar problem? Is that a sapui5 issue or can it be fixed by manually inserting the labels into the HTML if so how?
Thanks,
Ori
Using SVG text and jQuery I managed to manually insert the labels into the top middle of the blue rectangle columns.
This is the result, not perfect but works:
and this is the code:
chart.setVizProperties({
plotArea: {
dataLabel: {
formatString: {'פחת כללי': FIORI_PERCENTAGE_FORMAT_2},
renderer: function (oLabel) {
// Create empty text node to be returned by the function such that the label won't be rendered automatically
var node = document.createElement("text");
if (oLabel.ctx.measureNames === "כמות פחת כללי") {
var kamutLabelIdx = oLabel.ctx._context_row_number;
// Use jQuery and SVG to manipulate the HTML
var kamutLabelQuery = '[data-id=\"' + kamutLabelIdx + '\"]';
var kamutColumn = $(kamutLabelQuery)[0];
// Create text element as child of the column
kamutColumn.innerHTML += "<text>" + oLabel.text + "</text>";
var labelNode = $(kamutLabelQuery += ' text');
// Set the label position to be at the middle of the column
const labelLength = 60;
const xPos = (labelLength + oLabel.dataPointWidth) / 2;
const yPos = oLabel.styles['font-size'];
labelNode.attr({
"textLength" : labelLength,
"x" : xPos,
"y" : yPos,
"font-size" : yPos
});
return node;
}
}
}
}
});
The oLabel parameter of the renderer function provides useful info about the data label to be created:
I still wonder if that's a bug with sapui5 vizframe and if there is a simpler way to do this.
Please let me know of your thoughts

How can I align Chart title with the bar dynamically?

How can I align Chart title with the bar in highcharts?
The bar length may vary because of the data, so I want my title to end where the bar is ending.
I want to implement something like this:
To adjust the title you can set tittle.attr in the events.redraw event. You need to remember that a bar chart is an inverted column chart and where you have an x-axis there will be a y-axis.
chart: {
events: {
render: function() {
let chart = this,
series = chart.series[0],
title = this.title,
point = series.points[0];
title.attr({
x: chart.plotTop + point.x,
y: chart.plotLeft + point.y
});
}
}
},
API References:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement
Demo: https://jsfiddle.net/BlackLabel/ud45prLg/
I would suggest adding a padding-right: ##px as you havent provided any code to work with. try applying the method via inspect element and add the code into your css after with the right amount of "px" needed.

Working with text in pdfkit

How to set characterSpacing from pt/px?
How to set lineHeight from pt/px?
I just can not understand how to translate from points or pixels into a value for pdfkit. Help me please
https://github.com/devongovett/pdfkit
I need to convert html text to pdf. And you need to match the letter spacing and the line spacing.
CSS: Font - 18pt; LineHeight - 1.4 (not pt); letterSpacing - 2pt;
How to set this in pdfkit?
doc.text(element.content, element.left, element.top, {
width : element.width,
align : element.properties.textAlign,
characterSpacing : 2, //???
lineBreak : false,
lineGap : 1.4, //????
});
When using pdfKit, measurements are in points where 72 points is 1 inch.
So characterSpacing is how many "points" between each character. In the example provided of 2, it would be 2 points or 2/72 of an inch.
The lineGap, is the number of points between lines of text. For example, lineGap: 10 is 10/72 of an inch. This represents the space between the bottom of one row and the top of the subsequent row.
This is different than line-height in HTML, where line-height is more like a multiplier of the specified line height.
This is how it works for me, I hope it helps someone
doc
.fontSize(10)
.font('Helvetica-Bold')
.lineGap(5)
.text('your text', 50, 50, { align: 'right' });
// positioning of your text first 50 is for x, second for y

Finding the Y axis value for a plot line in HIghCharts.js

I am trying to size a background image on a HighCharts line chart dynamically depending on the position of the top plot line. The image I am trying to size is the bell curve in the image below.
I can't set the height of the image as a static value because the size of the screen can change and the top plot line also changes over time.
At the moment I am setting the position of the plot lines with external functions like this:
plotLines: [
value: upperControl3()}, {
color: '#ccc',
zIndex: 3,
width: 1,
label: {
text: '-2s',
x: 520,
y: 3
}
The closest thing to the y value of the top plot line I have been able to find is a dataMax value but this stays the same on every chart load.
I have been trying to overlay and size the image with a function at the end of the chart like this:
function(chart) {
console.log(chart.yAxis[0].plotLinesAndBands[7].axis.plotLinesAndBands[0].axis);
var h = chart.yAxis[0].plotLinesAndBands[7].axis.plotLinesAndBands[0].axis.dataMax;
var y = chart.yAxis[0].axisTitle.y + extra;
// X, Y, Width, Height
chart.renderer.image('images/bell.jpg', 60, y, 200, h).add();
}
Is the any way to find the coordinates of a plot line in highcharts?
You can use plotLinesAndBands object, where plotlines are kept. In the options you have value, whcih can be translated into pixels value by toPixels function.
var $button = $('#button'),
$report = $('#report'),
chart = $('#container').highcharts();
$button.click(function () {
chart.xAxis[0].addPlotLine({
value: 5.5,
color: 'red',
width: 2,
id: 'plot-line-1'
});
var plotline = chart.xAxis[0].plotLinesAndBands[0];
$report.html('Value: ' + plotline.options.value + ' Pixels: ' + chart.xAxis[0].toPixels(plotline.options.value));
});
http://jsfiddle.net/HhP39/1/
If you know which plot line (by index) it is, you can do this:
chart.yAxis[0].plotLinesAndBands[0].options.value
Of course, you need to make sure your data is actually normally distributed, or else that normal curve means nothing :)
And zero-bounded data is not usually normally distributed.

animating a rectangle with text in Raphael javascript library

I am quite new to javascript and to Raphael. I am trying to move a button-like rectangle with text inside. Here is my code :
window.onload = function() {
var paper = new Raphael(document.getElementById('canvas_container'), "100%", "100%");
var box1 = paper.rect(100, 100, 120, 50, 10).attr({fill: 'darkorange', stroke: '#3b4449', 'stroke-width': 2, cursor: 'pointer'});
var box2 = paper.rect(400,100,120,50,10).attr({fill: 'lightblue', stroke: '#3b4449', 'stroke-width': 2});
var text2 = paper.text(box2.attrs.x + box2.attrs.width/2,box2.attrs.y + box2.attrs.height/2,"[x: " + box2.attrs.x + " y: " + box2.attrs.y + "]").attr({"font-family": "arial", "font-size": 16});
var button2 = paper.set();
button2.push(box2);
button2.push(text2);
box1.click(function(){
// this did not work
// button2.animate({x: 100, y: 50 }, 1000, 'bounce', function() { // callback function
// text2.attr('text',"[x: " + box2.attrs.x + " y: " + box2.attrs.y + "]");
// });
button2.animate({transform: "t100,100"}, 1000, 'bounce', function() { // callback function
text2.attr('text',"[x: " + box2.attrs.x + " y: " + box2.attrs.y + "]");
});
});
}
The button2.animate({x: 100, y: 50 }, 1000, 'bounce'); line did not worked properly, the text was not in the right position at the end. By using the transform: I can not use coordinates, I would have to compute them. Also I am not able to get the right coordinates of the blue box at the end when using the transform method.
I was not able to find any answer yet, hope someone can help me.
Thank you
Since you didn't explain how exactly you want to move your button, I'm assuming you want to move the box2 above box1.
There are some misunderstandings and errors in your code, allow me explain one by one.
Why the first way cause text move to wrong position at end ?
Because a set is NOT a group of element which knows its relative position inside the group. A set is merely a collection of elements which is designed for us to operate them in a more convenient way.
So, the code below will move all element in the set to (100, 50)
set.animate({x: 100, y: 50 }, 1000);
and that's why the text is there.
I couldn't find the document, but you can find some explanation here .
Why x, y in attributes seems to be wrong when using transform ?
No, the attribute is correct.
When you transform an element, the result of the transformation will not reflect back to the attributes. You can think like this, when transform(), you are actually attach "transformation" to the elements. Therefore :
paper.circle(100, 100, 5).transform("t100");
You can describe the circle as :
a circle at (100, 100) which will be moved 100px horizontally.
but not - a circle at (200, 100) which will be moved 100px horizontally.
So, here is the code that dose what you want, note that I'm using getBBox() to get coordinate of the button2 set.
box1.click(function(){
var moveX = box1.attr("x") - button2.getBBox().x;
var moveY = (box1.attr("y") - 50) - button2.getBBox().y;
button2.animate({transform: "t" + moveX + "," + moveY}, 1000, 'ease-in-out', function () {
text2.attr('text', "[x: " + button2.getBBox().x + "y: " + button2.getBBox().x + "]");
});
});
Welcome to SO, and suggest you to write a SSCCE next time.
UPDATE
I do not fully understand why the transformation does not reflect back
to the attributes. If I move the circle at the position (100,100)
100px horizontally it will results in a circle at position (200,100).
This is what the bounding box gives me. So why I am not able to get
the coordinates from the circle after the transformation and have to
use the bounding-box method ?
Transform DOSE NOT change the original attribute in the element, because it is something you attach to a element, not function that change a element directly. If you want to know attributes AFTER the transformation applied, you have to use getBBox(), or take a look about matrix.
This is how Raphael.js works. Either you use bounding box function, or extend the Raphael.js by yourself like this
I have changed my previous answer about how I describe transformation a little bit, hope it can help you to understand better this time.
Your code works great but it has the drawback, that you have to
compute the transformation values instead of simply setting the
position. Is there any other way to move a rectangle with text inside
to a position of your choice ?
You can always write helper functions to do these ugly jobs for you anyway, I don't see there's anything wrong with it.

Categories