added a dispatch class

This commit is contained in:
Shelby Sturgis 2014-09-22 13:08:31 +03:00
parent 1f2aaaaeab
commit da0007388d
5 changed files with 223 additions and 110 deletions

View file

@ -0,0 +1,98 @@
define(function (require) {
return function DispatchClass(d3, Private) {
var _ = require('lodash');
/**
* Events Class
*/
function Dispatch(vis, chartData) {
if (!(this instanceof Dispatch)) {
return new Dispatch(vis, chartData);
}
var type = vis._attr.type;
this.chartData = chartData;
this.color = type === 'pie' ? vis.data.getPieColorFunc() : vis.data.getColorFunc();
this._attr = _.defaults(vis._attr || {}, {
yValue: function (d) {
return d.y;
},
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout')
});
}
// Response to `click` and `hover` events
Dispatch.prototype.eventResponse = function (d, i) {
var label = d.label ? d.label : d.name;
var getYValue = this._attr.yValue;
var color = this.color;
var chartData = this.chartData;
var attr = this._attr;
var vis = this.vis;
// Adding a look up for the field. Currently this relies on filtering the
// data for the label then using that with the pointIndex to get the aggConfig.
// It works for now... but we need something a little more robust. That will
// come after the first beta. :)
//
// TODO: Replace the following code with something more robust for finding the field
var field, series, aggConfig;
if (d.label) {
series = _.find(this.chartData.series, { label: d.label });
aggConfig = _.last(series.values[i].aggConfigs);
if (aggConfig.aggType.name === 'terms') {
field = aggConfig.field.name;
}
}
return {
value : getYValue(d, i),
point : d,
label : label,
color : color(label),
pointIndex: i,
series : chartData.series,
config : attr,
data : chartData,
e : d3.event,
field : field,
aggConfig : aggConfig,
vis : vis
};
};
// Add brush to the svg
Dispatch.prototype.addBrush = function (xScale, svg) {
var dispatch = this._attr.dispatch;
var attr = this._attr;
var chartData = this.chartData;
var isBrush = this._attr.addBrushing;
var height = this._attr.height;
var margin = this._attr.margin;
// Brush scale
var brush = d3.svg.brush()
.x(xScale)
.on('brushend', function brushEnd() {
// response returned on brush
return dispatch.brush({
range: brush.extent(),
config: attr,
e: d3.event,
data: chartData
});
});
// if `addBrushing` is true, add brush canvas
if (isBrush) {
return svg.append('g')
.attr('class', 'brush')
.call(brush)
.selectAll('rect')
.attr('height', height - margin.top - margin.bottom);
}
};
return Dispatch;
};
});

View file

