Related
I have a BackgroundService class that is load 60 point of data at first load then add a point every minute to chart.I have used SignalR with HighChart in .Net6,the problem is that adding point in javascript class does not work.I want to add a point with it's data's at the end of the chart then shift it .
this is backgroundService Class:
public class TxnRespHistoryBackgroundCaller : BackgroundService
{
public ITxnRespHistoryRepository Repository { get; }
public IHubContext<MonitoringHub> HubContext { get; }
private bool isFirstCall = true;
public TxnRespHistoryBackgroundCaller(ITxnRespHistoryRepository repository, IHubContext<MonitoringHub> hubContext)
{
Repository = repository;
HubContext = hubContext;
}
private static List<string> FailResps
{
get
{
try
{
return new List<string>() { "3", "92", "91", "96", "80", "84" };
}
catch
{
return new List<string>();
}
}
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Run(async () =>
{
while (!stoppingToken.IsCancellationRequested)
{
if (isFirstCall == true)
{
try
{
var datasets = new List<dynamic>();
DateTime FinishTime = DateTime.Now;
try
{
FinishTime = Repository.GetMax(TxnRespHistory.Columns.EndTime);
}
catch
{
try
{
FinishTime = Repository.GetServerTime();
}
catch
{
FinishTime = DateTime.Now;
}
}
var yesterdayalltxn = await Repository.GetTxnHisByResp(59, TransactionType.Yesterday, FinishTime, FailResps);
var failtxn = await Repository.GetTxnHisByResp(59, TransactionType.fail, FinishTime, FailResps);
var alltxn = await Repository.GetTxnHisByResp(59, TransactionType.All, FinishTime, FailResps);
var suctxn = await Repository.GetTxnHisByResp(59, TransactionType.successful, FinishTime, FailResps);
datasets.Add(new
{
data = suctxn.Value,
label = "Success",
Key = "Success",
color = "#308014"
});
datasets.Add(new
{
data = failtxn.Value,
label = "UnSuccess",
Key = "Fail",
color = "#ff0000"
});
datasets.Add(new
{
data = alltxn.Value,
label = "Total",
Key = "Total",
color = "#7094db"
});
datasets.Add(new
{
data = yesterdayalltxn.Value,
label = "Yesterday",
Key = "Yesterday",
color = "#b3b3b3"
});
var result = new
{
success = true,
labels = alltxn.Key,
datasets = datasets
};
await HubContext.Clients.All.SendAsync("populatetxns", JsonConvert.SerializeObject(result));
isFirstCall = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
else
{
try
{
var newtxn = Repository.AddtxnHisByResp(FailResps);
var result = new
{
labels = newtxn.Key,
datasets = newtxn.Value
};
await HubContext.Clients.All.SendAsync("populatetxns", JsonConvert.SerializeObject(result));
Thread.Sleep(10000);
}
catch (Exception)
{
throw;
}
}
}
});
}
}
and this is javaScript Code :
let txnresphisbycha = {};
$(document).ready(function () {
let isFirstCallSuccess = false;
var connection = new signalR
.HubConnectionBuilder()
.withUrl("/monitoringHub").build();
connection.start().then(() => console.log("hubconnected")).catch(() => console.log(error));//establish connection
connection.on("populatetxns", (result) => {
if (isFirstCallSuccess == false)
getChartData(JSON.parse(result));
else
addChartData(JSON.parse(result));
});
function getChartData(result) {
var dataSets = new Array();
for (i = 0; i < result.datasets.length; i++) {
var entity = {};
entity.name = result.datasets[i].label;
entity.data = result.datasets[i].data;
entity.color = result.datasets[i].color;
entity.type = 'area';
dataSets.push(entity);
}
txnresphisbycha = Highcharts.chart('txnhisbyrespcha', {
chart: {
zoomType: 'x',
alignTicks: false,
height: (10 / 22 * 100) + '%',// set ratio
},
title: {
text: 'Total Transaction Chart'
},
credits: {
text: ''
},
legend: {
enabled: true,
rtl: true,
y: 25,
margin: 0,
shadow: true,
verticalAlign: 'top',
itemStyle: {
cursor: "pointer",
}
},
tooltip: {
enabled: true,
rtl: true,
split: false,
shared: true,
xDateFormat: '%H:%M',
useHTML: true,
style: {
fontSize: '15px',
rtl: true,
},
distance: 30,
padding: 5,
headerFormat: '<span>{point.key}</span><br/>'
},
xAxis: {
zoomEnabled: true,
categories: result.labels,
type: 'datetime',
tickInterval: 1,
labels: {
type: 'datetime',
step: 1,
rotation: 55,
style: {
fontSize: '11px'
},
}
},
yAxis: {
title: {
text: "Quantity",
style: {
fontSize: '15px',
},
},
opposite: false,
endOnTick: true,
showLastLabel: true,
labels: {
style: {
fontSize: '15px',
},
align: 'right',
x: -7,
y: 5,
formatter: function () {
return this.value;
}
}
},
plotOptions: {
series: {
pointRange: 1 * 60 * 1000,
fillOpacity: 0.2,
marker: {
symbol: 'circle'
}
}
},
series: dataSets,
navigator: {
enabled: true
}
});
isFirstCallSuccess = true;
}
function addChartData(result) {
if (!isFirstCallSuccess) return;
debugger;
if (txnresphisbycha.series[0].data[txnresphisbycha.series[0].data.length - 1].category != result.labels[0]) {
txnresphisbycha.series[0].addPoint({
x: result.labels[0],
function() {
for (var i in result.datasets) {
y: result.datasets[i]
}
},
dataLables: { enabled: true }
},
true
,true)
txnresphisbycha.update();
}
}
})
I've seen tutorials and posts about getting data from the x axis into the tooltip but I am overriding it with categories and cannot figure out how to get the x axis to show up in the tooltip.
This is what im working with:
function showTooltip(x, y, contents) {
$('<div id="tooltip" class="flot-tooltip tooltip"><div class="tooltip-arrow"></div>' + contents + '</div>').css({
top: y - 43,
left: x - 15,
}).appendTo("body").fadeIn(200);
}
var data = [[1492854610, -1240],[1492939020, -1273],[1493025073, -1279],[1493117066, -1186],[1493198484, -1269],[1493289175, -1198],[1493370646, -1280],[1493458518, -1255],[1493543731, -1275],[1493630250, -1273],[1493716306, -1279],[1493803609, -1264],[1493889258, -1276],[1493975557, -1278],[1494064529, -1235],[1494155440, -1160],[1494237980, -1224],[1494321047, -1280],[1494407990, -1271],[1494494125, -1275],[1494581609, -1257],[1494668321, -1252],[1494753220, -1277],[1494847855, -1140],[1494925963, -1278],[1495012537, -1275],[1495099289, -1269],[1495188205, -1227],[1495273568, -1244],[1495358329, -1272]];
$.plot($("#placeholder"), [{
label: "Delay: ",
data: data,
color: "#3a8ce5"
}], {
xaxis: {
mode: "categories",
tickLength: 0,
ticks: [[0, "1:50 AM"],[1, "1:17 AM"],[2, "1:11 AM"],[3, "2:44 AM"],[4, "1:21 AM"],[5, "2:32 AM"],[6, "1:10 AM"],[7, "1:35 AM"],[8, "1:15 AM"],[9, "1:17 AM"],[10, "1:11 AM"],[11, "1:26 AM"],[12, "1:14 AM"],[13, "1:12 AM"],[14, "1:55 AM"],[15, "3:10 AM"],[16, "2:06 AM"],[17, "1:10 AM"],[18, "1:19 AM"],[19, "1:15 AM"],[20, "1:33 AM"],[21, "1:38 AM"],[22, "1:13 AM"],[23, "3:30 AM"],[24, "1:12 AM"],[25, "1:15 AM"],[26, "1:21 AM"],[27, "2:03 AM"],[28, "1:46 AM"],[29, "1:18 AM"]]
},
yaxis: {
min: -2000,
max: 1000,
},
series: {
lines: {
show: true,
fill: true
},
points: {
show: true,
}
},
grid: {
hoverable: true,
clickable: true,
markings: [
{ color: '#000', lineWidth: 1, yaxis: { from: 0, to: 0 } },
]
},
legend: {
show: false
}
});
$("#placeholder").bind("plothover", function(event, pos, item) {
if (item) {
if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex;
$("#tooltip").remove();
var y = item.datapoint[1].toFixed();
showTooltip(item.pageX, item.pageY,
item.series.label + " = " + y);
}
} else {
$("#tooltip").remove();
previousPoint = null;
}
});
I am trying to get the times part of the categories. The item array has 3 pieces of data, none of which are the times
jFiddle:
http://jsfiddle.net/zw14y8c3/2/
The item.datapoint[0] data has the index of the x-axis tick. With that you can get the actual tick label from the ticks array:
var x = $("#placeholder").data('plot').getAxes().xaxis.ticks[item.datapoint[0]].label;
See the updated fiddle for the full example.
I made a few graphs with the possibility of putting a mark inside, but I don't understand how to make the mark hoverable with the y-axis value.
$.plot($("#flot-chart-#ControlID"), series_#ControlID, {
series: {
lines: {
lineWidth: 2,
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
},
bars: {
barWidth: 0.6,
align: "center"
},
points: {
fill: #((Model.Series.Count() == 1).ToString().ToLower()),
}
},
xaxis: {
ticks: xlabels_#ControlID,
tickDecimals: 0
},
colors: #Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Series.Select(o => o.Color).ToArray())),
grid: {
color: "#999999",
hoverable: true,
clickable: true,
borderWidth: 0,
#if (Model.LimitLine != null)
{
<text>
markings: [
{ color: '#000', lineWidth: 1, yaxis: { from: #Model.LimitLine, to: #Model.LimitLine }},
]
</text>
}
},
legend: {
show: true
},
tooltip: true,
tooltipOpts: {
content: function(label, xval, yval) {
var content = getLabel_#(ControlID)(xval) + ": " + yval;
return content;
},
}
});
How can i show a tooltip with the value?
Graph example:
You can't do that with the tooltips plugin, but it is possible when doing the tooltips yourself. Something like this:
$("#placeholder").bind("plothover", function (event, pos, item) {
if (item) { // hovering over a datapoint
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
$("#tooltip").html(item.series.label + " of " + x + " = " + y)
.css({top: item.pageY+5, left: item.pageX+5}).fadeIn(200);
} else {
var hideTooltip = true;
// you need to save the Flot object for this (here as "plot")
$.each(plot.getOptions().grid.markings, function(idx, marking) {
if (Math.abs(pos.y - marking.yaxis.to) < 10) {
$("#tooltip").html("Limit: " + marking.yaxis.to)
.css({top: pos.pageY + 5, left: pos.pageX + 5}).fadeIn(200);
hideTooltip = false;
return false;
}
});
if (hideTooltip) {
$("#tooltip").hide();
}
}
});
Based on this example.
With the Highcharts value-in-legend plugin http://www.highcharts.com/plugin-registry/single/10/Value-In-Legend, I have been able to kind of implement a sort of multiple series total, but I do not understand how to get a total for a clicked y-axis point.
For example when I click, one day I will get the 3 separate series numbers, but I would like to get a total somehow as well, but I only know the y points on load and the visible y-points on redraw. I think the difficulty is getting the total of the 3 series points versus getting the individual point's value.
$(function() {
// Start the standard Highcharts setup
var seriesOptions = [],
yAxisOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'],
colors = Highcharts.getOptions().colors;
$.each(names, function(i, name) {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function(data) {
seriesOptions[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter++;
if(seriesCounter == names.length) {
createChart();
}
});
});
// create the chart when all data is loaded
function createChart() {
$('#container').highcharts('StockChart', {
chart: {
events: {
load: function(event) {
console.log('load');
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
total += this.series[0].yData[i];
}
totalText_posts = this.renderer.text('Total: ' + total, this.plotLeft, this.plotTop - 35).attr({
zIndex: 5
}).add()
},
redraw: function(chart) {
console.log('redraw');
console.log(totalText_posts);
var total = 0;
for(var i = 0, len = this.series[0].yData.length; i < len; i++) {
if(this.series[0].points[i] && this.series[0].points[i].visible) total += this.series[0].yData[i];
}
totalText_posts.element.innerHTML = 'Total: ' + total;
}
}
},
rangeSelector: {
selected: 4
},
yAxis: {
labels: {
formatter: function() {
return(this.value > 0 ? '+' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 35,
labelFormat: '<span style="color:{color}">{name}</span>: <b>{point.y:.2f} USD</b> ({point.change:.2f}%)<br/>',
borderWidth: 0
},
plotOptions: {
series: {
compare: 'percent',
cursor: 'pointer',
point: {
events: {
click: function () {
alert('Category: ' + this.category + ', value: ' + this.y);
}
}
}
}
},
series: seriesOptions
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/stock/highstock.src.js"></script>
<script src="http://code.highcharts.com/stock/modules/exporting.js"></script>
<script src="https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js"></script>
<div id="container" style="height: 400px; min-width: 500px"></div>
I was able to find out a way to put the total result as a title in a multi series by reading the source code for the Highcharts value-in-legend plugin https://rawgithub.com/highslide-software/value-in-legend/master/value-in-legend.js.
$(function () {
var seriesOptions_likes = [],
seriesCounter_likes = 0,
names_likes = ['MSFT', 'AAPL', 'GOOG'],
totalText_likes = 0;
/**
* Create the chart when all data is loaded
* #returns {undefined}
*/
function createLikesChart() {
Highcharts.stockChart('container_likes', {
chart: {
},
rangeSelector: {
selected: 4
},
title: {
text: 'Total Results: '
},
yAxis: {
labels: {
formatter: function () {
return (this.value > 0 ? ' + ' : '') + this.value + '%';
}
},
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
plotOptions: {
series: {
compare: 'percent',
showInNavigator: true
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
series: seriesOptions_likes,
legend: {
enabled: true,
floating: true,
align: 'left',
verticalAlign: 'top',
y: 65,
borderWidth: 0
},
});
}
$.each(names_likes, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
seriesOptions_likes[i] = {
name: name,
data: data
};
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter_likes += 1;
if (seriesCounter_likes === names_likes.length) {
createLikesChart();
}
});
});
});
(function (H) {
H.Series.prototype.point = {}; // The active point
H.Chart.prototype.callbacks.push(function (chart) {
$(chart.container).bind('mousemove', function () {
var legendOptions = chart.legend.options,
hoverPoints = chart.hoverPoints,
total = 0;
if (!hoverPoints && chart.hoverPoint) {
hoverPoints = [chart.hoverPoint];
}
if (hoverPoints) {
var total = 0,
ctr = 0;
H.each(hoverPoints, function (point) {
point.series.point = point;
total += point.y;
});
H.each(chart.legend.allItems, function (item) {
item.legendItem.attr({
text: legendOptions.labelFormat ?
H.format(legendOptions.labelFormat, item) :
legendOptions.labelFormatter.call(item)
});
});
chart.legend.render();
chart.title.update({ text: 'Total Results: ' + total.toFixed(2) });
}
});
});
// Hide the tooltip but allow the crosshair
H.Tooltip.prototype.defaultFormatter = function () { return false; };
}(Highcharts));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/stock/modules/exporting.js"></script>
<div id="container_likes" style="height: 400px; min-width: 600px"></div>
I have following example: http://jsfiddle.net/ondra15/7mb8K/1/.
I want to have together two example (multiple axes and zooming). Example zooming do not work correct - if I indicate some data in chart for zooming - do not work. Nothing happens.
Original Zooming (correct) solution works here http://www.flotcharts.org/flot/examples/zooming/index.html
Can any some idea for my code? Thanks
code
Hi I managed to get it working using code from an example I found here. I will update your jsfiddle too:
<script type="text/javascript">
var datasets = { ... };
data = null;
function plotByChoice(doAll) {
data = [];
if (doAll != null) {
$.each(datasets, function (key, val) {
data.push(val);
});
}
else {
$('#legend .legendCB').each(
function () {
if (this.checked) {
data.push(datasets[this.id]);
}
else {
data.push({ label: this.id, data: [] })
}
}
);
}
$.plot($("#placeholder"), data, {
yaxes: [{ min: 0 }, { position: "right" }],
xaxis: { tickDecimals: 0 },
legend: {
container: legend,
labelFormatter: function (label, series) {
var cb = '<input class="legendCB" type="checkbox" ';
if (series.data.length > 0) {
cb += 'checked="true" ';
}
cb += 'id="' + label + '" /> ';
cb += label;
return cb;
}
}, selection: { mode: "x" }
});
$('#legend').find("input").click(function () { setTimeout(plotByChoice, 100); });
}
plotByChoice(true);
// Create the overview plot
var overview = $.plot("#overview", data, {
legend: {
show: false
},
series: {
lines: {
show: true,
lineWidth: 1
},
shadowSize: 0
},
xaxis: {
ticks: 4
},
yaxes: [{ min: 0 }, { position: "right" }],
grid: {
color: "#999"
},
selection: {
mode: "x"
}
});
$("#placeholder").bind("plotselected", function (event, ranges) {
var options = {
series: {
lines: { show: true },
points: { show: true }
},
legend: { noColumns: 2 },
xaxis: { tickDecimals: 0 },
yaxis: { min: 0 },
selection: { mode: "x" }
};
var placeholder = $("#placeholder");
placeholder.bind("plotselected", function (event, ranges) {
$("#selection").text(ranges.xaxis.from.toFixed(1) + " to " + ranges.xaxis.to.toFixed(1));
plot = $.plot(placeholder, data,
$.extend(true, {}, options, {
xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
}));
});
// don't fire event on the overview to prevent eternal loop
overview.setSelection(ranges, true);
});
$("#overview").bind("plotselected", function (event, ranges) {
plot.setSelection(ranges);
});
</script>