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

event-drops

Package Overview
Dependencies
Maintainers
2
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

event-drops - npm Package Compare versions

Comparing version 0.1.1 to 0.2.0

.babelrc

281

lib/eventDrops.js

@@ -1,248 +0,65 @@

"use strict";
/* global require, module */
import d3 from 'd3';
var configurable = require('./util/configurable');
var eventLine = require('./eventLine');
var delimiter = require('./delimiter');
import configurable from 'configurable.js';
import defaultConfig from './config';
import drawer from './drawer';
import zoom from './zoom';
module.exports = function (d3) {
function eventDrops(config = {}) {
const finalConfiguration = {...defaultConfig, ...config};
var defaultConfig = {
start: new Date(0),
end: new Date(),
minScale: 0,
maxScale: Infinity,
width: 1000,
margin: {
top: 60,
left: 200,
bottom: 40,
right: 50
},
locale: null,
axisFormat: null,
tickFormat: [
[".%L", function(d) { return d.getMilliseconds(); }],
[":%S", function(d) { return d.getSeconds(); }],
["%I:%M", function(d) { return d.getMinutes(); }],
["%I %p", function(d) { return d.getHours(); }],
["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
["%b %d", function(d) { return d.getDate() != 1; }],
["%B", function(d) { return d.getMonth(); }],
["%Y", function() { return true; }]
],
eventHover: null,
eventZoom: null,
hasDelimiter: true,
hasTopAxis: true,
hasBottomAxis: function (data) {
return data.length >= 10;
},
eventLineColor: 'black',
eventColor: null
};
const yScale = (data) => {
const scale = d3.scale.ordinal();
return function eventDrops(config) {
var xScale = d3.time.scale();
var yScale = d3.scale.ordinal();
config = config || {};
for (var key in defaultConfig) {
config[key] = config[key] || defaultConfig[key];
}
return scale
.domain(data.map((d) => d.name))
.range(data.map((d, i) => i * 40));
};
const xScale = (width, timeBounds) => {
return d3.time.scale()
.range([0, width])
.domain(timeBounds);
};
function eventDropGraph(selection) {
selection.each(function (data) {
var zoom = d3.behavior.zoom().center(null).scaleExtent([config.minScale, config.maxScale]).on("zoom", updateZoom);
selection.each(function selector(data) {
d3.select(this).select('.event-drops-chart').remove();
zoom.on("zoomend", zoomEnd);
const height = data.length * 40;
const dimensions = {
width: finalConfiguration.width - finalConfiguration.margin.right - finalConfiguration.margin.left,
height,
outer_height: height + finalConfiguration.margin.top + finalConfiguration.margin.bottom,
};
var graphWidth = config.width - config.margin.right - config.margin.left;
var graphHeight = data.length * 40;
var height = graphHeight + config.margin.top + config.margin.bottom;
const scales = {
x: xScale(dimensions.width, [finalConfiguration.start, finalConfiguration.end]),
y: yScale(data),
};
d3.select(this).select('svg').remove();
const svg = d3.select(this).append('svg')
.classed('event-drops-chart', true)
.attr({
width: dimensions.width,
height: dimensions.outer_height,
});
var svg = d3.select(this)
.append('svg')
.attr('width', config.width)
.attr('height', height)
;
const draw = drawer(svg, dimensions, scales, finalConfiguration).bind(selection);
draw(data);
var graph = svg.append('g')
.attr('transform', 'translate(0, 25)');
var yDomain = [];
var yRange = [];
data.forEach(function (event, index) {
yDomain.push(event.name);
yRange.push(index * 40);
if (finalConfiguration.zoomable) {
zoom(d3.select(this), dimensions, scales, finalConfiguration, data, draw);
}
});
}
yScale.domain(yDomain).range(yRange);
configurable(eventDropGraph, finalConfiguration);
var yAxisEl = graph.append('g')
.classed('y-axis', true)
.attr('transform', 'translate(0, 60)');
return eventDropGraph;
}
var yTick = yAxisEl.append('g').selectAll('g').data(yDomain);
d3.chart = d3.chart || {};
d3.chart.eventDrops = eventDrops;
yTick.enter()
.append('g')
.attr('transform', function(d) {
return 'translate(0, ' + yScale(d) + ')';
})
.append('line')
.classed('y-tick', true)
.attr('x1', config.margin.left)
.attr('x2', config.margin.left + graphWidth);
yTick.exit().remove();
var curx, cury;
var zoomRect = svg
.append('rect')
.call(zoom)
.classed('zoom', true)
.attr('width', graphWidth)
.attr('height', height )
.attr('transform', 'translate(' + config.margin.left + ', 35)')
;
if (typeof config.eventHover === 'function') {
zoomRect.on('mousemove', function(d, e) {
var event = d3.event;
if (curx == event.clientX && cury == event.clientY) return;
curx = event.clientX;
cury = event.clientY;
zoomRect.attr('display', 'none');
var el = document.elementFromPoint(d3.event.clientX, d3.event.clientY);
zoomRect.attr('display', 'block');
if (el.tagName !== 'circle') return;
config.eventHover(el);
});
}
xScale.range([0, graphWidth]).domain([config.start, config.end]);
zoom.x(xScale);
function updateZoom() {
if (d3.event.sourceEvent.toString() === '[object MouseEvent]') {
zoom.translate([d3.event.translate[0], 0]);
}
if (d3.event.sourceEvent.toString() === '[object WheelEvent]') {
zoom.scale(d3.event.scale);
}
redraw();
}
function redrawDelimiter() {
svg.select('.delimiter').remove();
var delimiterEl = svg
.append('g')
.classed('delimiter', true)
.attr('width', graphWidth)
.attr('height', 10)
.attr('transform', 'translate(' + config.margin.left + ', ' + (config.margin.top - 45) + ')')
.call(delimiter({
xScale: xScale,
dateFormat: config.locale ? config.locale.timeFormat("%d %B %Y") : d3.time.format("%d %B %Y")
}))
;
}
function zoomEnd() {
if (config.eventZoom) {
config.eventZoom(xScale);
}
if (config.hasDelimiter) {
redrawDelimiter();
}
}
function drawXAxis(where) {
// copy config.tickFormat because d3 format.multi edit its given tickFormat data
var tickFormatData = [];
config.tickFormat.forEach(function (item) {
var tick = item.slice(0);
tickFormatData.push(tick);
});
var tickFormat = config.locale ? config.locale.timeFormat.multi(tickFormatData) : d3.time.format.multi(tickFormatData);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient(where)
.tickFormat(tickFormat)
;
if (typeof config.axisFormat === 'function') {
config.axisFormat(xAxis);
}
var y = (where == 'bottom' ? parseInt(graphHeight) : 0) + config.margin.top - 40;
graph.select('.x-axis.' + where).remove();
var xAxisEl = graph
.append('g')
.classed('x-axis', true)
.classed(where, true)
.attr('transform', 'translate(' + config.margin.left + ', ' + y + ')')
.call(xAxis)
;
}
function redraw() {
var hasTopAxis = typeof config.hasTopAxis === 'function' ? config.hasTopAxis(data) : config.hasTopAxis;
if (hasTopAxis) {
drawXAxis('top');
}
var hasBottomAxis = typeof config.hasBottomAxis === 'function' ? config.hasBottomAxis(data) : config.hasBottomAxis;
if (hasBottomAxis) {
drawXAxis('bottom');
}
zoom.size([config.width, height]);
graph.select('.graph-body').remove();
var graphBody = graph
.append('g')
.classed('graph-body', true)
.attr('transform', 'translate(' + config.margin.left + ', ' + (config.margin.top - 15) + ')');
var lines = graphBody.selectAll('g').data(data);
lines.enter()
.append('g')
.classed('line', true)
.attr('transform', function(d) {
return 'translate(0,' + yScale(d.name) + ')';
})
.style('fill', config.eventLineColor)
.call(eventLine({ xScale: xScale, eventColor: config.eventColor }))
;
lines.exit().remove();
}
redraw();
if (config.hasDelimiter) {
redrawDelimiter();
}
if (config.eventZoom) {
config.eventZoom(xScale);
}
});
}
configurable(eventDropGraph, config);
return eventDropGraph;
};
};
module.exports = eventDrops;

@@ -1,19 +0,4 @@

"use strict";
/* global module */
module.exports = function filterDate(data, scale) {
data = data || [];
var filteredData = [];
var boundary = scale.range();
var min = boundary[0];
var max = boundary[1];
data.forEach(function (datum) {
var value = scale(datum);
if (value < min || value > max) {
return;
}
filteredData.push(datum);
});
return filteredData;
};
export default function filterData(data = [], scale) {
const [min, max] = scale.domain();
return data.filter(d => d >= min && d <= max);
}
{
"name": "event-drops",
"version": "0.1.1",
"version": "0.2.0",
"description": "A time based / event series interactive visualization using d3.js. Use drag and zoom to navigate in time.",
"main": "src/EventDrop.js",
"main": "dist/eventDrops.js",
"repository": {

@@ -10,17 +10,30 @@ "type": "git",

},
"dependencies": {},
"dependencies": {
"d3": "3.5.3"
},
"devDependencies": {
"browserify": "5.11.2",
"d3": "3.4.11",
"gulp": "3.8.10",
"gulp-mocha": "0.5.2",
"gulp-streamify": "0.0.5",
"gulp-uglify": "^1.0.1",
"babel-core": "6.4.5",
"babel-eslint": "^4.1.8",
"babel-loader": "6.2.1",
"babel-preset-es2015": "6.3.13",
"babel-preset-stage-0": "^6.3.13",
"configurable.js": "0.1.0",
"css-loader": "0.19.0",
"eslint": "1.6.0",
"eslint-config-airbnb": "0.1.0",
"extract-text-webpack-plugin": "1.0.1",
"html-loader": "0.3.0",
"html-webpack-plugin": "1.6.1",
"jasmine-core": "2.4.1",
"jsdom": "1.0.0-pre.6",
"karma": "0.12.23",
"karma-chrome-launcher": "0.1.4",
"karma-jasmine": "0.1.5",
"karma": "^0.13.19",
"karma-jasmine": "^0.3.6",
"karma-firefox-launcher": "0.1.7",
"karma-webpack": "^1.7.0",
"mocha": "1.21.4",
"vinyl-source-stream": "0.1.1",
"watchify": "1.0.1"
"mocha-traceur": "2.1.0",
"scss-loader": "0.0.1",
"style-loader": "0.12.4",
"webpack": "1.12.2",
"webpack-dev-server": "1.11.0"
},

@@ -38,4 +51,16 @@ "bugs": {

},
"author": "thiery <thiery@marmelab.com>",
"license": "ISC"
"author": "Thiery Michel <thiery@marmelab.com>",
"contributors": [
{ "name": "Chad Ramos" },
{ "name": "Chulki Lee" },
{ "name": "Emmanuel Quentin" },
{ "name": "Francois Zaninotto" },
{ "name": "Joan Yin" },
{ "name": "Joel Schlosser" },
{ "name": "Jonathan Petitcolas", "email": "petitcolas.jonathan@gmail.com" },
{ "name": "Mélodie Benmouffek" },
{ "name": "messense" },
{ "name": "Robin Bressan" }
],
"license": "MIT"
}
EventDrops
==========
A time based / event series interactive visualization using d3.js. Use drag and zoom to navigate in time.
A time based / event series interactive visualization using d3.js. Use drag and zoom to navigate in time. [See the demo](http://marmelab.com/EventDrops/)
![EventDrops example](http://static.marmelab.com/EventDrops.gif)
## Installation
You can use `npm` to install event-drops
```
npm install event-drops --save
```
For Bower users, even if Bower is not officially supported, you can still use GitHub URL such as:
```
{
"dependencies": {
"eventDrops": "marmelab/EventDrops#0.1.2"
}
}
```
## Usage

@@ -55,6 +73,7 @@

- `locale`: locale used for the X axis labels. See [d3.locale](https://github.com/mbostock/d3/wiki/Localization#locale) for the expected format. Defaults to null (i.e. d3 default locale).
- `axisFormat`: function receiving the d3 axis object, to customize tick number and size.
- `axisFormat`: function receiving the d3 axis object, to customize tick number and size.
- `tickFormat`: tickFormat for the X axis. See [d3.timeFormat.multi()](https://github.com/mbostock/d3/wiki/Time-Formatting#format_multi) for expected format.
- `eventHover`: function to be called when hovering an event in the chart. Receives the DOM element hovered (uses event delegation).
- `eventZoom`: function to be called when done zooming on the chart. Receives the d3 scale at the end of the zoom.
- `eventClick`: function to be called on click event of data-point (circle). Receives the DOM element hovered (uses event delegation).
- `hasDelimiter`: whether to draw time boundaries on top of the chart. Defaults to true.

@@ -67,2 +86,3 @@ - `hasTopAxis`: whether the chart has a top X axis. Accepts both a boolean or a function receiving the data of the graph that returns a boolean.

- `maxScale`: The maximum scaling (zoom in), default to Infinity.
- `zoomable`: *true* by default. Enable zoom-in/zoom-out and dragging handlers.

@@ -78,27 +98,31 @@ ## Styling

```sh
$ npm install
make install
```
Source files are located under the `lib/` folder, and use [browserify](http://browserify.org/) for dependency management.
Once your changes are finished, regenerate the combined and minified source under `src/` by calling the following command:
For development purpose, you can use the following command:
```sh
$ gulp browserify
``` sh
make run
```
To update your change dynamically and have sourcemap that allow the console to map to the original file type:
It serves the demo at http://localhost:8080. It also watches source files and live
reloads your browser as soon as a change is detected.
When your changes are done, ensure that all tests pass with:
``` sh
make test
```
$ gulp watch
```
To run the test :
Finally, if everything is fine, you can rebuild the library using:
``` sh
make build
```
$ gulp test // all test
$ gulp karma-test
$ gulp mocha-test
```
You can test the result by launching a server at the project root, and navigating to the `examples/` directory.
However, for better Pull Request reviewing, please do not commit the build files
in the same PR. You can then rebuild it once merged.
## License
EventDrops is released under the MIT License, courtesy of [marmelab](http://marmelab.com) and [Canal Plus](https://github.com/canalplus).

@@ -1,100 +0,83 @@

"use strict";
require('../../lib/eventDrops');
describe('d3.chart.eventDrops', function () {
var eventDrops, elements;
describe('d3.chart.eventDrops', () => {
it('should append a SVG element to given selection', () => {
const div = document.createElement('div');
const data = [{ name: 'foo', dates: [] }];
beforeEach(function () {
var body = d3.select(document.createElement('body'));
elements = body
.selectAll('div')
.data([[{name: "field1", dates: []}, {name: "field2", dates: []}], [{name: "field1", dates: []}, {name: "field2", dates: []}]])
;
elements
.enter()
.append('div')
;
const chart = d3.chart.eventDrops();
d3.select(div).datum(data).call(chart);
elements.exit().remove();
expect(div.querySelectorAll('svg.event-drops-chart').length).toBe(1);
});
eventDrops = d3.chart.eventDrops();
it('should remove all previously created charts in current selection to prevent duplicates', () => {
const div = document.createElement('div');
const data = [{ name: 'foo', dates: [] }];
eventDrops(elements);
});
const chart = d3.chart.eventDrops();
d3.select(div).datum(data).call(chart);
d3.select(div).datum(data).call(chart);
it('should add a eventDrops function to d3 that return a function', function () {
expect(typeof d3.chart.eventDrops).toBe('function');
expect(div.querySelectorAll('svg.event-drops-chart').length).toBe(1);
});
expect(typeof d3.chart.eventDrops()).toBe('function');
});
describe('start period', () => {
it('should be configurable', () => {
const div = document.createElement('div');
const data = [{ name: 'foo', dates: [] }];
it ('should append one svg element to the given elements or replace it when called', function () {
elements.each(function (data) {
var svgs = d3.select(this).selectAll('svg')[0];
expect(svgs.length).toBe(1);
});
const chart = d3.chart.eventDrops().start(new Date('2010-01-25'));
d3.select(div).datum(data).call(chart);
eventDrops(elements);
elements.each(function (data) {
var svgs = d3.select(this).selectAll('svg')[0];
expect(svgs.length).toBe(1);
expect(div.querySelector('.extremum .minimum').textContent).toBe('25 January 2010');
});
});
});
it ('should have a configurable start', function () {
expect(typeof eventDrops.start).toBe('function');
expect(eventDrops.start().getTime()).toBe((new Date(0)).getTime());
it('should have as many lines as events', () => {
const div = document.createElement('div');
const data = [
{ name: 'foo', dates: [] },
{ name: 'bar', dates: [] },
{ name: 'quz', dates: [] },
];
eventDrops.start(new Date());
expect(eventDrops.start().getTime()).toBe((new Date()).getTime());
});
const chart = d3.chart.eventDrops().start(new Date('2010-01-25'));
d3.select(div).datum(data).call(chart);
it ('should have as many line as event', function () {
elements.each(function (data) {
var svg = d3.select(this).select('svg');
var lines = svg.selectAll('.line')[0];
expect(lines.length).toBe(2);
expect(div.querySelectorAll('.drop-line').length).toBe(3);
});
elements = elements.data([[{name: "field1", dates: []}]]);
it('should have as many drops as given dates', () => {
const div = document.createElement('div');
const data = [
{ name: 'foo', dates: [new Date('2010-01-01')] },
{ name: 'bar', dates: [] },
{ name: 'quz', dates: [new Date('2011-01-04'), new Date('2012-08-09')] },
];
eventDrops(elements);
const chart = d3.chart.eventDrops().start(new Date('2010-01-25'));
d3.select(div).datum(data).call(chart);
elements.each(function (data) {
var svg = d3.select(this).select('svg');
var lines = svg.selectAll('.line')[0];
expect(lines.length).toBe(1);
expect(div.querySelectorAll('.drop').length).toBe(3);
});
});
it('should enable zoom only if `zoomable` configuration property is true', () => {
const zoom = require('../../lib/zoom');
const data = [ { name: 'foo', dates: [new Date()] }];
it ('should have as many circle by name as timestamps', function () {
elements.each(function (data) {
var lines = d3.select(this).select('svg').selectAll('.line');
const test = (zoomable, expectedZoomableBehavior) => {
zoom.default = jasmine.createSpy();
lines.each(function (data) {
var circles = d3.select(this).selectAll('circle')[0];
expect(circles.length).toBe(data.dates.length);
});
});
const div = document.createElement('div');
elements = elements.data([[{name: "field1", dates: [new Date(1402318080000), new Date(1402323060000), new Date(1402332120000)]}]]);
const chart = d3.chart.eventDrops().zoomable(zoomable);
d3.select(div).datum(data).call(chart);
eventDrops(elements);
expect(zoom.default.calls.any()).toBe(expectedZoomableBehavior);
};
elements.each(function (data) {
var lines = d3.select(this).select('svg').selectAll('.line');
expect(data.length).toBe(1);
lines.each(function (data) {
expect(data.dates.length).toBe(3);
var circles = d3.select(this).selectAll('circle')[0];
expect(circles.length).toBe(data.dates.length);
});
test(false, false);
test(true, true);
});
});
});

@@ -1,13 +0,29 @@

// karma.conf.js
module.exports = function(config) {
config.set({
basePath: '../..',
frameworks: ['jasmine'],
browsers: ['Chrome'],
files: [
'node_modules/d3/d3.js',
'src/eventDrops.js',
'test/karma/*'
]
});
module.exports = function (config) {
// Retrieve a Webpack config specialized in tests
var webpackConfig = require('../../webpack.config.js');
webpackConfig.context = __dirname + '/../..';
delete webpackConfig.entry;
delete webpackConfig.output;
config.set({
basePath: '../..',
browserNoActivityTimeout: 30000,
frameworks: ['jasmine'],
browsers: ['Firefox'],
files: [
'./node_modules/d3/d3.js',
'./test/karma/*',
'./test/karma/**/*.js'
],
plugins: ['karma-webpack', 'karma-jasmine', 'karma-firefox-launcher'],
preprocessors: {
'lib/**/*.js': 'webpack',
'test/karma/**/*.js': 'webpack'
},
webpackMiddleware: {
noInfo: true,
devtool: 'inline-source-map'
},
webpack: webpackConfig
});
};

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