/**
* Bluff - beautiful graphs in JavaScript
* ======================================
*
* Get the latest version and docs at http://bluff.jcoglan.com
* Based on Gruff by Geoffrey Grosenbach: http://github.com/topfunky/gruff
*
* Copyright (C) 2008-2010 James Coglan
*
* Released under the MIT license and the GPL v2.
**/
Bluff = {
// This is the version of Bluff you are using.
VERSION: '0.3.6',
return ary;
},
var ary = [];
return ary;
},
}
},
}
return -1;
},
return ary;
},
var results = [];
});
return results;
},
},
return sum;
},
Mini: {}
};
extend: {
// Draw extra lines showing where the margins and text centers are
DEBUG: false,
// Used for navigating the array of data to plot
DATA_LABEL_INDEX: 0,
DATA_COLOR_INDEX: 2,
// Space around text elements. Mostly used for vertical spacing
LEGEND_MARGIN: 20,
TITLE_MARGIN: 20,
LABEL_MARGIN: 10,
DEFAULT_MARGIN: 20,
DEFAULT_TARGET_WIDTH: 800,
THOUSAND_SEPARATOR: ','
},
// Blank space above the graph
top_margin: null,
// Blank space below the graph
bottom_margin: null,
// Blank space to the right of the graph
right_margin: null,
// Blank space to the left of the graph
left_margin: null,
// Blank space below the title
title_margin: null,
// Blank space below the legend
legend_margin: null,
// A hash of names for the individual columns, where the key is the array
// index for the column this label represents.
//
// Not all columns need to be named.
//
// Example: {0: 2005, 3: 2006, 5: 2007, 7: 2008}
labels: null,
// Used internally for spacing.
//
// By default, labels are centered over the point they represent.
center_labels_over_point: null,
// Used internally for horizontal graph types.
has_left_labels: null,
// A label for the bottom of the graph
x_axis_label: null,
// A label for the left side of the graph
y_axis_label: null,
// x_axis_increment: null,
// Manually set increment of the horizontal marking lines
y_axis_increment: null,
// Get or set the list of colors that will be used to draw the bars or lines.
colors: null,
// The large title of the graph displayed at the top
title: null,
// Font used for titles, labels, etc.
font: null,
font_color: null,
// Prevent drawing of line markers
hide_line_markers: null,
// Prevent drawing of the legend
hide_legend: null,
// Prevent drawing of the title
hide_title: null,
// Prevent drawing of line numbers
hide_line_numbers: null,
// Message shown when there is no data. Fits up to 20 characters. Defaults
// to "No Data."
no_data_message: null,
// The font size of the large title at the top of the graph
title_font_size: null,
// Optionally set the size of the font. Based on an 800x600px graph.
// Default is 20.
//
// Will be scaled down if graph is smaller than 800px wide.
legend_font_size: null,
// The font size of the labels around the graph
marker_font_size: null,
// The color of the auxiliary lines
marker_color: null,
// The number of horizontal lines shown for reference
marker_count: null,
// You can manually set a minimum value instead of having the values
// guessed for you.
//
// Set it after you have given all your data to the graph object.
minimum_value: null,
// You can manually set a maximum value, such as a percentage-based graph
// that always goes to 100.
//
// If you use this, you must set it after you have given all your data to
// the graph object.
maximum_value: null,
// Set to false if you don't want the data to be sorted with largest avg
// values at the back.
sort: null,
// Experimental
additional_line_values: null,
// Experimental
stacked: null,
// Optionally set the size of the colored box by each item in the legend.
// Default is 20.0
//
// Will be scaled down if graph is smaller than 800px wide.
legend_box_size: null,
// Set to true to enable tooltip displays
tooltips: false,
// If one numerical argument is given, the graph is drawn at 4/3 ratio
// according to the given width (800 results in 800x600, 400 gives 400x300,
// etc.).
//
// Or, send a geometry string for other ratios ('800x400', '400x225').
var geo;
if (typeof target_width !== 'number') {
} else {
}
this.initialize_ivars();
this._reset_themes();
this.theme_keynote();
this._listeners = {};
},
// Set instance variables for this object.
//
// Subclasses can override this, call super, then set values separately.
//
// This makes it possible to set defaults in a subclass but still allow
// developers to change this values in their program.
initialize_ivars: function() {
// Internal for calculations
this._raw_columns = 800;
this._column_count = 0;
this.marker_count = null;
this.maximum_value = this.minimum_value = null;
this._has_data = false;
this._data = [];
this.labels = {};
this._labels_seen = {};
this.sort = true;
this.title = null;
this.marker_font_size = 21.0;
this.legend_font_size = 20.0;
this.title_font_size = 36.0;
this.top_margin = this.bottom_margin =
this.legend_box_size = 20.0;
this.no_data_message = "No Data";
this.center_labels_over_point = true;
this.has_left_labels = false;
this.additional_line_values = [];
this._additional_line_colors = [];
this._theme_options = {};
this.x_axis_label = this.y_axis_label = null;
this.y_axis_increment = null;
this.stacked = null;
this._norm_data = null;
},
// Sets the top, bottom, left and right margins to +margin+.
set_margins: function(margin) {
},
// Sets the font for graph text to the font at +font_path+.
},
// Add a color to the list of available colors for lines.
//
// Example:
// add_color('#c0e9d3')
},
// Replace the entire color list with a new array of colors. Also
// aliased as the colors= setter method.
//
// If you specify fewer colors than the number of datasets you intend
// to draw, 'increment_color' will cycle through the array, reusing
// colors as needed.
//
// Note that (as with the 'set_theme' method), you should set up the color
// list before you send your data (via the 'data' method). Calls to the
// 'data' method made prior to this call will use whatever color scheme
// was in place at the time data was called.
//
// Example:
// replace_colors ['#cc99cc', '#d9e043', '#34d8a2']
replace_colors: function(color_list) {
this.colors = color_list || [];
this._color_index = 0;
},
// You can set a theme manually. Assign a hash to this method before you
// send your data.
//
// graph.set_theme({
// colors: ['orange', 'purple', 'green', 'white', 'red'],
// marker_color: 'blue',
// background_colors: ['black', 'grey']
// })
//
// background_image: 'squirrel.png' is also possible.
//
// (Or hopefully something better looking than that.)
//
this._reset_themes();
this._theme_options = {
marker_color: 'white',
font_color: 'black',
background_colors: null,
background_image: null
};
this._render_background();
},
// Set just the background colors
set_background: function(options) {
this._render_background();
},
// A color scheme similar to the popular presentation software.
theme_keynote: function() {
// Colors
this._blue = '#6886B4';
this._yellow = '#FDD84E';
this._green = '#72AE6E';
this._red = '#D1695E';
this._purple = '#8A6EAF';
this._orange = '#EFAA43';
this._white = 'white';
this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._white];
this.set_theme({
marker_color: 'white',
font_color: 'white',
});
},
// A color scheme plucked from the colors on the popular usability blog.
theme_37signals: function() {
// Colors
this._green = '#339933';
this._purple = '#cc99cc';
this._blue = '#336699';
this._yellow = '#FFF804';
this._red = '#ff0000';
this._orange = '#cf5910';
this._black = 'black';
this.colors = [this._yellow, this._blue, this._green, this._red, this._purple, this._orange, this._black];
this.set_theme({
marker_color: 'black',
font_color: 'black',
});
},
// A color scheme from the colors used on the 2005 Rails keynote
// presentation at RubyConf.
theme_rails_keynote: function() {
// Colors
this._green = '#00ff00';
this._grey = '#333333';
this._orange = '#ff5d00';
this._red = '#f61100';
this._white = 'white';
this._light_grey = '#999999';
this._black = 'black';
this.colors = [this._green, this._grey, this._orange, this._red, this._white, this._light_grey, this._black];
this.set_theme({
marker_color: 'white',
font_color: 'white',
});
},
// A color scheme similar to that used on the popular podcast site.
theme_odeo: function() {
// Colors
this._grey = '#202020';
this._white = 'white';
this._dark_pink = '#a21764';
this._green = '#8ab438';
this._light_grey = '#999999';
this._dark_blue = '#3a5b87';
this._black = 'black';
this.colors = [this._grey, this._white, this._dark_blue, this._dark_pink, this._green, this._light_grey, this._black];
this.set_theme({
marker_color: 'white',
font_color: 'white',
});
},
// A pastel theme
theme_pastel: function() {
// Colors
this.colors = [
'#a9dada', // blue
'#aedaa9', // green
'#daaea9', // peach
'#dadaa9', // yellow
'#a9a9da', // dk purple
'#daaeda', // purple
'#dadada' // grey
];
this.set_theme({
font_color: 'black',
background_colors: 'white'
});
},
// A greyscale theme
theme_greyscale: function() {
// Colors
this.colors = [
'#282828', //
'#383838', //
'#686868', //
'#989898', //
'#c8c8c8', //
'#e8e8e8' //
];
this.set_theme({
font_color: 'black',
background_colors: 'white'
});
},
// Parameters are an array where the first element is the name of the dataset
// and the value is an array of values to plot.
//
// Can be called multiple times with different datasets for a multi-valued
// graph.
//
// If the color argument is nil, the next color from the default theme will
// be used.
//
// NOTE: If you want to use a preset theme, you must set it before calling
// data().
//
// Example:
// data("Bart S.", [95, 45, 78, 89, 88, 76], '#ffcc00')
// Set column count if this is larger than previous counts
this._column_count = (data_points.length > this._column_count) ? data_points.length : this._column_count;
// Pre-normalize
if (data_point === undefined) return;
if (this.maximum_value === null && this.minimum_value === null)
// TODO Doesn't work with stacked bar graphs
// Original: @maximum_value = _larger_than_max?(data_point, index) ? max(data_point, index) : @maximum_value
}, this);
},
// Overridden by subclasses to do the actual plotting of the graph.
//
// Subclasses should start by calling super() for this method.
draw: function() {
if (this.stacked) this._make_stacked();
this._setup_drawing();
this._debug(function() {
// Outer margin
// Graph area box
});
},
clear: function() {
this._render_background();
},
},
if (!list) return;
});
},
// Calculates size of drawable area and draws the decorations.
//
// * line markers
// * legend
// * title
_setup_drawing: function() {
// Maybe should be done in one of the following functions for more granularity.
if (!this._has_data) return this._draw_no_data();
this._normalize();
this._setup_graph_measurements();
if (this.sort) this._sort_norm_data();
this._draw_legend();
this._draw_line_markers();
this._draw_axis_labels();
this._draw_title();
},
// Make copy of data with values scaled between 0-100
_normalize: function(force) {
if (this._norm_data === null || force === true) {
this._norm_data = [];
if (!this._has_data) return;
this._calculate_spread();
var norm_data_points = [];
norm_data_points.push(null);
else
}, this);
this._norm_data.push([data_row[this.klass.DATA_LABEL_INDEX], norm_data_points, data_row[this.klass.DATA_COLOR_INDEX]]);
}, this);
}
},
_calculate_spread: function() {
},
// Calculates size of drawable area, general font dimensions, etc.
_setup_graph_measurements: function() {
this._calculate_caps_height(this.marker_font_size);
this._calculate_caps_height(this.title_font_size);
this._calculate_caps_height(this.legend_font_size);
var longest_label,
key;
if (this.hide_line_markers) {
this._graph_left = this.left_margin;
this._graph_right_margin = this.right_margin;
this._graph_bottom_margin = this.bottom_margin;
} else {
if (this.has_left_labels) {
longest_label = '';
}
} else {
longest_left_label_width = this._calculate_width(this.marker_font_size, this._label(this.maximum_value));
}
// Shift graph if left line numbers are hidden
0.0 :
this._graph_left = this.left_margin +
// Make space for half the width of the rightmost column label.
// Might be greater than the number of columns if between-style bar markers are used.
last_label = -Infinity;
extra_room_for_long_label = (last_label >= (this._column_count-1) && this.center_labels_over_point) ?
0;
this._graph_bottom_margin = this.bottom_margin +
}
// When hide_title, leave a title_margin space for aesthetics.
// Same with hide_legend
this._graph_top = this.top_margin +
},
// Draw the optional labels for the x axis and y axis.
_draw_axis_labels: function() {
if (this.x_axis_label) {
// X Axis
// Centered vertically and horizontally by setting the
// height to 1.0 and the width to the width of the graph.
var x_axis_label_y_coordinate = this._graph_bottom + this.klass.LABEL_MARGIN * 2 + this._marker_caps_height;
// TODO Center between graph area
this._d.annotate_scaled(
this._raw_columns, 1.0,
this.x_axis_label, this._scale);
this._debug(function() {
});
}
// TODO Y label (not generally possible in browsers)
},
// Draws horizontal background lines and labels
_draw_line_markers: function() {
if (this.hide_line_markers) return;
if (this.y_axis_increment === null) {
// Try to use a number of horizontal lines that will come out even.
//
// TODO Do the same for larger numbers...100, 75, 50, 25
if (this.marker_count === null) {
this.marker_count = lines;
}, this);
}
} else {
// TODO Make this work for negative values
this._calculate_spread();
this._normalize(true);
this._increment = this.y_axis_increment;
}
// Draw horizontal line markers and annotate with numbers
var index, n, y, marker_label;
if (!this.hide_line_numbers) {
// Vertically center with 1.0 for the height
1.0, 0.0, y,
}
}
},
},
// Draws a legend with the names of the datasets matched to the colors used
// to draw them.
_draw_legend: function() {
if (this.hide_legend) return;
}, this);
// May fix legend drawing problem at small sizes
var label_widths = [[]]; // Used to calculate line wrap
}, this);
var current_y_offset = this.hide_title ?
this.top_margin + this.title_margin :
this._debug(function() {
});
// Draw label
legend_label, this._scale);
// Now draw box with color of this dataset
// Handle wrapping
this._debug(function() {
});
// Wrap to next line and shrink available graph dimensions
this._graph_top += line_height;
}
} else {
}
}, this);
this._color_index = 0;
},
// Draws a title on the graph.
_draw_title: function() {
if (this.hide_title || !this.title) return;
0, this.top_margin,
},
// Draws column labels below graph, centered over x_offset
//--
// TODO Allow WestGravity as an option
if (this.hide_line_markers) return;
var y_offset;
this._labels_seen[index] = true;
this._debug(function() {
});
}
},
// Creates a mouse hover target rectangle for tooltip displays
if (!this.tooltips) return;
var point = {
};
}, this);
},
// Shows an error message because you have no data.
_draw_no_data: function() {
0, 10,
this.no_data_message, this._scale);
},
// Finds the best background to render based on the provided theme options.
_render_background: function() {
switch (true) {
case colors instanceof Array:
break;
case typeof colors === 'string':
this._render_solid_background(colors);
break;
default:
break;
}
},
// Make a new image at the current size with a solid +color+.
_render_solid_background: function(color) {
},
// Use with a theme definition method to draw a gradiated background.
},
// Use with a theme to use an image (800x600 original) background.
_render_image_background: function(image_path) {
// TODO
},
// Resets everything to defaults (except data).
_reset_themes: function() {
this._color_index = 0;
this._labels_seen = {};
this._theme_options = {};
},
_scale_value: function(value) {
},
// Return a comparable fontsize for the current graph.
_scale_fontsize: function(value) {
return new_fontsize;
},
},
// Overridden by subclasses such as stacked bar.
return data_point > this.maximum_value;
},
return data_point < this.minimum_value;
},
// Overridden by subclasses that need it.
return data_point;
},
// Overridden by subclasses that need it.
return data_point;
},
_significant: function(inc) {
var factor = 1.0;
while (inc < 10) {
inc *= 10;
factor /= 10;
}
while (inc > 100) {
inc /= 10;
factor *= 10;
}
},
// Sort with largest overall summed value at front of array so it shows up
// correctly in the drawn graph.
_sort_norm_data: function() {
this._norm_data.sort(function(a,b) {
});
});
},
var total_sum = 0;
return total_sum;
},
_make_stacked: function() {
var stacked_values = [], i = this._column_count;
while (i--) stacked_values[i] = 0;
}, this);
}, this);
},
// Takes a block and draws it if DEBUG is true.
//
// Example:
// debug { @d.rectangle x1, y1, x2, y2 }
}
},
// Returns the next color in your color list.
_increment_color: function() {
var offset = this._color_index;
},
// Return a formatted string representing a number value that should be
// printed as a label.
},
// Returns the height of the capital letter 'X' for the current font and
// size.
//
// Not scaled since it deals with dimensions that the regular scaling will
// handle.
_calculate_caps_height: function(font_size) {
},
// Returns the width of a string at this pointsize.
//
// Not scaled since it deals with dimensions that the regular
// scaling will handle.
}
});
draw: function() {
this.callSuper();
if (!this._has_data) return;
var poly_points = [],
prev_x = 0.0,
prev_y = 0.0;
// Use incremented x and scaled y
// this._d.polyline(prev_x, prev_y, new_x, new_y);
} else {
// this._d.polyline(this._graph_left, this._graph_bottom, new_x, new_y);
}
}, this);
// Add closing points, draw polygon
}, this);
}
});
// This class perfoms the y coordinats conversion for the bar class.
//
// There are three cases:
//
// 1. Bars all go from zero in positive direction
// 2. Bars all go from zero to negative direction
// 3. Bars either go from zero to positive or from zero to negative
//
mode: null,
zero: null,
graph_top: null,
graph_height: null,
minimum_value: null,
spread: null,
var val;
switch (this.mode) {
case 1: // Case one
// minimum value >= 0 ( only positiv values )
break;
case 2: // Case two
// only negativ values
break;
case 3: // Case three
// positiv and negativ values
if ( data_point >= this.zero ) {
} else {
}
break;
default:
}
}
});
// Spacing factor applied between bars
bar_spacing: 0.9,
draw: function() {
// Labels will be centered over the left of the bar if
// there are more labels than columns. This is basically the same
// as where it would be for a line graph.
this.callSuper();
if (!this._has_data) return;
this._draw_bars();
},
_draw_bars: function() {
// Setup the BarConversion Object
// Set up the right mode [1,2,3] see BarConversion for further explanation
if (this.minimum_value >= 0) {
// all bars go from zero to positiv
} else {
// all bars go from 0 to negativ
if (this.maximum_value <= 0) {
} else {
// bars either go from zero to negativ or to positiv
}
}
// iterate over all normalised data
// Use incremented x and scaled y
// x
var left_x = this._graph_left + (this._bar_width * (row_index + point_index + ((this._data.length - 1) * point_index))) + padding;
// y
var conv = [];
// create new bar
// create tooltip target
// Calculate center based on bar_width and current row
var label_center = this._graph_left +
// Subtract half a bar width to center left if requested
this._draw_label(label_center - (this.center_labels_over_point ? this._bar_width / 2.0 : 0.0), point_index);
}, this);
}, this);
// Draw the last label if requested
}
});
// Here's how to make a Line graph:
//
// g = new Bluff.Line('canvasId');
// g.title = "A Line Graph";
// g.data('Fries', [20, 23, 19, 8]);
// g.data('Hamburgers', [50, 19, 99, 29]);
// g.draw();
//
// There are also other options described below, such as #baseline_value, #baseline_color, #hide_dots, and #hide_lines.
// Draw a dashed line at the given value
baseline_value: null,
// Color of the baseline
baseline_color: null,
// Dimensions of lines and dots; calculated based on dataset size if left unspecified
line_width: null,
dot_radius: null,
// Hide parts of the graph to fit more datapoints, or for a different appearance.
hide_dots: null,
hide_lines: null,
// Call with target pixel width of graph (800, 400, 300), and/or 'false' to omit lines (points only).
//
// g = new Bluff.Line('canvasId', 400) // 400px wide with lines
//
// g = new Bluff.Line('canvasId', 400, false) // 400px wide, no lines (for backwards compatibility)
//
// g = new Bluff.Line('canvasId', false) // Defaults to 800px wide, no lines (for backwards compatibility)
//
// The preferred way is to call hide_dots or hide_lines instead.
initialize: function(renderer) {
if (arguments.length === 1 || (typeof arguments[1] !== 'number' && typeof arguments[1] !== 'string'))
else
this.callSuper();
this.hide_dots = this.hide_lines = false;
this.baseline_color = 'red';
this.baseline_value = null;
},
draw: function() {
this.callSuper();
if (!this._has_data) return;
// Check to see if more than one datapoint was given. NaN can result otherwise.
this.x_increment = (this._column_count > 1) ? (this._graph_width / (this._column_count - 1)) : this._graph_width;
var level;
if (this._norm_baseline !== undefined) {
// this._d.stroke_dasharray(10, 20);
}
if (typeof data_point !== 'number') return;
// Reset each time to avoid thin-line errors
this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 6), 3.0);
var circle_radius = this.dot_radius ||
this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2), 7.0);
} else if (this._one_point) {
// Show a circle if there's just one point
}
}, this);
}, this);
},
_normalize: function() {
this.callSuper();
},
_contains_one_point_only: function(data_row) {
// Spin through data to determine if there is just one value present.
var count = 0;
});
return count === 1;
}
});
// Graph with dots and labels along a vertical access
// see: 'Creating More Effective Graphs' by Robbins
draw: function() {
this.has_left_labels = true;
this.callSuper();
if (!this._has_data) return;
// Setup spacing.
//
var spacing_factor = 1.0;
var y_pos = this._graph_top + (this._items_width * point_index) + padding + Math.round(this._item_width/2.0);
if (row_index === 0) {
}
// Calculate center based on item_width and current row
var label_center = this._graph_top + (this._items_width * point_index + this._items_width / 2) + padding;
}, this);
}, this);
},
// Instead of base class version, draws vertical background lines and label
_draw_line_markers: function() {
if (this.hide_line_markers) return;
this._d.stroke_antialias = false;
// Draw horizontal line markers and annotate with numbers
var number_of_lines = 5;
// TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
if (!this.hide_line_numbers) {
// TODO Center text over line
marker_label, this._scale);
}
this._d.stroke_antialias = true;
}
},
// Draw on the Y axis instead of the X
this._labels_seen[index] = true;
}
}
});
// Experimental!!! See also the Spider graph.
// Hide parts of the graph to fit more datapoints, or for a different appearance.
hide_dots: null,
//Dimensions of lines and dots; calculated based on dataset size if left unspecified
line_width: null,
dot_radius: null,
initialize: function() {
this.callSuper();
this.hide_dots = false;
this.hide_line_numbers = true;
},
draw: function() {
this.callSuper();
if (!this._has_data) return;
var circle_radius = this.dot_radius ||
this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 2.5), 7.0);
this._clip_value_if_greater_than(this._columns / (this._norm_data[0][this.klass.DATA_VALUES_INDEX].length * 4), 3.0);
var level;
if (this._norm_baseline !== undefined) {
// this._d.stroke_dasharray(10, 20);
}
if (data_point === undefined) return;
}, this);
}, this);
},
// the lines connecting in the center, with the first line vertical
_draw_line_markers: function() {
if (this.hide_line_markers) return;
// have to do this here (AGAIN)... see draw() in this class
// because this funtion is called before the @radius, @center_x and @center_y are set
var rad_pos, marker_label;
// Draw horizontal line markers and annotate with numbers
this._d.line(this._center_x, this._center_y, this._center_x + Math.sin(rad_pos) * this._radius, this._center_y - Math.cos(rad_pos) * this._radius);
this._draw_label(this._center_x, this._center_y, rad_pos * 360 / (2 * Math.PI), this._radius, marker_label);
}
},
var r_offset = 1.1,
// Draw label
}
});
// Here's how to make a Pie graph:
//
// g = new Bluff.Pie('canvasId');
// g.title = "Visual Pie Graph Test";
// g.data('Fries', 20);
// g.data('Hamburgers', 50);
// g.draw();
//
// To control where the pie chart starts creating slices, use #zero_degree.
extend: {
TEXT_OFFSET_PERCENTAGE: 0.08
},
// Can be used to make the pie start cutting slices at the top (-90.0)
// or at another angle. Default is 0.0, which starts at 3 o'clock.
zero_degreee: null,
// Do not show labels for slices that are less than this percent. Use 0 to always show all labels.
hide_labels_less_than: null,
initialize_ivars: function() {
this.callSuper();
this.zero_degree = 0.0;
this.hide_labels_less_than = 0.0;
},
draw: function() {
this.hide_line_markers = true;
this.callSuper();
if (!this._has_data) return;
var diameter = this._graph_height,
total_sum = this._sums_for_pie(),
prev_degrees = this.zero_degree,
// Use full data since we can easily calculate percentages
// Gruff uses ellipse() here, but canvas doesn't seem to support it.
// circle() is fine for our purposes here.
prev_degrees, prev_degrees + current_degrees + 0.5); // <= +0.5 'fudge factor' gets rid of the ugly gaps
if (label_val >= this.hide_labels_less_than) {
data_row, i);
}
}
}, this);
// TODO debug a circle where the text is drawn...
},
// Labels are drawn around a slightly wider ellipse to give room for
// labels on the left and right.
// TODO Don't use so many hard-coded numbers
// Draw label
amount, i);
},
_sums_for_pie: function() {
var total_sum = 0;
}, this);
return total_sum;
}
});
// Graph with individual horizontal bars instead of vertical bars.
// Spacing factor applied between bars
bar_spacing: 0.9,
draw: function() {
this.has_left_labels = true;
this.callSuper();
if (!this._has_data) return;
this._draw_bars();
},
_draw_bars: function() {
// Using the original calcs from the stacked bar chart
// to get the difference between
// part of the bart chart we wish to stack.
var temp1 = this._graph_left + (this._graph_width - data_point * this._graph_width - height[point_index]),
left_y = this._graph_top + (this._bars_width * point_index) + (this._bar_width * row_index) + padding,
// Calculate center based on bar_width and current row
}, this)
}, this);
},
// Instead of base class version, draws vertical background lines and label
_draw_line_markers: function() {
if (this.hide_line_markers) return;
this._d.stroke_antialias = false;
// Draw horizontal line markers and annotate with numbers
var number_of_lines = 5;
// TODO Round maximum marker value to a round number like 100, 0.1, 0.5, etc.
if (!this.hide_line_numbers) {
// TODO Center text over line
this._d.annotate_scaled(
0, 0, // Width of box to draw text in
}
}
},
// Draw on the Y axis instead of the X
this._labels_seen[index] = true;
}
}
});
// Experimental!!! See also the Net graph.
//
// Submitted by Kevin Clark http://glu.ttono.us/
// Hide all text
hide_text: null,
hide_axes: null,
transparent_background: null,
this._max_value = max_value;
this.hide_legend = true;
},
draw: function() {
this.hide_line_markers = true;
this.callSuper();
if (!this._has_data) return;
// Setup basic positioning
var diameter = this._graph_height,
var total_sum = this._sums_for_spider(),
prev_degrees = 0.0,
current_angle = 0.0;
// Draw axes
// Draw polygon
},
_normalize_points: function(value) {
return value * this._unit_length;
},
// Draw label
x, y,
},
if (this.hide_axes) return;
var current_angle = 0.0;
if (!this.hide_text) this._draw_label(center_x, center_y, current_angle, radius, data_row[this.klass.DATA_LABEL_INDEX]);
}, this);
},
var points = [],
current_angle = 0.0;
points.push(center_x + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.cos(current_angle));
points.push(center_y + this._normalize_points(data_row[this.klass.DATA_VALUES_INDEX][0]) * Math.sin(current_angle));
}, this);
},
_sums_for_spider: function() {
var sum = 0.0;
}, this);
return sum;
}
});
// Used by StackedBar and child classes.
// Get sum of each stack
_get_maximum_by_stack: function() {
var max_hash = {};
max_hash[i] += data_point;
}, this);
}, this);
// this.maximum_value = 0;
}
this.minimum_value = 0;
}
});
last_series_goes_on_bottom: null,
draw: function() {
this._get_maximum_by_stack();
this.callSuper();
if (!this._has_data) return;
var data_points = null;
var prev_data_points = data_points;
data_points = [];
// Use incremented x and scaled y
var new_y = this._graph_top + (this._graph_height - data_point * this._graph_height - height[index]);
}, this);
var poly_points, i, n;
if (prev_data_points) {
}
} else {
}
}, this);
}
});
// Spacing factor applied between bars
bar_spacing: 0.9,
// Draws a bar graph, but multiple sets are stacked on top of each other.
draw: function() {
this._get_maximum_by_stack();
this.callSuper();
if (!this._has_data) return;
// Calculate center based on bar_width and current row
var label_center = this._graph_left + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
if (data_point == 0) return;
// Use incremented x and scaled y
data_point * this._graph_height -
// update the total height of the current stacked bar
}, this);
}, this);
}
});
// A special bar graph that shows a single dataset as a set of
// stacked bars. The bottom bar shows the running total and
// the top bar shows the new value being added to the array.
draw: function() {
var accumulator_array = [],
index = 0,
increment_array = [];
index += 1;
}, this);
this.callSuper();
}
});
// New gruff graph type added to enable sideways stacking bar charts
// (basically looks like a x/y flip of a standard stacking bar chart)
//
// alun.eyre@googlemail.com
// Spacing factor applied between bars
bar_spacing: 0.9,
draw: function() {
this.has_left_labels = true;
this._get_maximum_by_stack();
this.callSuper();
},
_draw_bars: function() {
// using the original calcs from the stacked bar chart to get the difference between
// part of the bart chart we wish to stack.
data_point * this._graph_width -
// Calculate center based on bar_width and current row
var label_center = this._graph_top + (this._bar_width * point_index) + (this._bar_width * this.bar_spacing / 2.0);
}, this);
}, this);
},
},
var sum = 0;
}, this);
return sum;
}
});
hide_mini_legend: false,
// The canvas needs to be bigger so we can put the legend beneath it.
_expand_canvas_for_vertical_legend: function() {
if (this.hide_mini_legend) return;
}, this);
var legend_height = this._scale_fontsize(
this.top_margin + this.bottom_margin);
this._original_rows = this._raw_rows;
this._original_columns = this._raw_columns;
switch (this.legend_position) {
case 'right':
break;
default:
this._rows += legend_height;
break;
}
this._render_background();
},
_calculate_line_height: function() {
},
_calculate_legend_width: function() {
var width = 0;
}, this);
},
// Draw the legend beneath the existing graph.
_draw_vertical_legend: function() {
if (this.hide_mini_legend) return;
legend_square_margin = 10.0,
legend_left_margin = 100.0,
legend_top_margin = 40.0;
// May fix legend drawing problem at small sizes
switch (this.legend_position) {
case 'right':
break;
default:
break;
}
this._debug(function() {
});
// Draw label
// Now draw box with color of this dataset
current_y_offset += this._calculate_line_height();
}, this);
this._color_index = 0;
},
// Shorten long labels so they will fit on the canvas.
_truncate_legend_label: function(label) {
var truncated_label = String(label);
while (this._calculate_width(this._scale_fontsize(this.legend_font_size), truncated_label) > (this._columns - this.legend_left_margin - this.right_margin) && (truncated_label.length > 1))
}
});
// Makes a small bar graph suitable for display at 200px or even smaller.
//
initialize_ivars: function() {
this.callSuper();
this.hide_legend = true;
this.hide_title = true;
this.hide_line_numbers = true;
this.marker_font_size = 50.0;
this.minimum_value = 0.0;
this.maximum_value = 0.0;
this.legend_font_size = 60.0;
},
draw: function() {
this.callSuper();
this._draw_vertical_legend();
}
});
// Makes a small pie graph suitable for display at 200px or even smaller.
//
initialize_ivars: function() {
this.callSuper();
this.hide_legend = true;
this.hide_title = true;
this.hide_line_numbers = true;
this.marker_font_size = 60.0;
this.legend_font_size = 60.0;
},
draw: function() {
this.callSuper();
this._draw_vertical_legend();
}
});
// Makes a small pie graph suitable for display at 200px or even smaller.
//
initialize_ivars: function() {
this.callSuper();
this.hide_legend = true;
this.hide_title = true;
this.hide_line_numbers = true;
this.marker_font_size = 50.0;
this.legend_font_size = 50.0;
},
draw: function() {
this.callSuper();
this._draw_vertical_legend();
}
});
extend: {
WRAPPER_CLASS: 'bluff-wrapper',
TEXT_CLASS: 'bluff-text',
TARGET_CLASS: 'bluff-tooltip-target'
},
font: 'Arial, Helvetica, Verdana, sans-serif',
gravity: 'north',
initialize: function(canvasId) {
},
},
caps_height: function(font_size) {
this._remove_node(X);
return height;
},
this._remove_node(element);
return width;
},
get_type_metrics: function(text) {
this._remove_node(node);
return size;
},
while (i--) {
this._remove_node(children[i]);
}
}
},
push: function() {
},
pop: function() {
},
},
},
},
});
});
return target;
},
this._ctx.moveTo(this._sx * (origin_x + radius * Math.cos(beta)), this._sy * (origin_y + radius * Math.sin(beta)));
this._ctx.lineTo(this._sx * (origin_x + radius * Math.cos(alpha)), this._sy * (origin_y + radius * Math.sin(alpha)));
}
this._ctx.arc(this._sx * origin_x, this._sy * origin_y, this._sx * radius, alpha, beta, false); // draw it clockwise
},
},
}
},
var temp;
try {
} catch (e) {}
try {
if (this.stroke !== 'transparent')
} catch (e) {}
},
switch (this.gravity) {
case 'west': return 0;
case 'east': return width - w;
case 'north': case 'south': case 'center':
return (width - w) / 2;
}
},
switch (this.gravity) {
case 'north': return 0;
case 'south': return height - h;
case 'west': case 'east': case 'center':
return (height - h) / 2;
}
},
_text_container: function() {
return wrapper;
},
return text;
},
_text_node: function(content) {
return div;
},
_remove_node: function(node) {
},
_element_size: function(element) {
}
});
// DOM event module, adapted from Prototype
// Copyright (c) 2005-2008 Sam Stephenson
_cache: [],
};
if (element.addEventListener)
else
},
stopObserving: function(element) {
else
});
},
var results = [];
});
return results;
},
if (!event) return false;
event._extendedByBluff = true;
return event;
},
return {
};
}
};
});
LEFT_OFFSET: 20,
TOP_OFFSET: -6,
DATA_LENGTH: 8,
CLASS_NAME: 'bluff-tooltip',
setup: function() {
this.hide();
}, this);
},
},
hide: function() {
}
});
: table;
},
// Get array of data series from the table
get_data: function() {
return this._data;
},
// Get set of axis labels to use for the graph
get_labels: function() {
return this._labels;
},
// Get the title from the table's caption
get_title: function() {
return this._title;
},
// Return series number i
get_series: function(i) {
},
// Gather data by reading from the table
_read: function() {
this._data = [];
this._labels = {};
this._row_headings = [];
this._col_headings = [];
this._skip_rows = [];
this._skip_cols = [];
this._cleanup();
this._orient();
}, this);
}, this);
},
// Walk the table's DOM tree
},
// Read a single DOM node from the table
case 'TR':
this._row += 1;
this._col = 0;
break;
case 'TD':
this._has_data = true;
this._col += 1;
if (content === null) {
this.get_series(x).points[y] = null;
} else {
}
break;
case 'TH':
this._col += 1;
}
else
break;
case 'CAPTION':
break;
}
},
while (i--) {
}
return false;
},
_cleanup: function() {
while (i--) {
index = this._skip_cols[i];
if (index <= this._col_offset) continue;
if (index >= this._col_offset)
}
while (i--) {
index = this._skip_rows[i];
if (index <= this._row_offset) continue;
if (index >= this._row_offset)
}, this);
}
},
_orient: function() {
switch (this._orientation) {
case 'auto':
this._transpose();
}
break;
case 'rows':
this._transpose();
break;
}
},
// Transpose data in memory
_transpose: function() {
this._data = [];
}, this);
}, this);
tmp = this._row_headings;
this._row_headings = this._col_headings;
this._col_headings = tmp;
tmp = this._row_offset;
this._row_offset = this._col_offset;
this._col_offset = tmp;
},
// Remove HTML from a string
_strip_tags: function(string) {
},
extend: {
}, this);
}
})
}
});