I am rendering a Stock/Candlestick chart using React but the issue is when I hover the cursor over a data point, the tooltip is generated but the chart is destroyed.
If I change chart.tooltip().positionMode('float'); to chart.tooltip().positionMode('point');, the tooltip doesn't render at all but the chart remains.
I have tried various different position() options and also the anchor() but none seems to have any effect on the tooltip.
take a look here for the full code https://gitlab.com/gsrnt/react-cc-tracker.git
Here is the full js page for the chart
import AnyChart from 'anychart-react'
import anychart from 'anychart'
export default class Chart extends Component {
render() {
var coinId = this.props.location.state.coinId.id
var coinName = this.props.location.state.coinName.name
//set type of chart
var chart = anychart.stock();
//if posistion mode is 'float', chart disappears
//if position mode is 'point', tooltip doesn't render
chart.tooltip().positionMode('float');
//chart background color
chart.background().fill("#282c34");
// load jsonfile + function
anychart.data.loadJsonFile("https://api.coingecko.com/api/v3/coins/" + coinId + "/ohlc?vs_currency=usd&days=max",
function (data) {
// create a data table
var dataTable = anychart.data.table(0, 'MMM d, yyyy');
dataTable.addData(data);
// map data
var mapping = dataTable.mapAs({ 'open': 1, 'high': 2, 'low': 3, 'close': 4 });
// set the series
var series = chart.plot(0).candlestick(mapping);
// set the series name
series.name(coinName + " Price Data");
// set the chart title
chart.title(coinName + " Price Data");
// create a plot
var plot = chart.plot(0);
// create an EMA(Exponential Moving Average) indicator with period 20
var ema20 = plot.ema(mapping, 20).series();
// set the EMA color
ema20.stroke('1, white');
// disable the scroller axis
chart.scroller().xAxis(false);
// map "open" values for the scroller
var openValue = dataTable.mapAs();
openValue.addField('value', 2);
// create a scroller series with the mapped data
chart.scroller().column(openValue);
})
chart.tooltip().anchor("bottomLeft");
return <AnyChart
width={'100%'}
height={900}
instance={chart}
/>;
}
}
AnyStock supports the float position mode of the tooltip only. So, you can simply remove that line.
Related
I am using anychart for creating a percentage horizontal gauge.
And i want to change the marker information to show what i want.
I found nothing on the documentation about it.
I'm using the javascript anychart playground (link below).
The final implementation is on Angular 5.
The original code :
https://playground.anychart.com/docs/v8/samples/GAUGE_Linear_04
(Optional) The typescript method :
createAnyChartsCustomGauges() {
let array = [];
this.listItem.forEach(item => {
// Gauge type and data
const gauge = anychart.gauges.linear();
gauge.layout('horizontal');
// Set the data
gauge.data([item.percent]); //number
// Create the custom scale bar
const scaleBarre = gauge.scaleBar(0);
// color and style setting
const colorScale = anychart.scales.ordinalColor().ranges([
{
from: 0,
to: 25,
color: ['#D81E05', '#EB7A02'],
},
{
from: 25,
to: 50,
color: ['#EB7A02', '#FFD700'],
},
{
from: 50,
to: 75,
color: ['#FFD700', '#CAD70b'],
},
{
from: 75,
to: 100,
color: ['#CAD70b', '#2AD62A'],
},
]);
scaleBarre.width('5%');
scaleBarre.offset('31.5%');
scaleBarre.colorScale(colorScale);
// Add a marker pointer
const marker = gauge.marker(0);
marker.offset('31.5%');
marker.type('triangle-up');
marker.zIndex(10);
marker.labels().format('{%data[0]}%');
// Add a scale
const scale = gauge.scale();
scale.minimum(0);
scale.maximum(100);
scale.maxTicksCount(10);
// Add an axis
const axis = gauge.axis();
axis.minorTicks(true);
axis.minorTicks().stroke('#cecece');
axis.width('1%');
axis.offset('29.5%');
axis.orientation('top');
// format axis labels
axis.labels().format('{%value}%');
// set paddings
gauge.padding([0, 20]);
array.push(gauge);
});
}
Actual :
{
Pointer 0
Value 63
}
Expected :
{
Value 63%
}
#gugateider was absolutely right! Also, if you don't want to use HTML styling for tooltip and disable tooltip title and separator, you can use the code below:
gauge.tooltip().title(false);
gauge.tooltip().separator(false);
gauge.tooltip().format("Value: {%value}%");
You should be using the format() methods of the Tooltip class.
There's a similar example on Any charts playground
// enable HTML for tooltips
chart.tooltip().useHtml(true);
// tooltip settings
var tooltip = gauge.tooltip();
tooltip.positionMode("point");
tooltip.format("Value: <b>${%value} %</b>");
Try that and see if works?
I have a c3.js line graph that represents the evolution of 2 values. I need that the tooltip of the line graph to be a pie chart (tooltip = another c3.js graph).
Here is what I succeeded:
http://jsfiddle.net/owhxgaqm/80/
// c3 - custom tooltip
function generateGraph(data1,data2) {
console.log(data1.name + '\t' + data1.value + '\t' + data2.name + '\t' + data2.value);
var chart1 = c3.generate(
{
bindto: "#t",
data: {columns : [[data1.name, data1.value],[data2.name, data2.value]],
type : 'pie'}
});
}
var chart = c3.generate({
data: {
columns: [
['data1', 1000, 200, 150, 300, 200],
['data2', 400, 500, 250, 700, 300], ]
},
tooltip: {
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
generateGraph(d[0], d[1]);
var divt = document.getElementById("t");
return '';
}
}
});
As you can see I'm binding the "tooltip" with an already existing div so this is not really what I want from c3.js.
Any idea is welcome.
Thanks.
Adding a Chart inside a C3 Tooltip
You can use the tooltip element that c3 already has. In your contents function call the generateGraph function (see next step). Pass in the tooltip element available in this.tooltip in addition to the data.
...
tooltip: {
contents: function (d) {
// this creates a chart inside the tooltips
var content = generateGraph(this.tooltip, d[0], d[1])
// we don't return anything - see .html function below
}
}
...
Your generateGraph function basically creates a c3 chart in your tooltip element (bindto supports a d3 element). We do a bit of optimization (if the data is same, the chart is not recreated) and cleanup (when a chart is recreated it is destroyed and removed from the DOM)
function generateGraph(tooltip, data1, data2) {
// if the data is same as before don't regenrate the graph - this avoids flicker
if (tooltip.data1 &&
(tooltip.data1.name === data1.name) && (tooltip.data1.value === data1.value) &&
(tooltip.data2.name === data2.name) && (tooltip.data2.value === data2.value))
return;
tooltip.data1 = data1;
tooltip.data2 = data2;
// remove the existing chart
if (tooltip.chart) {
tooltip.chart = tooltip.chart.destroy();
tooltip.selectAll('*').remove();
}
// create new chart
tooltip.chart = c3.generate({
bindto: tooltip,
size: {
width: 200,
height: 200
},
data: {
columns: [[data1.name, data1.value], [data2.name, data2.value]],
type: 'pie'
}
});
// creating a chart on an element sets its position attribute to relative
// reset it to absolute (the tooltip was absolute originally) for proper positioning
tooltip.style('position', 'absolute');
}
Note that we set the chart size so that it's more like tooltip content instead of a subchart.
The last bit is a bit hacky - since c3 requires that we set a HTML (which we don't want to do) and because we don't have any other callbacks we can easily hitch onto after the content handler, we have to disable the function that c3 uses to set the html content on the tooltip (this will affect only this chart's tooltip) i.e. .tooltip.html
// MONKEY PATCHING (MAY break if library updates change the code that sets tooltip content)
// we override the html function for the tooltip to not do anything (since we've already created the tooltip content inside it)
chart.internal.tooltip.html = function () {
// this needs to return the tooltip - it's used for positioning the tooltip
return chart.internal.tooltip;
}
Fiddle - http://jsfiddle.net/muuqvf1a/
Tooltip Positioning
Instead of using c3's tooltip positioning you could also size and position the tooltip at the bottom of the chart. Just style .c3-tooltip-container.
Alternatives
Note that c3 also support subcharts (http://c3js.org/reference.html#subchart-show) and data.mouseover (http://c3js.org/reference.html#data-onmouseover) which could also be a cleaner avenues worth exploring.
I have the following code:
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1', {'packages':['corechart']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawChart);
function drawChart() {
// Create our data table out of JSON data loaded from server.
// var data = new google.visualization.DataTable('<>');
var data = google.visualization.arrayToDataTable([['Generation', 'Descendants'],[0,300], [85,300],[125,0] ]);
var options = {
title: 'Derating chart',
// Draw a trendline for data series 0.
lineWidth: 2,
hAxis: {title: 'Temperature [°C]', titleTextStyle: {color: 'black'}, logScale: false},
vAxis: {
title: "Irms [A]",
maxValue:8
},
pointSize:5
};
// Instantiate and draw our chart, passing in some options.
// Do not forget to check your div ID
var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
It's quite simple, but I have the following problem:
- In my chart I have 3 points, is it possible to interpolate the values between that points? I need to display the values between them when you put the mouse over the line
There should be an option for this... but checking forums and documentation have found none. Closest to this is using a trendline, but values don´t match your line. So your only way is doing something manually. Here is a workaround I made using jquery :
//you need to have in options tooltip:{isHtml:true} for this to work
google.visualization.events.addListener(chart, 'ready', function(){
$('#chart_div svg path').mousemove(function(e){
$('.google-visualization-tooltip').remove(); // remove previous tooltips
var x=e.offsetX; // get x coordinate
var y=e.offsetY; //get y coordinate
var xValue= Math.round(chart.getChartLayoutInterface().getHAxisValue(x)); // get chart x value at coordinate
var yValue=Math.round( chart.getChartLayoutInterface().getVAxisValue(y)); // get chart y value at coordinate
// create tooltip
var tootlip = $('<div class= "google-visualization-tooltip"><ul class="google-visualization-tooltip-item-list"><li class="google-visualization-tooltip-item"><span >X : '+xValue+'</span></li><li class="google-visualization-tooltip-item"><span>Y : '+yValue+'</span></li></ul></div>');
tootlip.css({position:'absolute', left:(x+20)+'px', top:(y-100)+'px', width:'100px', height:'70px'}) // set tooltip position
$('#chart_div').append(tootlip); // add tooltip to chart
})
$('#chart_div svg path').mouseout(function(e){
$('.google-visualization-tooltip').remove();
})
})
Full fiddle: http://jsfiddle.net/juvian/48ouLbmm/
Note: without the mouseout it works better, but tooltip stays until next mouseover
Here is the scenario. I've multiple highstocks say 10 charts on a single page. Currently I've written 500 lines of code to position the legend, show tooltip and refresh the legend values on mousemove.
No. of legends vary per chart. On mousemove values of all the legends are updated. I need to optimize the code I am using highstocks v1.2.2.
Above screenshot shows 2 charts. Return, Basket, vs Basket Spread are legends and it's values are updated on every mousemove.
Please find this fiddle for example. In my case legends are positioned and updated values on mouse move with hundreds of lines of code. When I move the mouse the legend values of Return and Basket of first chart and the legend values of vs Basket Spread are updated. It's working fine but with lots of javascript code. So I need to optimize it less code or with highstocks built-in feature.
Update
User #wergeld has posted new fiddle. As I've shown in screenshot when cross-hair is being moved over any chart, the legend values of all the charts should be updated.
Is there anyway to implement the same functionality with less code or is there built-in feature available in highstocks ???
Using this as a reference.
Basic example would be to use the events.mouseover methods:
plotOptions: {
series: {
point: {
events: {
mouseOver: function () {
var theLegendList = $('#legend');
var theSeriesName = this.series.name;
var theYValue = this.y;
$('li', theLegendList).each(function (l) {
if (this.innerText.split(':')[0] == theSeriesName) {
this.innerText = theSeriesName + ': ' + theYValue;
}
});
}
}
}
}
}
This is assuming I have modded the <li> to be:
$('<li>')
.css('color', serie.color)
.text(serie.name + ': NA')
.click(function () {
toggleSeries(i);
})
.appendTo($legend);
You would then need to handle the mouseout event but I do not know what you want to do there.
Working example.
EDIT:
Here is a version using your reference OHLC chart to put the values in a different legend location when any point in the chart is hovered.
plotOptions: {
series: {
point: {
events: {
mouseOver: function () {
//using the ohlc and volumn data sets created at runtime.
var stockVal = ohlc[this.index][4]; // show close value
var stockVolume = volume[this.index][1];
var theChart = $('#container').highcharts();
var theLegendList = $('#legend');
$('li', theLegendList).each(function (l) {
var legendTitle = theChart.series[l].name;
if (l === 0) {
this.innerText = legendTitle + ': ' + stockVal;
}
if (l === 1) {
this.innerText = legendTitle + ': ' + stockVolume;
}
});
}
}
}
}
}
I would like to build some sort of forward/back pager that will navigate between the points on my chart, highlighting the current point.
The closest example I've seen is something similar to the news legend on google finance charts, https://www.google.ca/finance?q=goog&ei=AD6dUvjOLMi0iAL9Uw
(you can click each news article/event and it will jump in the graph to the relevant point in time on the graph)
Can this be done with Flot and any suggestions on how to do this? Thanks!
Here's a real quick example to demonstrate one approach to this problem. On previous/next button clicks it highlights the previous/next point in the series and adjusts the xaxis so that the hightlighted point stays centered on the screen.
var highlightPoint = 15; // our first highlight
var xmin = 10, xmax = 20; // some arbitrary slice of series
var plot = $.plot("#placeholder", [ d1 ], //initial plot call
{
xaxis:{min: xmin, max: xmax}
});
plot.highlight(0,highlightPoint); // initial highlight
$('#prevPoint').click(function(){
plot.unhighlight(0,highlightPoint); // unhighlight previous selection
highlightPoint -= 1; // move to left
xmin = highlightPoint - 5; // adjust xaxis
xmax = highlightPoint + 5;
plot.getOptions().xaxes[0].min = xmin; // set xaxis into options
plot.getOptions().xaxes[0].max = xmax;
plot.setupGrid(); // refresh chart with new xaxis
plot.draw(); // redraw
plot.highlight(0,highlightPoint); //highlight new point
});
Makes more sense to look at the Fiddle here.