Chart.js Radar Labels Coordinates - javascript

is there any way to get the coordinates for the labels in the radar chart?
I'm trying to put images instead of text in the labels area.

You can calculate it using the scale property. Here is something that draws a blue circle at those points after the animation completes.
onAnimationComplete: function () {
for (var i = 0; i < this.scale.valuesCount; i++) {
// get the poitn position
var pointLabelPosition = this.scale.getPointPosition(i, this.scale.calculateCenterOffset(this.scale.max) + 5);
// draw a circle at that point
this.chart.ctx.beginPath();
this.chart.ctx.arc(pointLabelPosition.x, pointLabelPosition.y, 5, 0, 2 * Math.PI, false);
this.chart.ctx.fillStyle = '#77e';
this.chart.ctx.fill();
this.chart.ctx.stroke();
}
}
Fiddle - http://jsfiddle.net/1jgmbyb7/

Related

How can I create a tooltip on mouse over in p5JS?

I have started playing with P5JS, but I wanted to create a tooltip on mouse over for each of the data points when the pointer is over it.
How can I do this? I have seen some examples using the map function, but unsure how this would work here.
Appreciate any help! I am not a JS dev just yet!
Generally speaking displaying tooltips that are specific to graphics displayed on a canvas involves "hit testing," which is to say: checking if the mouse is hovering over the specific graphics, and then some mechanism for displaying the tooltip.
Since your graphics are all circles, hit testing is quite simple. For each circle that you draw, check the distance to the mouse position. If the distance is less than the radius of the circle than the mouse is hovering over that circle:
let mouseDist = dist(posX, posY, mouseX, mouseY);
if (mouseDist < earthquakeMag * 5) {
// display tooltip, or set a flag to display the
// tooltip after the rest of the graphics have been
// displayed
}
As for displaying the tooltip you have two options: 1) you can rely on the native behavior of browser elements by setting the title attribute of the canvas element, or 2) you can display your own tooltip. The advantage of the former is that it is very trivial, but the advantage of the latter is that you have more control over where/when/how the tooltip is rendered.
Option 1:
let c;
function setup() {
c = createCanvas(500,500);
// ...
}
function draw() {
// ...
for (var i = 0; i < this.data.getRowCount(); i++) {
// ...
let mouseDist = dist(posX, posY, mouseX, mouseY);
if (mouseDist < earthquakeMag * 5) {
c.elt.title = 'hit!';
}
}
}
Option 2:
let tooltipText;
for (var i = 0; i < this.data.getRowCount(); i++) {
// ...
let mouseDist = dist(posX, posY, mouseX, mouseY);
if (mouseDist < earthquakeMag * 5) {
// If we displayed the tooltip at this point then
// some of the circles would overlap it.
tooltipText = date_[i];
}
// ...
}
if (tooltipText) {
// measure the width of the tooltip
let w = textWidth(tooltipText);
// save the current fill/stroke/textAlign state
push();
// draw a lightgray rectangle with a dimgray border
fill('lightgray');
stroke('dimgray');
strokeWeight(1);
// draw this rectangle slightly below and to the
// right of the mouse
rect(mouseX + 10, mouseY + 10, w + 20, 24, 4);
textAlign(LEFT, TOP);
noStroke();
fill('black');
text(tooltipText, mouseX + 20, mouseY + 16);
// restore the previous fill/stroke/textAlign state
pop();
}

Display multiple vertical lines on graph at various positions

I want to draw vertical lines at points on the x axis in dygraphs.
They should:
Span the entire y axis automatically, but not prevent other series from being automatically zoomed in on the y axis when manually zoomed to a range of the x axis
Be completely vertical
have no horizontal lines joining them
In that sense, a lot like having multiple extra axis lines drawn at random points.
But it would be helpful if they have the same features of regular series plots in that when it is hovered over, a label displays its value along the x axis.
In case it matters, they will be plotted on the same graph as other series lines, and may or may not have common x axis values with those series.
How might it be achieved?
A way to draw vertical lines, is to use the underlayCallback. It allows you to draw the background of the graph.
Here is a sample that draw 3 vertical lines at X=100, X=200 and X=500 :
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/1.1.1/dygraph-combined.js"></script>
<div id="div_g" style="width:400px; height:200px;"></div>
<script>
// A basic sinusoidal data series.
var data = [];
for (var i = 0; i < 1000; i++) {
var base = 10 * Math.sin(i / 90.0);
data.push([i, base]);
}
new Dygraph(
document.getElementById("div_g"),
data, {
labels: ['X', 'Y'],
underlayCallback: function(canvas, area, g) {
canvas.strokeStyle = 'red';
var lines = [100, 200, 500];
for (var idx = 0; idx < lines.length; idx++) {
var canvasx = g.toDomXCoord(lines[idx]);
var range = g.yAxisRange();
canvas.beginPath();
canvas.moveTo(canvasx, g.toDomYCoord(range[0]));
canvas.lineTo(canvasx, g.toDomYCoord(range[1]));
canvas.stroke();
canvas.closePath();
}
}
}
);
</script>

