/*
FILE ARCHIVED ON 22:57:02 Sep 27, 2012 AND RETRIEVED FROM THE
AN OPENWAYBACK INSTANCE ON 10:43:27 Oct 17, 2024.
JAVASCRIPT APPENDED BY OPENWAYBACK, COPYRIGHT INTERNET ARCHIVE.
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
SECTION 108(a)(3)).
*/
var leafHandlerLoaded = void 0;
var rootHandlerLoaded = void 0;
$(document).ready(function(){
/* SD 2012-03-13 The dropdowns had an onchange event
* that redirected the page to selected value. If you hit
* the browser back button the page went back to the original
* page, except for the dropdown that stayed the same. This
* was because the browser caches the form values; particularly IE.
* In order to avoid caching of the form elements we shall..
* 1. remove the onchange attributes on the dropdown
* 2. transfer the onchange to a JQuery onchange event
* 3. When an onchange is triggered, capture the new selected value
* 4. Revert the dropdowns to the original values, then
* 5. redirect the page to the newly selected values.
* This is an ugly solution. It could have been put in the
* meta tags in the original html files.
*/
if($('select[name="Drop1"]').length > 0)
{
/*
*SD 2012-03-13 The following 5 lines may not be necessary, but they do make the html valid-html.
*/
var dropdown = $('select[name="Drop1"]').html();
dropdown = dropdown.replace('SELECTED=""','selected="selected"');
dropdown = dropdown.replace('SELECTED','selected="selected"');
dropdown = dropdown.replace('selected=""','selected="selected"');
$('select[name="Drop1"]').html(dropdown);
//Drop1
$('select[name="Drop1"]').removeAttr('onchange');
var originalSelection = $('select[name="Drop1"] option:selected').attr('value');
$('select[name="Drop1"]').change(function(){
var currentSelection = $(this).attr('value');
$('select[name="Drop1"]').find('option[value="'+originalSelection+'"]').attr('selected','selected');
window.location = currentSelection;
return false;
});
}
//DropF
if($('select[name="DropF"]').length > 0)
{
$('select[name="DropF"]').removeAttr('onchange');
var originalSelectionF = $('select[name="DropF"] option:selected').attr('value');
$('select[name="DropF"]').change(function(){
var currentSelectionF = $(this).attr('value');
$('select[name="DropF"]').find('option[value="'+originalSelectionF+'"]').attr('selected','selected');
window.location = currentSelectionF;
return false;
});
}
});
(function(){
/**
* EIA Highcharts Theme v1.1.4 2012-02-28
*
* Created by Shivan Computers Corporation on behalf
* of the U.S. Energy Information Administration:
* Author : Ryan Lynch (Ryan.Lynch@eia.gov)
**/
(function(){
///////////////////////
// Private Variables //
///////////////////////
// Shortcuts
var HC = Highcharts,
Chart = HC.Chart,
StockChart = HC.StockChart,
extend = HC.extend,
each = HC.each,
map = HC.map,
// For compatability with Highcharts and Highstocks,
// splat is undefined in the former
splat = HC.splat ||
function (obj) {
if (!$.isArray(obj)) {
obj = [obj];
}
return obj;
},
merge = HC.merge,
max = Math.max,
min = Math.min,
pow = Math.pow,
abs = Math.abs,
doc = document,
win = window,
// Function for prototypal inheritence, from
// https://webarchive.library.unt.edu/web/20120927225702/http://webreflection.blogspot.com/2010/02/javascript-override-patterns.html
chain = (function () {
// recycled empty callback
// used to avoid constructors execution
// while extending
function proto() {}
// chain function
return function ($prototype) {
// associate the object/prototype
// to the __proto__.prototype
proto.prototype = $prototype;
// and create a chain
return new proto;
};
}()),
isIE = navigator.userAgent.match(/MSIE/) != null,
// References for caching default x and y axis options
defaultYAxisOptions,
defaultXAxisOptions,
// Flag to determine if an axis redraw is needed
axisLabelRedraw;
// We extend Highcharts with the colors and logo enumerations
// first so we can reference them later
extend(HC, {
///////////////////
// Theme Version //
///////////////////
eia_theme_version : '1.1.3',
///////////////////////
// Logo Enumerations //
///////////////////////
logos:{
none : 0,
eia : 1,
reuters : 2
},
////////////////
// EIA Colors //
////////////////
eia_blue : '#0096d7', //Blue
eia_tan : '#bd732a', //Tan
eia_green : '#5D9732', //Green
eia_yellow : '#ffc702', //Yellow
eia_red : '#a33340', //Red
eia_brown : '#403203', //Brown
eia_lt_blue : '#76d5ff', //Light Blue
eia_lt_green : '#bed5ad', //Light Green
eia_dk_red : '#410e14', //Dark Red
eia_grey : '#666666', //Grey
eia_dk_blue : '#003953', //Dark Blue
eia_dk_green : '#2a4b11', //Dark Green
eia_dk_grey : '#333333', //Dark Grey
/////////////////////////////////
// EIA Plotlines and Plotbands //
/////////////////////////////////
eia_projections_line: {
color: '#888',
dashStyle: 'Dash',
width : 1,
zIndex: 3
// value: {projection start time / category}
},
eia_projections_label: {
color: '#888',
fontWeight: 'bold'
},
// For use where the yAxis min is non-zero
eia_zero_axis_line : {
color: '#000',
dashStyle: 'Solid',
zIndex:1,
width: 1,
value : 0
}
});
extend(HC, {
///////////////
// EIA Theme //
///////////////
eiaTheme : {
chart: {
animation:!isIE, // Turn of animation in IE to improve performance
plotBackgroundColor: 'rgba(255, 255, 255, .1)',
defaultSeriesType: 'line',
spacingBottom:20,
// Determies the logo displayed on the chart. See logo enumerations
// above
logo:HC.logos.eia,
events:{
redraw:function(){
onRedraw.apply(this, arguments);
}
},
style: {
fontFamily: 'Arial, Verdana, Helvetica, sans-serif'
},
lineUpYAxisZeros : false,
borderColor : '#ffffff'
},
colors: [
HC.eia_blue,
HC.eia_tan,
HC.eia_green,
HC.eia_yellow,
HC.eia_red,
HC.eia_brown,
HC.eia_lt_blue,
HC.eia_lt_green,
HC.eia_dk_red,
HC.eia_grey,
HC.eia_dk_blue,
HC.eia_dk_green,
HC.eia_dk_grey
],
title: {
align: 'left',
margin: 35,
style: {
color: 'black',
fontSize: '16px',
fontWeight: 'bold'
}
},
subtitle: {
style: {
color: '#333',
fontSize: '12px'
},
align: 'left',
floating: true,
y:40
},
credits: {
style: {
color: '#888',
fontSize: '11px'
},
text: 'Source: U.S. Energy Information Administration',
href: 'https://webarchive.library.unt.edu/web/20120927225702/http://www.eia.gov',
position: {
align: 'left',
verticalAlign: 'bottom',
x:15
}
},
labels: {
style: {
fontSize: '12px',
color: '#333'
}
},
xAxis: {
labels: {
style: {
color: 'black'
}
},
endOnTick: false,
startOnTick: false,
tickColor: '#000',
lineColor: '#000',
title: {
style: {
color: '#888',
fontWeight: 'bold',
fontSize: '12px'
}
},
dateTimeLabelFormats : {
day: '%e. %b, %y',
week: '%e. %b, %y',
month: '%b \'%y',
year: '%Y'
}
},
yAxis: {
labels: {
style: {
color: '#333'
// formatter : see preprocessChart::preprocessAxis()
}
},
lineColor: '#A0A0A0',
minorTickInterval: null,
tickColor: '#A0A0A0',
//zero based axis is the EIA default. In the future, it would
// be useful to preprocess the data and determine if the chart
// contains negative values, and override this default when
// neccesary.
min: 0,
tickWidth: 0,
title: {
align:'above',
style: {
color: '#888',
fontWeight: 'bold',
fontSize: '12px'
}
}
},
tooltip: {
backgroundColor: 'rgba(255, 255, 255, 0.75)',
style: {
fontSize: '12px',
color: '#000000',
padding: 5
},
formatter:function(){
// We wrap this in a function, because we haven't defined
// the universal tooltip function yet
return HC.universalTooltipFormatter.apply(this, arguments);
}
},
plotOptions: {
series: {
animation:!isIE, // Turn of animation in IE to improve performance
tooltip:{
// Determines whether or not to display the name of the series
// in the tooltip. As with all plot options, this can be
// applied to the individual series as well.
showName: true
// The precision for rounding numbers in the tooltip.
// precision:0
}
},
line: {
shadow:0,
lineWidth: 2,
borderWidth:0,
dataLabels: {
color: '#333'
},
marker: {
enabled: false,
states: {
hover: {
enabled: true,
radius: 5
}
}
}
},
area: {
borderWidth: 0,
shadow: false,
lineWidth: 0,
marker: {
enabled: false,
states: {
hover: {
enabled: true,
radius: 4
}
}
}
},
spline: {
marker: {
lineColor: '#333'
}
},
column: {
borderWidth: 0,
shadow: false,
lineWidth: 0
},
bar: {
shadow: false
},
pie: {
allowPointSelect: true,
shadow: false,
dataLabels: {
style: {
fontSize: '12px',
color: 'red'
}
}
},
scatter: {
marker: {
radius: 3,
symbol: 'circle',
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
states: {
hover: {
marker: {
radius: 3,
enabled: true
}
}
}
}
},
legend: {
floating: false,
borderWidth: 1,
borderColor: '#e4e4e4',
backgroundColor: '#f1f1f1',
borderRadius: 0,
symbolPadding: 5,
itemStyle: {
textDecoration: 'none'
},
itemHoverStyle: {
color: '#189bd7',
textDecoration: 'underline'
},
itemHiddenStyle: {
color: '#CCC'
}
},
exporting: {
enableImages:true,
buttons:{
exportButton:{
menuItems: [{
text: 'Download Image',
onclick: function(){
this.exportChart(
{
url : '/global/scripts/jquery/highcharts/exporting-server/index.cfm'
},
HC.generateEIAExportOptions.apply(this)
);
}
},
/* commented out due to problem incorporating images such as logos. The other formats bake it in. Added final null button
{
text: 'Download SVG',
onclick: function(){
this.exportChart(
{type: 'image/svg+xml'},
HC.generateEIAExportOptions.apply(this)
);
}
}, */
{
text: 'Download PDF',
onclick: function(){
this.exportChart(
{
url : '/global/scripts/jquery/highcharts/exporting-server/index.cfm',
type: 'application/pdf'
},
HC.generateEIAExportOptions.apply(this)
);
}
},
{
text: 'Download Data',
onclick: function(){
this.generateCSV()
}
},
null
]
},
printButton:{
onclick:function(){
printChart.apply(this);
}
}
}
}
},
// X Value Types Labels, and Zooms
// These correspond to the indices of the label
// and zoom arrays. They also give oridnality
// to the various period types.
yTypes : {
mixed : 0,
positive : 1
},
xTypes: {
category:0,
annual:1,
quaterly:2, // Not currently implemented
monthly:3,
weekly:4,
daily:5
},
// Labels used in the csv export
csvXLabels: [
'Category',
'Year',
'Quarter',
'Month',
'Week of',
'Day'
],
// Labels used in the tooltip
tooltipXLabels: [
'',
'Year',
'Quarter',
'Month',
'Week of',
'Day'
],
// Max zooms for the various xTypes
xMaxZooms : [
1, // 1 Categories
126144E6, // 4 years
31536E6, // 1 Year
107136E5, // 4 months
24192E5, // 4 weeks
6048E5 // 1 Week
],
// X Value Parser
/**
* Parses X Values based on the passed x value type
**/
parseXValue : function(xType, xValue){
var ret;
switch(xType)
{
case HC.xTypes.annual:
ret = HC.dateFormat('%Y', xValue);
break;
case HC.xTypes.monthly:
ret = HC.dateFormat('%b %Y', xValue);
break;
case HC.xTypes.weekly:
ret = HC.dateFormat('%m/%e/%Y', xValue);
break;
case HC.xTypes.daily:
ret = HC.dateFormat('%m/%e/%Y', xValue);
break;
default:
ret = xValue;
break;
}
return ret;
},
// Universal Tooltip function
/**
* Returns tooltip strings for non-shared and shared tooltips.
**/
universalTooltipFormatter : function(){
var ret = '';
if(this.point != void 0){ // shared == false
var xString,
yString,
nameString,
series = this.series,
chart = this.series.chart,
seriesOpts = series.options,
tipOpts = seriesOpts.tooltip,
chartOpts = chart.options
isPie = chartOpts.chart.defaultSeriesType == 'pie',
isDateTime = isPie ? false : chartOpts.xAxis.type == 'datetime';
seriesName = series.name,
// If we haven't determined xTypes, then treat it as a category axis
xType = series.options.xType,
xLabel = isPie ? '' : series.xAxis.options.categoryTitle ||
series.xAxis.options.title.text || HC.tooltipXLabels[xType],
yLabel = isPie ? '' : series.yAxis.options.title.text || '';
if(!isPie){
nameString = seriesName;
xString = (xLabel.length > 0 ? xLabel + ' : ' : '') +
HC.parseXValue(xType,
// used by the seasonal analysis to display a different date in the tooltip
this.point.options && this.point.options.tooltipX !== void 0 ? this.point.options.tooltipX : this.x
);
yString = series.options.compare != null ?
HC.numberFormat(this.point.change, tipOpts.precision || void 0) + ' ' + yLabel:
HC.numberFormat(this.y, tipOpts.precision || void 0) + ' ' + yLabel;
}
else{
nameString = this.point.name;
xString = xLabel;
yString = this.y;
}
ret = (series.options.tooltip.showName ? '' + nameString + ' ' : '') +
xString + (xString != '' ? ' ' : '') + yString;
}
else{ // shared == true
var xString,
yString = '',
nameString, i,
series, point, yLabel, seriesOpts, tipOpts
points = this.points,
chart = points[0].series.chart,
isPie = chart.options.chart.defaultSeriesType == 'pie',
isDateTime = isPie ? false : chart.options.xAxis.type == 'datetime',
xType = chart.options.maxXType,
xLabel = HC.tooltipXLabels[xType];
if(!isPie){
xString = (xLabel != '' ? xLabel + ' : ' : '') +
HC.parseXValue(xType, this.x);
ret += xString + ' ';
for(i=0; i' + nameString + '' + ' ' + yString;
if(i < points.length)
ret += ' '
}
}
else{
for(i=0; i' + nameString + '' + ' ' + yString;
if(i < points.length)
ret += ''
}
}
}
return ret;
},
/**
* Currently, this function doesn't do anything. It is stubbed here for later
* use. For example, we may want to change some font sizes to account for
* different fonts on the exporting server.
**/
generateEIAExportOptions : function(){
var chart = this,
ret = {};
return ret;
},
/**
* Overrides the default number formatter so that a null value for decimals
* returns the number formatted without rounding/truncation, and a null value
* for number returns an empty string instead of 0.00.
**/
numberFormat : function(number, decimals, decPoint, thousandsSep) {
if(number !== null && number !== void 0 && !isNaN(number)){
var lang = HC.getOptions().lang,
// https://webarchive.library.unt.edu/web/20120927225702/http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_number_format/
n = number,
c = isNaN(decimals = Math.abs(decimals)) ?
// Here is the difference with the highcharts implementation, we default to the number of
// existing decimal places, they default to 2 when decimals is not defined. Number#toFixed
// can only work with a maximum of 20 decimal places, so we check and min it.
Math.min(n.toString().match(/\d+\.?(\d*)/)[1].length, 20) :
decimals,
d = decPoint === undefined ? lang.decimalPoint : decPoint,
t = thousandsSep === undefined ? lang.thousandsSep : thousandsSep,
s = n < 0 ? "-" : "",
i = String(parseInt(n = Math.abs(+n || 0).toFixed(c))),
j = i.length > 3 ? i.length % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
(c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
else
return '';
},
/**
* Alternate constructor for EIA Highcharts. This function inherits all the
* properties and methods of the super Highcharts.Chart, and takes the same
* arguments
*
* @param {Object} options : The Chart options
* @param {Function} callback : Chart onload callback function
**/
Chart : constructorGenerator(Chart, {}),
/**
* Alternate constructor for EIA Highstocks charts. This function inherits
* all the properties and methods of the super Highcharts.StockChart, and
* takes the same arguments
*
* @param {Object} options : The StockChart options
* @param {Function} callback : StockChart onload callback function
**/
StockChart : HC.StockChart ? constructorGenerator(StockChart, {
xAxis:{
type : 'dateTime'
}
})
: void 0
});
function constructorGenerator(originalConstructor, forcedOptions){
var ret = function(options, callback){
var chart = this,
forcedOptions = forcedOptions || {};
isPie = options.chart.defaultSeriesType != void 0 && options.chart.defaultSeriesType == 'pie';
ops = jQuery.extend(true, {}, HC.getOptions(), options);
// preprocess xAxis options
ops.xAxis = map(splat(ops.xAxis || {}), function (xAxisOptions) {
return merge(defaultXAxisOptions, xAxisOptions, forcedOptions.xAxis || {});
});
// preprocess yAxisOptions
ops.yAxis = map(splat(ops.yAxis || {}), function (yAxisOptions) {
opposite = yAxisOptions.opposite;
return merge(defaultYAxisOptions, yAxisOptions, forcedOptions.yAxis || {});
});
// Preprocess the options common to pie and non-pie charts
preprocessLogoOptions(ops);
preprocessContainers(ops);
if(isPie)
chart = processPieChart.call(chart, originalConstructor, ops, callback);
else
chart = processNonPieChart.call(chart, originalConstructor, ops, callback);
return chart;
}
ret.prototype = chain(originalConstructor.prototype);
return ret;
}
///////////////////////////////
// Reset and Title Functions //
///////////////////////////////
extend(Chart.prototype, {
/**
* Resets the zoom for the chart. The code is the same as the callback
* for the "Reset Zoom" control that appears on the chart when zoomed.
**/
resetZoom: function(){
var chart = this, axes = chart.xAxis;
each(axes, function (axis) {
axis.setExtremes(null, null, false);
});
},
/**
* Resets the chart to contain only the original series that existed at
* creation time. Set redraw to true to redraw the chart after adding
* the series.
**/
resetSeries: function(redraw){
var chart = this, i, s, remArr = [];
if(redraw === void 0) redraw = true;
chart.removeAllSeries(redraw);
for(i=0; i]*>.*?<\s*\/\2\s*>|<\s*\/[^>]+>|[^<>\s]+|(<[^>]+>))/g;
// We add an extra blank word to the array to ensure that the loop
// one more time if the last word is on it's own line.
words = text.match(rWords).concat('');
while(k < words.length){
k = lastBreak;
tmpLine = '';
do{
if(e){
// We get the line height before adding the new word
lineHeight = e.getBBox().height;
e.destroy();
}
word = words[k];
tmpLine += word + ' ';
// Prerender the text
e = renderer.text(tmpLine, -9999, -9999).css(style).add();
k++;
if(word.match(/<\s*\/?\s*br\/?\s*>/)){
// END OF LINE
words.splice(k-1, 1);
break;
}
boxWidth = e.getBBox().width;
}
while(boxWidth < textWidth && k < words.length)
// Where we have a realllly big word, or one word
if(k - 1 == lastBreak){
// we get the line height here, because in
// this case the above loop ran only once.
lineHeight = e.element.offsetHeight;
line = words[k-1];
lastBreak = k;
}
else{
// Join the words with spaces, then remove spaces around html tags to prevent
// extra space from being rendered when they are split into seperate spans
line = words.slice(lastBreak, k-1).join(' ')
// For IE, Highcharts renders text as regular HTML text, so we want to
// preserve the spaces. For SVG text, we want to elimate them, since
// there will already be a space between tspan elements.
if(!isIE)
line = line.replace(/\s+\s+/g, '>');
lastBreak = k - 1;
}
// Push the line into the collection
lines.push({
line : line,
lineHeight : lineHeight
});
// Clean up
e.destroy();
e = null;
}
return lines;
}
});
Chart.prototype.callbacks.push(function(){
var oldSetTitle = this.setTitle;
this.adjustTitleAlignment(true, true);
/**
* Overrides the setTitle function to account for spacing adjustments
**/
this.setTitle = function(title, subtitle){
oldSetTitle.call(this, title, subtitle);
if(title)
this.options.title = merge(this.options.title, title);
if(subtitle)
this.options.subtitle = merge(this.options.subtitle, subtitle);
this.adjustTitleAlignment(title, subtitle);
};
});
/////////////////////
// Private Methods //
/////////////////////
/**
* Processes pie charts options to apply various styles and
* initializes the chart object.
**/
function processPieChart(chartConstructor, ops, callback){
var chart = this;
// Wait, this function does nothing!! This may change
// in the future...
chart = chartConstructor.call(chart, ops, callback) || chart;
return chart;
}
/**
* Preprocess non-pie chart options to apply various styles
* and initializes the chart object.
**/
function processNonPieChart(chartConstructor, ops, callback)
{
var chart = this, renderTo = ops.chart.renderTo,
container = typeof(renderTo) == "string" ? $('#' + renderTo) : $(renderTo),
spacingTopAdjust = 0,
titleAdjust = 0,
i, xAndYTypes, assocAxis,
chart, xAxis,
yAxisOptions = $.isArray(ops.yAxis) ? ops.yAxis : [ops.yAxis],
dummyChart = {
options : ops,
// Copy of Highcarts ChartCounter object
counters : {
wrapColor: function (length) {
if (this.color >= length) {
this.color = 0;
}
},
wrapSymbol: function (length) {
if (this.symbol >= length) {
this.symbol = 0;
}
},
color:0,
symbol:0
},
series : [],
// Added for compatibility with Highstocks Series.bindAxis method
xAxis : [],
yAxis : []
},
// create a sandbox and a renderer to prerender the axis
// titles and chart title
sandbox = $('')
.appendTo('body').css({position:'absolute',top:-9999}),
sandboxRenderer = new HC.Renderer(sandbox[0], 0, 0);
// For some reason this set of operations breaks the export routine
// Have to look into this further at a later time. Besides, these
// options don't really need to be processed for exported charts.
if(!ops.chart.forExport){
// Initialize the series on the dummy chart
// object and determine the series xTYpes
if(ops.series) each(ops.series, function(seriesOps){
var serie = new HC.Series;
// Series.init modifies the series options, so we
// clone the series options with $.extend when
// creating the fake series here
serie.init(dummyChart, $.extend(true, {}, seriesOps));
dummyChart.series.push(serie);
xAndYTypes = determineSeriesXAndYType.call(dummyChart, serie);
seriesOps.xType = serie.options.xType =
seriesOps.xType !== void 0 ? seriesOps.xType : xAndYTypes.xType;
if(xAndYTypes.yType === HC.yTypes.mixed){
assocAxis = yAxisOptions[seriesOps.yAxis !== void 0 ? seriesOps.yAxis : 0];
// only set the min to null if the min in the options is zero or otherwise falsey
assocAxis.min = assocAxis.min ? assocAxis.min : null;
}
});
// Determine the min and max xType
ops.minXType = determineMaxMinXType.call(dummyChart, min);
ops.maxXType = determineMaxMinXType.call(dummyChart, max);
ops.chart.zoomType = ops.chart.zoomType !== void 0 ? ops.chart.zoomType : determineZoomType.call(dummyChart);
// Set the max zoom to the maximum zoom for the
// Minimum xType. So if there is annual and monthly
// data, our max zoom will be the annual max zoom.
xAxis = splat(ops.xAxis)
xAxis[0].maxZoom = xAxis[0].maxZoom !== void 0 ? xAxis[0].maxZoom : HC.xMaxZooms[ops.minXType];
// Determine the appropriate zoom type
}
// Enable the crosshairs for shared tooltips
ops.tooltip.crosshairs = ops.tooltip.shared;
// Process the yAxis options
for(i=0; i').css({
height:'auto',
width:'auto'
}).addClass('outerChartContainer');
printContainer = $('').css({
height:'auto',
width:'auto'
}).addClass('printChartContainer');
// Set up the outer and print containers. We
// add the outer container before the container
// so that it will occupy it's index when we
// remove it and add it to the outer continer.
container.before(outerContainer);
printContainer.appendTo(outerContainer);
container.appendTo(printContainer);
}
options.chart.outerContainer = outerContainer[0];
options.chart.printContainer = printContainer[0];
options.chart.container = container[0];
}
}
/**
* Preprocesses the options for vertical axis objects. This function
* processes above axis titles, and applies the label formatter which
* formats labels with consistent precision. Note that the formatter
* will never decrease precision, because of the danger of an infinite
* loop. Sometimes this results in excess precision in the final
* lables if a higher precision was found on first render, or if the
* chart has been resized.
**/
function preprocessAxis(axisOptions, renderer){
var chart = this,
opts = jQuery.extend(
true,
{},
defaultYAxisOptions,
axisOptions
),
titleOpts = opts.title,
yAxisPrecision = 0,
newYAxisPrecision = 0,
titleSpan,
originalAlign = titleOpts.originalAlign || titleOpts.align.toLowerCase(),
spacingTopAdjust = 0;
if(originalAlign == 'above'){
// return if the text is undefined, null, or empty
if(titleOpts.text == void 0 || opts.text == ''){
// Set the align to middle so that we don't have
// any rendering issues, since 'above' is not
// actually a valid align
jQuery.extend(true, axisOptions, {
align:'middle',
originalAlign:'middle'
});
}
else{
titleSpan = renderer.text(
titleOpts.text,
0,
0
).attr({
rotation:0
})
.css(titleOpts.style).add();
var titleBox = titleSpan.getBBox();
// Extend the axis options with the highcharts options
// that will position the title above the axis
if(titleOpts.align == 'above')
jQuery.extend(true, axisOptions, {
title:{
margin: -1 * titleBox.width,
rotation: 0,
align:'high',
x:axisOptions.opposite ? titleBox.width : 0,
y:-10
}
});
spacingTopAdjust = titleBox.height;
}
}
// Store the original align so we can shift the yAxis title
// on export for above axis titles
jQuery.extend(true, axisOptions, {
title:{
originalAlign:originalAlign
}
});
if(!axisOptions.labels || !axisOptions.labels.formatter){
jQuery.extend(true, axisOptions, {
labels:{
// This function has to be defined in preprocessAxis because it
// needs to be applied to each axis, and because we store the
// yAxisPrecision in a reference scoped to that closure.
formatter : function() {
var ret = this.value.toString(),
decimalRegex = /\d+\.?(\d*)/;
if(decimalRegex.test(ret)){
// Determine The number of numeric characters
// after the decimal point.
newYAxisPrecision= Math.max(this.value.toString()
.match(decimalRegex)[1].length,
newYAxisPrecision);
// If we haven't defined a yAxisPrecision for this
// axis, then lets do it here.
if(yAxisPrecision === void 0)
yAxisPrecision = newYAxisPrecision;
// If this value has a greater precision than
// the one we've previously recorded, set the
// value on the chart and force a redraw.
if(this.isLast){
if(newYAxisPrecision != yAxisPrecision){
yAxisPrecision = newYAxisPrecision;
// Set the axisLabelRedraw flag so that the yAxis
// will be redrawn on load or on redraw
axisLabelRedraw = true;
}
newYAxisPrecision = 0;
ret = HC.numberFormat(this.value, yAxisPrecision,'.',',');
}
// Otherwise, round and format the number
else{
ret = HC.numberFormat(this.value, yAxisPrecision,'.',',');
}
}
return ret;
}
}
});
}
return spacingTopAdjust;
}
function preprocessChartTitle(titleOps, renderer, chartWidth){
var spacingTopAdjust = 0,
titleLines, titleBox;
if(titleOps || titleOps.text){
titleLines = Chart.prototype.splitText(titleOps.text, titleOps.style, chartWidth, renderer);
titleOps.text = $.map(titleLines, function(item){return item.line}).join(' ');
if(titleLines.length > 1){
for(i=1; i Year, Week > Month, etc.
**/
function determineMaxMinXType(checker){
var chart = this,
i, s, maxType, xType
;
for(i=0; i 1){
for(i = 0; i < chart.yAxis.length; i++){
axi = axis[i];
extremes = axi.getExtremes();
ratios[i] = {
min : minimum = Math.abs(extremes.min),
max : maximum = Math.abs(extremes.max),
axisLength : axisLength = maximum + minimum,
positiveRatio : Math.abs(maximum) / axisLength,
negativeRatio : Math.abs(minimum) / axisLength
};
}
for(i = 0; i < ratios.length; i++){
var positiveRatio = ratios[i].positiveRatio;
var negativeRatio = ratios[i].negativeRatio;
var ratioDiff = Math.abs(positiveRatio - negativeRatio);
if(!isNaN(positiveRatio) && !isNaN(negativeRatio)){
allPositive &= positiveRatio == 1;
allNegative &= negativeRatio == 1;
if(minimumRatioDiff === void 0 || ratioDiff < minimumRatioDiff){
minimumRatioDiff = ratioDiff;
optimumRatios = {
positiveRatio : positiveRatio,
negativeRatio : negativeRatio
}
}
}
}
if(minimumRatioDiff == 1 && (!allPositive && !allNegative)){
optimumRatios = {
positiveRatio : 0.5,
negativeRatio : 0.5
};
}
for(i=0; i= 0 ; k--)
if(cat < categories[k]) break;
categories.splice(k+1, 0, cat);
}
else categories.push(cat);
// Add it to the hash so we know we've processed it
categoriesHash[cat] = 1;
}
}
// "Constants"
var chart = this,
POST_URL = chart.options.exporting.csvOptions.postURL,
OVERRIDE_URL = chart.options.exporting.csvOptions.overrideURL,
//// CSV Characters
NULL_STRING = '--',
FIELD_DELIM_REGEXP = /,/g,
RECORD_DELIM_REGEXP = /\n/g,
//// Other REGEXP
HTML_TAG_REGEXP = /<[\/\w]+>/g,
FILE_CHAR_REGEXP = /[\?%\*:\|"\<\>\\,]/g,
PER_REGEXP = /\//g,
MULTI_SPACE_REGEXP = /\s+/g,
// Variables
i, j, k, cat, p, s, d, xTitle, propertiesHash, linkHeaders,
csvArr, headers, record, dataHash, input1, input2, dataStart,
xType, xAxisOps = splat(chart.options.xAxis)[0], keyHeaders
firstTime = true,
isDateTime = false,
categories = [],
dataHashes = {},
propertiesHashes = {},
categoriesHash = {},
hasSourceLink = false,
hasSourceKey = false,
chartTitle = 'chartData';
// If we have an override URL, then we change the window location and return
if(OVERRIDE_URL)
return window.location = OVERRIDE_URL;
// See if we have a chart title, if so, use for the file name
try{
if(chart.options.title.text !== void 0 && chart.options.title.text.length > 0)
chartTitle = chart.options.title.text
.replace(HTML_TAG_REGEXP, ' ')
.replace(FILE_CHAR_REGEXP, '')
.replace(PER_REGEXP, ' per ')
.replace(MULTI_SPACE_REGEXP, ' ');
if(chart.options.subtitle.text !== void 0 && chart.options.subtitle.text.length > 0)
chartTitle += ' (' + chart.options.subtitle.text
.replace(HTML_TAG_REGEXP, ' ')
.replace(FILE_CHAR_REGEXP, '')
.replace(PER_REGEXP, ' per ')
.replace(MULTI_SPACE_REGEXP, ' ') + ')';
}catch(e){/*DO NOTHING*/}
// See if we are dealing with a date time or a category axis
try{
isDateTime = xAxisOps.type == 'datetime';
}catch(e){/*DO NOTHING*/}
// See if we have an XAxis title, if so use for the date/category header
try{
if(
xAxisOps.title.text !== void 0 &&
xAxisOps.title.text.length > 0
) xTitle = xAxisOps.title.text;
}catch(e){/*DO NOTHING*/}
// Loop through the chart series
for(i=0; i pairs
if(!chart.options.navigator){
dataHash = dataHashes[s.name] = {};
// Store the sourceKey and
propertiesHashes[s.name] = {
sourceKey : s.options.sourceKey,
sourceLink : s.options.sourceLink
};
// We use this flag later to determine if we should add a
// row for source links in the csv file
hasSourceLink |= typeof propertiesHashes[s.name].sourceLink != 'undefined';
hasSourceKey |= typeof propertiesHashes[s.name].sourceKey != 'undefined';
for(j=0; j= 0 ; k--)
if(cat < categories[k]) break;
categories.splice(k+1, 0, cat);
}
else categories.push(cat);
// Add it to the hash so we know we've processed it
categoriesHash[cat] = 1;
}
}
}
else if(!chart.options.navigator.enabled || s.name != 'Navigator'){
dataHash = dataHashes[s.name] = {};
if(s.type == 'pie'){
for(j=0; j').val(JSON.stringify(csvArr));
input2 = $('').val(chartTitle);
jQuery('')
.append(input1).append(input2) .appendTo('body').submit().remove();
}
});
/////////////////////
// Export Override //
/////////////////////
extend(Chart.prototype,{
/**
* Add the export button to the chart. This overrides the addButton
* function found in the export module to add the buttons to a group,
* so they can be hidden when the chart is printed.
*/
addButton: function(options) {
var chart = this,
renderer = chart.renderer,
btnOptions = merge(chart.options.navigation.buttonOptions, options),
onclick = btnOptions.onclick,
menuItems = btnOptions.menuItems,
/*position = chart.getAlignment(btnOptions),
buttonLeft = position.x,
buttonTop = position.y,*/
buttonWidth = btnOptions.width,
buttonHeight = btnOptions.height,
box,
symbol,
button,
borderWidth = btnOptions.borderWidth,
boxAttr = {
stroke: btnOptions.borderColor
},
symbolAttr = {
stroke: btnOptions.symbolStroke,
fill: btnOptions.symbolFill
}
symbolSize = btnOptions.symbolSize || 12;
// Keeps references to the button elements
if (!chart.exportDivElements) {
chart.exportDivElements = [];
chart.exportSVGElements = [];
}
if (btnOptions.enabled === false) {
return;
}
if(!chart.buttonGroup)
chart.buttonGroup = renderer.g('buttonGroup').add();
// element to capture the click
function revert() {
symbol.attr(symbolAttr);
box.attr(boxAttr);
}
// the box border
box = renderer.rect(
0,
0,
buttonWidth,
buttonHeight,
btnOptions.borderRadius,
borderWidth
)
//.translate(buttonLeft, buttonTop) // to allow gradients
.align(btnOptions, true)
.attr(extend({
fill: btnOptions.backgroundColor,
'stroke-width': borderWidth,
zIndex: 19
}, boxAttr)).add(chart.buttonGroup);
// the invisible element to track the clicks
button = renderer.rect(
0,
0,
buttonWidth,
buttonHeight,
0
)
.align(btnOptions)
.attr({
fill: 'rgba(255, 255, 255, 0.001)',
title: HC.getOptions().lang[btnOptions._titleKey],
zIndex: 21
}).css({
cursor: 'pointer'
})
.on('mouseover', function() {
symbol.attr({
stroke: btnOptions.hoverSymbolStroke,
fill: btnOptions.hoverSymbolFill
});
box.attr({
stroke: btnOptions.hoverBorderColor
});
})
.on('mouseout', revert)
.on('click', revert)
.add(chart.buttonGroup);
//addEvent(button.element, 'click', revert);
// add the click event
if (menuItems) {
onclick = function(e) {
revert();
var bBox = button.getBBox();
chart.contextMenu('export-menu', menuItems, bBox.x, bBox.y, buttonWidth, buttonHeight);
};
}
/*addEvent(button.element, 'click', function() {
onclick.apply(chart, arguments);
});*/
button.on('click', function() {
onclick.apply(chart, arguments);
});
// the icon
symbol = renderer.symbol(
btnOptions.symbol,
btnOptions.symbolX - (symbolSize / 2),
btnOptions.symbolY - (symbolSize / 2),
symbolSize,
symbolSize
)
.align(btnOptions, true)
.attr(extend(symbolAttr, {
'stroke-width': btnOptions.symbolStrokeWidth || 1,
zIndex: 20
})).add(chart.buttonGroup);
}
});
}());
if(/\/hist\//.test(window.location.pathname)){
/**
* The Petroleum Navigator leaf page charting function
**/
var leafHandler = function($){
return function(){
// Is this the Natural Gas Navigator?
var isNG;
//min must not be zero if negative values
negativeValues = false;
// An array of months for performing lookups
var monthsArray = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
];
// Returns the Chart Title and Units as an array
var getTitleMatch = function(){
//var titleRegex = /[^\(\)]+/g;
var title = $('.Title1').html();
//return title.match(titleRegex); <- this didn't work as some series name have parenthical phrases
var aTitle = [title.substring(0,title.lastIndexOf('(')-1), title.substring(title.lastIndexOf('(')+1,title.lastIndexOf(')')) ];
return aTitle;
}
// Returns the table rows in a page for iteration
var getTableRows = function(){
if(isNG)
return $('body > table:eq(2) tr');
else
return $('table.FloatTitle tr');
}
// Trims null values from the beginning and end of data
// arrays
var trimNulls = function(data){
var i;
var dataCopy = data.slice(0);
for(i=data.length - 1; i>0; i--){
if(data[i][1] === null) dataCopy.pop();
else break;
}
for(i=0; i -1)console.info(JSON.stringify(ret));
return ret;
}
//Indicates whether this is a Reutures series
var isReuters = function(){
var tr_series = ['RWTC','RBRTE','EER_EPMRU_PF4_Y35NY_DPG','EER_EPMRU_PF4_RGC_DPG','EER_EPMRR_PF4_Y05LA_DPG','EER_EPD2F_PF4_Y35NY_DPG','EER_EPJK_PF4_RGC_DPG','EER_EPLLPA_PF4_Y44MB_DPG'];
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i').width('100%').appendTo(imageParent);
// Make the chart 100% width
chartTable.width('100%');
// Hide the chart during processing
chartParent.children().hide();
return chartParent;
}
// This is the function that creates the chart object.
// Executes immediately i.e.: function(args){/*do*/}(args);
var createLeafChart = function(){
isNG = window.location.pathname.match(/\/ng\//) !== null;
var chartParent = prepareChartParent();
var titleMatch = getTitleMatch();
var data = processData();
leafChart = new Highcharts.Chart(
createOptions(
chartParent.get(0),
titleMatch[0],
titleMatch[1],
data
)
);
}();
}
}(jQuery); /**
* Created by Shivan Computers Corporation on behalf of the
* U.S. Energy Information Administration:
* Author : Ryan Lynch (Ryan.Lynch@eia.gov)
*
* EIA Analyis Module:
*
* This module extend the EIA Theme to add various analytical
* functions to the chart, along with a set of controls to
* activate them.
*
* Depends on: highcharts.js, eia-theme.js
**/
(function(){
// Shortcuts
var HC = Highcharts,
Chart = HC.Chart;
each = HC.each,
extend = HC.extend,
map = HC.map,
eiaTheme = HC.eiaTheme,
seasonalPalletAlpha = 0.3;
// Default Analysis Options
HC.setOptions(extend(eiaTheme, {
analysis: {
enableMovingAverage:true,
enableSeasonalAnalysis:true
}
}));
function seasonalPalletConverter(h){
return 'rgba(' +
parseInt(h.substring(1,3), 16) + ',' +
parseInt(h.substring(3,5), 16) + ',' +
parseInt(h.substring(5), 16) + ',' +
seasonalPalletAlpha + ')';
}
// Colors for seasonal analysis
extend(HC, {
eia_seasonal_pallet : map(eiaTheme.colors.slice(1), seasonalPalletConverter)
});
//////////////////////////
// Analytical Functions //
//////////////////////////
extend(Chart.prototype,{
addMovingAverage : function(index, duration){
var chart = this, baseSeries = chart.series[index],
interval = baseSeries.options.xType, baseXData = baseSeries.xData,
baseYData = baseSeries.yData, avgData = [], helperArray = [],
dayInterval, durationTitle, avg = total = i = j = calcDuration = 0;
// If we are dealing with a series that has been destroyed, then
// return
if(!baseXData) return;
// else
switch(interval){
case HC.xTypes.Annual:
case HC.xTypes.Quarterly:
case HC.xTypes.Monthly:
return;
break;
case HC.xTypes.weekly:
durationTitle = duration + ' Week';
dayInterval = 7 * 24 * 60 * 60 * 1000;
break;
case HC.xTypes.daily:
durationTitle = duration + ' Day';
dayInterval = 1 * 24 * 60 * 60 * 1000;
break;
}
for(i = duration; helperArray.length == 0; i++){
for(j = i - duration; j < i; j++){
if(
baseYData[j] != null &&
baseXData[j] >= baseXData[i] - dayInterval * duration
){
total += baseYData[j];
helperArray.push({
x : baseXData[j],
y : baseYData[j]
});
}
}
}
avgData.push([baseXData[i], total/helperArray.length]);
for(i = duration + 1; i < baseXData.length; i++){
if(
helperArray[0].x <= baseXData[i] - dayInterval * duration
){
total -= helperArray[0].y;
helperArray.shift();
}
j = i - 1
if(
baseYData[j] != null &&
baseXData[j] >= baseXData[i] - dayInterval * duration
){
total += baseYData[j];
helperArray.push({
x : baseXData[j],
y : baseYData[j]
});
}
avgData.push([baseXData[i], total / helperArray.length]);
}
//chart.legend.enabled = true;
return chart.addSeries({
//name : baseSeries.name + durationTitle + ' Moving Average',
name : durationTitle + ' Moving Average',
data : avgData
});
},
createSeasonalAnalysis : function(index, interval){
var chart = this, baseSeries = chart.series[index], yearOffset,
baseXData = baseSeries.xData, baseYData = baseSeries.yData,
i = j = 0, series = [], seriesData, xType = baseSeries.options.xType,
serie, startDate, currentDate, firstDate, originalStartDate, lastDate,
dateString;
if(!baseXData) return;
j = baseXData.length - 1;
startDate = originalStartDate = new Date(baseXData[j]);
for(i = 0; i <= interval && j > 0; i++){
endDate = new Date(
startDate.getUTCFullYear() - 1,
startDate.getUTCMonth(),
startDate.getUTCDate()
)
seriesData = [];
lastDate = new Date(baseXData[j]);
while(
j >= 0 &&
(!currentDate || currentDate.getTime() >= endDate.getTime())
){
currentDate = new Date(baseXData[j]);
seriesData.push({
x: Date.UTC(
currentDate.getUTCFullYear() + i,
currentDate.getUTCMonth(),
currentDate.getUTCDate()),
tooltipX : currentDate.getTime(),
y: baseYData[j]
});
firstDate = currentDate;
j--;
}
j++;
switch(xType){
case HC.xTypes.daily:
dateString = HC.dateFormat('%m/%d/%Y', firstDate.getTime()) +
' to ' + HC.dateFormat('%m/%d/%Y', lastDate.getTime());
break;
case HC.xTypes.weekly:
dateString = HC.dateFormat('%m/%d/%Y', firstDate.getTime()) +
' to ' + HC.dateFormat('%m/%d/%Y', lastDate.getTime());
break;
case HC.xTypes.monthly:
dateString = HC.dateFormat('%m/%Y', firstDate.getTime()) + ' to ' +
HC.dateFormat('%m/%Y', lastDate.getTime());
break;
}
serie = {
//name:baseSeries.options.name + ' ' + dateString,
name: dateString,
data:seriesData,
legendIndex:i
};
if(i > 0) serie.color = HC.eia_seasonal_pallet[i-1];
series.push(serie);
startDate = endDate;
}
chart.removeAllSeries(false);
for(j=series.length - 1; j>=0; j--){
chart.addSeries(series[j], false);
}
chart.resetZoom();
chart.redraw();
}
});
function createSeasonalAnalysisOptions(s, index){
var chart = this, xType = s.options.xType;
if(s.type == 'line' && xType != HC.xTypes.category){
var link, durations, maxInterval;
if(xType > HC.xTypes.annual){
maxInterval = (s.data[s.data.length - 1].x - s.data[0].x) / 31536E6 /*365 days*/;
// Add moving averages
each([5, 10], function(interval){
if(interval < maxInterval){
//option = $('').html(s.name + ': ' + interval + ' Year Seasonal Analysis')
option = $('').html(interval + ' Year Seasonal Analysis')
.data({
method:chart.createSeasonalAnalysis,
arguments:[index, interval]
});
option.appendTo(chart.options.chart.analysisSelect);
}
});
}
}
}
function createMovingAverageOptions(s, index){
var chart = this, xType = s.options.xType;
if(s.type == 'line' && xType != HC.xTypes.category){
var link, durations,
maxDuration = s.data.length;
if(xType == HC.xTypes.daily){
// Add moving averages
each([30, 60, 90], function(duration){
if(duration < maxDuration){
//option = $('').html(s.name + ': ' + duration + ' Day Moving Average ')
option = $('').html(duration + ' Day Moving Average ')
.data({
method:chart.addMovingAverage,
arguments:[index, duration]
});
option.appendTo(chart.options.chart.analysisSelect);
}
});
}
if(xType == HC.xTypes.weekly){
each([4, 8, 12], function(duration){
if(duration < maxDuration){
//option = $('').html(s.name + ': ' + duration + ' Week Moving Average ')
option = $('').html(duration + ' Week Moving Average ')
.data({
method:chart.addMovingAverage,
arguments:[index, duration]
});
option.appendTo(chart.options.chart.analysisSelect);
}
});
}
}
}
function processAnalysis(){
var chart = this, ops = chart.options,
container = $(chart.options.chart.container),
outerContainer = $(chart.options.chart.outerContainer);
analysisContainer = $('').css({
height:'auto',
width:'auto',
// We set the margin and padding on the
// captions container to match the chart
// container so that the links are
// lined up correctly
marginLeft:container.css('marginLeft'),
marginRight:container.css('marginRight')
/*paddingLeft:container.css('paddingLeft'),
paddingRight:container.css('paddingRight')*/
}).addClass('chartAnalysisContainer').append(''),
analysisSelect = $(''),
analysisTable = $('
');
// Enable or disable analysis based on maxXType
switch(ops.maxXType){
case HC.xTypes.annual:
ops.analysis.enableMovingAverage &= false;
ops.analysis.enableSeasonalAnalysis &= false;
break;
case HC.xTypes.monthly:
ops.analysis.enableMovingAverage &= false;
ops.analysis.enableSeasonalAnalysis &= true;
break;
case HC.xTypes.weekly:
ops.analysis.enableMovingAverage &= true;
ops.analysis.enableSeasonalAnalysis &= true;
break;
case HC.xTypes.daily:
ops.analysis.enableMovingAverage &= true;
ops.analysis.enableSeasonalAnalysis &= true;
break;
default:
ops.analysis.enableMovingAverage &= false;
ops.analysis.enableSeasonalAnalysis &= false;
break;
}
if((
ops.analysis.enableMovingAverage ||
ops.analysis.enableSeasonalAnalysis
) && !ops.chart.analysisContainer){
analysisContainer.appendTo(outerContainer);
analysisTable.append(
$('