Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

coconut-graph

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

coconut-graph - npm Package Compare versions

Comparing version 1.0.5 to 1.0.6

src/template.js

13

package.json
{
"name": "coconut-graph",
"version": "1.0.5",
"version": "1.0.6",
"description": "Graph lib using d3 ",

@@ -8,4 +8,4 @@ "main": "index.js",

"test": "npm run bundle && npm run lint && npm run testsuite",
"bundle": "browserify index.js -o bundle.js",
"watchify": "watchify index.js -d -o bundle.js",
"bundle": "browserify index.js --debug | exorcist bundle.js.map > bundle.js",
"watchify": "watchify index.js -o 'exorcist bundle.js.map > bundle.js' -d",
"lint": "eslint index.js src/ test/",

@@ -28,3 +28,4 @@ "testsuite": "mocha-phantomjs test/index.html",

"d3-legend": "^1.0.0",
"d3-tip": "^0.6.7"
"d3-tip": "^0.6.7",
"extend": "^2.0.1"
},

@@ -36,7 +37,9 @@ "devDependencies": {

"eslint": "^0.21.2",
"exorcist": "^0.4.0",
"mocha": "^2.2.5",
"mocha-phantomjs": "^3.5.3",
"mversion": "^1.10.0",
"phantomjs": "^1.9.17"
"phantomjs": "^1.9.17",
"source-map-support": "^0.3.1"
}
}
# coconut-graph
Quick and dirty reusable graph with d3.
Quick and dirty reusable timeseries graphs with d3, developed to visualize usage.
Currently supports line, bar, scatter.
Depends heavily on json structure used in the coconut wepapp:
Depends heavily on JSON structure used in the coconut wepapp:
```json
{
"meta": {
"period": "day",
"urls": {
"next": "<url to get json for the next day>",
"previous": "<url to get json for previous day>"
},
"readable_interval": "15 minuten"
},
"data": {
"keys": ["timestamp", "amount"],
"extents": ["2015-05-29T00:00:00", "2015-05-29T23:59:59"],
"values": [
["2015-05-29T14:00:00", 50],
["2015-05-29T14:15:00", 0],
["2015-05-29T14:30:00", 5],
["2015-05-29T15:00:00", 6]
],
"slices": 96
}
"meta": {
"period": "day",
"urls": {
"next": "<url to get json for the next day>",
"previous": "<url to get json for previous day>"
},
"readable_interval": "15 minuten"
},
"data": {
"keys": ["timestamp", "amount"],
"extents": ["2015-05-29T00:00:00", "2015-05-29T23:59:59"],
"values": [
["2015-05-29T14:00:00", 50],
["2015-05-29T14:15:00", 0],
["2015-05-29T14:30:00", 5],
["2015-05-29T15:00:00", 6]
],
"slices": 96
}
}

@@ -39,3 +39,3 @@ ```

graphs: [{
container: 'graph-flow',
container: 'container',
plot: { type: 'bar', key: 'amount', label: 'verbruik [l]'}

@@ -42,0 +42,0 @@ }]

