I have implemented an algorithm for dividing overlapping existing ranges into a list of date / number ranges.
The algorithm is working but I was wondering if you can avoid the last loop of the algorithm.
It's possible?
Input Data
0-100(red)
90-150(green)
90-150(blue)
140-300(yellow)
170-240(black)
350-530(orange)
50-500(silver)
50-60(pink)
Output Data
0-49(red)
50-60(red,silver,pink)
61-89(red,silver)
90-100(red,green,blue,silver)
101-139(green,blue,silver)
140-150(green,blue,yellow,silver)
151-169(yellow,silver)
170-240(yellow,black,silver)
241-300(yellow,silver)
301-349(silver)
350-500(orange,silver)
501-530(orange)
Javascript Code:
function splitRanges(original_intervals) {
for (var to = [], from = [], n, i = original_intervals.length; i--;) {
if (to.indexOf(n = original_intervals[i].to) < 0)
to.push(n);
if (from.indexOf(n = original_intervals[i].from) < 0)
from.push(n);
}
to.sort(function(a, b) {
return a - b;
});
from.sort(function(a, b) {
return a - b;
});
var intervals = [];
while (to.length) {
var sFrom = from.shift();
var sTo = 0;
if (from.length == 0) {
sTo = (from.push((n = to.shift()) + 1), n);
} else {
if (from[0] > to[0]) {
while (to[0] < from[0]) {
from.unshift(to[0] + 1);
to.shift();
}
sTo = from[0] - 1;
} else {
sTo = from[0] - 1;
}
}
intervals.push({
from: sFrom,
to: sTo,
colors: []
});
}
/***********************Loop that i want remove*/
intervals.forEach(function(item, index) {
original_intervals.forEach(function(item1, index1) {
if ((item.from >= item1.from && item.from <= item1.to) || (item.to >= item1.from && item.to <= item1.to))
item.colors.push(item1.color);
});
});
return intervals;
}
var r1 = [{
id: 1,
from: 0,
to: 100,
color:'red'
}, {
id: 2,
from: 90,
to: 150,
color:'green'
}, {
id: 3,
from: 90,
to: 150,
color:'blue'
}, {
id: 4,
from: 140,
to: 300,
color:'yellow'
}, {
id: 5,
from: 170,
to: 240,
color:'black'
}, {
id: 6,
from: 350,
to: 530,
color:'orange'
}, {
id: 7,
from: 50,
to: 500,
color:'silver'
}
, {
id: 8,
from: 50,
to: 60,
color:'pink'
}
];
console.log(splitRanges(r1));
You need some iterations, at least the one with getting all range points, and then generate an array out of it and take the subset of colors for each small interval.
var data = [{ from: 0, to: 100, color: 'red' }, { from: 90, to: 150, color: 'green' }, { from: 90, to: 150, color: 'blue' }, { from: 140, to: 300, color: 'yellow' }, { from: 170, to: 240, color: 'black' }, { from: 350, to: 530, color: 'orange' }, { from: 50, to: 500, color: 'silver' }, { from: 50, to: 60, color: 'pink' }],
ranges = new Set,
parts,
result;
data.forEach(({ from, to }) => (ranges.add(from), ranges.add(to)));
parts = [...ranges].sort((a, b) => a - b);
result = parts.slice(1).map(function (a, i, aa) {
var from = i ? aa[i - 1] : parts[0],
to = a,
colors = data.filter(d => d.from <= from && to <= d.to).map(({ color }) => color);
return { from, to, colors };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Related
i have the next problem with Highcharts. This is a new Highchart for an other site.
See here: https://imgur.com/a/VQQLU
The arrow show to -3 Megawatts but the value at the bottom shows another value. At the first pageload the values are identical, but there comes all 5 seconds new values. And they are not updated at the bottom.
Edit: The tolltip will be updated correctly.
My code:
$(function () {
$.getJSON('jsonlive.php', function(chartData) {
var ADatum; var Eheit; var AktL; var MinL; var MaxL; var chartValue; var i;
ADatum = chartData[0].AktDatum;
Eheit = chartData[0].Einheit;
AktL = chartData[0].AktuelleLeistung;
MinL = chartData[0].MinLeistung;
MaxL = chartData[0].MaxLeistung;
var tMin = (MinL*-1); var tMax = MaxL;
var ttt = new Array();
if (tMin < tMax) { chartValue = tMax; } else if (tMin > tMax) { chartValue = tMin; } // Ermitteln ob neg/pos Zahl die größere ist.
ttt[0] = (chartValue*-1); // Skala mit Zahlen beschriften
for (i = 1; i < chartValue; i++) { ttt[i] = (i*-1); }
var tz = ttt.length ;
for (i = 0; i < chartValue; i++) { ttt[(tz+i)] = i; }
ttt[ttt.length] = chartValue;
var gaugeOptions = {
chart:{ events: {
load: function () { setInterval(function () {
$.getJSON('jsonlive.php', function(chartData) {
ADatum = chartData[0].AktDatum;
AktL = chartData[0].AktuelleLeistung;
var point = $('#inhalt').highcharts().series[0].setData([AktL], true);
});}, 5000);}
}, type: 'gauge' },
title: null,
pane: {
center: ['50%', '85%'], size: '140%', startAngle: -90, endAngle: 90,
background: [{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [[0, '#00fb00'],[1, '#003f00']]},
borderWidth: 2,
outerRadius: '109%',
innerRadius: '102%', shape: 'arc' }]
},
series: [{
data: [AktL],
dataLabels: { borderWidth: 0,align: 'center',x: 0,y: 110,
format: '<div style="text-align:center;font-size:24px;color:black">'+AktL+' ' +Eheit+'</span></div>'
}
}],
tooltip: {
formatter: function () { return 'Datum: <b>' + (new Date(ADatum).toLocaleString("de-DE", { timeZone: 'UTC' })) +
'</b> <br>Leistung <b>' + AktL + ' ' + Eheit + '</b>';}, enabled: true },
yAxis: {lineWidth: 10, minorTickInterval: null, tickPixelInterval: 100, tickWidth: 5, title: { y: -250 }, labels: { y: 2 }}
};
// Anzeige
$('#inhalt').highcharts(Highcharts.merge(gaugeOptions, {
yAxis: {
min: (chartValue*-1),max: chartValue,tickPositions: ttt,tickColor: '#666',minorTickColor: '#666',
plotBands: [{ // optionaler Bereich, zeigt von 0-1 grün, 1 bis hälfte maximum gelb, und hälfte max bis max rot
from: 0, to: -1, color: '#55BF3B' }, { // green
from: -1, to: ((chartValue*-1)/2), color: '#DDDF0D' }, { // yellow
from: ((chartValue*-1)/2),to: (chartValue*-1),color: '#DF5353' }, { // red
from: 0,to: 1,color: '#55BF3B' }, { // green
from: 1,to: (chartValue/2),color: '#DDDF0D' }, { // yellow
from: (chartValue/2),to: chartValue,color: '#DF5353' }],// red
title: { style: { color: 'black', fontWeight: 'bold', fontSize: '24px' }, text: 'Leistung in '+Eheit },
labels: { formatter: function () { return this.value; }}},
credits: { enabled: false } // Link auf highcharts rechts unten an/aus
}));
});
});
</script>
The problem here is that you use a hard-coded value (AktL) in your dataLabels.format. In your example format is just a string that's used all the time.
Use {point.y} to have the label updated on every setData():
series: [{
data: [val],
dataLabels: {
// format: val // WONT WORK
format: '{point.y}'
}
}],
Live demo: http://jsfiddle.net/BlackLabel/v28q5n09/
The following JavaScript code works, but is there a more compact way to write it using n parameter, to "eval" y1axis, y2axis, y3axis field names?
switch (n) {
case 1:
markingsY = [
{ color: colorErr, y1axis: { from: maxVal } },
{ color: colorErr, y1axis: { to: minVal } },
{ color: "#00f", lineWidth: 1, y1axis: { from: minVal, to: minVal } },
{ color: "#00f", lineWidth: 1, y1axis: { from: maxVal, to: maxVal } }
];
break;
case 2:
markingsY = [
{ color: colorErr, y2axis: { from: maxVal } },
{ color: colorErr, y2axis: { to: minVal } },
{ color: "#00f", lineWidth: 1, y2axis: { from: minVal, to: minVal } },
{ color: "#00f", lineWidth: 1, y2axis: { from: maxVal, to: maxVal } }
];
break;
case 3:
markingsY = [
{ color: colorErr, y3axis: { from: maxVal } },
{ color: colorErr, y3axis: { to: minVal } },
{ color: "#00f", lineWidth: 1, y3axis: { from: minVal, to: minVal } },
{ color: "#00f", lineWidth: 1, y3axis: { from: maxVal, to: maxVal } }
];
break;
default:
break;
}
Edit: Misread the question, Sorry!
You could use a static key instead of the one you need to change, then change it dynamically, so:
markingsY = [
{ color: colorErr, yaxis: { from: maxVal } },
{ color: colorErr, yaxis: { to: minVal } },
{ color: "#00f", lineWidth: 1, yaxis: { from: minVal, to: minVal } },
{ color: "#00f", lineWidth: 1, yaxis: { from: maxVal, to: maxVal } }
];
markingsY.forEach(function(item){
item["y"+n+"axis"]=item.yaxis;//copy it to its new key
delete item.yaxis;//remove the old one
});
Try:
var n = 10
var collections = [];
for(var i = 0; i < 10; i++){
var json1 = {}
var row = [];
json1['color'] = '#000000';
json1['y'+i+'axis'] = {from: 1234};
row.push(json1);
collections.push(row);
}
console.log(collections);
You will have the collection of 10 markingsY arrays.
each markingsY array has (my code) 1 JSON
collections = [
[{color:#0000000, y0axis:{form:1234}}],
[{color:#0000000, y1axis:{form:1234}}]
.....];
Then your switch(n) can be replaced:
collections[n]
https://jsfiddle.net/kingychiu/ow1e3h4x/
I've made this bar chart http://imageshack.com/a/img901/7186/cnOfhh.png, and the code for it is:
//compute & mark average color
for (var i = 0; i < zdata.length; i++) {
if (zdata[i].TargetTime == null) zdata[i].TargetTime = 0;
if (zdata[i].TimePlayed == null) zdata[i].TimePlayed = 0;
if (zdata[i].TargetTime >= zdata[i].TimePlayed) {
zdata[i]['Color'] = 'green';
} else {
zdata[i]['Color'] = 'red';
}
}
//localsitelist
var element = {
rt: 'D',
Id: rid,
courselist: clist,
selcourseId: selCid,
selcourse: selCname,
cartlist: wData,
selSiteId: lsid,
selsite: sitename,
dataList: zdata
}; //, carts: _mVM.availableCarts()}; //
//if rid exists, is update, else its new
var found = -1;
for (var k = 0; k < document.pvm.rapArray().length; k++) {
if (document.pvm.rapArray()[k].Id() == rid) {
document.pvm.rapArray()[k].update(element);
//build chart data
var values = []; //, series = Math.floor(Math.random() * 6) + 6;
for (var i = 0; i < zdata.length; i++) {
values[i] = {
data: [
[zdata[i].HoleSequence, zdata[i].TimePlayed]
],
color: zdata[i].Color
};
}
//var data = [{ data: [[0, 1]], color: "red" }, { data: [[1, 2]], color: "yellow" },{ data: [[2, 3]], color: "green" }];
BarChart('#ChartD-Overview' + rid, values);
found = 1;
break;
}
}
if (found == -1) {
var rvm = new panelViewModel(element);
document.pvm.rapArray.push(rvm);
//build chart data
var values = []; //, series = Math.floor(Math.random() * 6) + 6;
for (var i = 0; i < zdata.length; i++) {
values[i] = {
data: [
[zdata[i].HoleSequence, zdata[i].TimePlayed]
],
color: zdata[i].Color
};
}
BarChart('#ChartD-Overview' + rvm.Id(), values);
}
and the BarChart function:
function BarChart(id, data) {
$.plot(id, data, {
series: {
bars: {
show: true,
barWidth: 0.6,
align: "center"
}
},
stack: true,
xaxis: {
mode: "categories",
tickLength: 0
}
});
}
The problem is that I can't manage to get something like this https://imageshack.us/i/expGGpOkp, the little line should be zdata[i].TargetTime. I've tried something using stacked bar chart idea but the result was way different... What am I doing wrong? Can anyone help me with a suggestion to start with to get the same bar chart like in the last image?
Here is something like your second picture using another bar dataseries where the start and end of the bars are the same thereby reducing them to lines, you don't need to stack any of the bars just give them the right y-values (fiddle):
$(function () {
var dataBarsRed = {
data: [
[2, 3], ],
label: 'Bars in Red',
color: 'red'
};
var dataBarsGreen = {
data: [
[1, 2],
[3, 1],
[4, 3]
],
label: 'Bars in Green',
color: 'green'
};
var dataLines = {
data: [
[1, 3, 3],
[2, 3.5, 3.5],
[3, 1.5, 1.5],
[4, 2.5, 2.5]
],
label: 'Lines',
color: 'navy',
bars: {
barWidth: 0.5
}
};
var plot = $.plot("#placeholder", [dataBarsRed, dataBarsGreen, dataLines], {
points: {
show: false
},
lines: {
show: false
},
bars: {
show: true,
align: 'center',
barWidth: 0.6
},
grid: {
hoverable: true,
autoHighlight: true
},
xaxis: {
min: 0,
max: 5
},
yaxis: {
min: 0,
max: 5
}
});
});
I'm creating an angular directive for realtime chart displaying here is the code which returns everything including link:function() { } inside directive.
Here is the code for static directive which works perfectly
angular.module('app').directive("flotChartRealtime", [
function() {
return {
restrict: "AE",
link: function(scope, ele) {
var realTimedata,
realTimedata2,
totalPoints,
getSeriesObj,
getRandomData,
getRandomData2,
updateInterval,
plot,
update;
return realTimedata = [],
realTimedata2 = [],
totalPoints = 100,
getSeriesObj = function() {
return [
{
data: getRandomData(),
lines: {
show: true,
lineWidth: 1,
fill: true,
fillColor: {
colors: [
{
opacity: 0
}, {
opacity: 1
}
]
},
steps: false
},
shadowSize: 0
}, {
data: getRandomData2(),
lines: {
lineWidth: 0,
fill: true,
fillColor: {
colors: [
{
opacity: .5
}, {
opacity: 1
}
]
},
steps: false
},
shadowSize: 0
}
];
},
getRandomData = function() {
if (realTimedata.length > 0)
realTimedata = realTimedata.slice(1);
// Do a random walk
//console.log(realTimedata);
while (realTimedata.length < totalPoints) {
var prev = realTimedata.length > 0 ? realTimedata[realTimedata.length - 1] : 50,
y = prev + Math.random() * 10 - 5;
if (y < 0) {
y = 0;
} else if (y > 100) {
y = 100;
}
realTimedata.push(y);
}
// Zip the generated y values with the x values
var res = [];
for (var i = 0; i < realTimedata.length; ++i) {
res.push([i, realTimedata[i]]);
}
return res;
},
getRandomData2 = function() {
if (realTimedata2.length > 0)
realTimedata2 = realTimedata2.slice(1);
// Do a random walk
while (realTimedata2.length < totalPoints) {
var prev = realTimedata2.length > 0 ? realTimedata[realTimedata2.length] : 50,
y = prev - 25;
if (y < 0) {
y = 0;
} else if (y > 100) {
y = 100;
}
realTimedata2.push(y);
}
var res = [];
for (var i = 0; i < realTimedata2.length; ++i) {
res.push([i, realTimedata2[i]]);
}
return res;
},
// Set up the control widget
updateInterval = 500,
plot = $.plot(ele[0], getSeriesObj(), {
yaxis: {
color: '#f3f3f3',
min: 0,
max: 100,
tickFormatter: function(val, axis) {
return "";
}
},
xaxis: {
color: '#f3f3f3',
min: 0,
max: 100,
tickFormatter: function(val, axis) {
return "";
}
},
grid: {
hoverable: true,
clickable: false,
borderWidth: 0,
aboveData: false
},
colors: ['#eee', scope.settings.color.themeprimary],
}),
update = function() {
plot.setData(getSeriesObj()); // getting .data filled here perfectly
plot.draw();
setTimeout(update, updateInterval);
},
update();
}
};
}
]);
My code with HTTP request which doesn't work
getSeriesObj = function () {
return [{
data: getRandomData(function(res) {
console.log(res) // getting array result here from http call but not returning to data:
return res;
}),
lines: {
show: true,
lineWidth: 1,
fill: true,
fillColor: {
colors: [{
opacity: 0
}, {
opacity: 1
}]
},
steps: false
},
shadowSize: 0
}, {
data: getRandomData2(function (res) {
return res;
}),
lines: {
lineWidth: 0,
fill: true,
fillColor: {
colors: [{
opacity: .5
}, {
opacity: 1
}]
},
steps: false
},
shadowSize: 0
}];
},
getRandomData = function (callback) {
var authToken = window.localStorage.getItem('token');
var url = $rootScope.apiPath + 'Elasticsearch/countget?token=' + authToken;
var res = [];
$http.get(url).then(function (result) {
realTimedata = result.data;
if (realTimedata.length > 0)
//result = [10,22,33,11,32,88,77,66,21,90,92,98,99.9,88.8,76,66,56,88];
for (var i = 0; i < realTimedata.length; ++i) {
var y = realTimedata[i] + Math.random() * 10 - 5;
if (y < 0) {
y = 0;
} else if (y > 100) {
y = 100;
}
res.push([i, y]);
}
callback(res);
});
},
Problem:
When i try following code:
update = function () {
//console.log(getSeriesObj());
plot.setData(getSeriesObj()); // .data property gets undefined
plot.draw();
setTimeout(update, updateInterval);
}
function getSeriesObj() return array of object which return data property to undefined what can be the reason?
how can i resolve this?
Note: This is far different from this question.
When do this
data: getRandomData(function(res) {
return res;
});
You assign the rValue of getRandomData to data.
As stated in your post, getRandomData now has no return statement, so return undefined.
The main problem here is that you expect that plot.setData(getSeriesObj()); work synchronously
Steps
get the data to fill plot
set the data to the plot
draw it
update the values again
Now as the http request work async you cannot expect to retrieve a value from getSeriesObj(). You have to think that getSeriesObj work now async so you can only work with callback that will be fired when the resource is ready to be used
so the update method become
update = function () {
var updateTime = +new Date;
getSeriesObj(function(res){ // execute that stuff when ready
plot.setData(res);
plot.draw();
setTimeout(update, Math.max(10, updateInterval - (+new Date - updateTime)) );
});
}
and getSeriesObj
getSeriesObj = function (callback) {
getRandomData(function(res) {
getRandomData2(function(res2){
var data = [{
data: res,
lines: {
show: true,
lineWidth: 1,
fill: true,
fillColor: {
colors: [{
opacity: 0
}, {
opacity: 1
}]
},
steps: false
},
shadowSize: 0
}, {
data: res2,
lines: {
lineWidth: 0,
fill: true,
fillColor: {
colors: [{
opacity: .5
}, {
opacity: 1
}]
},
steps: false
},
shadowSize: 0
}];
callback(data); // now the ressource obj is now ready to be used
});
});
}
I've made this bar chart http://imageshack.com/a/img901/7186/cnOfhh.png, and the code for it is:
//compute & mark average color
for (var i = 0; i < zdata.length; i++) {
if (zdata[i].TargetTime == null) zdata[i].TargetTime = 0;
if (zdata[i].TimePlayed == null) zdata[i].TimePlayed = 0;
if (zdata[i].TargetTime >= zdata[i].TimePlayed) {
zdata[i]['Color'] = 'green';
} else {
zdata[i]['Color'] = 'red';
}
}
//localsitelist
var element = {
rt: 'D',
Id: rid,
courselist: clist,
selcourseId: selCid,
selcourse: selCname,
cartlist: wData,
selSiteId: lsid,
selsite: sitename,
dataList: zdata
}; //, carts: _mVM.availableCarts()}; //
//if rid exists, is update, else its new
var found = -1;
for (var k = 0; k < document.pvm.rapArray().length; k++) {
if (document.pvm.rapArray()[k].Id() == rid) {
document.pvm.rapArray()[k].update(element);
//build chart data
var values = []; //, series = Math.floor(Math.random() * 6) + 6;
for (var i = 0; i < zdata.length; i++) {
values[i] = {
data: [
[zdata[i].HoleSequence, zdata[i].TimePlayed]
],
color: zdata[i].Color
};
}
//var data = [{ data: [[0, 1]], color: "red" }, { data: [[1, 2]], color: "yellow" },{ data: [[2, 3]], color: "green" }];
BarChart('#ChartD-Overview' + rid, values);
found = 1;
break;
}
}
if (found == -1) {
var rvm = new panelViewModel(element);
document.pvm.rapArray.push(rvm);
//build chart data
var values = []; //, series = Math.floor(Math.random() * 6) + 6;
for (var i = 0; i < zdata.length; i++) {
values[i] = {
data: [
[zdata[i].HoleSequence, zdata[i].TimePlayed]
],
color: zdata[i].Color
};
}
BarChart('#ChartD-Overview' + rvm.Id(), values);
}
and the BarChart function:
function BarChart(id, data) {
$.plot(id, data, {
series: {
bars: {
show: true,
barWidth: 0.6,
align: "center"
}
},
stack: true,
xaxis: {
mode: "categories",
tickLength: 0
}
});
}
The problem is that I can't manage to get something like this https://imageshack.us/i/expGGpOkp, the little line should be zdata[i].TargetTime. I've tried something using stacked bar chart idea but the result was way different... What am I doing wrong? Can anyone help me with a suggestion to start with to get the same bar chart like in the last image?
Here is something like your second picture using another bar dataseries where the start and end of the bars are the same thereby reducing them to lines, you don't need to stack any of the bars just give them the right y-values (fiddle):
$(function () {
var dataBarsRed = {
data: [
[2, 3], ],
label: 'Bars in Red',
color: 'red'
};
var dataBarsGreen = {
data: [
[1, 2],
[3, 1],
[4, 3]
],
label: 'Bars in Green',
color: 'green'
};
var dataLines = {
data: [
[1, 3, 3],
[2, 3.5, 3.5],
[3, 1.5, 1.5],
[4, 2.5, 2.5]
],
label: 'Lines',
color: 'navy',
bars: {
barWidth: 0.5
}
};
var plot = $.plot("#placeholder", [dataBarsRed, dataBarsGreen, dataLines], {
points: {
show: false
},
lines: {
show: false
},
bars: {
show: true,
align: 'center',
barWidth: 0.6
},
grid: {
hoverable: true,
autoHighlight: true
},
xaxis: {
min: 0,
max: 5
},
yaxis: {
min: 0,
max: 5
}
});
});