@ -3,6 +3,7 @@ define(function (require) {
var _ = require('lodash');
var Legend = Private(require('components/vislib/lib/legend'));
var Dispatch = Private(require('components/vislib/lib/dispatch'));
/*
* Base Class for all visualizations.
@ -16,6 +17,7 @@ define(function (require) {
this.vis = vis;
this.chartEl = el;
this.chartData = chartData;
this.events = new Dispatch(vis, chartData);
this._attr = _.defaults(vis._attr || {}, {});
}

View file

@ -22,26 +22,10 @@ define(function (require) {
// Column chart specific attributes
this._attr = _.defaults(vis._attr || {}, {
xValue: function (d, i) { return d.x; },
yValue: function (d, i) { return d.y; },
dispatch: d3.dispatch('brush', 'click', 'hover', 'mouseenter', 'mouseleave', 'mouseover', 'mouseout'),
yValue: function (d, i) { return d.y; }
});
}
// Response to `click` and `hover` events
ColumnChart.prototype.eventResponse = function (d, i) {
return {
value: this._attr.yValue(d, i),
point: d,
label: d.label,
color: this.vis.data.getColorFunc()(d.label),
pointIndex: i,
series : this.chartData.series,
config : this._attr,
data : this.chartData,
e : d3.event
};
};
// Stack data
// TODO: refactor so that this is called from the data module
ColumnChart.prototype.stackData = function (data) {
@ -59,33 +43,6 @@ define(function (require) {
}));
};
// Add brush to the svg
ColumnChart.prototype.addBrush = function (xScale, svg) {
var self = this;
// Brush scale
var brush = d3.svg.brush()
.x(xScale)
.on('brushend', function brushEnd() {
// response returned on brush
return self._attr.dispatch.brush({
range: brush.extent(),
config: self._attr,
e: d3.event,
data: self.chartData
});
});
// if `addBrushing` is true, add brush canvas
if (self._attr.addBrushing) {
svg.append('g')
.attr('class', 'brush')
.call(brush)
.selectAll('rect')
.attr('height', this._attr.height - this._attr.margin.top - this._attr.margin.bottom);
}
};
ColumnChart.prototype.addBars = function (svg, layers) {
var data = this.chartData;
var color = this.vis.data.getColorFunc();
@ -124,56 +81,56 @@ define(function (require) {
// update
bars
.attr('x', function (d) {
return xScale(d.x);
})
.attr('width', function () {
var barWidth;
var barSpacing;
.attr('x', function (d) {
return xScale(d.x);
})
.attr('width', function () {
var barWidth;
var barSpacing;
if (data.ordered && data.ordered.date) {
barWidth = xScale(data.ordered.min + data.ordered.interval) - xScale(data.ordered.min);
barSpacing = barWidth * 0.25;
if (data.ordered && data.ordered.date) {
barWidth = xScale(data.ordered.min + data.ordered.interval) - xScale(data.ordered.min);
barSpacing = barWidth * 0.25;
return barWidth - barSpacing;
}
return barWidth - barSpacing;
}
return xScale.rangeBand();
})
.attr('y', function (d) {
return yScale(d.y0 + d.y);
})
.attr('height', function (d) {
return yScale(d.y0) - yScale(d.y0 + d.y);
});
return xScale.rangeBand();
})
.attr('y', function (d) {
return yScale(d.y0 + d.y);
})
.attr('height', function (d) {
return yScale(d.y0) - yScale(d.y0 + d.y);
});
return bars;
};
ColumnChart.prototype.addBarEvents = function (bars) {
var self = this;
var events = this.events;
var tooltip = this.vis.tooltip;
var isTooltip = this._attr.addTooltip;
var dispatch = this._attr.dispatch;
var dispatch = this.events._attr.dispatch;
bars
.on('mouseover.bar', function (d, i) {
d3.select(this)
.classed('hover', true)
.style('stroke', '#333')
.style('cursor', 'pointer');
.on('mouseover.bar', function (d, i) {
d3.select(this)
.classed('hover', true)
.style('stroke', '#333')
.style('cursor', 'pointer');
dispatch.hover(self.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('click.bar', function (d, i) {
dispatch.click(self.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('mouseout.bar', function () {
d3.select(this).classed('hover', false)
.style('stroke', null);
});
dispatch.hover(events.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('click.bar', function (d, i) {
dispatch.click(events.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('mouseout.bar', function () {
d3.select(this).classed('hover', false)
.style('stroke', null);
});
// Add tooltip
if (isTooltip) {
@ -222,7 +179,7 @@ define(function (require) {
.attr('transform', 'translate(0,' + margin.top + ')');
// addBrush canvas
self.addBrush(xScale, svg);
self.events.addBrush(xScale, svg);
// add bars
bars = self.addBars(svg, layers);

View file

@ -24,31 +24,11 @@ define(function (require) {
});
}
PieChart.prototype.eventResponse = function (d, i) {
var getSize = this._attr.getSize;
var color = this.vis.data.getPieColorFunc();
var slices = this.chartData.slices;
var config = this._attr;
var chartData = this.chartData;
return {
value: getSize(d, i),
point: d,
label: d.name,
color: color(d.name),
pointIndex: i,
series: slices,
config: config,
data: chartData,
e: d3.event
};
};
PieChart.prototype.addPathEvents = function (path) {
var self = this;
var events = this.events;
var tooltip = this.vis.tooltip;
var isTooltip = this._attr.addTooltip;
var dispatch = this._attr.dispatch;
var dispatch = this.events._attr.dispatch;
path
.on('mouseover.pie', function mouseOverPie(d, i) {
@ -56,11 +36,11 @@ define(function (require) {
.classed('hover', true)
.style('cursor', 'pointer');
dispatch.hover(self.eventResponse(d, i));
dispatch.hover(events.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('click.pie', function clickPie(d, i) {
dispatch.click(self.eventResponse(d, i));
dispatch.click(events.eventResponse(d, i));
d3.event.stopPropagation();
})
.on('mouseout.pie', function mouseOutPie() {

View file

@ -7,10 +7,77 @@ define(function (require) {
describe('VisLib _chart Test Suite', function () {
var ColumnChart;
var Chart;
var Data;
var Vis;
var chartData = {};
var vis;
var el;
var myChart;
var config;
var data = {
hits : 621,
label : '',
ordered : {
date: true,
interval: 30000,
max : 1408734982458,
min : 1408734082458
},
series : [
{
values: [
{
x: 1408734060000,
y: 8
},
{
x: 1408734090000,
y: 23
},
{
x: 1408734120000,
y: 30
},
{
x: 1408734150000,
y: 28
},
{
x: 1408734180000,
y: 36
},
{
x: 1408734210000,
y: 30
},
{
x: 1408734240000,
y: 26
},
{
x: 1408734270000,
y: 22
},
{
x: 1408734300000,
y: 29
},
{
x: 1408734330000,
y: 24
}
]
}
],
tooltipFormatter: function (datapoint) {
return datapoint;
},
xAxisFormatter: function (thing) {
return thing;
},
xAxisLabel: 'Date Histogram',
yAxisLabel: 'Count'
};
beforeEach(function () {
module('ChartBaseClass');
@ -19,15 +86,24 @@ define(function (require) {
beforeEach(function () {
inject(function (d3, Private) {
Vis = Private(require('components/vislib/vis'));
Data = Private(require('components/vislib/lib/data'));
ColumnChart = Private(require('components/vislib/visualizations/column_chart'));
Chart = Private(require('components/vislib/visualizations/_chart'));
el = d3.select('body').append('div').attr('class', 'column-chart');
vis = {
_attr: {
stack: d3.layout.stack()
}
config = {
type: 'histogram',
shareYAxis: true,
addTooltip: true,
addLegend: true,
stack: d3.layout.stack(),
};
vis = new Vis(el[0][0], config);
vis.data = new Data(data, config);
myChart = new ColumnChart(vis, el, chartData);
});
});