
js.models.charting.Model.js Maven / Gradle / Ivy
define(function(require){
require("jquery.flot.crosshair");
require("jquery.flot.resize");
require("jquery.flot.time");
require("jquery.flot.fillbetween");
var View = require("text!./View.html"),
$ = require("jquery"),
MV = require("mv"),
Plot = require("jquery.flot"),//https://github.com/flot/flot/blob/master/API.md
Markings = require("./Markings"),
RangeSelectorModel = require("./rangeselector/Model"),
StatModel = require("./stat/Model"),
ContextModel = require("./context/Model");
return function(cfg){
var self = this;
/*
* Submodels
*/
this.stat = new StatModel();
/**
* Date range selector
*/
this.rangeselector = new RangeSelectorModel();
/**
* Context (stack) model
*/
this.context = new ContextModel({
setFromDate: function(date){
//update date range
self.rangeselector.from.date(date);
},
setToDate: function(date){
//update date range
self.rangeselector.to.date(date);
}
});
/**
* Default config
*/
cfg = MV.extend({
url: "",
plotConfig: {
grid: {
hoverable: true,
clickable: true,
markings: Markings
},
crosshair: {
mode: "x"
},
xaxis: {
mode: "time",
//timeformat: "%Y/%m/%d"
//timezone: "",
},
legend: {
show: true,
labelFormatter: function(label, series){
if (series.computed)
//hide computed plots in the legend
return null;
if (series.unit)
//Add units if any
return series.label + " ["+series.unit+"]";
else
//Plain label
return series.label;
},
position: "sw"
}
},
hover: function(event, pos, item){},
select: function(event, pos, item){},
/**
* Retrieve metadata
* format:
* [{
* fields: [{
* label: "",
* unit: ""
* }],
* name: ""
* },{
* ...
* }]
*/
getMetadata: function(callback){
$.getJSON(cfg.url + "api/charting", function(data){
callback(data.sources);
});
},
/**
* Retrieve actual data
* format:
* [{
* label: "",
* unit: "",
* data: [ {time: 0, value: 1, min: -1, max: 2}, {}, {} ],
* },{
* ...
* }]
*/
getData: function(sourceName, from, to, maxItems, callback){
$.getJSON(cfg.url + "api/charting/" + sourceName + "/" + from + "/" + to + "?&maxItems=" + maxItems, callback);
}
}, cfg);
/**
* Enhances the metadata with ui observables
*/
var enhanceMetadata = function(metadata){
metadata.forEach(function(source){
source.fields.forEach(function(field){
field.enabled = MV.observable(false);
field.toggle = function(){
field.enabled( !field.enabled() );
};
});
});
}
this.html = View;
/**
* Loading icon in update button
*/
this.loading = MV.observable(false);
/**
* Available data sources
*/
this.sources = MV.observableArray();
/**
* Plot target element
*/
this.plotEl = undefined;
/**
* flot reference
*/
this.plot = undefined;
var hoverBinding = function(event, pos, item){
if (item){
var x = item.datapoint[0],
y = item.datapoint[1],
series = item.series;
self.context.hover(x, y, series);
cfg.hover(x, y, series);
}
};
var clickBinding = function(event, pos, item){
if (item){
var x = item.datapoint[0],
y = item.datapoint[1],
series = item.series;
self.context.select(x, y, series);
cfg.select(x, y, series);
}
};
/**
* Creates the plot with given data
*/
var createPlot = function(data){
if (self.plot){
//unsubscribe from events
self.plotEl.unbind("plothover", hoverBinding);
self.plotEl.unbind("plotclick", clickBinding);
self.plot.shutdown();
self.plotEl.html("");
}
self.plot = Plot(self.plotEl, data, cfg.plotConfig);
//Subscribe to events
self.plotEl.bind("plothover", hoverBinding);
self.plotEl.bind("plotclick", clickBinding);
};
this.afterRender = function($el){
//Retrieve metadata
cfg.getMetadata(function(md){
//Enhance
enhanceMetadata(md);
//Push to local sources
md.forEach(function(source){
self.sources.push(source);
});
});
//Plot element
self.plotEl = $el.find(".plot");
//Empty plot
createPlot([]);
};
this.update = function(){
self.loading(true);
var stations = [],
//done count
count = 0,
items = 0,
results = [];
var processResults = function(){
self.loading(false);
var axisMap = {},
axisIndex = 2,
colorIndex = 0,
computedPlots = [];
//Filter out disabled fields
results = results.filter(function(plot){
var found = false;
self.sources().forEach(function(source){
source.fields.forEach(function(field){
//Check starting string
if (field.label == plot.label && source.name == plot.source)
found = field.enabled();
});
});
return found;
});
//Preprocess plots
results.forEach(function(plot){
//Set yaxis for same units
if (plot.unit == undefined)
plot.yaxis = 1; //default to 1
else {
if (axisMap[plot.unit] == undefined)
axisMap[plot.unit] = axisIndex++;
plot.yaxis = axisMap[plot.unit];
}
//Add color and increment
plot.color = colorIndex++;
//Prefix source id
plot.label = plot.sourceId + " " + plot.label;
//Assign id
plot.id = plot.label;
//line stub
plot.lines = {
show: true,
lineWidth: 1
};
if (plot.data.some(function(e){ return e.max != undefined; })){
//Max plot
computedPlots.push({
color: plot.color,
label: plot.label + " Max",
unit: plot.unit,
yaxis: plot.yaxis,
id: plot.label + "-max",
data: plot.data.map(function(e){ return [e.time, e.max]; }),
//fill to average plot
fillBetween: plot.id,
lines: {
show: true,
lineWidth: 0,
fill: 0.4
},
computed: {
type: "max"
}
});
}
if (plot.data.some(function(e){ return e.min != undefined; })){
//Min plot
computedPlots.push({
color: plot.color,
label: plot.label + " Min",
yaxis: plot.yaxis,
unit: plot.unit,
id: plot.label + "-min",
data: plot.data.map(function(e){ return [e.time, e.min]; }),
lines: {
show: true,
lineWidth: 0
},
computed: {
type: "min"
}
});
//Fill from average to min
plot.fillBetween = plot.label + "-min";
plot.lines.fill = 0.4;
}
//Rewrite plot data
plot.data = plot.data.map(function(e){ return [e.time, e.value]; });
});
//Append computed plots
computedPlots.forEach(function(cp){ results.push(cp); });
//Update stats
self.stat.update(results);
createPlot(results);
};
//map station/source list
self.sources().forEach(function(source){
if (source.fields.some(function(f){ return f.enabled(); }))
stations.push(source.name);
});
if (stations.length == 0)
self.loading(false);
stations.forEach(function(station){
//sourceName, from, to, maxItems, callback
cfg.getData(station, self.rangeselector.from.date().getTime(), self.rangeselector.to.date().getTime(), 1000, function(data){
data.forEach(function(plot){
//Assign sourceId
plot.source = station;
//Add to results
results.push(plot);
});
//Increment and check source count
if (++count == stations.length)
//All sources retrieved
processResults();
});
});
};
};
});
© 2015 - 2025 Weber Informatics LLC | Privacy Policy