cxviz-timeseries
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -0,1 +1,13 @@ | ||
2015-06-03, Version 1.0.1 | ||
========================= | ||
* adjustments to fix clipped axis labels (seanbrookes) | ||
* fix chart legend (seanbrookes) | ||
* updates to support Arc integration (seanbrookes) | ||
* adustments for Arc integration (Setogit) | ||
2015-04-01, Version 1.0.0 | ||
@@ -2,0 +14,0 @@ ========================= |
317
index.js
'use strict'; | ||
var d3 = require('d3') | ||
var EventEmitter = require('events').EventEmitter | ||
var inherits = require('util').inherits | ||
var Schema = require('./lib/schema') | ||
var format = require('cxviz-format') | ||
var Draw = require('./lib/draw') | ||
var d3 = require('d3'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var inherits = require('util').inherits; | ||
var Schema = require('./lib/schema'); | ||
var format = require('cxviz-format'); | ||
var Draw = require('./lib/draw'); | ||
@@ -47,4 +47,4 @@ module.exports = Line; | ||
this.parent = d3.select(parent); | ||
this.options = options | ||
this.schema = new Schema(options) | ||
this.options = options; | ||
this.schema = new Schema(options); | ||
this.reset(options); | ||
@@ -59,3 +59,3 @@ EventEmitter.call(this); | ||
options = options || {}; | ||
svgElement.remove() | ||
svgElement.remove(); | ||
@@ -68,9 +68,11 @@ this.raw = []; | ||
this.type = 'line'; | ||
this.parentNode = this.parent.node() | ||
this.parentNode = this.parent.node(); | ||
this.width = (this.parentNode && this.parentNode.offsetWidth) || 1000; | ||
this.height = Math.round(this.width / DEFAULT_RATIO); | ||
this.margin = {top: 20, right: 80, bottom: 30, left: 80}; // TODO better defaults? | ||
this.height = options.height || Math.round(this.width / DEFAULT_RATIO); | ||
this.selectedTime = options.selectedTime || 0; | ||
this.margin = options.margin || {top: 20, right: 80, bottom: 30, left: 80}; // TODO better defaults? | ||
this.showXAxis = true; | ||
this.showYAxis = true; | ||
this.isHoverLineEnabled = true; | ||
this.xGridTicks = 0; | ||
@@ -80,3 +82,3 @@ this.yGridTicks = 1; | ||
this.bgfill = 'none' | ||
this.bgfill = 'none'; | ||
@@ -95,3 +97,3 @@ this.formatter = options.formatter; | ||
this.color = (options.color && options.color.moduleColor) || d3.scale.category10() | ||
this.color = (options.color && options.color.moduleColor) || d3.scale.category10(); | ||
@@ -110,5 +112,5 @@ // TODO y gridlines based on data extent? | ||
this.y = d3.scale.linear() | ||
.range([this.innerHeight, 0]) | ||
.range([this.innerHeight, 0]); | ||
this.y1 = d3.scale.linear() | ||
.range([this.innerHeight, 0]) | ||
.range([this.innerHeight, 0]); | ||
@@ -126,4 +128,4 @@ this.xAxis = d3.svg.axis() | ||
this.yAxis = this._yAxis('y') | ||
this.y1Axis = this._yAxis('y1') | ||
this.yAxis = this._yAxis('y'); | ||
this.y1Axis = this._yAxis('y1'); | ||
@@ -147,3 +149,3 @@ this.yGrid = d3.svg.axis() | ||
.y0(function(d){ return self[self.schema.y(d)](d.val.min)}) | ||
.y1(function(d){ return self[self.schema.y(d)](d.val.max)}) | ||
.y1(function(d){ return self[self.schema.y(d)](d.val.max)}); | ||
@@ -165,3 +167,3 @@ this.svg = this.parent.append('svg') | ||
} | ||
}; | ||
@@ -171,3 +173,3 @@ | ||
Line.prototype.draw = function (data) { | ||
var self = this | ||
var self = this; | ||
@@ -183,5 +185,5 @@ if (!data || data.length === 0) { | ||
//TODO--make resize more dynamic | ||
var tempwidth = (this.parentNode && this.parentNode.offsetWidth) || 1000; | ||
var tempwidth = (this.parentNode && this.parentNode.offsetWidth) || 4000; | ||
if( tempwidth != this.width ){ | ||
this.reset(this.options) | ||
this.reset(this.options); | ||
} | ||
@@ -196,12 +198,12 @@ this.raw = data; | ||
if (series.length > MAX_SERIES){ | ||
return | ||
return; | ||
} | ||
if (key === '_t' || key === 'date'){ | ||
return | ||
return; | ||
} | ||
if( key === '__data'){ | ||
return | ||
return; | ||
} | ||
if (series.indexOf(key) < 0 && record[key] != null ){ | ||
series.push(key) | ||
series.push(key); | ||
} | ||
@@ -213,3 +215,3 @@ }); | ||
if (series.length > MAX_SERIES) { | ||
console.log('Refusing to plot line graph with %s series', series.length) | ||
console.log('Refusing to plot line graph with %s series', series.length); | ||
return new Error('Too many series detected'); | ||
@@ -252,30 +254,30 @@ } | ||
.attr('class', 'anomalies') | ||
.selectAll('path').data(data.filter(function(d, i){ return !!d.__data.lm_a })) | ||
.selectAll('path').data(data.filter(function(d, i){ return !!d.__data.lm_a })); | ||
anomalies.enter().append('path') | ||
.on('mouseover', anomalyHover) | ||
.on('click', anomalyClick) | ||
.on('click', anomalyClick); | ||
anomalies | ||
.attr('fill', function(d){ return d.__data.lm_a == 1 ? 'red' : '#ff7518' }) | ||
.attr('stroke', 'none') | ||
.attr('d', triangle) | ||
anomalies.exit().remove() | ||
.attr('d', triangle); | ||
anomalies.exit().remove(); | ||
// Triangles | ||
function triangle(d) { | ||
var x = self.x(d.date) | ||
var y = self.innerHeight | ||
var top = 'M ' + x + ' ' + (y + 3) | ||
var bottomLeft = 'L ' + (x - 5) + ' ' + (y + 13) | ||
var bottomRight = 'L ' + (x + 5) + ' ' + (y + 13) | ||
return top + ' ' + bottomLeft + ' ' + bottomRight + ' Z' | ||
var x = self.x(d.date); | ||
var y = self.innerHeight; | ||
var top = 'M ' + x + ' ' + (y + 3); | ||
var bottomLeft = 'L ' + (x - 5) + ' ' + (y + 13); | ||
var bottomRight = 'L ' + (x + 5) + ' ' + (y + 13); | ||
return top + ' ' + bottomLeft + ' ' + bottomRight + ' Z'; | ||
} | ||
function anomalyHover(d) { | ||
self.hoverAt(d._t) | ||
self.hoverAt(d._t); | ||
} | ||
function anomalyClick(d) { | ||
self.emit('click', d.__data) | ||
self.emit('click', d.__data); | ||
} | ||
} | ||
}; | ||
@@ -327,3 +329,3 @@ // Redraw the data with different options | ||
if( this.color.moduleColor ) { | ||
this.color = this.color.moduleColor | ||
this.color = this.color.moduleColor; | ||
} | ||
@@ -346,3 +348,3 @@ | ||
this._draw(); | ||
} | ||
}; | ||
@@ -360,11 +362,11 @@ // New incoming data, transition in/transition out old | ||
// TODO consider transitioning these out. | ||
this.graph.selectAll('.axis').remove() | ||
this.graph.selectAll('.grid').remove() | ||
this.graph.selectAll('.timeline').remove() | ||
this.graph.selectAll('#gradient').remove() | ||
this.graph.selectAll('.hover-line').remove() | ||
this.graph.selectAll('.select-line').remove() | ||
this.graph.selectAll('.overlay').remove() | ||
this.svg.selectAll('.x-legend').remove() | ||
this.svg.selectAll('.y-legend').remove() | ||
this.graph.selectAll('.axis').remove(); | ||
this.graph.selectAll('.grid').remove(); | ||
this.graph.selectAll('.timeline').remove(); | ||
this.graph.selectAll('#gradient').remove(); | ||
this.graph.selectAll('.hover-line').remove(); | ||
this.graph.selectAll('.select-line').remove(); | ||
this.graph.selectAll('.overlay').remove(); | ||
this.svg.selectAll('.x-legend').remove(); | ||
this.svg.selectAll('.y-legend').remove(); | ||
@@ -385,3 +387,3 @@ this.svg.selectAll('.underlay') | ||
.attr('class', 'y axis') | ||
.call(this.yAxis) | ||
.call(this.yAxis); | ||
} | ||
@@ -392,3 +394,3 @@ if( true /*this.showY1Axis*/){ | ||
.attr('transform', 'translate(' + (this.innerWidth) + ', 0)') | ||
.call(this.y1Axis) | ||
.call(this.y1Axis); | ||
} | ||
@@ -439,16 +441,16 @@ | ||
this.svg.append('g') | ||
.attr('class', 'y-legend') | ||
.attr('transform', 'translate(8, 15)') | ||
.attr('class', 'y-legend') | ||
.attr('transform', 'translate(8, 15)') | ||
.selectAll('g') | ||
.data(this.series) | ||
.enter() | ||
.append('text') | ||
.attr('class', 'legend-text') | ||
.text(function (d) { return d; }) | ||
.attr('x', function (d, i) { | ||
var offset = nextX; | ||
nextX += (d.length + 1) * 8; | ||
return offset; | ||
}) | ||
.style('fill', function (d) { return self.color(d) }); | ||
.data(this.series) | ||
.enter() | ||
.append('text') | ||
.attr('class', 'legend-text') | ||
.text(function (d) { return d; }) | ||
.attr('x', function (d, i) { | ||
var offset = nextX; | ||
nextX += (d.length + 1) * 8; | ||
return offset; | ||
}) | ||
.style('fill', function (d) { return self.color(d) }); | ||
} | ||
@@ -465,4 +467,15 @@ | ||
} | ||
var ts = self.selectedTime; | ||
if (ts) { | ||
var rec = self.getRecordAt(ts); | ||
var x = self.x(rec.date) | 0; | ||
self.selectionX = x; | ||
self.selectLine | ||
.attr('x1', x).attr('x2', x) | ||
.attr('style', 'display: visible') ; | ||
} | ||
}; | ||
Line.prototype._yAxis = function (type) { | ||
@@ -477,3 +490,3 @@ var axis = d3.svg.axis() | ||
else if (this.options.format && this.options.format[type] ) { | ||
axis.tickFormat(format[this.options.format[type]]) | ||
axis.tickFormat(format[this.options.format[type]]); | ||
} else { | ||
@@ -496,3 +509,3 @@ axis.tickFormat(format.mb); | ||
return axis; | ||
} | ||
}; | ||
@@ -502,8 +515,8 @@ // Draw the loaded data as a line graph | ||
var self = this; | ||
var draw = Draw(self) | ||
var draw = Draw(self); | ||
self.graph.selectAll('.timeline') | ||
.data(self.timeseries) | ||
.data(self.timeseries) | ||
.enter().append('g') | ||
.attr('class', 'timeline') | ||
.call(draw) | ||
.attr('class', 'timeline') | ||
.call(draw); | ||
@@ -521,4 +534,4 @@ if (self.interactive) { | ||
self.selectLineGroup = self.graph.append('g') | ||
.attr('class', 'select-line') | ||
.attr('style', self.selectionX ? 'display: visible' : 'display: none') | ||
.attr('class', 'select-line'); | ||
//.attr('style', self.selectionX ? 'display: visible' : 'display: none') | ||
@@ -535,14 +548,17 @@ self.selectLine = self.selectLineGroup.append('line') | ||
.on('mousemove', getHoverX) | ||
.on('click', handleClick) | ||
.on('click', handleClick); | ||
} | ||
function handleClick(){ | ||
var coords = d3.mouse(this) | ||
var ts = self.x.invert(coords[0]).getTime() | ||
var rec = self.getRecordAt(ts) | ||
var ts = self.x.invert(coords[0]).getTime(); | ||
var rec = self.getRecordAt(ts); | ||
var x = self.x(rec.date) | 0; | ||
self.selectionX = x | ||
self.selectionX = x; | ||
self.selectLine | ||
.attr('x1', x).attr('x2', x) | ||
.attr('style', 'display: visible') | ||
self.emit('click', rec.__data) | ||
.attr('x1', x) | ||
.attr('x2', x) | ||
.attr('stroke', function (d, i) { return rec.__data.lm_a ? 'red' : 'black' }) | ||
.attr('stroke-width', 1) | ||
.attr('style', 'display: visible'); | ||
self.emit('click', rec.__data); | ||
} | ||
@@ -556,9 +572,17 @@ | ||
} | ||
} | ||
}; | ||
Line.prototype.clearSelection = function clearSelection(){ | ||
delete this.selectionX | ||
} | ||
delete this.selectionX; | ||
}; | ||
Line.prototype.setSelection = function setSelection(timestamp){ | ||
var ts = timestamp; | ||
var rec = this.getRecordAt(ts); | ||
var x = this.x(rec.date) | 0; | ||
this.selectionX = x; | ||
this.hoverAt(ts); | ||
}; | ||
Line.prototype.getRecordAt = function getRecordAt(timestamp){ | ||
@@ -571,11 +595,15 @@ var self = this; | ||
var right = self.raw[entry]; | ||
if (!left || !right) return right || left | ||
if (!left || !right) { | ||
return right || left; | ||
} | ||
record = (timestamp - left._t > right._t - timestamp) ? right : left; | ||
} | ||
return record | ||
} | ||
// TODO emit/listen for highlight events when other graphs are highlighting | ||
Line.prototype.hoverAt = function (timestamp) { | ||
return record; | ||
}; | ||
Line.prototype.disableHoverLine = function() { | ||
var self = this; | ||
self.isHoverLineEnabled = false; | ||
}; | ||
Line.prototype.setSelection = function(timestamp) { | ||
var self = this; | ||
@@ -590,4 +618,40 @@ var record = self.getRecordAt(timestamp) | ||
.attr('stroke', function (d, i) { return record.__data.lm_a ? 'red' : 'black' }) | ||
.attr('stroke-width', 1); | ||
self.selectionX = x; | ||
self.selectLine | ||
.attr('x1', x) | ||
.attr('x2', x) | ||
.attr('stroke', function (d, i) { return record.__data.lm_a ? 'red' : 'black' }) | ||
.attr('stroke-width', 1) | ||
.attr('y1', 0).attr('y2', self.innerHeight) | ||
.attr('style', 'display: visible'); | ||
self.disableHoverLine(); | ||
}; | ||
// TODO emit/listen for highlight events when other graphs are highlighting | ||
Line.prototype.hoverAt = function (timestamp) { | ||
var self = this; | ||
var record = self.getRecordAt(timestamp); | ||
var x = self.x(record.date) | 0; | ||
if (this.isHoverLineEnabled) { | ||
self.hoverLine | ||
.attr('x1', x) | ||
.attr('x2', x) | ||
.attr('stroke', function (d, i) { | ||
return record.__data.lm_a ? 'red' : 'black'; | ||
}) | ||
.attr('stroke-width', 1); | ||
} | ||
if (this.isHoverLineEnabled) { | ||
self.hoverLine | ||
.attr('x1', x) | ||
.attr('x2', x) | ||
.attr('stroke', function (d, i) { | ||
return record.__data.lm_a ? 'red' : 'black'; | ||
}) | ||
.attr('stroke-width', 1); | ||
} | ||
var formattedDate = self.formatDate(record.date); | ||
@@ -597,42 +661,45 @@ | ||
var legendValues = self.series.slice(0).sort(function(a, b) { | ||
if (record[a] == null){ | ||
return b | ||
} | ||
if (record[b] == null) { | ||
return a | ||
} | ||
return record[b] - record[a] | ||
}).map(function (key) { | ||
var value | ||
var f = self.schema.formatByKey(key) | ||
if( (record[key] !== undefined) && record[key] !== null) { | ||
if( typeof record[key] == 'object' ){ | ||
value = [f(record[key].min), f(record[key].max)].join('/') | ||
if (record[a] == null){ | ||
return b | ||
} | ||
if (record[b] == null) { | ||
return a | ||
} | ||
return record[b] - record[a] | ||
}) | ||
.map(function (key) { | ||
var value; | ||
var f = self.schema.formatByKey(key); | ||
if( (record[key] !== undefined) && record[key] !== null) { | ||
if( typeof record[key] == 'object' ){ | ||
value = [f(record[key].min), f(record[key].max)].join('/'); | ||
} else { | ||
value = f(record[key]); | ||
} | ||
} else { | ||
value = f(record[key]) | ||
value = 'N/A'; | ||
} | ||
} else { | ||
value = 'N/A' | ||
} | ||
colors.push(self.color(key)) | ||
return key + ': ' + value | ||
}); | ||
colors.push(self.color(key)); | ||
return key + ': ' + value; | ||
}); | ||
// TODO better handling when it runs off the end | ||
self.svg.selectAll('.y-legend') | ||
.attr('transform', 'translate(' + (formattedDate.length + 2) * 8 + ', 15)') | ||
var nextX = 0 | ||
.attr('transform', 'translate(' + (formattedDate.length + 2) * 8 + ', 15)'); | ||
var nextX = 0; | ||
self.svg.selectAll('.y-legend > .legend-text') | ||
.text(function (d, i) { | ||
return legendValues[i] | ||
}) | ||
.attr('x', function (d, i) { | ||
var offset = nextX; | ||
nextX += (legendValues[i].length + 1) * 8; | ||
return offset; | ||
}) | ||
.style('fill', function (d, i) { return colors[i] }) | ||
.text(function (d, i) { | ||
return legendValues[i]; | ||
}) | ||
.attr('x', function (d, i) { | ||
var offset = nextX; | ||
nextX += (legendValues[i].length + 1) * 8; | ||
return offset; | ||
}) | ||
.style('fill', function (d, i) { | ||
return colors[i] | ||
}); | ||
self.xLegend.select('text').text(formattedDate) | ||
} | ||
self.xLegend.select('text').text(formattedDate); | ||
}; |
{ | ||
"name": "cxviz-timeseries", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Strongloop TimeSeries Graph Visualization", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
7235091
30291