Display negative values in canvas line graph

I am using html5 canvas element to draw line chart. The chart works fine with positive values. But when provided negative values, the chart is not drawn correctly.
This is what I have tried. Any help will be appreciated.
http://jsfiddle.net/nshX6/142/
function getMinY () {
var min = 0;
for(var i = 0; i < data.values.length; i ++) {
if(data.values[i].Y < min) {
min = data.values[i].Y;
}
}
return Math.ceil(min);
}
Here are some tool functions you can use to build a flexible graph.
Your flexible graph will be able to show any range of data and it will always fit on the available canvas size.
calcSourceMinMax: Calculates the minimum and maximum value from a data array.
mapRange: Takes any data value and maps it into a proportional value that is guaranteed to be inside the minimum and maximum of the graphs displayable width & height. This allows your data array to contain any range of values and still never fall outside the graphing display area.
getDisplayXY: Takes a specified x,y data value and finds its display X,Y coordinate on the graph.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var xPadding = 40;
var yPadding = 30;
// Notice I changed The X values
var data = { values:[
{ X: 0, Y: -120 },
{ X: 2, Y: 28 },
{ X: 3, Y: 18 },
{ X: 4, Y: 34 },
{ X: 5, Y: 40 },
{ X: 6, Y: 80 },
{ X: 7, Y: 80 }
]};
// calc the drawable graph boundaries
var graphLeft=xPadding;
var graphRight=canvas.width-xPadding;
var graphTop=yPadding;
var graphBottom=canvas.height-yPadding;
// graph styling
var dotRadius=3;
// calc the min & max values of data.values (calc both X & Y ranges)
var rangeX=calcSourceMinMax(data.values,'X');
var rangeY=calcSourceMinMax(data.values,'Y');
// draw the graph content
var starting=getDisplayXY(data.values[0].X,data.values[0].Y);
dot(starting,dotRadius);
for(var i=1;i<data.values.length;i++){
var ending=getDisplayXY(data.values[i].X,data.values[i].Y);
connector(starting,ending);
dot(ending,dotRadius);
starting=ending;
}
// draw the graph axes
var y0=getDisplayXY(graphLeft,0).displayY;
ctx.beginPath();
ctx.moveTo(graphLeft,graphTop);
ctx.lineTo(graphLeft,graphBottom);
ctx.moveTo(graphLeft,y0);
ctx.lineTo(graphRight,y0);
ctx.strokeStyle='#D3E';
ctx.stroke();
// draw the graph legends
ctx.textAlign='right';
ctx.textBaseline='middle';
var y0=getDisplayXY(graphLeft,0).displayY;
var yMin=getDisplayXY(graphLeft,rangeY.min).displayY;
var yMax=getDisplayXY(graphLeft,rangeY.max).displayY;
var xMax=getDisplayXY(graphRight,rangeX.max).displayX;
ctx.fillText(rangeY.min,graphLeft-10,yMin);
ctx.fillText(0,graphLeft-10,y0);
ctx.fillText(rangeY.max,graphLeft-10,yMax);
ctx.fillText(rangeX.max,graphRight+10,y0);
///////////////////////////////////
// HELPER FUNCTIONS
///////////////////////////////////
//
function getDisplayXY(valueX,valueY){
// calc the display X & Y from data.values[i]
x=mapRange(valueX,rangeX.min,rangeX.max,graphLeft,graphRight);
// Note: canvas y values increase going downward
// so swap graphTop & graphBottom
y=mapRange(valueY,rangeY.min,rangeY.max,graphBottom,graphTop);
return({displayX:x,displayY:y})
}
//
function connector(starting,ending){
ctx.beginPath();
ctx.moveTo(starting.displayX,starting.displayY);
ctx.lineTo(ending.displayX,ending.displayY);
ctx.stroke();
}
//
function dot(position,radius){
ctx.beginPath();
ctx.moveTo(position.displayX,position.displayY);
ctx.arc(position.displayX,position.displayY,radius,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
// map source values into a designated range
function mapRange(value, sourceLow, sourceHigh, mappedLow, mappedHigh) {
return mappedLow + (mappedHigh - mappedLow) * (value - sourceLow) / (sourceHigh - sourceLow);
}
// mapping helper function
function calcSourceMinMax(a,prop){
var min=1000000;
var max=-1000000;
for(var i=0;i<a.length;i++){
var value=a[i][prop];
if(value<min){min=value;}
if(value>max){max=value;}
}
return({min:min,max:max});
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=350 height=300></canvas>
You will want to style the graph according to your design needs. This minimal example shows a legend containing the x,y axes and the min,max ranges of values.
Also, the x-axis is put at the y=0 value. You will also want to check that there is indeed a y=0 in the range of your y values. If not, you might move the x-axis at the bottom of your graph.
Good luck with your project!
Try modifaying this parameters :
var xPadding = 30;
var yPadding = 30;
To :
var xPadding = 30;
var yPadding = 100;
After that you need to change Y step to be bigger.
EDIT
In case that you have dynamic data you need to normalize values.
step 1 : find min value for Y
step 2 : if min value is less than zero (0) you need to normalize all values to be positive. Add that value to every element of array
step 3 : shift Y axes to it's new position.

html canvas a line following mouse

So i want to make a line follow mouse and on click to draw that line, i need this for drawing polygons. My idea was to draw a line every time mouse moves but then it makes mess with a lot of lines, so i decided to draw over old lines after mouse moves with white lines to clean up and so that there would be only one line that goes from a point of last clicked spot to current mouse location.My jsFiddle for this. but it doesn't work the way i want yes i draws polygons on clicking but there is no line following the mouse so i can't see what line I'm drawing. I don't see where is it wrong ? Maybe there is some ready solution that i didn't find ? Mycode :
var polygonX = [];
var polygonY = [];
var lineReady = 0;
var whileLineX;
var whiteLineY;
$("#body").bind('mousemove', function (ev) {
if (lineReady >= 2) {
var context;
//clear old lines
if (whiteLineX !== null && whiteLineY !== null) {
context = $("#canvas")[0].getContext('2d');
context.moveTo(polygonX[lineReady - 1], polygonY[lineReady - 1]);
context.lineTo(whiteLineX, whiteLineY);
context.strokeStyle = '#ffffff';
context.stroke();
}
//draw a new line
context = $("#canvas")[0].getContext('2d');
var offset = $('#body').offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
context.beginPath();
context.moveTo(polygonX[lineReady - 1], polygonY[lineReady - 1]);
context.strokeStyle = '#000000';
context.lineTo(x, y);
context.stroke();
whileLineX = x;
whiteLineY = y;
}
});
$("#body").bind('click', function (ev) {
var offset = $('#body').offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
polygonX
.push(x);
polygonY.push(y);
lineReady++;
if (lineReady >= 2) {
var context = $("#canvas")[0].getContext('2d');
context.beginPath();
context.moveTo(polygonX[lineReady - 2], polygonY[lineReady - 2]);
context.lineTo(polygonX[lineReady - 1], polygonY[lineReady - 1]);
context.stroke();
}
});`
The best way to do this is to use a bit of animation.
Everytime you draw a line, push its coordinates (first point and last point) in an array. Then draw your array at every animation loop(check out this link which will explain you how to animate)
. Then you'll want to draw a single line, say colored in red, from the last point of the last line of the array where you're pushing lines to your mouse position.
Doing it this way will allow you to have a red line following your mouse at all times, giving you a "preview" of a line.
Algo-wise it would look like:
var arrayOflines = [];
canvas.onclick ->
var coordinates = mouseposition()
arrayOfLines.push(coordinates)
function mouseposition(){
returns x and y of your mouse on the canvas
}
function draw(array){
loop through array
draw line from array[0] to array[1], then from array[1] to array[2] on canvas
}
function drawPreview(){
draw line from last point of arrayOflines to mouseposition;
}
//so here we are:
function animationloop{
erase your canvas
draw(arrayOfLines); //draw your array
drawPreview(); //draw your 'preview' line
requestAnimationFrame(animationloop); //animate
}
Doing things this way will allow you to achieve a clean result.

HTML Canvas: Drawing grid below a plot

I'm plotting a graph on a canvas and having trouble to draw the grid of the plot underneath the graph. My data points are drawn as rectangles (fillRect). When I first draw the graph and then draw the grid it works as expected, but since the grid is on the graph it doesnt look good. But when I draw the grid first and then plot the graph, all the grids disappear underneath.
I draw my plots as follows:
var plots = document.getElementsByClassName("PlotCanvas");
for (var x=0; x < tokens.length; x++)
{
var canvas = plots[x];
canvas.width = arrayOfArrays[x].length;
var context = canvas.getContext("2d");
for(var point=1; point<arrayOfArrays[x].length; point++)
{
context.fillRect(point, arrayOfArrays[x][point],...);
}
}
Then draw the grids as:
function DrawGrids(plots)
{
for(var count=0; count<plots.length; count++)
{
var ctx = plots[count].getContext("2d");
ctx.beginPath();
for (var x = 0.5; x < plots[count].width; x += 20) {
ctx.moveTo(x, 0);
ctx.lineTo(x, plots[count].height);
}
for (var y = 0.5; y < plots[count].height; y += 20) {
ctx.moveTo(0, y);
ctx.lineTo(plots[count].width, y);
}
ctx.strokeStyle = "#eee";
ctx.stroke();
}
}
Could someone suggest me how I can draw the grid underneath the plot. Or how to draw the graph such that it doesn't draw on the whole canvas thus disappearing the grid drawn earlier.
Thank you.
Use ctx.globalCompositeOperation="destination-over" to draw your grid behind your plots!
// draw your plots here
// save the context
ctx.save();
// set compositing to "destination-over"
// New drawings are drawn behind the existing canvas content.
ctx.globalCompositeOperation = "destination-over";
// draw your grids behind your plots!
DrawGrids();
// restore the context
ctx.restore();

Categories

Resources