Pie Charts now inherit from Bootstrap Theme

Horizon's pie charts had hard coded styles directly in the JavaScript
code.  This made it impossible for them to inherit any of their look
and feel from the install theme.  This patch fixes that problem.

It was noted, while doing the refactor, that the legend was being
implemented within D3, but this was not necessary at all, since it
has no graphing visuals associated with it.  It was impossible to
allow the legend label sizes to inherit and be configurable from
the css while they were being generated in the SVG.  The height
could never be known unless D3 knew the height of each element.

Noted Improvements:
* Consistent Colors! Colors, even for distribution charts, now come
  from the palette
* All aspects of the charts are now resizable and can inherit the
  sizes of the charts, as well as the paddings and type settings
  from the theme
* A bug in the 'Show Numbers' function was discovered and will be
  fixed as a result
* The legend symbol, which was a hardcoded cube before, is now an
  icon font, and therefore can be customized per theme.  I.E., you
  can now use rectangles, circles, ovals, smiley faces, etc
* It now inherits directly from the Theme

Change-Id: I5d5c13e57553f8b504593aac6d7611175e900f3c
Partially-Implements: blueprint horizon-theme-css-reorg
This commit is contained in:
Diana Whitten 2015-08-29 23:49:46 -07:00
parent 3c6783e18b
commit 2d007cb1b7
5 changed files with 186 additions and 102 deletions

View File

