[vislis/alerts] warn the user when they stack an area chart that has posotive and negative values

This commit is contained in:
Spencer Alger 2015-02-05 19:40:44 -07:00
parent 093e7a22fa
commit 94705cd91b
12 changed files with 153 additions and 18 deletions

View file

@ -0,0 +1,61 @@
define(function (require) {
return function AlertsFactory(d3, Private) {
var $ = require('jquery');
var _ = require('lodash');
var ErrorHandler = Private(require('components/vislib/lib/_error_handler'));
/**
* Appends chart titles to the visualization
*
* @class Alerts
* @constructor
* @param el {HTMLElement} Reference to DOM element
*/
function Alerts(vis, data, alertDefs) {
if (!(this instanceof Alerts)) {
return new Alerts(vis, data, alertDefs);
}
this.vis = vis;
this.data = data;
this.alertDefs = alertDefs || [];
}
/**
* Renders chart titles
*
* @method render
* @returns {D3.Selection|D3.Transition.Transition} DOM element with chart titles
*/
Alerts.prototype.render = function () {
var vis = this.vis;
var data = this.data;
var alerts = _(this.alertDefs)
.map(function (alertDef) {
if (!alertDef) return;
if (alertDef.test && !alertDef.test(vis, data)) return;
var type = alertDef.type || 'info';
var icon = alertDef.icon || type;
var msg = alertDef.msg;
// alert container
var $icon = $('<i>').addClass('vis-alerts-icon fa fa-' + icon);
var $text = $('<p>').addClass('vis-alerts-text').text(msg);
return $('<div>').addClass('vis-alert vis-alert-' + type).append([$icon, $text]);
})
.compact();
if (!alerts.size()) return;
$(vis.el).find('.vis-alerts').append(
$('<div>').addClass('vis-alerts-tray').append(alerts.value())
);
};
return Alerts;
};
});

View file

@ -21,7 +21,6 @@ define(function (require) {
}
this.data = opts.data || new Data(vis.data, vis._attr);
this.vis = vis;
this.el = vis.el;
this.ChartClass = vis.ChartClass;
@ -36,6 +35,7 @@ define(function (require) {
this.yAxis = opts.yAxis;
this.chartTitle = opts.chartTitle;
this.axisTitle = opts.axisTitle;
this.alerts = opts.alerts;
if (this._attr.addLegend) {
this.legend = opts.legend;
@ -46,6 +46,7 @@ define(function (require) {
this.legend,
this.axisTitle,
this.chartTitle,
this.alerts,
this.xAxis,
this.yAxis
], Boolean);

View file

@ -1,5 +1,7 @@
define(function (require) {
return function ColumnHandler(d3, Private) {
var $ = require('jquery');
var injectZeros = Private(require('components/vislib/components/zero_injection/inject_zeros'));
var Handler = Private(require('components/vislib/lib/handler/handler'));
var Data = Private(require('components/vislib/lib/data'));
@ -8,15 +10,18 @@ define(function (require) {
var YAxis = Private(require('components/vislib/lib/y_axis'));
var AxisTitle = Private(require('components/vislib/lib/axis_title'));
var ChartTitle = Private(require('components/vislib/lib/chart_title'));
var Alerts = Private(require('components/vislib/lib/alerts'));
/*
* Create handlers for Area, Column, and Line charts which
* are all nearly the same minus a few details
*/
function create(zeroFill, expandLastBucket) {
function create(opts) {
opts = opts || {};
return function (vis) {
var data;
if (zeroFill) {
if (opts.zeroFill) {
data = new Data(injectZeros(vis.data), vis._attr);
} else {
data = new Data(vis.data, vis._attr);
@ -32,9 +37,10 @@ define(function (require) {
xValues : data.xValues(),
ordered : data.get('ordered'),
xAxisFormatter : data.get('xAxisFormatter'),
expandLastBucket : expandLastBucket,
expandLastBucket : opts.expandLastBucket,
_attr : vis._attr
}),
alerts: new Alerts(vis, data, opts.alerts),
yAxis: new YAxis({
el : vis.el,
yMin : data.getYMinValue(),
@ -46,9 +52,26 @@ define(function (require) {
}
return {
line: create(false, false),
area: create(true, false),
column: create(true, true)
line: create(),
column: create({
zeroFill: true,
expandLastBucket: true
}),
area: create({
zeroFill: true,
alerts: [
{
type: 'warning',
msg: 'Positive and negative values are not accurately represented by stacked ' +
'area charts. The line chart is better suited for this type of data.',
test: function (vis, data) {
return vis._attr.mode === 'stacked' && data.getYMaxValue() > 0 && data.getYMinValue() < 0;
}
}
]
})
};
};
});

View file

@ -73,6 +73,10 @@ define(function (require) {
class: 'chart-wrapper',
splits: chartSplit
},
{
type: 'div',
class: 'vis-alerts'
},
{
type: 'div',
class: 'x-axis-wrapper',

View file

@ -0,0 +1,48 @@
.vis-alerts {
position: relative;
&-tray {
position: absolute;
bottom: 5px;
left: 0px;
right: 0px;
list-style: none;
padding: 0;
}
.vis-alert {
margin: 0 10px 10px;
padding: 5px 10px 5px 5px; // @alert-padding
color: white;
border-radius: @alert-border-radius;
border: 1px solid white;
.display(flex);
&-success {
.alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
}
&-info {
.alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
}
&-warning {
.alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
}
&-danger {
.alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
}
}
&-icon {
margin: 0;
padding: 0 10px;
.flex(0, 0, auto);
.align-self(center);
}
&-text {
.flex(1, 1, auto);
margin: 0;
padding: 0;
}
}

View file

@ -1,5 +1,3 @@
@import (reference) "lesshat.less";
.error {
.flex(1 1 100%);
text-align: center;

View file

@ -1,5 +1,3 @@
@import (reference) "lesshat.less";
.visualize-chart {
.display(flex);
.flex(1 1 100%);

View file

@ -1,5 +1,3 @@
@import (reference) "lesshat.less";
.legend-col-wrapper {
.flex(0 1 auto);
z-index: 10;

View file

@ -1,5 +1,3 @@
@import (reference) "../../../styles/main.less";
/* _tilemap */
.tilemap {

View file

@ -1,5 +1,3 @@
@import (reference) "../../../styles/main";
@tooltip-padding: 8px;
.vis-tooltip,

View file

@ -1,6 +1,10 @@
@import (reference) "../../../styles/main.less";
@import (reference) "lesshat.less";
@import "_error";
@import "_layout";
@import "_legend";
@import "_svg";
@import "_tooltip";
@import "_tilemap";
@import "_tilemap";
@import "_alerts";

View file

@ -82,6 +82,10 @@ button {
color: @brand-danger;
}
// alias for alert types - allows class="fa fa-{{alertType}}"
.fa-success:before { content: @fa-var-check; }
.fa-danger:before { content: @fa-var-exclamation-circle; }
ul.navbar-inline li {
display: inline;
}