@@ -12,3 +12,3 @@ /*!

L.extend = L.Util.extend;
var extend = require('extend');
L.setOptions = L.Util.setOptions;

@@ -57,3 +57,3 @@

if (props.statics) {
L.extend(NewClass, props.statics);
extend(NewClass, props.statics);
delete props.statics;

@@ -64,3 +64,3 @@ }

if (props.includes) {
L.Util.extend.apply(null, [proto].concat(props.includes));
extend.apply(null, [proto].concat(props.includes));
delete props.includes;

@@ -71,7 +71,7 @@ }

if (props.options && proto.options) {
props.options = L.extend({}, proto.options, props.options);
props.options = extend({}, proto.options, props.options);
}
// mix given properties into the prototype
L.extend(proto, props);
extend(proto, props);

@@ -106,3 +106,3 @@ proto._initHooks = [];

L.Class.include = function (props) {
L.extend(this.prototype, props);
extend(this.prototype, props);
};

@@ -112,3 +112,3 @@

L.Class.mergeOptions = function (options) {
L.extend(this.prototype.options, options);
extend(this.prototype.options, options);
};

@@ -115,0 +115,0 @@

var Class = require('./class.js');
var extend = require('extend');
var Util = require('./util.js');
var d3 = require('d3');
var d3legend = require('d3-legend')(d3);
var timeAxis = require('./time-xaxis.js');
var xaxis = require('./time-xaxis.js');
var yaxis = require('./yaxis.js');

@@ -20,2 +21,3 @@ var Graph = Class.extend({

axes: {
x: {},
y: {orient: 'left'}

@@ -33,4 +35,6 @@ }

this.container = document.getElementById(options.container);
// enable reuse of container;
d3.select(this.container).selectAll('svg').remove();
options.axes = Util.extend({}, this.options.axes, options.axes || {});
options.axes = extend({}, this.options.axes, options.axes || {});

@@ -45,3 +49,3 @@ if (options.plot) {

if (!('key' in plot)) {
throw 'key must be suplied.';
throw 'key must be supplied.';
}

@@ -65,3 +69,4 @@ if (!('axis' in plot)) {

if (!Graph.onResizeCounter) { Graph.onResizeCounter = 0; }
d3.select(window).on('resize.' + (Graph.onResizeCounter++), function () {
this._resizeEvent = 'resize.' + (Graph.onResizeCounter++);
d3.select(window).on(this._resizeEvent, function () {
self.onResize();

@@ -71,2 +76,7 @@ });

remove: function () {
d3.select(window).on(this._resizeEvent, null);
d3.select(this.container).selectAll('svg').remove();
},
data_key: function (name) {

@@ -91,4 +101,4 @@ return this.data.keys.indexOf(name);

eachAxis: function (callback) {
for (var name in this.options.axes) {
callback.call(this, name, this.options.axes[name]);
for (var name in this.axes) {
callback.call(this, name, this.axes[name]);
}

@@ -103,56 +113,12 @@ },

_initAxes: function () {
var scale = this.scale = {
x: d3.time.scale().range([0, this.width()])
};
var axes = this.axes = {};
var axes = this.axes = {
xticks: d3.svg.axis().scale(this.scale.x).orient('bottom').tickFormat(''),
xlabels: d3.svg.axis().scale(this.scale.x).orient('bottom').tickSize(0).tickPadding(7)
};
for (var name in this.options.axes) {
var options = extend({name: name}, this.options.axes[name]);
this.eachAxis(function (name, axis) {
scale[name] = d3.scale.linear().rangeRound([this.height(), 0]);
axes[name] = d3.svg.axis().scale(scale[name]).orient(axis.orient || 'left');
axes[name] = (name === 'x' ? xaxis : yaxis)(this, options);
axes[name].render();
}
},
if ('tickFormat' in axis) {
if (typeof axis.tickFormat === 'string') {
axes[name].tickFormat(d3.format(axis.tickFormat));
} else {
axes[name].tickFormat(axis.tickFormat);
}
}
});
var svg = this.svg;
// initialize the (double) x-axis
var height = this.height();
[
{axis: this.axes.xticks},
{axis: this.axes.xlabels, class: 'labels'}
].forEach(function(axis) {
svg.append('g').attr({
class: 'x axis ' + (axis.class || ''),
transform: 'translate(0, ' + height + ')'
});
});
// initialize the y axes
this.eachAxis(function (name, axis) {
var el = svg.append('g').attr('class', 'axis ' + name);
var text = el.append('text')
.attr({
class: 'axislabel',
transform: 'rotate(-90)'
}).text(axis.label || this.options.ylabel);
if (axis.orient && axis.orient === 'right') {
text.attr('dy', '-.5em');
el.attr('translate( ' + (this.width()) + ', 0)');
} else {
text.attr({y: 6, dy: '.71em'});
}
});
},
_initContainer: function () {

@@ -173,27 +139,4 @@ var container = d3.select(this.container);

_updateAxes: function () {
var svg = this.svg;
var width = this.width();
// x axis
this.scale.x.range([0, width]);
this.scale.x.domain(this.extents());
svg.selectAll('.x.axis').call(this.axes.xticks);
svg.selectAll('.x.axis.labels').call(this.axes.xlabels);
timeAxis[this.meta.period](this.axes, this.width());
svg.select('.x.axis').call(this.axes.xticks);
svg.select('.x.axis.labels').call(this.axes.xlabels);
var axes = this.axes;
this.eachAxis(function (name, axis) {
if (axis.ticks) {
axes[name].ticks(axis.ticks);
}
// right oriented y axes
var ax = svg.selectAll('.axis.' + name).call(axes[name]);
if (axis.orient && axis.orient === 'right') {
ax.attr('transform', 'translate(' + width + ', 0)');
}
axis.update();
});

@@ -204,9 +147,3 @@ },

render: function (callback) {
this._updateAxes();
var xscale = this.scale.x;
this.plots = {};
// var yaxis_extents = {};
this.eachPlot(function(plot) {

@@ -223,3 +160,2 @@ plot.data_key = this.data_key(plot.key);

d3.select(this.container).style('display', 'block');
this._updateAxes();
}

@@ -232,9 +168,11 @@

}
// update the extent for this scale.
this.scale[plot.axis].domain(extent).nice();
this.axes[plot.axis].domain(extent);
});
this.svg.selectAll('.axis.' + plot.axis).call(this.axes[plot.axis]);
this._updateAxes();
// Do the actual plotting
this.plots[plot.key] = this['plot_' + plot.type](xscale, this.scale[plot.axis], plot, this);
var xscale = this.axes.x.scale;
this.eachPlot(function (plot) {
var plot_fn = this['plot_' + plot.type];
plot.fn = plot_fn(xscale, this.axes[plot.axis].scale, plot, this);
});

@@ -273,7 +211,3 @@

this.eachPlot(function (plot) {
if (plot.type === 'bar') {
this.svg.selectAll('.bar.' + plot.key).call(this.plots[plot.key]);
} else {
this.svg.selectAll('.plot.' + plot.key).call(this.plots[plot.key]);
}
this.svg.selectAll('.plot.series-' + plot.key).call(plot.fn);
});

@@ -280,0 +214,0 @@ },

@@ -14,3 +14,3 @@ var d3 = require('d3');

}
return amount + ' / ' + readable_interval;
return amount + (readable_interval ? ' / ' + readable_interval : '');
});

@@ -21,14 +21,12 @@ };

var key = plot.data_key;
var yaxis = graph.axes.y;
var max = d3.max(graph.data.values, function(d) { return d[key]; }) * 1.1;
y.domain([0, max]).nice();
// TODO: make sure it uses the right axis.
if (max > 1000) {
graph.axes.y.tickFormat(function (d) { return Math.round(d / 100) / 10; });
graph.svg.selectAll('.y.axis > text').text('verbruik [m³]');
} else {
graph.axes.y.tickFormat(function (d) { return d; });
graph.svg.selectAll('.y.axis > text').text('verbruik [l]');
}
graph.svg.selectAll('.axis.y').call(graph.axes.y);
// scale axis if above 1000l
// TODO: move out of plot_bar.
yaxis.options.tickFormat = function (d) { return (max > 1000) ? (Math.round(d / 100) / 10) : d; };
yaxis.options.label = 'verbruik ' + ((max > 1000) ? '[m³]' : '[l]');
yaxis.update();

@@ -53,7 +51,7 @@ graph.svg.call(tip(key, graph.meta.readable_interval));

var sel = graph.plotContainer.selectAll('.bar.' + plot.key).data(graph.data.values);
var sel = graph.plotContainer.selectAll('.plot.series-' + plot.key).data(graph.data.values);
sel.exit().remove();
sel.enter().append('rect')
.attr('class', 'bar ' + plot.key)
.attr('class', 'plot plot-bar series-' + plot.key)
.on({mouseover: tip.show, mouseout: tip.hide});

@@ -60,0 +58,0 @@

@@ -7,21 +7,24 @@ var d3 = require('d3');

var line = function (s) {
s.attr('d', d3.svg.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[plot.data_key]); })
);
var line = d3.svg.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[plot.data_key]); });
var line_plot = function (sel) {
sel.attr('d', line);
};
graph.plotContainer.selectAll('.line.' + plot.key)
.data([graph.data.values])
.enter()
.append('path')
.attr('class', 'plot line ' + plot.key)
.attr('data-legend', plot.label || 'series ' + unnamed_series++);
var selection = graph.plotContainer
.selectAll('.series-' + plot.key)
.data([graph.data.values]);
graph.svg.selectAll('.line.' + plot.key)
.transition().duration(200)
.call(line);
selection.enter().append('path')
.attr({
class: 'plot plot-line series-' + plot.key,
'data-legend': plot.label || 'series ' + unnamed_series++
})
.call(line_plot);
return line;
selection.exit().remove();
return line_plot;
};

@@ -8,3 +8,3 @@ module.exports = function(x, y, plot, graph) {

};
var sel = graph.plotContainer.selectAll('circle.' + plot.key).data(graph.data.values);
var sel = graph.plotContainer.selectAll('circle.series-' + plot.key).data(graph.data.values);
sel.exit().remove();

@@ -14,3 +14,3 @@ sel.enter()

.attr({
class: 'plot ' + plot.key,
class: 'plot series-' + plot.key,
r: 2

@@ -17,0 +17,0 @@ }).call(scatter);

@@ -0,6 +1,7 @@

var extend = require('extend');
var d3 = require('d3');
require('./d3.nl_nl.js')(d3);
module.exports = {
day: function (axes, width) {
var formatters = {
day: function (xticks, xlabels, width) {
var interval = width > 800 ? 1 :

@@ -10,8 +11,8 @@ width > 550 ? 2 :

axes.xticks.ticks(d3.time.hours, interval);
axes.xlabels.ticks(d3.time.hours, interval)
xticks.ticks(d3.time.hours, interval);
xlabels.ticks(d3.time.hours, interval)
.tickFormat(d3.locale.nl_NL.timeFormat('%H:%M'));
},
week: function (axes, width) {
axes.xticks.ticks(d3.time.day);
week: function (xticks, xlabels, width) {
xticks.ticks(d3.time.day);

@@ -22,3 +23,3 @@ var tickFormat = (width > 700 ? '%A' : '%a') + ' %-d ';

axes.xlabels
xlabels
.ticks(d3.time.hour, 12)

@@ -31,7 +32,7 @@ .tickFormat(function (d) {

},
month: function (axes, width) {
month: function (xticks, xlabels, width) {
var wide = width > 550;
axes.xticks.ticks(d3.time.day, wide ? 1 : 4);
axes.xlabels.ticks(d3.time.hour, wide ? 12 : 24)
xticks.ticks(d3.time.day, wide ? 1 : 4);
xlabels.ticks(d3.time.hour, wide ? 12 : 24)
.tickFormat(function (d) {

@@ -47,7 +48,7 @@ if (wide) {

},
year: function (axes, width) {
axes.xticks.ticks(d3.time.month);
year: function (xticks, xlabels, width) {
xticks.ticks(d3.time.month);
var tickFormat = (width > 550 ? '%B' : '%b');
axes.xlabels
xlabels
.ticks(d3.time.day, 15)

@@ -61,1 +62,42 @@ .tickFormat(function (d) {

};
module.exports = function (graph, options) {
options = extend({}, options);
var name = options.name;
var scale = d3.time.scale().range([0, graph.width()]);
var xticks = d3.svg.axis().scale(scale).orient('bottom').tickFormat('');
var xlabels = d3.svg.axis().scale(scale).orient('bottom').tickSize(0).tickPadding(7);
var Axis = function () {};
Axis.name = name;
Axis.scale = scale;
Axis.render = function () {
var height = graph.height();
[
{axis: xticks},
{axis: xlabels, class: 'labels'}
].forEach(function(axis) {
graph.svg.append('g').attr({
class: 'x axis ' + (axis.class || ''),
transform: 'translate(0, ' + height + ')'
});
});
};
Axis.update = function (extent) {
var svg = graph.svg;
scale.range([0, graph.width()]);
scale.domain(extent || graph.extents());
formatters[graph.meta.period](xticks, xlabels, graph.width());
svg.selectAll('.x.axis').call(xticks);
svg.selectAll('.x.axis.labels').call(xlabels);
};
return Axis;
};
var util = {
extend: function (dest) {
var sources = Array.prototype.slice.call(arguments, 1),
i, j, len, src;
extend: require('extend'),
template: require('./template.js'),
for (j = 0, len = sources.length; j < len; j++) {
src = sources[j] || {};
for (i in src) {
if (src.hasOwnProperty(i)) {
dest[i] = src[i];
}
}
}
return dest;
},
// create an object from a given prototype

@@ -24,13 +13,3 @@ create: Object.create || function () {

},
template: function (str, data) {
return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
var value = data[key];
if (value === undefined) {
throw new Error('No value provided for variable ' + str);
} else if (typeof value === 'function') {
value = value(data);
}
return value;
});
},
setOptions: function (obj, options) {

@@ -37,0 +16,0 @@ obj.options = util.extend({}, obj.options, options);

/* globals
describe:true it:true chai:true
describe:true
it:true
chai:true
d3: true
Graph:true

@@ -16,11 +19,11 @@ */