@ -16,36 +16,14 @@
</div>
*/
// Pie chart dimensions
// Pie chart SVG internal dimensions
var WIDTH = 100;
var HEIGHT = 100;
var RADIUS = 45;
// Colors
var BKGRND = "#F2F2F2";
var FRGRND = "#006CCF";
var FULL = "#D0342B";
var NEARLY_FULL = "#FFA500";
var STROKE_USAGE = "#CCCCCC";
var STROKE_DISTRIBUTION = "#609ED2";
var BLUE_SHADES = [
"#609ED2",
"#BFD8ED",
"#EFF5FB",
"#2D6997",
"#1F4A6F",
"#122A40",
"#428BCA",
"#90BAE0",
"#DFEBF6"
];
function create_vis(chart) {
return d3.select(chart).append("svg:svg")
.attr("class", "chart")
.attr("width", WIDTH)
.attr("height", HEIGHT)
.attr("class", "chart pie-chart")
.attr("viewBox", "0 0 " + WIDTH + " " + HEIGHT )
.append("g")
.attr("transform",
@ -99,10 +77,7 @@ horizon.d3_pie_chart_usage = {
.enter()
.append("path")
.attr("class","arc")
.attr("d", arc)
.style("fill", BKGRND)
.style("stroke", STROKE_USAGE)
.style("stroke-width", 1);
.attr("d", arc);
// Animate filling the pie chart
var animate = function(data) {
@ -110,25 +85,16 @@ horizon.d3_pie_chart_usage = {
.data(pie(data))
.enter()
.append("path")
.attr("class","arc")
.attr("d", arc)
.style("fill", function(){
.attr("class", function() {
var ret_val = "arc inner";
if (self.data[0].percentage >= 100) {
return FULL;
ret_val += " FULL";
} else if (self.data[0].percentage >= 80) {
return NEARLY_FULL;
} else {
return FRGRND;
}
})
.style("stroke", STROKE_USAGE)
.style("stroke-width", function() {
if (self.data[0].percentage <= 0 || self.data[0].percentage >= 100) {
return 0;
} else {
return 1;
ret_val += " NEARLY_FULL";
}
return ret_val;
})
.attr("d", arc)
.transition()
.duration(500)
.attrTween("d", function(start) {
@ -144,8 +110,7 @@ horizon.d3_pie_chart_usage = {
var show_numbers = function() {
vis.append("text")
.style("fill", "black")
.style("font-size","28px")
.attr("class", "chart-numbers")
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'central')
.text(self.data);
@ -154,6 +119,10 @@ horizon.d3_pie_chart_usage = {
if (fill) {
animate(self.data);
} else {
// TODO: this seems to be very broken...
// https://bugs.launchpad.net/horizon/+bug/1490787
// It prints: [object Object] to the screen
show_numbers(self.data);
}
}
@ -161,8 +130,6 @@ horizon.d3_pie_chart_usage = {
horizon.d3_pie_chart_distribution = {
colors: BLUE_SHADES,
init: function() {
var self = this;
var pie_chart_data = $(".d3_pie_chart_distribution");
@ -181,11 +148,11 @@ horizon.d3_pie_chart_distribution = {
self.data.push(d);
self.keys.push(key_value[0]);
}
self.pieChart(i);
self.pieChart(i, $(pie_chart_data[i]));
}
},
// Draw a pie chart
pieChart: function(i) {
pieChart: function(i, $elem) {
var self = this;
var vis = create_vis(self.chart[0][i]);
var arc = create_arc();
@ -207,10 +174,7 @@ horizon.d3_pie_chart_distribution = {
.enter()
.append("path")
.attr("class","arc")
.attr("d", arc)
.style("fill", BKGRND)
.style("stroke", STROKE_DISTRIBUTION)
.style("stroke-width", 1);
.attr("d", arc);
// Animate filling the pie chart
var animate = function(data) {
@ -218,13 +182,8 @@ horizon.d3_pie_chart_distribution = {
.data(pie(data))
.enter()
.append("path")
.attr("class","arc")
.attr("class","arc inner")
.attr("d", arc)
.style("fill", function(d) {
return self.colors[self.data.indexOf(d.data)];
})
.style("stroke", STROKE_DISTRIBUTION)
.style("stroke-width", 1)
.transition()
.duration(500)
.attrTween("d", function(start) {
@ -240,51 +199,50 @@ horizon.d3_pie_chart_distribution = {
animate(self.data);
}
// Add a legend
var legend = d3.select(self.chart[0][i])
.append("svg")
.attr("class", "legend")
.attr("width", WIDTH * 2)
.attr("height", self.data.length * 18 + 20)
.selectAll("g")
.data(self.keys)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
// The legend actually doesn't need to be an SVG element at all
// By making it standard markup, we can allow greater customization
var $legend = $(document.createElement('div')).addClass('legend');
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) {
var item;
for (var i = 0; i < self.data.length; i++) {
if (self.data[i].key == d) {
item = self.data[i];
break;
}
}
return self.colors[self.data.indexOf(item)];
});
// This loop might seem wasteful, but we need to determine the total for the label
var total = 0;
for (var j = 0; j < self.data.length; j++) {
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) {
if (total === 0) {
return d + " 0%";
}
var value = 0;
for (var j = 0; j < self.data.length; j++) {
if (self.data[j].key == d) {
value = self.data[j].value;
break;
}
}
return d + " " + Math.round(value/total * 100) + "%";
});
// We need to use it as a float again later, convert it now and store ... its faster
self.data[j].value = parseFloat(self.data[j].value);
total += self.data[j].value;
}
for (var j = 0; j < self.data.length; j++) {
var this_item = self.data[j];
var $this_group = $(document.createElement('div'))
.addClass('legend-group')
.appendTo($legend);
$(document.createElement('span'))
.addClass('legend-symbol')
.appendTo($this_group);
$(document.createElement('span'))
.addClass('legend-key')
.text(this_item.key)
.appendTo($this_group);
var $this_value = $(document.createElement('span'))
.addClass('legend-value');
// If its zero, then we don't need to Math it.
if (this_item.value === 0) {
$this_item.text("0%");
} else {
$this_value.text(Math.round((this_item.value/total) * 100) + "%");
}
// Append it to the container
$this_value.appendTo($this_group);
}
// Append the container last ... cause its faster
$elem.append($legend);
}
};

View File

@ -0,0 +1,112 @@
// General Pie Chart Styles
// The idea behind this mixin in to allow a variety of
// colors to be configured, from 1 - $num, that will
// toggle between an incrementing percentage ($increment)
// from the theme's primary brand color. This should
// adapt nicely to most themes.
@mixin make_pie_chart_distribution($num, $increment) {
@for $ii from 1 through $num {
$color_increment: $increment * ($ii/2);
// Set the arc color
.arc:nth-child(#{$ii}n) {
@if $ii % 2 == 0 {
fill: lighten($brand-primary, $color_increment * 1%);
} @else {
fill: darken($brand-primary, $color_increment * 1%);
}
}
// Set the corresponding legend symbol
.legend-group:nth-child(#{$ii}n) .legend-symbol {
@if $ii % 2 == 0 {
color: lighten($brand-primary, $color_increment * 1%);
} @else {
color: darken($brand-primary, $color_increment * 1%);
}
}
}
}
// This is who sets the size of the pie chart
.pie-chart {
width: $font-size-h1*3;
height: $font-size-h1*3;
// The container arc's color and stroke
.arc {
fill: $table-border-color;
stroke-width: 1px;
}
}
// Chart Usage Specifics
.d3_pie_chart_usage {
.arc {
stroke: $table-border-color;
}
// The inner arc
.arc.inner {
fill: $brand-primary;
stroke: none;
// Specialness if its full
&.FULL {
fill: $brand-danger;
}
// Specialness if its almost full
&.NEARLY_FULL {
fill: $brand-warning;
}
}
}
// Chart Distribution Specifics
.d3_pie_chart_distribution {
// The container arc's color and stroke
.arc {
stroke: $brand-primary;
}
// Set the colors!
@include make_pie_chart_distribution(8, 8);
.legend {
padding: $padding-base-horizontal $padding-base-vertical;
text-align: left;
}
.legend-group {
padding: $padding-xs-horizontal $padding-small-vertical;
}
.legend-symbol {
@extend .fa;
@extend .fa-square;
font-size: $font-size-h3;
padding-right: $padding-small-vertical;
}
.legend-symbol,
.legend-key,
.legend-value {
display: inline-block;
line-height: $line-height-computed;
vertical-align: middle;
}
.legend-key {
padding-right: $padding-small-vertical;
}
}
.chart-numbers {
fill: $gray-dark;
font-size: $font-size-h3;
}

View File

@ -22,6 +22,7 @@
@import "components/workflow";
@import "components/network_topology";
@import "components/context_selection";
@import "components/pie_charts";
@import "/framework/framework";

View File

@ -2,6 +2,7 @@
@import 'components/_context_selection';
@import 'components/sidebar';
@import 'components/pie_charts';
.navbar-brand {

View File

@ -0,0 +1,12 @@
.d3_pie_chart_usage {
.arc {
stroke: $gray-light;
fill: $gray-lighter;
}
}
.d3_pie_chart_distribution {
.legend-group {
padding: 1px $padding-small-vertical;
}
}