'data': {
'keys': ['timestamp', 'amount', 'test'],
'keys': ['timestamp', 'amount', 'test', 'foo'],
'extents': ['2015-05-29T00:00:00', '2015-05-29T23:59:59'],
'values': [
['2015-05-29T00:00:00', 0, 1],
['2015-05-29T14:00:00', 50, 2],
['2015-05-29T14:15:00', 0, 3],
['2015-05-29T14:30:00', 5, 4],
['2015-05-29T14:45:00', 15, 5],
['2015-05-29T15:00:00', 6, 5]
['2015-05-29T00:00:00', 0, 1, 7],
['2015-05-29T14:00:00', 10, 2, 5],
['2015-05-29T14:15:00', 0, 3, 7],
['2015-05-29T14:30:00', 5, 4, 7],
['2015-05-29T14:45:00', 4, 5, 7],
['2015-05-29T15:00:00', 6, 5, 7]
],

@@ -31,2 +34,12 @@ 'slices': 96

(function disableD3animations() {
// add a duration function to the selection prototype
d3.selection.prototype.duration = function() { return this; };
// hack the transition function of d3's select API
d3.selection.prototype.transition = function() { return this; };
})();
var container = 'container';
var c = document.getElementById(container);
describe('coconut-graph', function () {

@@ -41,3 +54,3 @@ chai.should();

{
container: 'container1',
container: container,
className: 'extra',

@@ -50,11 +63,10 @@ axes: {y: {includeZero: true}},

});
var container = document.getElementById('container1');
it('adds classnames to graph container', function () {
container.className.should.contain('chart');
container.className.should.contain('extra');
c.className.should.contain('chart');
c.className.should.contain('extra');
});
it('preserves existing classnames on containers', function () {
container.className.should.contain('container');
c.className.should.contain('container');
});

@@ -70,4 +82,7 @@

it('Can be removed', function () {
loader.graphs[container].remove();
});
it('should create multiple plots in one chart', function () {
var container = 'container2';
loader = new Graph.Loader(Graph.util.extend({}, data), {

@@ -77,9 +92,11 @@ graphs: [

container: container,
margin_right: 40,
axes: {
y: {includeZero: true},
y1: {orient: 'right'}
y1: {includeZero: true, orient: 'right'}
},
plots: [
{key: 'amount', axis: 'y', label: 'verbruik [l]', type: 'bar'},
{key: 'test', axis: 'y1', label: 'test', type: 'line'}
{key: 'test', axis: 'y1', label: 'test', type: 'line'},
{key: 'foo', axis: 'y1', label: 'foo', type: 'scatter'}
]

@@ -91,11 +108,21 @@ }

var graph = loader.graphs[container];
graph.plots.should.have.keys('amount', 'test');
// var graph = loader.graphs[container];
// graph.plots.should.have.keys('amount', 'test', 'foo');
});
});
});
describe('bar graph', function () {
it('it should draw 6 bars', function () {
d3.select(c).selectAll('rect')[0].length.should.equal(6);
});
it('4/6 have non-zero height', function () {
var nonzero = d3.select(c).selectAll('rect');
nonzero = nonzero.filter(function () {
return d3.select(this).attr('height') > 0;
});
nonzero[0].length.should.equal(4);
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc