From 5f5adb62bf13ace887c03522b0b8e83181cd6503 Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 23 Jul 2019 11:24:56 -0500 Subject: Added change to automatically update datasets list using rest api instead of json file Removed option to edit certain html pages, like news, policies, etc --- etc/default_settings.py | 1 + 1 file changed, 1 insertion(+) (limited to 'etc') diff --git a/etc/default_settings.py b/etc/default_settings.py index a1fe81e5..a16ac3ad 100644 --- a/etc/default_settings.py +++ b/etc/default_settings.py @@ -91,4 +91,5 @@ JS_GN_PATH = os.environ['HOME']+"/genenetwork/javascript" # ---- GN2 Executables (overwrite for testing only) # PLINK_COMMAND = str.strip(os.popen("which plink2").read()) # GEMMA_COMMAND = str.strip(os.popen("which gemma").read()) +REAPER_COMMAND = HOME + "/gn2-zach/rust-qtlreaper/target/release/qtlreaper" # GEMMA_WRAPPER_COMMAND = str.strip(os.popen("which gemma-wrapper").read()) -- cgit v1.2.3 From bf3f98fb51e20d3ced96c7004c60d8b19b2aad55 Mon Sep 17 00:00:00 2001 From: zsloan Date: Tue, 24 Sep 2019 10:59:15 -0500 Subject: Fixed issue that caused logging in to stop working with new GUIX build Removed some unused JS libraries --- bin/genenetwork2 | 2 +- etc/default_settings.py | 2 +- wqflask/wqflask/heatmap/heatmap.py | 83 +- .../wqflask/marker_regression/qtlreaper_mapping.py | 4 +- wqflask/wqflask/marker_regression/run_mapping.py | 5 + .../new/javascript/dataset_menu_structure.json | 142 +- .../new/javascript/get_traits_from_collection.js | 74 +- .../wqflask/static/new/javascript/network_graph.js | 17 +- wqflask/wqflask/static/new/packages/nvd3/nv.d3.css | 641 - wqflask/wqflask/static/new/packages/nvd3/nv.d3.js | 13363 ------------------- .../wqflask/static/new/packages/nvd3/nv.d3.min.css | 1 - .../wqflask/static/new/packages/nvd3/nv.d3.min.js | 8 - .../static/packages/DT_bootstrap/DT_bootstrap.css | 179 - .../static/packages/DT_bootstrap/DT_bootstrap.js | 159 - .../wqflask/static/packages/DT_bootstrap/images | 1 - wqflask/wqflask/templates/index_page_orig.html | 2 + wqflask/wqflask/templates/show_trait.html | 2 - wqflask/wqflask/user_manager.py | 5 +- 18 files changed, 203 insertions(+), 14487 deletions(-) delete mode 100644 wqflask/wqflask/static/new/packages/nvd3/nv.d3.css delete mode 100644 wqflask/wqflask/static/new/packages/nvd3/nv.d3.js delete mode 100644 wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.css delete mode 100644 wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.js delete mode 100644 wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.css delete mode 100644 wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.js delete mode 120000 wqflask/wqflask/static/packages/DT_bootstrap/images (limited to 'etc') diff --git a/bin/genenetwork2 b/bin/genenetwork2 index 7c875274..1c538e86 100755 --- a/bin/genenetwork2 +++ b/bin/genenetwork2 @@ -25,7 +25,7 @@ # webserver) run from the base-dir with settings file and add that # script with a -c switch, e.g. # -# env GN2_PROFILE=/usr/local/guix-profiles/gn-latest-20181119 TMPDIR=/export/local/home/zas1024/gn2-zach/tmp WEBSERVER_MODE=DEBUG LOG_LEVEL=DEBUG SERVER_PORT=5002 GENENETWORK_FILES=/export/local/home/zas1024/gn2-zach/genotype_files SQL_URI=mysql://webqtlout:webqtlout@lily.uthsc.edu/db_webqtl ./bin/genenetwork2 ./etc/default_settings.py -c ./maintenance/gen_select_dataset.py +# env GN2_PROFILE=/usr/local/guix-profiles/gn-latest-20190905 TMPDIR=/export/local/home/zas1024/gn2-zach/tmp WEBSERVER_MODE=DEBUG LOG_LEVEL=DEBUG SERVER_PORT=5002 GENENETWORK_FILES=/export/local/home/zas1024/gn2-zach/genotype_files SQL_URI=mysql://webqtlout:webqtlout@lily.uthsc.edu/db_webqtl ./bin/genenetwork2 ./etc/default_settings.py -c ./maintenance/gen_select_dataset.py # # To run any script in the environment # diff --git a/etc/default_settings.py b/etc/default_settings.py index a16ac3ad..75f84dc4 100644 --- a/etc/default_settings.py +++ b/etc/default_settings.py @@ -91,5 +91,5 @@ JS_GN_PATH = os.environ['HOME']+"/genenetwork/javascript" # ---- GN2 Executables (overwrite for testing only) # PLINK_COMMAND = str.strip(os.popen("which plink2").read()) # GEMMA_COMMAND = str.strip(os.popen("which gemma").read()) -REAPER_COMMAND = HOME + "/gn2-zach/rust-qtlreaper/target/release/qtlreaper" +REAPER_COMMAND = os.environ['GN2_PROFILE'] + "/bin/qtlreaper" # GEMMA_WRAPPER_COMMAND = str.strip(os.popen("which gemma-wrapper").read()) diff --git a/wqflask/wqflask/heatmap/heatmap.py b/wqflask/wqflask/heatmap/heatmap.py index 37454dfb..e82aa0ef 100644 --- a/wqflask/wqflask/heatmap/heatmap.py +++ b/wqflask/wqflask/heatmap/heatmap.py @@ -10,6 +10,7 @@ import datetime import time import pp import math +import random import collections import resource @@ -23,9 +24,11 @@ import reaper from base.trait import GeneralTrait from base import data_set from base import species +from base import webqtlConfig from utility import helper_functions from utility import Plot, Bunch from utility import temp_data +from utility.tools import flat_files, REAPER_COMMAND, TEMPDIR from MySQLdb import escape_string as escape @@ -119,10 +122,15 @@ class Heatmap(object): for trait_db in self.trait_list: self.dataset.group.get_markers() this_trait = trait_db[0] - #this_db = trait_db[1] - genotype = self.dataset.group.read_genotype_file(use_reaper=True) + + genotype = self.dataset.group.read_genotype_file(use_reaper=False) samples, values, variances, sample_aliases = this_trait.export_informative() + if self.dataset.group.genofile != None: + genofile_name = self.dataset.group.genofile[:-5] + else: + genofile_name = self.dataset.group.name + trimmed_samples = [] trimmed_values = [] for i in range(0, len(samples)): @@ -130,14 +138,73 @@ class Heatmap(object): trimmed_samples.append(str(samples[i])) trimmed_values.append(values[i]) - reaper_results = genotype.regression(strains = trimmed_samples, - trait = trimmed_values) + trait_filename = str(this_trait.name) + "_" + str(self.dataset.name) + "_pheno" + gen_pheno_txt_file(trimmed_samples, trimmed_values, trait_filename) + + output_filename = self.dataset.group.name + "_GWA_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) + + reaper_command = REAPER_COMMAND + ' --geno {0}/{1}.geno --traits {2}/gn2/{3}.txt -n 1000 -o {4}{5}.txt'.format(flat_files('genotype'), + genofile_name, + TEMPDIR, + trait_filename, + webqtlConfig.GENERATED_IMAGE_DIR, + output_filename) + + os.system(reaper_command) + + reaper_results = parse_reaper_output(output_filename) - lrs_values = [float(qtl.lrs) for qtl in reaper_results] + lrs_values = [float(qtl['lrs_value']) for qtl in reaper_results] self.trait_results[this_trait.name] = [] for qtl in reaper_results: - if qtl.additive > 0: - self.trait_results[this_trait.name].append(-float(qtl.lrs)) + if qtl['additive'] > 0: + self.trait_results[this_trait.name].append(-float(qtl['lrs_value'])) else: - self.trait_results[this_trait.name].append(float(qtl.lrs)) + self.trait_results[this_trait.name].append(float(qtl['lrs_value'])) + +def gen_pheno_txt_file(samples, vals, filename): + """Generates phenotype file for GEMMA""" + + with open("{0}/gn2/{1}.txt".format(TEMPDIR, filename), "w") as outfile: + outfile.write("Trait\t") + + filtered_sample_list = [] + filtered_vals_list = [] + for i, sample in enumerate(samples): + if vals[i] != "x": + filtered_sample_list.append(sample) + filtered_vals_list.append(str(vals[i])) + + samples_string = "\t".join(filtered_sample_list) + outfile.write(samples_string + "\n") + outfile.write("T1\t") + values_string = "\t".join(filtered_vals_list) + outfile.write(values_string) + +def parse_reaper_output(gwa_filename): + included_markers = [] + p_values = [] + marker_obs = [] + + with open("{}{}.txt".format(webqtlConfig.GENERATED_IMAGE_DIR, gwa_filename)) as output_file: + for line in output_file: + if line.startswith("ID\t"): + continue + else: + marker = {} + marker['name'] = line.split("\t")[1] + try: + marker['chr'] = int(line.split("\t")[2]) + except: + marker['chr'] = line.split("\t")[2] + marker['cM'] = float(line.split("\t")[3]) + marker['Mb'] = float(line.split("\t")[4]) + if float(line.split("\t")[7]) != 1: + marker['p_value'] = float(line.split("\t")[7]) + marker['lrs_value'] = float(line.split("\t")[5]) + marker['lod_score'] = marker['lrs_value'] / 4.61 + marker['additive'] = float(line.split("\t")[6]) + marker_obs.append(marker) + + return marker_obs \ No newline at end of file diff --git a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py index bbc8b513..50e6bd7e 100644 --- a/wqflask/wqflask/marker_regression/qtlreaper_mapping.py +++ b/wqflask/wqflask/marker_regression/qtlreaper_mapping.py @@ -18,7 +18,7 @@ def run_reaper(this_trait, this_dataset, samples, vals, json_data, num_perm, boo genofile_name = this_dataset.group.name trait_filename = str(this_trait.name) + "_" + str(this_dataset.name) + "_pheno" - gen_pheno_txt_file(this_dataset, genofile_name, samples, vals, trait_filename) + gen_pheno_txt_file(samples, vals, trait_filename) output_filename = this_dataset.group.name + "_GWA_" + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) bootstrap_filename = None @@ -61,7 +61,7 @@ def run_reaper(this_trait, this_dataset, samples, vals, json_data, num_perm, boo return marker_obs, permu_vals, suggestive, significant, bootstrap_vals, [output_filename, permu_filename, bootstrap_filename] -def gen_pheno_txt_file(this_dataset, genofile_name, samples, vals, trait_filename): +def gen_pheno_txt_file(samples, vals, trait_filename): """Generates phenotype file for GEMMA""" with open("{}/gn2/{}.txt".format(TEMPDIR, trait_filename), "w") as outfile: diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 56d901fc..7c526f33 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -54,6 +54,11 @@ class RunMapping(object): self.temp_uuid = temp_uuid #needed to pass temp_uuid to gn1 mapping code (marker_regression_gn1.py) + #ZS: Needed to zoom in or remap temp traits like PCA traits + if "temp_trait" in start_vars: + self.temp_trait = "True" + self.group = self.dataset.group.name + self.json_data = {} self.json_data['lodnames'] = ['lod.hk'] diff --git a/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json b/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json index 6531f5a0..492d4313 100644 --- a/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json +++ b/wqflask/wqflask/static/new/javascript/dataset_menu_structure.json @@ -116,15 +116,15 @@ "B30_K_1206_M", "Barley1 Leaf MAS 5.0 SCRI (Dec06)" ], - [ - "126", - "B30_K_1206_Rn", - "Barley1 Leaf gcRMAn SCRI (Dec06)" - ], [ "125", "B30_K_1206_R", "Barley1 Leaf gcRMA SCRI (Dec06)" + ], + [ + "126", + "B30_K_1206_Rn", + "Barley1 Leaf gcRMAn SCRI (Dec06)" ] ], "Phenotypes": [ @@ -1622,15 +1622,15 @@ "NCI_Agil_Mam_Tum_RMA_0409", "NCI Mammary LMT miRNA v2 (Apr09) RMA" ], - [ - "37", - "MA_M_0704_R", - "NCI Mammary mRNA M430 (July04) RMA" - ], [ "36", "MA_M_0704_M", "NCI Mammary mRNA M430 (July04) MAS5" + ], + [ + "37", + "MA_M_0704_R", + "NCI Mammary mRNA M430 (July04) RMA" ] ] }, @@ -1697,15 +1697,15 @@ ] ], "Liver mRNA": [ - [ - "39", - "LVF2_M_0704_R", - "(B6 x BTBR)F2-ob/ob Liver mRNA M430 (Jul04) RMA" - ], [ "38", "LVF2_M_0704_M", "(B6 x BTBR)F2-ob/ob Liver mRNA M430 (Jul04) MAS5" + ], + [ + "39", + "LVF2_M_0704_R", + "(B6 x BTBR)F2-ob/ob Liver mRNA M430 (Jul04) RMA" ] ], "Phenotypes": [ @@ -1727,6 +1727,11 @@ }, "B6D2F2": { "Brain mRNA": [ + [ + "78", + "BRF2_M_0805_P", + "OHSU/VA B6D2F2 Brain mRNA M430 (Aug05) PDNN" + ], [ "77", "BRF2_M_0805_R", @@ -1737,25 +1742,20 @@ "BRF2_M_0805_M", "OHSU/VA B6D2F2 Brain mRNA M430 (Aug05) MAS5" ], - [ - "78", - "BRF2_M_0805_P", - "OHSU/VA B6D2F2 Brain mRNA M430 (Aug05) PDNN" - ], [ "33", "BRF2_M_0304_P", "OHSU/VA B6D2F2 Brain mRNA M430A (Mar04) PDNN" ], - [ - "32", - "BRF2_M_0304_R", - "OHSU/VA B6D2F2 Brain mRNA M430A (Mar04) RMA" - ], [ "31", "BRF2_M_0304_M", "OHSU/VA B6D2F2 Brain mRNA M430A (Mar04) MAS5" + ], + [ + "32", + "BRF2_M_0304_R", + "OHSU/VA B6D2F2 Brain mRNA M430A (Mar04) RMA" ] ], "Genotypes": [ @@ -1833,6 +1833,11 @@ ] ], "Striatum mRNA": [ + [ + "83", + "SA_M2_0905_M", + "OHSU/VA B6D2F2 Striatum M430v2 (Sep05) MAS5" + ], [ "85", "SA_M2_0905_P", @@ -1842,11 +1847,6 @@ "84", "SA_M2_0905_R", "OHSU/VA B6D2F2 Striatum M430v2 (Sep05) RMA" - ], - [ - "83", - "SA_M2_0905_M", - "OHSU/VA B6D2F2 Striatum M430v2 (Sep05) MAS5" ] ] }, @@ -2121,16 +2121,16 @@ "IBR_M_0606_R", "INIA Brain mRNA M430 (Jun06) RMA" ], - [ - "102", - "IBR_M_0106_R", - "INIA Brain mRNA M430 (Jan06) RMA" - ], [ "101", "IBR_M_0106_P", "INIA Brain mRNA M430 (Jan06) PDNN" ], + [ + "102", + "IBR_M_0106_R", + "INIA Brain mRNA M430 (Jan06) RMA" + ], [ "95", "BR_U_1105_P", @@ -2550,16 +2550,16 @@ ] ], "Kidney mRNA": [ - [ - "239", - "MA_M2F_0706_R", - "Mouse kidney M430v2 Female (Aug06) RMA" - ], [ "240", "MA_M2M_0706_R", "Mouse kidney M430v2 Male (Aug06) RMA" ], + [ + "239", + "MA_M2F_0706_R", + "Mouse kidney M430v2 Female (Aug06) RMA" + ], [ "118", "MA_M2_0806_R", @@ -2570,28 +2570,28 @@ "MA_M2_0806_P", "Mouse Kidney M430v2 Sex Balanced (Aug06) PDNN" ], - [ - "116", - "MA_M2_0706_P", - "Mouse Kidney M430v2 (Jul06) PDNN" - ], [ "115", "MA_M2_0706_R", "Mouse Kidney M430v2 (Jul06) RMA" + ], + [ + "116", + "MA_M2_0706_P", + "Mouse Kidney M430v2 (Jul06) PDNN" ] ], "Liver Metabolome": [ - [ - "836", - "UTHSC-ETHZ-EPFL_LivPMetExtAHFD0817", - "UTHSC/ETHZ/EPFL BXD Liver Polar Metabolites Extraction, HFD Cohorts (Jul 2017) log2" - ], [ "835", "UTHSC-ETHZ-EPFL_LivPMetExtACD0817", "UTHSC/ETHZ/EPFL BXD Liver Polar Metabolites Extraction, Chow Diet Cohorts (Jul 2017) log2" ], + [ + "836", + "UTHSC-ETHZ-EPFL_LivPMetExtAHFD0817", + "UTHSC/ETHZ/EPFL BXD Liver Polar Metabolites Extraction, HFD Cohorts (Jul 2017) log2" + ], [ "473", "EPFL-LISP_LivPMetCDHFD1213", @@ -2844,16 +2844,16 @@ ] ], "Neocortex mRNA": [ - [ - "375", - "DevNeocortex_ILM6.2P14RInv_1111", - "BIDMC/UTHSC Dev Neocortex P14 ILMv6.2 (Nov11) RankInv" - ], [ "374", "DevNeocortex_ILM6.2P3RInv_1111", "BIDMC/UTHSC Dev Neocortex P3 ILMv6.2 (Nov11) RankInv" ], + [ + "375", + "DevNeocortex_ILM6.2P14RInv_1111", + "BIDMC/UTHSC Dev Neocortex P14 ILMv6.2 (Nov11) RankInv" + ], [ "284", "HQFNeoc_1210v2_RankInv", @@ -3109,6 +3109,11 @@ ] ], "Ventral Tegmental Area mRNA": [ + [ + "228", + "VCUSal_0609_R", + "VCU BXD VTA Sal M430 2.0 (Jun09) RMA" + ], [ "230", "VCUEtvsSal_0609_R", @@ -3118,11 +3123,6 @@ "229", "VCUEtOH_0609_R", "VCU BXD VTA EtOH M430 2.0 (Jun09) RMA" - ], - [ - "228", - "VCUSal_0609_R", - "VCU BXD VTA Sal M430 2.0 (Jun09) RMA" ] ] }, @@ -3264,7 +3264,7 @@ [ "808", "UCSD_CFW_HIP_RNA-Seq_0117", - "UCSD CFW Hippocampus (Jan17) RNA-Seq" + "UCSD CFW Hippocampus RNA-Seq (Jan17) FPKM Quantile" ] ], "Phenotypes": [ @@ -3462,15 +3462,15 @@ ] ], "Hippocampus mRNA": [ - [ - "100", - "HC_M2CB_1205_R", - "Hippocampus Consortium M430v2 CXB (Dec05) RMA" - ], [ "99", "HC_M2CB_1205_P", "Hippocampus Consortium M430v2 CXB (Dec05) PDNN" + ], + [ + "100", + "HC_M2CB_1205_R", + "Hippocampus Consortium M430v2 CXB (Dec05) RMA" ] ], "Liver mRNA": [ @@ -3674,15 +3674,15 @@ ] ], "Hippocampus mRNA": [ - [ - "273", - "UMUTAffyExon_0209_RMA_MDP", - "UMUTAffy Hippocampus Exon (Feb09) RMA MDP" - ], [ "272", "HC_M2_0606_MDP", "Hippocampus Consortium M430v2 (Jun06) RMA MDP" + ], + [ + "273", + "UMUTAffyExon_0209_RMA_MDP", + "UMUTAffy Hippocampus Exon (Feb09) RMA MDP" ] ], "Liver mRNA": [ diff --git a/wqflask/wqflask/static/new/javascript/get_traits_from_collection.js b/wqflask/wqflask/static/new/javascript/get_traits_from_collection.js index d89264c6..a34394a1 100644 --- a/wqflask/wqflask/static/new/javascript/get_traits_from_collection.js +++ b/wqflask/wqflask/static/new/javascript/get_traits_from_collection.js @@ -42,23 +42,27 @@ $('#trait_table').dataTable( { } ); $('#collection_table').dataTable( { - "createdRow": function ( row, data, index ) { - if ($('td', row).eq(1).text().length > 40) { - $('td', row).eq(1).text($('td', row).eq(1).text().substring(0, 40)); - $('td', row).eq(1).text($('td', row).eq(1).text() + '...') - } - if ($('td', row).eq(3).text().length > 50) { - $('td', row).eq(3).text($('td', row).eq(3).text().substring(0, 50)); - $('td', row).eq(3).text($('td', row).eq(3).text() + '...') - } - }, - "order": [[0, "asc" ]], - "sDom": "ZRtr", - "iDisplayLength": -1, - "autoWidth": true, - "bSortClasses": false, - "paging": false, - "orderClasses": true + "createdRow": function ( row, data, index ) { + if ($('td', row).eq(2).text().length > 40) { + $('td', row).eq(2).text($('td', row).eq(2).text().substring(0, 40)); + $('td', row).eq(2).text($('td', row).eq(2).text() + '...') + } + if ($('td', row).eq(4).text().length > 50) { + $('td', row).eq(4).text($('td', row).eq(4).text().substring(0, 50)); + $('td', row).eq(4).text($('td', row).eq(4).text() + '...') + } + }, + "columnDefs": [ { + "targets": 0, + "orderable": false + } ], + "order": [[1, "asc" ]], + "sDom": "ZRtr", + "iDisplayLength": -1, + "autoWidth": true, + "bSortClasses": false, + "paging": false, + "orderClasses": true } ); collection_click = function() { @@ -364,37 +368,29 @@ color_by_trait = function(trait_sample_data, textStatus, jqXHR) { process_traits = function(trait_data, textStatus, jqXHR) { var the_html, trait, _i, _len; console.log('in process_traits with trait_data:', trait_data); - the_html = ""; - if ($('.corr_compute').length){ - the_html += " "; - } - if ($('#scatterplot2').length){ - the_html += " Please click the row of the trait you wish to select as a cofactor."; - } - the_html += ""; - if ($('.corr_compute').length){ - the_html += ""; - } else { - the_html += ""; - } + the_html += " "; + the_html += "
RecordData SetDescriptionMean
RecordData SetDescription
"; + the_html += ""; the_html += ""; for (_i = 0, _len = trait_data.length; _i < _len; _i++) { trait = trait_data[_i]; the_html += ""; - if ($('.corr_compute').length){ - the_html += ""; + the_html += ""; + if ("abbreviation" in trait) { + the_html += ""; + } else if ("symbol" in trait) { + the_html += ""; + } else { + the_html += ""; } - the_html += ""; - the_html += ""; - the_html += ""; + the_html += ""; + the_html += ""; } the_html += ""; the_html += "
RecordData SetDescription
" + trait.name + "" + trait.name + "" + trait.name + "" + trait.name + "" + trait.dataset + "" + trait.description + "" + trait.dataset_name + "" + trait.description + "
"; - the_html += "
" - the_html += collection_list - the_html += "
" - the_html += "" + the_html += "" $("#collections_holder").html(the_html); return $('#collections_holder').colorbox.resize(); }; diff --git a/wqflask/wqflask/static/new/javascript/network_graph.js b/wqflask/wqflask/static/new/javascript/network_graph.js index bc02181f..4d507a18 100644 --- a/wqflask/wqflask/static/new/javascript/network_graph.js +++ b/wqflask/wqflask/static/new/javascript/network_graph.js @@ -144,7 +144,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $('#pos_slide').change(function() { @@ -157,7 +157,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); @@ -168,7 +168,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $('select[name=focus_select]').change(function() { @@ -180,7 +180,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $('select[name=layout_select]').change(function() { @@ -188,7 +188,7 @@ window.onload=function() { cy.layout({ name: layout_type, fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $('select[name=font_size]').change(function() { @@ -219,7 +219,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $('select[name=edge_width]').change(function() { @@ -243,7 +243,7 @@ window.onload=function() { cy.layout({ name: $('select[name=layout_select]').val(), fit: true, // whether to fit the viewport to the graph padding: 25 // the padding on fit - }); + }).run(); }); $("a#image_link").click(function(e) { @@ -251,9 +251,6 @@ window.onload=function() { $(this).attr('href', pngData); $(this).attr('download', 'network_graph.png'); - - console.log("TESTING:", image_link) - }); diff --git a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.css b/wqflask/wqflask/static/new/packages/nvd3/nv.d3.css deleted file mode 100644 index 593d3889..00000000 --- a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.css +++ /dev/null @@ -1,641 +0,0 @@ -/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-05-25 */ -.nvd3 .nv-axis { - pointer-events:none; - opacity: 1; -} - -.nvd3 .nv-axis path { - fill: none; - stroke: #000; - stroke-opacity: .75; - shape-rendering: crispEdges; -} - -.nvd3 .nv-axis path.domain { - stroke-opacity: .75; -} - -.nvd3 .nv-axis.nv-x path.domain { - stroke-opacity: 1; -} - -.nvd3 .nv-axis line { - fill: none; - stroke: #e5e5e5; - shape-rendering: crispEdges; -} - -.nvd3 .nv-axis .zero line, - /*this selector may not be necessary*/ .nvd3 .nv-axis line.zero { - stroke-opacity: .75; -} - -.nvd3 .nv-axis .nv-axisMaxMin text { - font-weight: bold; -} - -.nvd3 .x .nv-axis .nv-axisMaxMin text, -.nvd3 .x2 .nv-axis .nv-axisMaxMin text, -.nvd3 .x3 .nv-axis .nv-axisMaxMin text { - text-anchor: middle -} - -.nvd3 .nv-axis.nv-disabled { - opacity: 0; -} - -.nvd3 .nv-bars rect { - fill-opacity: .75; - - transition: fill-opacity 250ms linear; - -moz-transition: fill-opacity 250ms linear; - -webkit-transition: fill-opacity 250ms linear; -} - -.nvd3 .nv-bars rect.hover { - fill-opacity: 1; -} - -.nvd3 .nv-bars .hover rect { - fill: lightblue; -} - -.nvd3 .nv-bars text { - fill: rgba(0,0,0,0); -} - -.nvd3 .nv-bars .hover text { - fill: rgba(0,0,0,1); -} - -.nvd3 .nv-multibar .nv-groups rect, -.nvd3 .nv-multibarHorizontal .nv-groups rect, -.nvd3 .nv-discretebar .nv-groups rect { - stroke-opacity: 0; - - transition: fill-opacity 250ms linear; - -moz-transition: fill-opacity 250ms linear; - -webkit-transition: fill-opacity 250ms linear; -} - -.nvd3 .nv-multibar .nv-groups rect:hover, -.nvd3 .nv-multibarHorizontal .nv-groups rect:hover, -.nvd3 .nv-candlestickBar .nv-ticks rect:hover, -.nvd3 .nv-discretebar .nv-groups rect:hover { - fill-opacity: 1; -} - -.nvd3 .nv-discretebar .nv-groups text, -.nvd3 .nv-multibarHorizontal .nv-groups text { - font-weight: bold; - fill: rgba(0,0,0,1); - stroke: rgba(0,0,0,0); -} - -/* boxplot CSS */ -.nvd3 .nv-boxplot circle { - fill-opacity: 0.5; -} - -.nvd3 .nv-boxplot circle:hover { - fill-opacity: 1; -} - -.nvd3 .nv-boxplot rect:hover { - fill-opacity: 1; -} - -.nvd3 line.nv-boxplot-median { - stroke: black; -} - -.nv-boxplot-tick:hover { - stroke-width: 2.5px; -} -/* bullet */ -.nvd3.nv-bullet { font: 10px sans-serif; } -.nvd3.nv-bullet .nv-measure { fill-opacity: .8; } -.nvd3.nv-bullet .nv-measure:hover { fill-opacity: 1; } -.nvd3.nv-bullet .nv-marker { stroke: #000; stroke-width: 2px; } -.nvd3.nv-bullet .nv-markerTriangle { stroke: #000; fill: #fff; stroke-width: 1.5px; } -.nvd3.nv-bullet .nv-tick line { stroke: #666; stroke-width: .5px; } -.nvd3.nv-bullet .nv-range.nv-s0 { fill: #eee; } -.nvd3.nv-bullet .nv-range.nv-s1 { fill: #ddd; } -.nvd3.nv-bullet .nv-range.nv-s2 { fill: #ccc; } -.nvd3.nv-bullet .nv-title { font-size: 14px; font-weight: bold; } -.nvd3.nv-bullet .nv-subtitle { fill: #999; } - - -.nvd3.nv-bullet .nv-range { - fill: #bababa; - fill-opacity: .4; -} -.nvd3.nv-bullet .nv-range:hover { - fill-opacity: .7; -} - -.nvd3.nv-candlestickBar .nv-ticks .nv-tick { - stroke-width: 1px; -} - -.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover { - stroke-width: 2px; -} - -.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect { - stroke: #2ca02c; - fill: #2ca02c; -} - -.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect { - stroke: #d62728; - fill: #d62728; -} - -.with-transitions .nv-candlestickBar .nv-ticks .nv-tick { - transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -} - -.nvd3.nv-candlestickBar .nv-ticks line { - stroke: #333; -} - - -.nvd3 .nv-legend .nv-disabled rect { - /*fill-opacity: 0;*/ -} - -.nvd3 .nv-check-box .nv-box { - fill-opacity:0; - stroke-width:2; -} - -.nvd3 .nv-check-box .nv-check { - fill-opacity:0; - stroke-width:4; -} - -.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check { - fill-opacity:0; - stroke-opacity:0; -} - -.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check { - opacity: 0; -} - -/* line plus bar */ -.nvd3.nv-linePlusBar .nv-bar rect { - fill-opacity: .75; -} - -.nvd3.nv-linePlusBar .nv-bar rect:hover { - fill-opacity: 1; -} -.nvd3 .nv-groups path.nv-line { - fill: none; -} - -.nvd3 .nv-groups path.nv-area { - stroke: none; -} - -.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point { - fill-opacity: 0; - stroke-opacity: 0; -} - -.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point { - fill-opacity: .5 !important; - stroke-opacity: .5 !important; -} - - -.with-transitions .nvd3 .nv-groups .nv-point { - transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -moz-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -webkit-transition: stroke-width 250ms linear, stroke-opacity 250ms linear; - -} - -.nvd3.nv-scatter .nv-groups .nv-point.hover, -.nvd3 .nv-groups .nv-point.hover { - stroke-width: 7px; - fill-opacity: .95 !important; - stroke-opacity: .95 !important; -} - - -.nvd3 .nv-point-paths path { - stroke: #aaa; - stroke-opacity: 0; - fill: #eee; - fill-opacity: 0; -} - - - -.nvd3 .nv-indexLine { - cursor: ew-resize; -} - -/******************** - * SVG CSS - */ - -/******************** - Default CSS for an svg element nvd3 used -*/ -svg.nvd3-svg { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -ms-user-select: none; - -moz-user-select: none; - user-select: none; - display: block; - width:100%; - height:100%; -} - -/******************** - Box shadow and border radius styling -*/ -.nvtooltip.with-3d-shadow, .with-3d-shadow .nvtooltip { - -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2); - -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2); - box-shadow: 0 5px 10px rgba(0,0,0,.2); - - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; -} - - -.nvd3 text { - font: normal 14px Arial; -} - -.nvd3 .title { - font: bold 14px Arial; -} - -.nvd3 .nv-background { - fill: white; - fill-opacity: 0; -} - -.nvd3.nv-noData { - font-size: 18px; - font-weight: bold; -} - - -/********** -* Brush -*/ - -.nv-brush .extent { - fill-opacity: .125; - shape-rendering: crispEdges; -} - -.nv-brush .resize path { - fill: #eee; - stroke: #666; -} - - -/********** -* Legend -*/ - -.nvd3 .nv-legend .nv-series { - cursor: pointer; -} - -.nvd3 .nv-legend .nv-disabled circle { - fill-opacity: 0; -} - -/* focus */ -.nvd3 .nv-brush .extent { - fill-opacity: 0 !important; -} - -.nvd3 .nv-brushBackground rect { - stroke: #000; - stroke-width: .4; - fill: #fff; - fill-opacity: .7; -} - - -.nvd3.nv-ohlcBar .nv-ticks .nv-tick { - stroke-width: 1px; -} - -.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover { - stroke-width: 2px; -} - -.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive { - stroke: #2ca02c; -} - -.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative { - stroke: #d62728; -} - - -.nvd3 .background path { - fill: none; - stroke: #EEE; - stroke-opacity: .4; - shape-rendering: crispEdges; -} - -.nvd3 .foreground path { - fill: none; - stroke-opacity: .7; -} - -.nvd3 .nv-parallelCoordinates-brush .extent -{ - fill: #fff; - fill-opacity: .6; - stroke: gray; - shape-rendering: crispEdges; -} - -.nvd3 .nv-parallelCoordinates .hover { - fill-opacity: 1; - stroke-width: 3px; -} - - -.nvd3 .missingValuesline line { - fill: none; - stroke: black; - stroke-width: 1; - stroke-opacity: 1; - stroke-dasharray: 5, 5; -} -.nvd3.nv-pie path { - stroke-opacity: 0; - transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; - -moz-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; - -webkit-transition: fill-opacity 250ms linear, stroke-width 250ms linear, stroke-opacity 250ms linear; - -} - -.nvd3.nv-pie .nv-pie-title { - font-size: 24px; - fill: rgba(19, 196, 249, 0.59); -} - -.nvd3.nv-pie .nv-slice text { - stroke: #000; - stroke-width: 0; -} - -.nvd3.nv-pie path { - stroke: #fff; - stroke-width: 1px; - stroke-opacity: 1; -} - -.nvd3.nv-pie .hover path { - fill-opacity: .7; -} -.nvd3.nv-pie .nv-label { - pointer-events: none; -} -.nvd3.nv-pie .nv-label rect { - fill-opacity: 0; - stroke-opacity: 0; -} - -/* scatter */ -.nvd3 .nv-groups .nv-point.hover { - stroke-width: 20px; - stroke-opacity: .5; -} - -.nvd3 .nv-scatter .nv-point.hover { - fill-opacity: 1; -} -.nv-noninteractive { - pointer-events: none; -} - -.nv-distx, .nv-disty { - pointer-events: none; -} - -/* sparkline */ -.nvd3.nv-sparkline path { - fill: none; -} - -.nvd3.nv-sparklineplus g.nv-hoverValue { - pointer-events: none; -} - -.nvd3.nv-sparklineplus .nv-hoverValue line { - stroke: #333; - stroke-width: 1.5px; -} - -.nvd3.nv-sparklineplus, -.nvd3.nv-sparklineplus g { - pointer-events: all; -} - -.nvd3 .nv-hoverArea { - fill-opacity: 0; - stroke-opacity: 0; -} - -.nvd3.nv-sparklineplus .nv-xValue, -.nvd3.nv-sparklineplus .nv-yValue { - stroke-width: 0; - font-size: .9em; - font-weight: normal; -} - -.nvd3.nv-sparklineplus .nv-yValue { - stroke: #f66; -} - -.nvd3.nv-sparklineplus .nv-maxValue { - stroke: #2ca02c; - fill: #2ca02c; -} - -.nvd3.nv-sparklineplus .nv-minValue { - stroke: #d62728; - fill: #d62728; -} - -.nvd3.nv-sparklineplus .nv-currentValue { - font-weight: bold; - font-size: 1.1em; -} -/* stacked area */ -.nvd3.nv-stackedarea path.nv-area { - fill-opacity: .7; - stroke-opacity: 0; - transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; - -moz-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; - -webkit-transition: fill-opacity 250ms linear, stroke-opacity 250ms linear; -} - -.nvd3.nv-stackedarea path.nv-area.hover { - fill-opacity: .9; -} - - -.nvd3.nv-stackedarea .nv-groups .nv-point { - stroke-opacity: 0; - fill-opacity: 0; -} - - -.nvtooltip { - position: absolute; - background-color: rgba(255,255,255,1.0); - color: rgba(0,0,0,1.0); - padding: 1px; - border: 1px solid rgba(0,0,0,.2); - z-index: 10000; - display: block; - - font-family: Arial; - font-size: 13px; - text-align: left; - pointer-events: none; - - white-space: nowrap; - - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.nvtooltip { - background: rgba(255,255,255, 0.8); - border: 1px solid rgba(0,0,0,0.5); - border-radius: 4px; -} - -/*Give tooltips that old fade in transition by - putting a "with-transitions" class on the container div. -*/ -.nvtooltip.with-transitions, .with-transitions .nvtooltip { - transition: opacity 50ms linear; - -moz-transition: opacity 50ms linear; - -webkit-transition: opacity 50ms linear; - - transition-delay: 200ms; - -moz-transition-delay: 200ms; - -webkit-transition-delay: 200ms; -} - -.nvtooltip.x-nvtooltip, -.nvtooltip.y-nvtooltip { - padding: 8px; -} - -.nvtooltip h3 { - margin: 0; - padding: 4px 14px; - line-height: 18px; - font-weight: normal; - background-color: rgba(247,247,247,0.75); - color: rgba(0,0,0,1.0); - text-align: center; - - border-bottom: 1px solid #ebebeb; - - -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; -} - -.nvtooltip p { - margin: 0; - padding: 5px 14px; - text-align: center; -} - -.nvtooltip span { - display: inline-block; - margin: 2px 0; -} - -.nvtooltip table { - margin: 6px; - border-spacing:0; -} - - -.nvtooltip table td { - padding: 2px 9px 2px 0; - vertical-align: middle; -} - -.nvtooltip table td.key { - font-weight:normal; -} -.nvtooltip table td.value { - text-align: right; - font-weight: bold; -} - -.nvtooltip table tr.highlight td { - padding: 1px 9px 1px 0; - border-bottom-style: solid; - border-bottom-width: 1px; - border-top-style: solid; - border-top-width: 1px; -} - -.nvtooltip table td.legend-color-guide div { - width: 8px; - height: 8px; - vertical-align: middle; -} - -.nvtooltip table td.legend-color-guide div { - width: 12px; - height: 12px; - border: 1px solid #999; -} - -.nvtooltip .footer { - padding: 3px; - text-align: center; -} - -.nvtooltip-pending-removal { - pointer-events: none; - display: none; -} - - -/**** -Interactive Layer -*/ -.nvd3 .nv-interactiveGuideLine { - pointer-events:none; -} -.nvd3 line.nv-guideline { - stroke: #ccc; -} \ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.js b/wqflask/wqflask/static/new/packages/nvd3/nv.d3.js deleted file mode 100644 index f64a6c14..00000000 --- a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.js +++ /dev/null @@ -1,13363 +0,0 @@ -/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-05-25 */ -(function(){ - -// set up main nv object -var nv = {}; - -// the major global objects under the nv namespace -nv.dev = false; //set false when in production -nv.tooltip = nv.tooltip || {}; // For the tooltip system -nv.utils = nv.utils || {}; // Utility subsystem -nv.models = nv.models || {}; //stores all the possible models/components -nv.charts = {}; //stores all the ready to use charts -nv.logs = {}; //stores some statistics and potential error messages -nv.dom = {}; //DOM manipulation functions - -nv.dispatch = d3.dispatch('render_start', 'render_end'); - -// Function bind polyfill -// Needed ONLY for phantomJS as it's missing until version 2.0 which is unreleased as of this comment -// https://github.com/ariya/phantomjs/issues/10522 -// http://kangax.github.io/compat-table/es5/#Function.prototype.bind -// phantomJS is used for running the test suite -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - return fBound; - }; -} - -// Development render timers - disabled if dev = false -if (nv.dev) { - nv.dispatch.on('render_start', function(e) { - nv.logs.startTime = +new Date(); - }); - - nv.dispatch.on('render_end', function(e) { - nv.logs.endTime = +new Date(); - nv.logs.totalTime = nv.logs.endTime - nv.logs.startTime; - nv.log('total', nv.logs.totalTime); // used for development, to keep track of graph generation times - }); -} - -// Logs all arguments, and returns the last so you can test things in place -// Note: in IE8 console.log is an object not a function, and if modernizr is used -// then calling Function.prototype.bind with with anything other than a function -// causes a TypeError to be thrown. -nv.log = function() { - if (nv.dev && window.console && console.log && console.log.apply) - console.log.apply(console, arguments); - else if (nv.dev && window.console && typeof console.log == "function" && Function.prototype.bind) { - var log = Function.prototype.bind.call(console.log, console); - log.apply(console, arguments); - } - return arguments[arguments.length - 1]; -}; - -// print console warning, should be used by deprecated functions -nv.deprecated = function(name, info) { - if (console && console.warn) { - console.warn('nvd3 warning: `' + name + '` has been deprecated. ', info || ''); - } -}; - -// The nv.render function is used to queue up chart rendering -// in non-blocking async functions. -// When all queued charts are done rendering, nv.dispatch.render_end is invoked. -nv.render = function render(step) { - // number of graphs to generate in each timeout loop - step = step || 1; - - nv.render.active = true; - nv.dispatch.render_start(); - - var renderLoop = function() { - var chart, graph; - - for (var i = 0; i < step && (graph = nv.render.queue[i]); i++) { - chart = graph.generate(); - if (typeof graph.callback == typeof(Function)) graph.callback(chart); - } - - nv.render.queue.splice(0, i); - - if (nv.render.queue.length) { - setTimeout(renderLoop); - } - else { - nv.dispatch.render_end(); - nv.render.active = false; - } - }; - - setTimeout(renderLoop); -}; - -nv.render.active = false; -nv.render.queue = []; - -/* -Adds a chart to the async rendering queue. This method can take arguments in two forms: -nv.addGraph({ - generate: - callback: -}) - -or - -nv.addGraph(, ) - -The generate function should contain code that creates the NVD3 model, sets options -on it, adds data to an SVG element, and invokes the chart model. The generate function -should return the chart model. See examples/lineChart.html for a usage example. - -The callback function is optional, and it is called when the generate function completes. -*/ -nv.addGraph = function(obj) { - if (typeof arguments[0] === typeof(Function)) { - obj = {generate: arguments[0], callback: arguments[1]}; - } - - nv.render.queue.push(obj); - - if (!nv.render.active) { - nv.render(); - } -}; - -// Node/CommonJS exports -if (typeof(module) !== 'undefined' && typeof(exports) !== 'undefined') { - module.exports = nv; -} - -if (typeof(window) !== 'undefined') { - window.nv = nv; -} -/* Facade for queueing DOM write operations - * with Fastdom (https://github.com/wilsonpage/fastdom) - * if available. - * This could easily be extended to support alternate - * implementations in the future. - */ -nv.dom.write = function(callback) { - if (window.fastdom !== undefined) { - return fastdom.write(callback); - } - return callback(); -}; - -/* Facade for queueing DOM read operations - * with Fastdom (https://github.com/wilsonpage/fastdom) - * if available. - * This could easily be extended to support alternate - * implementations in the future. - */ -nv.dom.read = function(callback) { - if (window.fastdom !== undefined) { - return fastdom.read(callback); - } - return callback(); -};/* Utility class to handle creation of an interactive layer. - This places a rectangle on top of the chart. When you mouse move over it, it sends a dispatch - containing the X-coordinate. It can also render a vertical line where the mouse is located. - - dispatch.elementMousemove is the important event to latch onto. It is fired whenever the mouse moves over - the rectangle. The dispatch is given one object which contains the mouseX/Y location. - It also has 'pointXValue', which is the conversion of mouseX to the x-axis scale. - */ -nv.interactiveGuideline = function() { - "use strict"; - - var tooltip = nv.models.tooltip(); - tooltip.duration(0).hideDelay(0)._isInteractiveLayer(true).hidden(false); - - //Public settings - var width = null; - var height = null; - - //Please pass in the bounding chart's top and left margins - //This is important for calculating the correct mouseX/Y positions. - var margin = {left: 0, top: 0} - , xScale = d3.scale.linear() - , dispatch = d3.dispatch('elementMousemove', 'elementMouseout', 'elementClick', 'elementDblclick') - , showGuideLine = true; - //Must pass in the bounding chart's container. - //The mousemove event is attached to this container. - var svgContainer = null; - - // check if IE by looking for activeX - var isMSIE = "ActiveXObject" in window; - - - function layer(selection) { - selection.each(function(data) { - var container = d3.select(this); - var availableWidth = (width || 960), availableHeight = (height || 400); - var wrap = container.selectAll("g.nv-wrap.nv-interactiveLineLayer") - .data([data]); - var wrapEnter = wrap.enter() - .append("g").attr("class", " nv-wrap nv-interactiveLineLayer"); - wrapEnter.append("g").attr("class","nv-interactiveGuideLine"); - - if (!svgContainer) { - return; - } - - function mouseHandler() { - var d3mouse = d3.mouse(this); - var mouseX = d3mouse[0]; - var mouseY = d3mouse[1]; - var subtractMargin = true; - var mouseOutAnyReason = false; - if (isMSIE) { - /* - D3.js (or maybe SVG.getScreenCTM) has a nasty bug in Internet Explorer 10. - d3.mouse() returns incorrect X,Y mouse coordinates when mouse moving - over a rect in IE 10. - However, d3.event.offsetX/Y also returns the mouse coordinates - relative to the triggering . So we use offsetX/Y on IE. - */ - mouseX = d3.event.offsetX; - mouseY = d3.event.offsetY; - - /* - On IE, if you attach a mouse event listener to the container, - it will actually trigger it for all the child elements (like , , etc). - When this happens on IE, the offsetX/Y is set to where ever the child element - is located. - As a result, we do NOT need to subtract margins to figure out the mouse X/Y - position under this scenario. Removing the line below *will* cause - the interactive layer to not work right on IE. - */ - if(d3.event.target.tagName !== "svg") { - subtractMargin = false; - } - - if (d3.event.target.className.baseVal.match("nv-legend")) { - mouseOutAnyReason = true; - } - - } - - if(subtractMargin) { - mouseX -= margin.left; - mouseY -= margin.top; - } - - /* If mouseX/Y is outside of the chart's bounds, - trigger a mouseOut event. - */ - if (mouseX < 0 || mouseY < 0 - || mouseX > availableWidth || mouseY > availableHeight - || (d3.event.relatedTarget && d3.event.relatedTarget.ownerSVGElement === undefined) - || mouseOutAnyReason - ) { - - if (isMSIE) { - if (d3.event.relatedTarget - && d3.event.relatedTarget.ownerSVGElement === undefined - && (d3.event.relatedTarget.className === undefined - || d3.event.relatedTarget.className.match(tooltip.nvPointerEventsClass))) { - - return; - } - } - dispatch.elementMouseout({ - mouseX: mouseX, - mouseY: mouseY - }); - layer.renderGuideLine(null); //hide the guideline - tooltip.hidden(true); - return; - } else { - tooltip.hidden(false); - } - - var pointXValue = xScale.invert(mouseX); - dispatch.elementMousemove({ - mouseX: mouseX, - mouseY: mouseY, - pointXValue: pointXValue - }); - - //If user double clicks the layer, fire a elementDblclick - if (d3.event.type === "dblclick") { - dispatch.elementDblclick({ - mouseX: mouseX, - mouseY: mouseY, - pointXValue: pointXValue - }); - } - - // if user single clicks the layer, fire elementClick - if (d3.event.type === 'click') { - dispatch.elementClick({ - mouseX: mouseX, - mouseY: mouseY, - pointXValue: pointXValue - }); - } - } - - svgContainer - .on("touchmove",mouseHandler) - .on("mousemove",mouseHandler, true) - .on("mouseout" ,mouseHandler,true) - .on("dblclick" ,mouseHandler) - .on("click", mouseHandler) - ; - - layer.guideLine = null; - //Draws a vertical guideline at the given X postion. - layer.renderGuideLine = function(x) { - if (!showGuideLine) return; - if (layer.guideLine && layer.guideLine.attr("x1") === x) return; - nv.dom.write(function() { - var line = wrap.select(".nv-interactiveGuideLine") - .selectAll("line") - .data((x != null) ? [nv.utils.NaNtoZero(x)] : [], String); - line.enter() - .append("line") - .attr("class", "nv-guideline") - .attr("x1", function(d) { return d;}) - .attr("x2", function(d) { return d;}) - .attr("y1", availableHeight) - .attr("y2",0); - line.exit().remove(); - }); - } - }); - } - - layer.dispatch = dispatch; - layer.tooltip = tooltip; - - layer.margin = function(_) { - if (!arguments.length) return margin; - margin.top = typeof _.top != 'undefined' ? _.top : margin.top; - margin.left = typeof _.left != 'undefined' ? _.left : margin.left; - return layer; - }; - - layer.width = function(_) { - if (!arguments.length) return width; - width = _; - return layer; - }; - - layer.height = function(_) { - if (!arguments.length) return height; - height = _; - return layer; - }; - - layer.xScale = function(_) { - if (!arguments.length) return xScale; - xScale = _; - return layer; - }; - - layer.showGuideLine = function(_) { - if (!arguments.length) return showGuideLine; - showGuideLine = _; - return layer; - }; - - layer.svgContainer = function(_) { - if (!arguments.length) return svgContainer; - svgContainer = _; - return layer; - }; - - return layer; -}; - -/* Utility class that uses d3.bisect to find the index in a given array, where a search value can be inserted. - This is different from normal bisectLeft; this function finds the nearest index to insert the search value. - - For instance, lets say your array is [1,2,3,5,10,30], and you search for 28. - Normal d3.bisectLeft will return 4, because 28 is inserted after the number 10. But interactiveBisect will return 5 - because 28 is closer to 30 than 10. - - Unit tests can be found in: interactiveBisectTest.html - - Has the following known issues: - * Will not work if the data points move backwards (ie, 10,9,8,7, etc) or if the data points are in random order. - * Won't work if there are duplicate x coordinate values. - */ -nv.interactiveBisect = function (values, searchVal, xAccessor) { - "use strict"; - if (! (values instanceof Array)) { - return null; - } - var _xAccessor; - if (typeof xAccessor !== 'function') { - _xAccessor = function(d) { - return d.x; - } - } else { - _xAccessor = xAccessor; - } - var _cmp = function(d, v) { - // Accessors are no longer passed the index of the element along with - // the element itself when invoked by d3.bisector. - // - // Starting at D3 v3.4.4, d3.bisector() started inspecting the - // function passed to determine if it should consider it an accessor - // or a comparator. This meant that accessors that take two arguments - // (expecting an index as the second parameter) are treated as - // comparators where the second argument is the search value against - // which the first argument is compared. - return _xAccessor(d) - v; - }; - - var bisect = d3.bisector(_cmp).left; - var index = d3.max([0, bisect(values,searchVal) - 1]); - var currentValue = _xAccessor(values[index]); - - if (typeof currentValue === 'undefined') { - currentValue = index; - } - - if (currentValue === searchVal) { - return index; //found exact match - } - - var nextIndex = d3.min([index+1, values.length - 1]); - var nextValue = _xAccessor(values[nextIndex]); - - if (typeof nextValue === 'undefined') { - nextValue = nextIndex; - } - - if (Math.abs(nextValue - searchVal) >= Math.abs(currentValue - searchVal)) { - return index; - } else { - return nextIndex - } -}; - -/* - Returns the index in the array "values" that is closest to searchVal. - Only returns an index if searchVal is within some "threshold". - Otherwise, returns null. - */ -nv.nearestValueIndex = function (values, searchVal, threshold) { - "use strict"; - var yDistMax = Infinity, indexToHighlight = null; - values.forEach(function(d,i) { - var delta = Math.abs(searchVal - d); - if ( d != null && delta <= yDistMax && delta < threshold) { - yDistMax = delta; - indexToHighlight = i; - } - }); - return indexToHighlight; -}; -/* Tooltip rendering model for nvd3 charts. - window.nv.models.tooltip is the updated,new way to render tooltips. - - window.nv.tooltip.show is the old tooltip code. - window.nv.tooltip.* also has various helper methods. - */ -(function() { - "use strict"; - - /* Model which can be instantiated to handle tooltip rendering. - Example usage: - var tip = nv.models.tooltip().gravity('w').distance(23) - .data(myDataObject); - - tip(); //just invoke the returned function to render tooltip. - */ - nv.models.tooltip = function() { - - /* - Tooltip data. If data is given in the proper format, a consistent tooltip is generated. - Example Format of data: - { - key: "Date", - value: "August 2009", - series: [ - {key: "Series 1", value: "Value 1", color: "#000"}, - {key: "Series 2", value: "Value 2", color: "#00f"} - ] - } - */ - var data = null; - var gravity = 'w' //Can be 'n','s','e','w'. Determines how tooltip is positioned. - , distance = 25 //Distance to offset tooltip from the mouse location. - , snapDistance = 0 //Tolerance allowed before tooltip is moved from its current position (creates 'snapping' effect) - , fixedTop = null //If not null, this fixes the top position of the tooltip. - , classes = null //Attaches additional CSS classes to the tooltip DIV that is created. - , chartContainer = null //Parent dom element of the SVG that holds the chart. - , hidden = true // start off hidden, toggle with hide/show functions below - , hideDelay = 400 // delay before the tooltip hides after calling hide() - , tooltip = null // d3 select of tooltipElem below - , tooltipElem = null //actual DOM element representing the tooltip. - , position = {left: null, top: null} //Relative position of the tooltip inside chartContainer. - , offset = {left: 0, top: 0} //Offset of tooltip against the pointer - , enabled = true //True -> tooltips are rendered. False -> don't render tooltips. - , duration = 100 // duration for tooltip movement - , headerEnabled = true - ; - - // set to true by interactive layer to adjust tooltip positions - // eventually we should probably fix interactive layer to get the position better. - // for now this is needed if you want to set chartContainer for normal tooltips, else it "fixes" it to broken - var isInteractiveLayer = false; - - //Generates a unique id when you create a new tooltip() object - var id = "nvtooltip-" + Math.floor(Math.random() * 100000); - - //CSS class to specify whether element should not have mouse events. - var nvPointerEventsClass = "nv-pointer-events-none"; - - //Format function for the tooltip values column - var valueFormatter = function(d,i) { - return d; - }; - - //Format function for the tooltip header value. - var headerFormatter = function(d) { - return d; - }; - - var keyFormatter = function(d, i) { - return d; - }; - - //By default, the tooltip model renders a beautiful table inside a DIV. - //You can override this function if a custom tooltip is desired. - var contentGenerator = function(d) { - if (d === null) { - return ''; - } - - var table = d3.select(document.createElement("table")); - if (headerEnabled) { - var theadEnter = table.selectAll("thead") - .data([d]) - .enter().append("thead"); - - theadEnter.append("tr") - .append("td") - .attr("colspan", 3) - .append("strong") - .classed("x-value", true) - .html(headerFormatter(d.value)); - } - - var tbodyEnter = table.selectAll("tbody") - .data([d]) - .enter().append("tbody"); - - var trowEnter = tbodyEnter.selectAll("tr") - .data(function(p) { return p.series}) - .enter() - .append("tr") - .classed("highlight", function(p) { return p.highlight}); - - trowEnter.append("td") - .classed("legend-color-guide",true) - .append("div") - .style("background-color", function(p) { return p.color}); - - trowEnter.append("td") - .classed("key",true) - .html(function(p, i) {return keyFormatter(p.key, i)}); - - trowEnter.append("td") - .classed("value",true) - .html(function(p, i) { return valueFormatter(p.value, i) }); - - - trowEnter.selectAll("td").each(function(p) { - if (p.highlight) { - var opacityScale = d3.scale.linear().domain([0,1]).range(["#fff",p.color]); - var opacity = 0.6; - d3.select(this) - .style("border-bottom-color", opacityScale(opacity)) - .style("border-top-color", opacityScale(opacity)) - ; - } - }); - - var html = table.node().outerHTML; - if (d.footer !== undefined) - html += ""; - return html; - - }; - - var dataSeriesExists = function(d) { - if (d && d.series) { - if (d.series instanceof Array) { - return !!d.series.length; - } - // if object, it's okay just convert to array of the object - if (d.series instanceof Object) { - d.series = [d.series]; - return true; - } - } - return false; - }; - - var calcTooltipPosition = function(pos) { - if (!tooltipElem) return; - - nv.dom.read(function() { - var height = parseInt(tooltipElem.offsetHeight, 10), - width = parseInt(tooltipElem.offsetWidth, 10), - windowWidth = nv.utils.windowSize().width, - windowHeight = nv.utils.windowSize().height, - scrollTop = window.pageYOffset, - scrollLeft = window.pageXOffset, - left, top; - - windowHeight = window.innerWidth >= document.body.scrollWidth ? windowHeight : windowHeight - 16; - windowWidth = window.innerHeight >= document.body.scrollHeight ? windowWidth : windowWidth - 16; - - - //Helper functions to find the total offsets of a given DOM element. - //Looks up the entire ancestry of an element, up to the first relatively positioned element. - var tooltipTop = function ( Elem ) { - var offsetTop = top; - do { - if( !isNaN( Elem.offsetTop ) ) { - offsetTop += (Elem.offsetTop); - } - Elem = Elem.offsetParent; - } while( Elem ); - return offsetTop; - }; - var tooltipLeft = function ( Elem ) { - var offsetLeft = left; - do { - if( !isNaN( Elem.offsetLeft ) ) { - offsetLeft += (Elem.offsetLeft); - } - Elem = Elem.offsetParent; - } while( Elem ); - return offsetLeft; - }; - - // calculate position based on gravity - var tLeft, tTop; - switch (gravity) { - case 'e': - left = pos[0] - width - distance; - top = pos[1] - (height / 2); - tLeft = tooltipLeft(tooltipElem); - tTop = tooltipTop(tooltipElem); - if (tLeft < scrollLeft) left = pos[0] + distance > scrollLeft ? pos[0] + distance : scrollLeft - tLeft + left; - if (tTop < scrollTop) top = scrollTop - tTop + top; - if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; - break; - case 'w': - left = pos[0] + distance; - top = pos[1] - (height / 2); - tLeft = tooltipLeft(tooltipElem); - tTop = tooltipTop(tooltipElem); - if (tLeft + width > windowWidth) left = pos[0] - width - distance; - if (tTop < scrollTop) top = scrollTop + 5; - if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; - break; - case 'n': - left = pos[0] - (width / 2) - 5; - top = pos[1] + distance; - tLeft = tooltipLeft(tooltipElem); - tTop = tooltipTop(tooltipElem); - if (tLeft < scrollLeft) left = scrollLeft + 5; - if (tLeft + width > windowWidth) left = left - width/2 + 5; - if (tTop + height > scrollTop + windowHeight) top = scrollTop + windowHeight - tTop + top - height; - break; - case 's': - left = pos[0] - (width / 2); - top = pos[1] - height - distance; - tLeft = tooltipLeft(tooltipElem); - tTop = tooltipTop(tooltipElem); - if (tLeft < scrollLeft) left = scrollLeft + 5; - if (tLeft + width > windowWidth) left = left - width/2 + 5; - if (scrollTop > tTop) top = scrollTop; - break; - case 'none': - left = pos[0]; - top = pos[1] - distance; - tLeft = tooltipLeft(tooltipElem); - tTop = tooltipTop(tooltipElem); - break; - } - - // adjust tooltip offsets - left -= offset.left; - top -= offset.top; - - // using tooltip.style('transform') returns values un-usable for tween - var box = tooltipElem.getBoundingClientRect(); - var scrollTop = window.pageYOffset || document.documentElement.scrollTop; - var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; - var old_translate = 'translate(' + (box.left + scrollLeft) + 'px, ' + (box.top + scrollTop) + 'px)'; - var new_translate = 'translate(' + left + 'px, ' + top + 'px)'; - var translateInterpolator = d3.interpolateString(old_translate, new_translate); - - var is_hidden = tooltip.style('opacity') < 0.1; - - // delay hiding a bit to avoid flickering - if (hidden) { - tooltip - .transition() - .delay(hideDelay) - .duration(0) - .style('opacity', 0); - } else { - tooltip - .interrupt() // cancel running transitions - .transition() - .duration(is_hidden ? 0 : duration) - // using tween since some versions of d3 can't auto-tween a translate on a div - .styleTween('transform', function (d) { - return translateInterpolator; - }, 'important') - // Safari has its own `-webkit-transform` and does not support `transform` - // transform tooltip without transition only in Safari - .style('-webkit-transform', new_translate) - .style('opacity', 1); - } - - - - }); - }; - - //In situations where the chart is in a 'viewBox', re-position the tooltip based on how far chart is zoomed. - function convertViewBoxRatio() { - if (chartContainer) { - var svg = d3.select(chartContainer); - if (svg.node().tagName !== "svg") { - svg = svg.select("svg"); - } - var viewBox = (svg.node()) ? svg.attr('viewBox') : null; - if (viewBox) { - viewBox = viewBox.split(' '); - var ratio = parseInt(svg.style('width'), 10) / viewBox[2]; - - position.left = position.left * ratio; - position.top = position.top * ratio; - } - } - } - - //Creates new tooltip container, or uses existing one on DOM. - function initTooltip() { - if (!tooltip) { - var body; - if (chartContainer) { - body = chartContainer; - } else { - body = document.body; - } - //Create new tooltip div if it doesn't exist on DOM. - tooltip = d3.select(body).append("div") - .attr("class", "nvtooltip " + (classes ? classes : "xy-tooltip")) - .attr("id", id); - tooltip.style("top", 0).style("left", 0); - tooltip.style('opacity', 0); - tooltip.selectAll("div, table, td, tr").classed(nvPointerEventsClass, true); - tooltip.classed(nvPointerEventsClass, true); - tooltipElem = tooltip.node(); - } - } - - //Draw the tooltip onto the DOM. - function nvtooltip() { - if (!enabled) return; - if (!dataSeriesExists(data)) return; - - convertViewBoxRatio(); - - var left = position.left; - var top = (fixedTop !== null) ? fixedTop : position.top; - - nv.dom.write(function () { - initTooltip(); - // generate data and set it into tooltip - // Bonus - If you override contentGenerator and return falsey you can use something like - // React or Knockout to bind the data for your tooltip - var newContent = contentGenerator(data); - if (newContent) { - tooltipElem.innerHTML = newContent; - } - - if (chartContainer && isInteractiveLayer) { - nv.dom.read(function() { - var svgComp = chartContainer.getElementsByTagName("svg")[0]; - var svgOffset = {left:0,top:0}; - if (svgComp) { - var svgBound = svgComp.getBoundingClientRect(); - var chartBound = chartContainer.getBoundingClientRect(); - var svgBoundTop = svgBound.top; - - //Defensive code. Sometimes, svgBoundTop can be a really negative - // number, like -134254. That's a bug. - // If such a number is found, use zero instead. FireFox bug only - if (svgBoundTop < 0) { - var containerBound = chartContainer.getBoundingClientRect(); - svgBoundTop = (Math.abs(svgBoundTop) > containerBound.height) ? 0 : svgBoundTop; - } - svgOffset.top = Math.abs(svgBoundTop - chartBound.top); - svgOffset.left = Math.abs(svgBound.left - chartBound.left); - } - //If the parent container is an overflow
with scrollbars, subtract the scroll offsets. - //You need to also add any offset between the element and its containing
- //Finally, add any offset of the containing
on the whole page. - left += chartContainer.offsetLeft + svgOffset.left - 2*chartContainer.scrollLeft; - top += chartContainer.offsetTop + svgOffset.top - 2*chartContainer.scrollTop; - - if (snapDistance && snapDistance > 0) { - top = Math.floor(top/snapDistance) * snapDistance; - } - calcTooltipPosition([left,top]); - }); - } else { - calcTooltipPosition([left,top]); - } - }); - - return nvtooltip; - } - - nvtooltip.nvPointerEventsClass = nvPointerEventsClass; - nvtooltip.options = nv.utils.optionsFunc.bind(nvtooltip); - - nvtooltip._options = Object.create({}, { - // simple read/write options - duration: {get: function(){return duration;}, set: function(_){duration=_;}}, - gravity: {get: function(){return gravity;}, set: function(_){gravity=_;}}, - distance: {get: function(){return distance;}, set: function(_){distance=_;}}, - snapDistance: {get: function(){return snapDistance;}, set: function(_){snapDistance=_;}}, - classes: {get: function(){return classes;}, set: function(_){classes=_;}}, - chartContainer: {get: function(){return chartContainer;}, set: function(_){chartContainer=_;}}, - fixedTop: {get: function(){return fixedTop;}, set: function(_){fixedTop=_;}}, - enabled: {get: function(){return enabled;}, set: function(_){enabled=_;}}, - hideDelay: {get: function(){return hideDelay;}, set: function(_){hideDelay=_;}}, - contentGenerator: {get: function(){return contentGenerator;}, set: function(_){contentGenerator=_;}}, - valueFormatter: {get: function(){return valueFormatter;}, set: function(_){valueFormatter=_;}}, - headerFormatter: {get: function(){return headerFormatter;}, set: function(_){headerFormatter=_;}}, - keyFormatter: {get: function(){return keyFormatter;}, set: function(_){keyFormatter=_;}}, - headerEnabled: {get: function(){return headerEnabled;}, set: function(_){headerEnabled=_;}}, - - // internal use only, set by interactive layer to adjust position. - _isInteractiveLayer: {get: function(){return isInteractiveLayer;}, set: function(_){isInteractiveLayer=!!_;}}, - - // options with extra logic - position: {get: function(){return position;}, set: function(_){ - position.left = _.left !== undefined ? _.left : position.left; - position.top = _.top !== undefined ? _.top : position.top; - }}, - offset: {get: function(){return offset;}, set: function(_){ - offset.left = _.left !== undefined ? _.left : offset.left; - offset.top = _.top !== undefined ? _.top : offset.top; - }}, - hidden: {get: function(){return hidden;}, set: function(_){ - if (hidden != _) { - hidden = !!_; - nvtooltip(); - } - }}, - data: {get: function(){return data;}, set: function(_){ - // if showing a single data point, adjust data format with that - if (_.point) { - _.value = _.point.x; - _.series = _.series || {}; - _.series.value = _.point.y; - _.series.color = _.point.color || _.series.color; - } - data = _; - }}, - - // read only properties - tooltipElem: {get: function(){return tooltipElem;}, set: function(_){}}, - id: {get: function(){return id;}, set: function(_){}} - }); - - nv.utils.initOptions(nvtooltip); - return nvtooltip; - }; - -})(); - - -/* -Gets the browser window size - -Returns object with height and width properties - */ -nv.utils.windowSize = function() { - // Sane defaults - var size = {width: 640, height: 480}; - - // Most recent browsers use - if (window.innerWidth && window.innerHeight) { - size.width = window.innerWidth; - size.height = window.innerHeight; - return (size); - } - - // IE can use depending on mode it is in - if (document.compatMode=='CSS1Compat' && - document.documentElement && - document.documentElement.offsetWidth ) { - - size.width = document.documentElement.offsetWidth; - size.height = document.documentElement.offsetHeight; - return (size); - } - - // Earlier IE uses Doc.body - if (document.body && document.body.offsetWidth) { - size.width = document.body.offsetWidth; - size.height = document.body.offsetHeight; - return (size); - } - - return (size); -}; - -/* -Binds callback function to run when window is resized - */ -nv.utils.windowResize = function(handler) { - if (window.addEventListener) { - window.addEventListener('resize', handler); - } else { - nv.log("ERROR: Failed to bind to window.resize with: ", handler); - } - // return object with clear function to remove the single added callback. - return { - callback: handler, - clear: function() { - window.removeEventListener('resize', handler); - } - } -}; - - -/* -Backwards compatible way to implement more d3-like coloring of graphs. -Can take in nothing, an array, or a function/scale -To use a normal scale, get the range and pass that because we must be able -to take two arguments and use the index to keep backward compatibility -*/ -nv.utils.getColor = function(color) { - //if you pass in nothing, get default colors back - if (color === undefined) { - return nv.utils.defaultColor(); - - //if passed an array, turn it into a color scale - // use isArray, instanceof fails if d3 range is created in an iframe - } else if(Array.isArray(color)) { - var color_scale = d3.scale.ordinal().range(color); - return function(d, i) { - var key = i === undefined ? d : i; - return d.color || color_scale(key); - }; - - //if passed a function or scale, return it, or whatever it may be - //external libs, such as angularjs-nvd3-directives use this - } else { - //can't really help it if someone passes rubbish as color - return color; - } -}; - - -/* -Default color chooser uses a color scale of 20 colors from D3 - https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors - */ -nv.utils.defaultColor = function() { - // get range of the scale so we'll turn it into our own function. - return nv.utils.getColor(d3.scale.category20().range()); -}; - - -/* -Returns a color function that takes the result of 'getKey' for each series and -looks for a corresponding color from the dictionary -*/ -nv.utils.customTheme = function(dictionary, getKey, defaultColors) { - // use default series.key if getKey is undefined - getKey = getKey || function(series) { return series.key }; - defaultColors = defaultColors || d3.scale.category20().range(); - - // start at end of default color list and walk back to index 0 - var defIndex = defaultColors.length; - - return function(series, index) { - var key = getKey(series); - if (typeof dictionary[key] === 'function') { - return dictionary[key](); - } else if (dictionary[key] !== undefined) { - return dictionary[key]; - } else { - // no match in dictionary, use a default color - if (!defIndex) { - // used all the default colors, start over - defIndex = defaultColors.length; - } - defIndex = defIndex - 1; - return defaultColors[defIndex]; - } - }; -}; - - -/* -From the PJAX example on d3js.org, while this is not really directly needed -it's a very cool method for doing pjax, I may expand upon it a little bit, -open to suggestions on anything that may be useful -*/ -nv.utils.pjax = function(links, content) { - - var load = function(href) { - d3.html(href, function(fragment) { - var target = d3.select(content).node(); - target.parentNode.replaceChild( - d3.select(fragment).select(content).node(), - target); - nv.utils.pjax(links, content); - }); - }; - - d3.selectAll(links).on("click", function() { - history.pushState(this.href, this.textContent, this.href); - load(this.href); - d3.event.preventDefault(); - }); - - d3.select(window).on("popstate", function() { - if (d3.event.state) { - load(d3.event.state); - } - }); -}; - - -/* -For when we want to approximate the width in pixels for an SVG:text element. -Most common instance is when the element is in a display:none; container. -Forumla is : text.length * font-size * constant_factor -*/ -nv.utils.calcApproxTextWidth = function (svgTextElem) { - if (typeof svgTextElem.style === 'function' - && typeof svgTextElem.text === 'function') { - - var fontSize = parseInt(svgTextElem.style("font-size").replace("px",""), 10); - var textLength = svgTextElem.text().length; - return textLength * fontSize * 0.5; - } - return 0; -}; - - -/* -Numbers that are undefined, null or NaN, convert them to zeros. -*/ -nv.utils.NaNtoZero = function(n) { - if (typeof n !== 'number' - || isNaN(n) - || n === null - || n === Infinity - || n === -Infinity) { - - return 0; - } - return n; -}; - -/* -Add a way to watch for d3 transition ends to d3 -*/ -d3.selection.prototype.watchTransition = function(renderWatch){ - var args = [this].concat([].slice.call(arguments, 1)); - return renderWatch.transition.apply(renderWatch, args); -}; - - -/* -Helper object to watch when d3 has rendered something -*/ -nv.utils.renderWatch = function(dispatch, duration) { - if (!(this instanceof nv.utils.renderWatch)) { - return new nv.utils.renderWatch(dispatch, duration); - } - - var _duration = duration !== undefined ? duration : 250; - var renderStack = []; - var self = this; - - this.models = function(models) { - models = [].slice.call(arguments, 0); - models.forEach(function(model){ - model.__rendered = false; - (function(m){ - m.dispatch.on('renderEnd', function(arg){ - m.__rendered = true; - self.renderEnd('model'); - }); - })(model); - - if (renderStack.indexOf(model) < 0) { - renderStack.push(model); - } - }); - return this; - }; - - this.reset = function(duration) { - if (duration !== undefined) { - _duration = duration; - } - renderStack = []; - }; - - this.transition = function(selection, args, duration) { - args = arguments.length > 1 ? [].slice.call(arguments, 1) : []; - - if (args.length > 1) { - duration = args.pop(); - } else { - duration = _duration !== undefined ? _duration : 250; - } - selection.__rendered = false; - - if (renderStack.indexOf(selection) < 0) { - renderStack.push(selection); - } - - if (duration === 0) { - selection.__rendered = true; - selection.delay = function() { return this; }; - selection.duration = function() { return this; }; - return selection; - } else { - if (selection.length === 0) { - selection.__rendered = true; - } else if (selection.every( function(d){ return !d.length; } )) { - selection.__rendered = true; - } else { - selection.__rendered = false; - } - - var n = 0; - return selection - .transition() - .duration(duration) - .each(function(){ ++n; }) - .each('end', function(d, i) { - if (--n === 0) { - selection.__rendered = true; - self.renderEnd.apply(this, args); - } - }); - } - }; - - this.renderEnd = function() { - if (renderStack.every( function(d){ return d.__rendered; } )) { - renderStack.forEach( function(d){ d.__rendered = false; }); - dispatch.renderEnd.apply(this, arguments); - } - } - -}; - - -/* -Takes multiple objects and combines them into the first one (dst) -example: nv.utils.deepExtend({a: 1}, {a: 2, b: 3}, {c: 4}); -gives: {a: 2, b: 3, c: 4} -*/ -nv.utils.deepExtend = function(dst){ - var sources = arguments.length > 1 ? [].slice.call(arguments, 1) : []; - sources.forEach(function(source) { - for (var key in source) { - var isArray = dst[key] instanceof Array; - var isObject = typeof dst[key] === 'object'; - var srcObj = typeof source[key] === 'object'; - - if (isObject && !isArray && srcObj) { - nv.utils.deepExtend(dst[key], source[key]); - } else { - dst[key] = source[key]; - } - } - }); -}; - - -/* -state utility object, used to track d3 states in the models -*/ -nv.utils.state = function(){ - if (!(this instanceof nv.utils.state)) { - return new nv.utils.state(); - } - var state = {}; - var _self = this; - var _setState = function(){}; - var _getState = function(){ return {}; }; - var init = null; - var changed = null; - - this.dispatch = d3.dispatch('change', 'set'); - - this.dispatch.on('set', function(state){ - _setState(state, true); - }); - - this.getter = function(fn){ - _getState = fn; - return this; - }; - - this.setter = function(fn, callback) { - if (!callback) { - callback = function(){}; - } - _setState = function(state, update){ - fn(state); - if (update) { - callback(); - } - }; - return this; - }; - - this.init = function(state){ - init = init || {}; - nv.utils.deepExtend(init, state); - }; - - var _set = function(){ - var settings = _getState(); - - if (JSON.stringify(settings) === JSON.stringify(state)) { - return false; - } - - for (var key in settings) { - if (state[key] === undefined) { - state[key] = {}; - } - state[key] = settings[key]; - changed = true; - } - return true; - }; - - this.update = function(){ - if (init) { - _setState(init, false); - init = null; - } - if (_set.call(this)) { - this.dispatch.change(state); - } - }; - -}; - - -/* -Snippet of code you can insert into each nv.models.* to give you the ability to -do things like: -chart.options({ - showXAxis: true, - tooltips: true -}); - -To enable in the chart: -chart.options = nv.utils.optionsFunc.bind(chart); -*/ -nv.utils.optionsFunc = function(args) { - if (args) { - d3.map(args).forEach((function(key,value) { - if (typeof this[key] === "function") { - this[key](value); - } - }).bind(this)); - } - return this; -}; - - -/* -numTicks: requested number of ticks -data: the chart data - -returns the number of ticks to actually use on X axis, based on chart data -to avoid duplicate ticks with the same value -*/ -nv.utils.calcTicksX = function(numTicks, data) { - // find max number of values from all data streams - var numValues = 1; - var i = 0; - for (i; i < data.length; i += 1) { - var stream_len = data[i] && data[i].values ? data[i].values.length : 0; - numValues = stream_len > numValues ? stream_len : numValues; - } - nv.log("Requested number of ticks: ", numTicks); - nv.log("Calculated max values to be: ", numValues); - // make sure we don't have more ticks than values to avoid duplicates - numTicks = numTicks > numValues ? numTicks = numValues - 1 : numTicks; - // make sure we have at least one tick - numTicks = numTicks < 1 ? 1 : numTicks; - // make sure it's an integer - numTicks = Math.floor(numTicks); - nv.log("Calculating tick count as: ", numTicks); - return numTicks; -}; - - -/* -returns number of ticks to actually use on Y axis, based on chart data -*/ -nv.utils.calcTicksY = function(numTicks, data) { - // currently uses the same logic but we can adjust here if needed later - return nv.utils.calcTicksX(numTicks, data); -}; - - -/* -Add a particular option from an options object onto chart -Options exposed on a chart are a getter/setter function that returns chart -on set to mimic typical d3 option chaining, e.g. svg.option1('a').option2('b'); - -option objects should be generated via Object.create() to provide -the option of manipulating data via get/set functions. -*/ -nv.utils.initOption = function(chart, name) { - // if it's a call option, just call it directly, otherwise do get/set - if (chart._calls && chart._calls[name]) { - chart[name] = chart._calls[name]; - } else { - chart[name] = function (_) { - if (!arguments.length) return chart._options[name]; - chart._overrides[name] = true; - chart._options[name] = _; - return chart; - }; - // calling the option as _option will ignore if set by option already - // so nvd3 can set options internally but the stop if set manually - chart['_' + name] = function(_) { - if (!arguments.length) return chart._options[name]; - if (!chart._overrides[name]) { - chart._options[name] = _; - } - return chart; - } - } -}; - - -/* -Add all options in an options object to the chart -*/ -nv.utils.initOptions = function(chart) { - chart._overrides = chart._overrides || {}; - var ops = Object.getOwnPropertyNames(chart._options || {}); - var calls = Object.getOwnPropertyNames(chart._calls || {}); - ops = ops.concat(calls); - for (var i in ops) { - nv.utils.initOption(chart, ops[i]); - } -}; - - -/* -Inherit options from a D3 object -d3.rebind makes calling the function on target actually call it on source -Also use _d3options so we can track what we inherit for documentation and chained inheritance -*/ -nv.utils.inheritOptionsD3 = function(target, d3_source, oplist) { - target._d3options = oplist.concat(target._d3options || []); - oplist.unshift(d3_source); - oplist.unshift(target); - d3.rebind.apply(this, oplist); -}; - - -/* -Remove duplicates from an array -*/ -nv.utils.arrayUnique = function(a) { - return a.sort().filter(function(item, pos) { - return !pos || item != a[pos - 1]; - }); -}; - - -/* -Keeps a list of custom symbols to draw from in addition to d3.svg.symbol -Necessary since d3 doesn't let you extend its list -_- -Add new symbols by doing nv.utils.symbols.set('name', function(size){...}); -*/ -nv.utils.symbolMap = d3.map(); - - -/* -Replaces d3.svg.symbol so that we can look both there and our own map - */ -nv.utils.symbol = function() { - var type, - size = 64; - function symbol(d,i) { - var t = type.call(this,d,i); - var s = size.call(this,d,i); - if (d3.svg.symbolTypes.indexOf(t) !== -1) { - return d3.svg.symbol().type(t).size(s)(); - } else { - return nv.utils.symbolMap.get(t)(s); - } - } - symbol.type = function(_) { - if (!arguments.length) return type; - type = d3.functor(_); - return symbol; - }; - symbol.size = function(_) { - if (!arguments.length) return size; - size = d3.functor(_); - return symbol; - }; - return symbol; -}; - - -/* -Inherit option getter/setter functions from source to target -d3.rebind makes calling the function on target actually call it on source -Also track via _inherited and _d3options so we can track what we inherit -for documentation generation purposes and chained inheritance -*/ -nv.utils.inheritOptions = function(target, source) { - // inherit all the things - var ops = Object.getOwnPropertyNames(source._options || {}); - var calls = Object.getOwnPropertyNames(source._calls || {}); - var inherited = source._inherited || []; - var d3ops = source._d3options || []; - var args = ops.concat(calls).concat(inherited).concat(d3ops); - args.unshift(source); - args.unshift(target); - d3.rebind.apply(this, args); - // pass along the lists to keep track of them, don't allow duplicates - target._inherited = nv.utils.arrayUnique(ops.concat(calls).concat(inherited).concat(ops).concat(target._inherited || [])); - target._d3options = nv.utils.arrayUnique(d3ops.concat(target._d3options || [])); -}; - - -/* -Runs common initialize code on the svg before the chart builds -*/ -nv.utils.initSVG = function(svg) { - svg.classed({'nvd3-svg':true}); -}; - - -/* -Sanitize and provide default for the container height. -*/ -nv.utils.sanitizeHeight = function(height, container) { - return (height || parseInt(container.style('height'), 10) || 400); -}; - - -/* -Sanitize and provide default for the container width. -*/ -nv.utils.sanitizeWidth = function(width, container) { - return (width || parseInt(container.style('width'), 10) || 960); -}; - - -/* -Calculate the available height for a chart. -*/ -nv.utils.availableHeight = function(height, container, margin) { - return nv.utils.sanitizeHeight(height, container) - margin.top - margin.bottom; -}; - -/* -Calculate the available width for a chart. -*/ -nv.utils.availableWidth = function(width, container, margin) { - return nv.utils.sanitizeWidth(width, container) - margin.left - margin.right; -}; - -/* -Clear any rendered chart components and display a chart's 'noData' message -*/ -nv.utils.noData = function(chart, container) { - var opt = chart.options(), - margin = opt.margin(), - noData = opt.noData(), - data = (noData == null) ? ["No Data Available."] : [noData], - height = nv.utils.availableHeight(opt.height(), container, margin), - width = nv.utils.availableWidth(opt.width(), container, margin), - x = margin.left + width/2, - y = margin.top + height/2; - - //Remove any previously created chart components - container.selectAll('g').remove(); - - var noDataText = container.selectAll('.nv-noData').data(data); - - noDataText.enter().append('text') - .attr('class', 'nvd3 nv-noData') - .attr('dy', '-.7em') - .style('text-anchor', 'middle'); - - noDataText - .attr('x', x) - .attr('y', y) - .text(function(t){ return t; }); -}; - -nv.models.axis = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var axis = d3.svg.axis(); - var scale = d3.scale.linear(); - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 75 //only used for tickLabel currently - , height = 60 //only used for tickLabel currently - , axisLabelText = null - , showMaxMin = false //TODO: showMaxMin should be disabled on all ordinal scaled axes - , rotateLabels = 0 - , rotateYLabel = true - , staggerLabels = false - , isOrdinal = false - , ticks = null - , axisLabelDistance = 0 - , duration = 250 - , dispatch = d3.dispatch('renderEnd') - ; - axis - .scale(scale) - .orient('bottom') - .tickFormat(function(d) { return d }) - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var scale0; - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var container = d3.select(this); - nv.utils.initSVG(container); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-axis').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-axis'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - if (ticks !== null) - axis.ticks(ticks); - else if (axis.orient() == 'top' || axis.orient() == 'bottom') - axis.ticks(Math.abs(scale.range()[1] - scale.range()[0]) / 100); - - //TODO: consider calculating width/height based on whether or not label is added, for reference in charts using this component - g.watchTransition(renderWatch, 'axis').call(axis); - - scale0 = scale0 || axis.scale(); - - var fmt = axis.tickFormat(); - if (fmt == null) { - fmt = scale0.tickFormat(); - } - - var axisLabel = g.selectAll('text.nv-axislabel') - .data([axisLabelText || null]); - axisLabel.exit().remove(); - - var xLabelMargin; - var axisMaxMin; - var w; - switch (axis.orient()) { - case 'top': - axisLabel.enter().append('text').attr('class', 'nv-axislabel'); - if (scale.range().length < 2) { - w = 0; - } else if (scale.range().length === 2) { - w = scale.range()[1]; - } else { - w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]); - } - axisLabel - .attr('text-anchor', 'middle') - .attr('y', 0) - .attr('x', w/2); - if (showMaxMin) { - axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') - .data(scale.domain()); - axisMaxMin.enter().append('g').attr('class',function(d,i){ - return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ') - }).append('text'); - axisMaxMin.exit().remove(); - axisMaxMin - .attr('transform', function(d,i) { - return 'translate(' + nv.utils.NaNtoZero(scale(d)) + ',0)' - }) - .select('text') - .attr('dy', '-0.5em') - .attr('y', -axis.tickPadding()) - .attr('text-anchor', 'middle') - .text(function(d,i) { - var v = fmt(d); - return ('' + v).match('NaN') ? '' : v; - }); - axisMaxMin.watchTransition(renderWatch, 'min-max top') - .attr('transform', function(d,i) { - return 'translate(' + nv.utils.NaNtoZero(scale.range()[i]) + ',0)' - }); - } - break; - case 'bottom': - xLabelMargin = axisLabelDistance + 36; - var maxTextWidth = 30; - var textHeight = 0; - var xTicks = g.selectAll('g').select("text"); - var rotateLabelsRule = ''; - if (rotateLabels%360) { - //Calculate the longest xTick width - xTicks.each(function(d,i){ - var box = this.getBoundingClientRect(); - var width = box.width; - textHeight = box.height; - if(width > maxTextWidth) maxTextWidth = width; - }); - rotateLabelsRule = 'rotate(' + rotateLabels + ' 0,' + (textHeight/2 + axis.tickPadding()) + ')'; - //Convert to radians before calculating sin. Add 30 to margin for healthy padding. - var sin = Math.abs(Math.sin(rotateLabels*Math.PI/180)); - xLabelMargin = (sin ? sin*maxTextWidth : maxTextWidth)+30; - //Rotate all xTicks - xTicks - .attr('transform', rotateLabelsRule) - .style('text-anchor', rotateLabels%360 > 0 ? 'start' : 'end'); - } - axisLabel.enter().append('text').attr('class', 'nv-axislabel'); - if (scale.range().length < 2) { - w = 0; - } else if (scale.range().length === 2) { - w = scale.range()[1]; - } else { - w = scale.range()[scale.range().length-1]+(scale.range()[1]-scale.range()[0]); - } - axisLabel - .attr('text-anchor', 'middle') - .attr('y', xLabelMargin) - .attr('x', w/2); - if (showMaxMin) { - //if (showMaxMin && !isOrdinal) { - axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') - //.data(scale.domain()) - .data([scale.domain()[0], scale.domain()[scale.domain().length - 1]]); - axisMaxMin.enter().append('g').attr('class',function(d,i){ - return ['nv-axisMaxMin','nv-axisMaxMin-x',(i == 0 ? 'nv-axisMin-x':'nv-axisMax-x')].join(' ') - }).append('text'); - axisMaxMin.exit().remove(); - axisMaxMin - .attr('transform', function(d,i) { - return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)' - }) - .select('text') - .attr('dy', '.71em') - .attr('y', axis.tickPadding()) - .attr('transform', rotateLabelsRule) - .style('text-anchor', rotateLabels ? (rotateLabels%360 > 0 ? 'start' : 'end') : 'middle') - .text(function(d,i) { - var v = fmt(d); - return ('' + v).match('NaN') ? '' : v; - }); - axisMaxMin.watchTransition(renderWatch, 'min-max bottom') - .attr('transform', function(d,i) { - return 'translate(' + nv.utils.NaNtoZero((scale(d) + (isOrdinal ? scale.rangeBand() / 2 : 0))) + ',0)' - }); - } - if (staggerLabels) - xTicks - .attr('transform', function(d,i) { - return 'translate(0,' + (i % 2 == 0 ? '0' : '12') + ')' - }); - - break; - case 'right': - axisLabel.enter().append('text').attr('class', 'nv-axislabel'); - axisLabel - .style('text-anchor', rotateYLabel ? 'middle' : 'begin') - .attr('transform', rotateYLabel ? 'rotate(90)' : '') - .attr('y', rotateYLabel ? (-Math.max(margin.right, width) + 12) : -10) //TODO: consider calculating this based on largest tick width... OR at least expose this on chart - .attr('x', rotateYLabel ? (d3.max(scale.range()) / 2) : axis.tickPadding()); - if (showMaxMin) { - axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') - .data(scale.domain()); - axisMaxMin.enter().append('g').attr('class',function(d,i){ - return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ') - }).append('text') - .style('opacity', 0); - axisMaxMin.exit().remove(); - axisMaxMin - .attr('transform', function(d,i) { - return 'translate(0,' + nv.utils.NaNtoZero(scale(d)) + ')' - }) - .select('text') - .attr('dy', '.32em') - .attr('y', 0) - .attr('x', axis.tickPadding()) - .style('text-anchor', 'start') - .text(function(d, i) { - var v = fmt(d); - return ('' + v).match('NaN') ? '' : v; - }); - axisMaxMin.watchTransition(renderWatch, 'min-max right') - .attr('transform', function(d,i) { - return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')' - }) - .select('text') - .style('opacity', 1); - } - break; - case 'left': - /* - //For dynamically placing the label. Can be used with dynamically-sized chart axis margins - var yTicks = g.selectAll('g').select("text"); - yTicks.each(function(d,i){ - var labelPadding = this.getBoundingClientRect().width + axis.tickPadding() + 16; - if(labelPadding > width) width = labelPadding; - }); - */ - axisLabel.enter().append('text').attr('class', 'nv-axislabel'); - axisLabel - .style('text-anchor', rotateYLabel ? 'middle' : 'end') - .attr('transform', rotateYLabel ? 'rotate(-90)' : '') - .attr('y', rotateYLabel ? (-Math.max(margin.left, width) + 25 - (axisLabelDistance || 0)) : -10) - .attr('x', rotateYLabel ? (-d3.max(scale.range()) / 2) : -axis.tickPadding()); - if (showMaxMin) { - axisMaxMin = wrap.selectAll('g.nv-axisMaxMin') - .data(scale.domain()); - axisMaxMin.enter().append('g').attr('class',function(d,i){ - return ['nv-axisMaxMin','nv-axisMaxMin-y',(i == 0 ? 'nv-axisMin-y':'nv-axisMax-y')].join(' ') - }).append('text') - .style('opacity', 0); - axisMaxMin.exit().remove(); - axisMaxMin - .attr('transform', function(d,i) { - return 'translate(0,' + nv.utils.NaNtoZero(scale0(d)) + ')' - }) - .select('text') - .attr('dy', '.32em') - .attr('y', 0) - .attr('x', -axis.tickPadding()) - .attr('text-anchor', 'end') - .text(function(d,i) { - var v = fmt(d); - return ('' + v).match('NaN') ? '' : v; - }); - axisMaxMin.watchTransition(renderWatch, 'min-max right') - .attr('transform', function(d,i) { - return 'translate(0,' + nv.utils.NaNtoZero(scale.range()[i]) + ')' - }) - .select('text') - .style('opacity', 1); - } - break; - } - axisLabel.text(function(d) { return d }); - - if (showMaxMin && (axis.orient() === 'left' || axis.orient() === 'right')) { - //check if max and min overlap other values, if so, hide the values that overlap - g.selectAll('g') // the g's wrapping each tick - .each(function(d,i) { - d3.select(this).select('text').attr('opacity', 1); - if (scale(d) < scale.range()[1] + 10 || scale(d) > scale.range()[0] - 10) { // 10 is assuming text height is 16... if d is 0, leave it! - if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL - d3.select(this).attr('opacity', 0); - - d3.select(this).select('text').attr('opacity', 0); // Don't remove the ZERO line!! - } - }); - - //if Max and Min = 0 only show min, Issue #281 - if (scale.domain()[0] == scale.domain()[1] && scale.domain()[0] == 0) { - wrap.selectAll('g.nv-axisMaxMin').style('opacity', function (d, i) { - return !i ? 1 : 0 - }); - } - } - - if (showMaxMin && (axis.orient() === 'top' || axis.orient() === 'bottom')) { - var maxMinRange = []; - wrap.selectAll('g.nv-axisMaxMin') - .each(function(d,i) { - try { - if (i) // i== 1, max position - maxMinRange.push(scale(d) - this.getBoundingClientRect().width - 4); //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case) - else // i==0, min position - maxMinRange.push(scale(d) + this.getBoundingClientRect().width + 4) - }catch (err) { - if (i) // i== 1, max position - maxMinRange.push(scale(d) - 4); //assuming the max and min labels are as wide as the next tick (with an extra 4 pixels just in case) - else // i==0, min position - maxMinRange.push(scale(d) + 4); - } - }); - // the g's wrapping each tick - g.selectAll('g').each(function(d, i) { - if (scale(d) < maxMinRange[0] || scale(d) > maxMinRange[1]) { - if (d > 1e-10 || d < -1e-10) // accounts for minor floating point errors... though could be problematic if the scale is EXTREMELY SMALL - d3.select(this).remove(); - else - d3.select(this).select('text').remove(); // Don't remove the ZERO line!! - } - }); - } - - //Highlight zero tick line - g.selectAll('.tick') - .filter(function (d) { - /* - The filter needs to return only ticks at or near zero. - Numbers like 0.00001 need to count as zero as well, - and the arithmetic trick below solves that. - */ - return !parseFloat(Math.round(d * 100000) / 1000000) && (d !== undefined) - }) - .classed('zero', true); - - //store old scales for use in transitions on update - scale0 = scale.copy(); - - }); - - renderWatch.renderEnd('axis immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.axis = axis; - chart.dispatch = dispatch; - - chart.options = nv.utils.optionsFunc.bind(chart); - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - axisLabelDistance: {get: function(){return axisLabelDistance;}, set: function(_){axisLabelDistance=_;}}, - staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, - rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}}, - rotateYLabel: {get: function(){return rotateYLabel;}, set: function(_){rotateYLabel=_;}}, - showMaxMin: {get: function(){return showMaxMin;}, set: function(_){showMaxMin=_;}}, - axisLabel: {get: function(){return axisLabelText;}, set: function(_){axisLabelText=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}}, - width: {get: function(){return width;}, set: function(_){width=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration=_; - renderWatch.reset(duration); - }}, - scale: {get: function(){return scale;}, set: function(_){ - scale = _; - axis.scale(scale); - isOrdinal = typeof scale.rangeBands === 'function'; - nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']); - }} - }); - - nv.utils.initOptions(chart); - nv.utils.inheritOptionsD3(chart, axis, ['orient', 'tickValues', 'tickSubdivide', 'tickSize', 'tickPadding', 'tickFormat']); - nv.utils.inheritOptionsD3(chart, scale, ['domain', 'range', 'rangeBand', 'rangeBands']); - - return chart; -}; -nv.models.boxPlot = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , x = d3.scale.ordinal() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , color = nv.utils.defaultColor() - , container = null - , xDomain - , yDomain - , xRange - , yRange - , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - , duration = 250 - , maxBoxWidth = null - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0; - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - // Setup Scales - x .domain(xDomain || data.map(function(d,i) { return getX(d,i); })) - .rangeBands(xRange || [0, availableWidth], .1); - - // if we know yDomain, no need to calculate - var yData = [] - if (!yDomain) { - // (y-range is based on quartiles, whiskers and outliers) - - // lower values - var yMin = d3.min(data.map(function(d) { - var min_arr = []; - - min_arr.push(d.values.Q1); - if (d.values.hasOwnProperty('whisker_low') && d.values.whisker_low !== null) { min_arr.push(d.values.whisker_low); } - if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { min_arr = min_arr.concat(d.values.outliers); } - - return d3.min(min_arr); - })); - - // upper values - var yMax = d3.max(data.map(function(d) { - var max_arr = []; - - max_arr.push(d.values.Q3); - if (d.values.hasOwnProperty('whisker_high') && d.values.whisker_high !== null) { max_arr.push(d.values.whisker_high); } - if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { max_arr = max_arr.concat(d.values.outliers); } - - return d3.max(max_arr); - })); - - yData = [ yMin, yMax ] ; - } - - y.domain(yDomain || yData); - y.range(yRange || [availableHeight, 0]); - - //store old scales if they exist - x0 = x0 || x; - y0 = y0 || y.copy().range([y(0),y(0)]); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap'); - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var boxplots = wrap.selectAll('.nv-boxplot').data(function(d) { return d }); - var boxEnter = boxplots.enter().append('g').style('stroke-opacity', 1e-6).style('fill-opacity', 1e-6); - boxplots - .attr('class', 'nv-boxplot') - .attr('transform', function(d,i,j) { return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)'; }) - .classed('hover', function(d) { return d.hover }); - boxplots - .watchTransition(renderWatch, 'nv-boxplot: boxplots') - .style('stroke-opacity', 1) - .style('fill-opacity', .75) - .delay(function(d,i) { return i * duration / data.length }) - .attr('transform', function(d,i) { - return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05) + ', 0)'; - }); - boxplots.exit().remove(); - - // ----- add the SVG elements for each boxPlot ----- - - // conditionally append whisker lines - boxEnter.each(function(d,i) { - var box = d3.select(this); - - ['low', 'high'].forEach(function(key) { - if (d.values.hasOwnProperty('whisker_' + key) && d.values['whisker_' + key] !== null) { - box.append('line') - .style('stroke', (d.color) ? d.color : color(d,i)) - .attr('class', 'nv-boxplot-whisker nv-boxplot-' + key); - - box.append('line') - .style('stroke', (d.color) ? d.color : color(d,i)) - .attr('class', 'nv-boxplot-tick nv-boxplot-' + key); - } - }); - }); - - // outliers - // TODO: support custom colors here - var outliers = boxplots.selectAll('.nv-boxplot-outlier').data(function(d) { - if (d.values.hasOwnProperty('outliers') && d.values.outliers !== null) { return d.values.outliers; } - else { return []; } - }); - outliers.enter().append('circle') - .style('fill', function(d,i,j) { return color(d,j) }).style('stroke', function(d,i,j) { return color(d,j) }) - .on('mouseover', function(d,i,j) { - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - series: { key: d, color: color(d,j) }, - e: d3.event - }); - }) - .on('mouseout', function(d,i,j) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - series: { key: d, color: color(d,j) }, - e: d3.event - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({e: d3.event}); - }); - - outliers.attr('class', 'nv-boxplot-outlier'); - outliers - .watchTransition(renderWatch, 'nv-boxplot: nv-boxplot-outlier') - .attr('cx', x.rangeBand() * .45) - .attr('cy', function(d,i,j) { return y(d); }) - .attr('r', '3'); - outliers.exit().remove(); - - var box_width = function() { return (maxBoxWidth === null ? x.rangeBand() * .9 : Math.min(75, x.rangeBand() * .9)); }; - var box_left = function() { return x.rangeBand() * .45 - box_width()/2; }; - var box_right = function() { return x.rangeBand() * .45 + box_width()/2; }; - - // update whisker lines and ticks - ['low', 'high'].forEach(function(key) { - var endpoint = (key === 'low') ? 'Q1' : 'Q3'; - - boxplots.select('line.nv-boxplot-whisker.nv-boxplot-' + key) - .watchTransition(renderWatch, 'nv-boxplot: boxplots') - .attr('x1', x.rangeBand() * .45 ) - .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); }) - .attr('x2', x.rangeBand() * .45 ) - .attr('y2', function(d,i) { return y(d.values[endpoint]); }); - - boxplots.select('line.nv-boxplot-tick.nv-boxplot-' + key) - .watchTransition(renderWatch, 'nv-boxplot: boxplots') - .attr('x1', box_left ) - .attr('y1', function(d,i) { return y(d.values['whisker_' + key]); }) - .attr('x2', box_right ) - .attr('y2', function(d,i) { return y(d.values['whisker_' + key]); }); - }); - - ['low', 'high'].forEach(function(key) { - boxEnter.selectAll('.nv-boxplot-' + key) - .on('mouseover', function(d,i,j) { - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - series: { key: d.values['whisker_' + key], color: color(d,j) }, - e: d3.event - }); - }) - .on('mouseout', function(d,i,j) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - series: { key: d.values['whisker_' + key], color: color(d,j) }, - e: d3.event - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({e: d3.event}); - }); - }); - - // boxes - boxEnter.append('rect') - .attr('class', 'nv-boxplot-box') - // tooltip events - .on('mouseover', function(d,i) { - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - key: d.label, - value: d.label, - series: [ - { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) }, - { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) }, - { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) } - ], - data: d, - index: i, - e: d3.event - }); - }) - .on('mouseout', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - key: d.label, - value: d.label, - series: [ - { key: 'Q3', value: d.values.Q3, color: d.color || color(d,i) }, - { key: 'Q2', value: d.values.Q2, color: d.color || color(d,i) }, - { key: 'Q1', value: d.values.Q1, color: d.color || color(d,i) } - ], - data: d, - index: i, - e: d3.event - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({e: d3.event}); - }); - - // box transitions - boxplots.select('rect.nv-boxplot-box') - .watchTransition(renderWatch, 'nv-boxplot: boxes') - .attr('y', function(d,i) { return y(d.values.Q3); }) - .attr('width', box_width) - .attr('x', box_left ) - - .attr('height', function(d,i) { return Math.abs(y(d.values.Q3) - y(d.values.Q1)) || 1 }) - .style('fill', function(d,i) { return d.color || color(d,i) }) - .style('stroke', function(d,i) { return d.color || color(d,i) }); - - // median line - boxEnter.append('line').attr('class', 'nv-boxplot-median'); - - boxplots.select('line.nv-boxplot-median') - .watchTransition(renderWatch, 'nv-boxplot: boxplots line') - .attr('x1', box_left) - .attr('y1', function(d,i) { return y(d.values.Q2); }) - .attr('x2', box_right) - .attr('y2', function(d,i) { return y(d.values.Q2); }); - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - }); - - renderWatch.renderEnd('nv-boxplot immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - maxBoxWidth: {get: function(){return maxBoxWidth;}, set: function(_){maxBoxWidth=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - // rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.boxPlotChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var boxplot = nv.models.boxPlot() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - ; - - var margin = {top: 15, right: 10, bottom: 50, left: 60} - , width = null - , height = null - , color = nv.utils.getColor() - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , staggerLabels = false - , tooltip = nv.models.tooltip() - , x - , y - , noData = "No Data Available." - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'beforeUpdate', 'renderEnd') - , duration = 250 - ; - - xAxis - .orient('bottom') - .showMaxMin(false) - .tickFormat(function(d) { return d }) - ; - yAxis - .orient((rightAlignYAxis) ? 'right' : 'left') - .tickFormat(d3.format(',.1f')) - ; - - tooltip.duration(0); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(boxplot); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = (width || parseInt(container.style('width')) || 960) - - margin.left - margin.right, - availableHeight = (height || parseInt(container.style('height')) || 400) - - margin.top - margin.bottom; - - chart.update = function() { - dispatch.beforeUpdate(); - container.transition().duration(duration).call(chart); - }; - chart.container = this; - - // Display No Data message if there's nothing to show. (quartiles required at minimum) - if (!data || !data.length || - !data.filter(function(d) { return d.values.hasOwnProperty("Q1") && d.values.hasOwnProperty("Q2") && d.values.hasOwnProperty("Q3"); }).length) { - var noDataText = container.selectAll('.nv-noData').data([noData]); - - noDataText.enter().append('text') - .attr('class', 'nvd3 nv-noData') - .attr('dy', '-.7em') - .style('text-anchor', 'middle'); - - noDataText - .attr('x', margin.left + availableWidth / 2) - .attr('y', margin.top + availableHeight / 2) - .text(function(d) { return d }); - - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = boxplot.xScale(); - y = boxplot.yScale().clamp(true); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-boxPlotWithAxes').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-boxPlotWithAxes').append('g'); - var defsEnter = gEnter.append('defs'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis') - .append('g').attr('class', 'nv-zeroLine') - .append('line'); - - gEnter.append('g').attr('class', 'nv-barsWrap'); - - g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - // Main Chart Component(s) - boxplot - .width(availableWidth) - .height(availableHeight); - - var barsWrap = g.select('.nv-barsWrap') - .datum(data.filter(function(d) { return !d.disabled })) - - barsWrap.transition().call(boxplot); - - - defsEnter.append('clipPath') - .attr('id', 'nv-x-label-clip-' + boxplot.id()) - .append('rect'); - - g.select('#nv-x-label-clip-' + boxplot.id() + ' rect') - .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1)) - .attr('height', 16) - .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 )); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - .ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis').attr('transform', 'translate(0,' + y.range()[0] + ')'); - g.select('.nv-x.nv-axis').call(xAxis); - - var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); - if (staggerLabels) { - xTicks - .selectAll('text') - .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' }) - } - } - - if (showYAxis) { - yAxis - .scale(y) - .ticks( Math.floor(availableHeight/36) ) // can't use nv.utils.calcTicksY with Object data - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis').call(yAxis); - } - - // Zero line - g.select(".nv-zeroLine line") - .attr("x1",0) - .attr("x2",availableWidth) - .attr("y1", y(0)) - .attr("y2", y(0)) - ; - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - }); - - renderWatch.renderEnd('nv-boxplot chart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - boxplot.dispatch.on('elementMouseover.tooltip', function(evt) { - tooltip.data(evt).hidden(false); - }); - - boxplot.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.data(evt).hidden(true); - }); - - boxplot.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.boxplot = boxplot; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - tooltips: {get: function(){return tooltips;}, set: function(_){tooltips=_;}}, - tooltipContent: {get: function(){return tooltip;}, set: function(_){tooltip=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - boxplot.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - boxplot.color(color); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( (_) ? 'right' : 'left'); - }} - }); - - nv.utils.inheritOptions(chart, boxplot); - nv.utils.initOptions(chart); - - return chart; -} -// Chart design based on the recommendations of Stephen Few. Implementation -// based on the work of Clint Ivy, Jamie Love, and Jason Davies. -// http://projects.instantcognition.com/protovis/bulletchart/ - -nv.models.bullet = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , orient = 'left' // TODO top & bottom - , reverse = false - , ranges = function(d) { return d.ranges } - , markers = function(d) { return d.markers ? d.markers : [0] } - , measures = function(d) { return d.measures } - , rangeLabels = function(d) { return d.rangeLabels ? d.rangeLabels : [] } - , markerLabels = function(d) { return d.markerLabels ? d.markerLabels : [] } - , measureLabels = function(d) { return d.measureLabels ? d.measureLabels : [] } - , forceX = [0] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.) - , width = 380 - , height = 30 - , container = null - , tickFormat = null - , color = nv.utils.getColor(['#1f77b4']) - , dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove') - ; - - function chart(selection) { - selection.each(function(d, i) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - var rangez = ranges.call(this, d, i).slice().sort(d3.descending), - markerz = markers.call(this, d, i).slice().sort(d3.descending), - measurez = measures.call(this, d, i).slice().sort(d3.descending), - rangeLabelz = rangeLabels.call(this, d, i).slice(), - markerLabelz = markerLabels.call(this, d, i).slice(), - measureLabelz = measureLabels.call(this, d, i).slice(); - - // Setup Scales - // Compute the new x-scale. - var x1 = d3.scale.linear() - .domain( d3.extent(d3.merge([forceX, rangez])) ) - .range(reverse ? [availableWidth, 0] : [0, availableWidth]); - - // Retrieve the old x-scale, if this is an update. - var x0 = this.__chart__ || d3.scale.linear() - .domain([0, Infinity]) - .range(x1.range()); - - // Stash the new scale. - this.__chart__ = x1; - - var rangeMin = d3.min(rangez), //rangez[2] - rangeMax = d3.max(rangez), //rangez[0] - rangeAvg = rangez[1]; - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-bullet').data([d]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('rect').attr('class', 'nv-range nv-rangeMax'); - gEnter.append('rect').attr('class', 'nv-range nv-rangeAvg'); - gEnter.append('rect').attr('class', 'nv-range nv-rangeMin'); - gEnter.append('rect').attr('class', 'nv-measure'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0) - w1 = function(d) { return Math.abs(x1(d) - x1(0)) }; - var xp0 = function(d) { return d < 0 ? x0(d) : x0(0) }, - xp1 = function(d) { return d < 0 ? x1(d) : x1(0) }; - - g.select('rect.nv-rangeMax') - .attr('height', availableHeight) - .attr('width', w1(rangeMax > 0 ? rangeMax : rangeMin)) - .attr('x', xp1(rangeMax > 0 ? rangeMax : rangeMin)) - .datum(rangeMax > 0 ? rangeMax : rangeMin) - - g.select('rect.nv-rangeAvg') - .attr('height', availableHeight) - .attr('width', w1(rangeAvg)) - .attr('x', xp1(rangeAvg)) - .datum(rangeAvg) - - g.select('rect.nv-rangeMin') - .attr('height', availableHeight) - .attr('width', w1(rangeMax)) - .attr('x', xp1(rangeMax)) - .attr('width', w1(rangeMax > 0 ? rangeMin : rangeMax)) - .attr('x', xp1(rangeMax > 0 ? rangeMin : rangeMax)) - .datum(rangeMax > 0 ? rangeMin : rangeMax) - - g.select('rect.nv-measure') - .style('fill', color) - .attr('height', availableHeight / 3) - .attr('y', availableHeight / 3) - .attr('width', measurez < 0 ? - x1(0) - x1(measurez[0]) - : x1(measurez[0]) - x1(0)) - .attr('x', xp1(measurez)) - .on('mouseover', function() { - dispatch.elementMouseover({ - value: measurez[0], - label: measureLabelz[0] || 'Current', - color: d3.select(this).style("fill") - }) - }) - .on('mousemove', function() { - dispatch.elementMousemove({ - value: measurez[0], - label: measureLabelz[0] || 'Current', - color: d3.select(this).style("fill") - }) - }) - .on('mouseout', function() { - dispatch.elementMouseout({ - value: measurez[0], - label: measureLabelz[0] || 'Current', - color: d3.select(this).style("fill") - }) - }); - - var h3 = availableHeight / 6; - - var markerData = markerz.map( function(marker, index) { - return {value: marker, label: markerLabelz[index]} - }); - gEnter - .selectAll("path.nv-markerTriangle") - .data(markerData) - .enter() - .append('path') - .attr('class', 'nv-markerTriangle') - .attr('transform', function(d) { return 'translate(' + x1(d.value) + ',' + (availableHeight / 2) + ')' }) - .attr('d', 'M0,' + h3 + 'L' + h3 + ',' + (-h3) + ' ' + (-h3) + ',' + (-h3) + 'Z') - .on('mouseover', function(d) { - dispatch.elementMouseover({ - value: d.value, - label: d.label || 'Previous', - color: d3.select(this).style("fill"), - pos: [x1(d.value), availableHeight/2] - }) - - }) - .on('mousemove', function(d) { - dispatch.elementMousemove({ - value: d.value, - label: d.label || 'Previous', - color: d3.select(this).style("fill") - }) - }) - .on('mouseout', function(d, i) { - dispatch.elementMouseout({ - value: d.value, - label: d.label || 'Previous', - color: d3.select(this).style("fill") - }) - }); - - wrap.selectAll('.nv-range') - .on('mouseover', function(d,i) { - var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum"); - dispatch.elementMouseover({ - value: d, - label: label, - color: d3.select(this).style("fill") - }) - }) - .on('mousemove', function() { - dispatch.elementMousemove({ - value: measurez[0], - label: measureLabelz[0] || 'Previous', - color: d3.select(this).style("fill") - }) - }) - .on('mouseout', function(d,i) { - var label = rangeLabelz[i] || (!i ? "Maximum" : i == 1 ? "Mean" : "Minimum"); - dispatch.elementMouseout({ - value: d, - label: label, - color: d3.select(this).style("fill") - }) - }); - }); - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good) - markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal) - measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast) - forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom - orient = _; - reverse = orient == 'right' || orient == 'bottom'; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; - - - -// Chart design based on the recommendations of Stephen Few. Implementation -// based on the work of Clint Ivy, Jamie Love, and Jason Davies. -// http://projects.instantcognition.com/protovis/bulletchart/ -nv.models.bulletChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var bullet = nv.models.bullet(); - var tooltip = nv.models.tooltip(); - - var orient = 'left' // TODO top & bottom - , reverse = false - , margin = {top: 5, right: 40, bottom: 20, left: 120} - , ranges = function(d) { return d.ranges } - , markers = function(d) { return d.markers ? d.markers : [0] } - , measures = function(d) { return d.measures } - , width = null - , height = 55 - , tickFormat = null - , ticks = null - , noData = null - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide') - ; - - tooltip.duration(0).headerEnabled(false); - - function chart(selection) { - selection.each(function(d, i) { - var container = d3.select(this); - nv.utils.initSVG(container); - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = height - margin.top - margin.bottom, - that = this; - - chart.update = function() { chart(selection) }; - chart.container = this; - - // Display No Data message if there's nothing to show. - if (!d || !ranges.call(this, d, i)) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - var rangez = ranges.call(this, d, i).slice().sort(d3.descending), - markerz = markers.call(this, d, i).slice().sort(d3.descending), - measurez = measures.call(this, d, i).slice().sort(d3.descending); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-bulletWrap'); - gEnter.append('g').attr('class', 'nv-titles'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Compute the new x-scale. - var x1 = d3.scale.linear() - .domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) // TODO: need to allow forceX and forceY, and xDomain, yDomain - .range(reverse ? [availableWidth, 0] : [0, availableWidth]); - - // Retrieve the old x-scale, if this is an update. - var x0 = this.__chart__ || d3.scale.linear() - .domain([0, Infinity]) - .range(x1.range()); - - // Stash the new scale. - this.__chart__ = x1; - - var w0 = function(d) { return Math.abs(x0(d) - x0(0)) }, // TODO: could optimize by precalculating x0(0) and x1(0) - w1 = function(d) { return Math.abs(x1(d) - x1(0)) }; - - var title = gEnter.select('.nv-titles').append('g') - .attr('text-anchor', 'end') - .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')'); - title.append('text') - .attr('class', 'nv-title') - .text(function(d) { return d.title; }); - - title.append('text') - .attr('class', 'nv-subtitle') - .attr('dy', '1em') - .text(function(d) { return d.subtitle; }); - - bullet - .width(availableWidth) - .height(availableHeight) - - var bulletWrap = g.select('.nv-bulletWrap'); - d3.transition(bulletWrap).call(bullet); - - // Compute the tick format. - var format = tickFormat || x1.tickFormat( availableWidth / 100 ); - - // Update the tick groups. - var tick = g.selectAll('g.nv-tick') - .data(x1.ticks( ticks ? ticks : (availableWidth / 50) ), function(d) { - return this.textContent || format(d); - }); - - // Initialize the ticks with the old scale, x0. - var tickEnter = tick.enter().append('g') - .attr('class', 'nv-tick') - .attr('transform', function(d) { return 'translate(' + x0(d) + ',0)' }) - .style('opacity', 1e-6); - - tickEnter.append('line') - .attr('y1', availableHeight) - .attr('y2', availableHeight * 7 / 6); - - tickEnter.append('text') - .attr('text-anchor', 'middle') - .attr('dy', '1em') - .attr('y', availableHeight * 7 / 6) - .text(format); - - // Transition the updating ticks to the new scale, x1. - var tickUpdate = d3.transition(tick) - .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' }) - .style('opacity', 1); - - tickUpdate.select('line') - .attr('y1', availableHeight) - .attr('y2', availableHeight * 7 / 6); - - tickUpdate.select('text') - .attr('y', availableHeight * 7 / 6); - - // Transition the exiting ticks to the new scale, x1. - d3.transition(tick.exit()) - .attr('transform', function(d) { return 'translate(' + x1(d) + ',0)' }) - .style('opacity', 1e-6) - .remove(); - }); - - d3.timer.flush(); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - bullet.dispatch.on('elementMouseover.tooltip', function(evt) { - evt['series'] = { - key: evt.label, - value: evt.value, - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - bullet.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - bullet.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.bullet = bullet; - chart.dispatch = dispatch; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - ranges: {get: function(){return ranges;}, set: function(_){ranges=_;}}, // ranges (bad, satisfactory, good) - markers: {get: function(){return markers;}, set: function(_){markers=_;}}, // markers (previous, goal) - measures: {get: function(){return measures;}, set: function(_){measures=_;}}, // measures (actual, forecast) - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - tickFormat: {get: function(){return tickFormat;}, set: function(_){tickFormat=_;}}, - ticks: {get: function(){return ticks;}, set: function(_){ticks=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - orient: {get: function(){return orient;}, set: function(_){ // left, right, top, bottom - orient = _; - reverse = orient == 'right' || orient == 'bottom'; - }} - }); - - nv.utils.inheritOptions(chart, bullet); - nv.utils.initOptions(chart); - - return chart; -}; - - - -nv.models.candlestickBar = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = null - , height = null - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container - , x = d3.scale.linear() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , getOpen = function(d) { return d.open } - , getClose = function(d) { return d.close } - , getHigh = function(d) { return d.high } - , getLow = function(d) { return d.low } - , forceX = [] - , forceY = [] - , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart - , clipEdge = true - , color = nv.utils.defaultColor() - , interactive = false - , xDomain - , yDomain - , xRange - , yRange - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - function chart(selection) { - selection.each(function(data) { - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - nv.utils.initSVG(container); - - // Width of the candlestick bars. - var barWidth = (availableWidth / data[0].values.length) * .45; - - // Setup Scales - x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); - - if (padData) - x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); - else - x.range(xRange || [5 + barWidth / 2, availableWidth - barWidth / 2 - 5]); - - y.domain(yDomain || [ - d3.min(data[0].values.map(getLow).concat(forceY)), - d3.max(data[0].values.map(getHigh).concat(forceY)) - ] - ).range(yRange || [availableHeight, 0]); - - // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point - if (x.domain()[0] === x.domain()[1]) - x.domain()[0] ? - x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) - : x.domain([-1,1]); - - if (y.domain()[0] === y.domain()[1]) - y.domain()[0] ? - y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) - : y.domain([-1,1]); - - // Setup containers and skeleton of chart - var wrap = d3.select(this).selectAll('g.nv-wrap.nv-candlestickBar').data([data[0].values]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-candlestickBar'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-ticks'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - container - .on('click', function(d,i) { - dispatch.chartClick({ - data: d, - index: i, - pos: d3.event, - id: id - }); - }); - - defsEnter.append('clipPath') - .attr('id', 'nv-chart-clip-path-' + id) - .append('rect'); - - wrap.select('#nv-chart-clip-path-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); - - var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick') - .data(function(d) { return d }); - ticks.exit().remove(); - - // The colors are currently controlled by CSS. - var tickGroups = ticks.enter().append('g') - .attr('class', function(d, i, j) { return (getOpen(d, i) > getClose(d, i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i}); - - var lines = tickGroups.append('line') - .attr('class', 'nv-candlestick-lines') - .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; }) - .attr('x1', 0) - .attr('y1', function(d, i) { return y(getHigh(d, i)); }) - .attr('x2', 0) - .attr('y2', function(d, i) { return y(getLow(d, i)); }); - - var rects = tickGroups.append('rect') - .attr('class', 'nv-candlestick-rects nv-bars') - .attr('transform', function(d, i) { - return 'translate(' + (x(getX(d, i)) - barWidth/2) + ',' - + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0)) - + ')'; - }) - .attr('x', 0) - .attr('y', 0) - .attr('width', barWidth) - .attr('height', function(d, i) { - var open = getOpen(d, i); - var close = getClose(d, i); - return open > close ? y(close) - y(open) : y(open) - y(close); - }); - - container.selectAll('.nv-candlestick-lines').transition() - .attr('transform', function(d, i) { return 'translate(' + x(getX(d, i)) + ',0)'; }) - .attr('x1', 0) - .attr('y1', function(d, i) { return y(getHigh(d, i)); }) - .attr('x2', 0) - .attr('y2', function(d, i) { return y(getLow(d, i)); }); - - container.selectAll('.nv-candlestick-rects').transition() - .attr('transform', function(d, i) { - return 'translate(' + (x(getX(d, i)) - barWidth/2) + ',' - + (y(getY(d, i)) - (getOpen(d, i) > getClose(d, i) ? (y(getClose(d, i)) - y(getOpen(d, i))) : 0)) - + ')'; - }) - .attr('x', 0) - .attr('y', 0) - .attr('width', barWidth) - .attr('height', function(d, i) { - var open = getOpen(d, i); - var close = getClose(d, i); - return open > close ? y(close) - y(open) : y(open) - y(close); - }); - }); - - return chart; - } - - - //Create methods to allow outside functions to highlight a specific bar. - chart.highlightPoint = function(pointIndex, isHoverOver) { - chart.clearHighlights(); - container.select(".nv-candlestickBar .nv-tick-0-" + pointIndex) - .classed("hover", isHoverOver) - ; - }; - - chart.clearHighlights = function() { - container.select(".nv-candlestickBar .nv-tick.hover") - .classed("hover", false) - ; - }; - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - padData: {get: function(){return padData;}, set: function(_){padData=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, - - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - open: {get: function(){return getOpen();}, set: function(_){getOpen=_;}}, - close: {get: function(){return getClose();}, set: function(_){getClose=_;}}, - high: {get: function(){return getHigh;}, set: function(_){getHigh=_;}}, - low: {get: function(){return getLow;}, set: function(_){getLow=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top != undefined ? _.top : margin.top; - margin.right = _.right != undefined ? _.right : margin.right; - margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; - margin.left = _.left != undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; - -nv.models.cumulativeLineChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var lines = nv.models.line() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , controls = nv.models.legend() - , interactiveLayer = nv.interactiveGuideline() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 30, bottom: 50, left: 60} - , color = nv.utils.defaultColor() - , width = null - , height = null - , showLegend = true - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , showControls = true - , useInteractiveGuideline = false - , rescaleY = true - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , id = lines.id() - , state = nv.utils.state() - , defaultState = null - , noData = null - , average = function(d) { return d.average } - , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') - , transitionDuration = 250 - , duration = 250 - , noErrorCheck = false //if set to TRUE, will bypass an error check in the indexify function. - ; - - state.index = 0; - state.rescaleY = rescaleY; - - xAxis.orient('bottom').tickPadding(7); - yAxis.orient((rightAlignYAxis) ? 'right' : 'left'); - - tooltip.valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }).headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - controls.updateState(false); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var dx = d3.scale.linear() - , index = {i: 0, x: 0} - , renderWatch = nv.utils.renderWatch(dispatch, duration) - ; - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }), - index: index.i, - rescaleY: rescaleY - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.index !== undefined) - index.i = state.index; - if (state.rescaleY !== undefined) - rescaleY = state.rescaleY; - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(lines); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - selection.each(function(data) { - var container = d3.select(this); - nv.utils.initSVG(container); - container.classed('nv-chart-' + id, true); - var that = this; - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - if (duration === 0) - container.call(chart); - else - container.transition().duration(duration).call(chart) - }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - var indexDrag = d3.behavior.drag() - .on('dragstart', dragStart) - .on('drag', dragMove) - .on('dragend', dragEnd); - - - function dragStart(d,i) { - d3.select(chart.container) - .style('cursor', 'ew-resize'); - } - - function dragMove(d,i) { - index.x = d3.event.x; - index.i = Math.round(dx.invert(index.x)); - updateZero(); - } - - function dragEnd(d,i) { - d3.select(chart.container) - .style('cursor', 'auto'); - - // update state and send stateChange with new index - state.index = index.i; - dispatch.stateChange(state); - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = lines.xScale(); - y = lines.yScale(); - - if (!rescaleY) { - var seriesDomains = data - .filter(function(series) { return !series.disabled }) - .map(function(series,i) { - var initialDomain = d3.extent(series.values, lines.y()); - - //account for series being disabled when losing 95% or more - if (initialDomain[0] < -.95) initialDomain[0] = -.95; - - return [ - (initialDomain[0] - initialDomain[1]) / (1 + initialDomain[1]), - (initialDomain[1] - initialDomain[0]) / (1 + initialDomain[0]) - ]; - }); - - var completeDomain = [ - d3.min(seriesDomains, function(d) { return d[0] }), - d3.max(seriesDomains, function(d) { return d[1] }) - ]; - - lines.yDomain(completeDomain); - } else { - lines.yDomain(null); - } - - dx.domain([0, data[0].values.length - 1]) //Assumes all series have same length - .range([0, availableWidth]) - .clamp(true); - - var data = indexify(index.i, data); - - // Setup containers and skeleton of chart - var interactivePointerEvents = (useInteractiveGuideline) ? "none" : "all"; - var wrap = container.selectAll('g.nv-wrap.nv-cumulativeLine').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-cumulativeLine').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-interactive'); - gEnter.append('g').attr('class', 'nv-x nv-axis').style("pointer-events","none"); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-background'); - gEnter.append('g').attr('class', 'nv-linesWrap').style("pointer-events",interactivePointerEvents); - gEnter.append('g').attr('class', 'nv-avgLinesWrap').style("pointer-events","none"); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-controlsWrap'); - - // Legend - if (showLegend) { - legend.width(availableWidth); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')') - } - - // Controls - if (showControls) { - var controlsData = [ - { key: 'Re-scale y-axis', disabled: !rescaleY } - ]; - - controls - .width(140) - .color(['#444', '#444', '#444']) - .rightAlign(false) - .margin({top: 5, right: 0, bottom: 5, left: 20}) - ; - - g.select('.nv-controlsWrap') - .datum(controlsData) - .attr('transform', 'translate(0,' + (-margin.top) +')') - .call(controls); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - // Show error if series goes below 100% - var tempDisabled = data.filter(function(d) { return d.tempDisabled }); - - wrap.select('.tempDisabled').remove(); //clean-up and prevent duplicates - if (tempDisabled.length) { - wrap.append('text').attr('class', 'tempDisabled') - .attr('x', availableWidth / 2) - .attr('y', '-.71em') - .style('text-anchor', 'end') - .text(tempDisabled.map(function(d) { return d.key }).join(', ') + ' values cannot be calculated for this time period.'); - } - - //Set up interactive layer - if (useInteractiveGuideline) { - interactiveLayer - .width(availableWidth) - .height(availableHeight) - .margin({left:margin.left,top:margin.top}) - .svgContainer(container) - .xScale(x); - wrap.select(".nv-interactive").call(interactiveLayer); - } - - gEnter.select('.nv-background') - .append('rect'); - - g.select('.nv-background rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - lines - //.x(function(d) { return d.x }) - .y(function(d) { return d.display.y }) - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled && !data[i].tempDisabled; })); - - var linesWrap = g.select('.nv-linesWrap') - .datum(data.filter(function(d) { return !d.disabled && !d.tempDisabled })); - - linesWrap.call(lines); - - //Store a series index number in the data array. - data.forEach(function(d,i) { - d.seriesIndex = i; - }); - - var avgLineData = data.filter(function(d) { - return !d.disabled && !!average(d); - }); - - var avgLines = g.select(".nv-avgLinesWrap").selectAll("line") - .data(avgLineData, function(d) { return d.key; }); - - var getAvgLineY = function(d) { - //If average lines go off the svg element, clamp them to the svg bounds. - var yVal = y(average(d)); - if (yVal < 0) return 0; - if (yVal > availableHeight) return availableHeight; - return yVal; - }; - - avgLines.enter() - .append('line') - .style('stroke-width',2) - .style('stroke-dasharray','10,10') - .style('stroke',function (d,i) { - return lines.color()(d,d.seriesIndex); - }) - .attr('x1',0) - .attr('x2',availableWidth) - .attr('y1', getAvgLineY) - .attr('y2', getAvgLineY); - - avgLines - .style('stroke-opacity',function(d){ - //If average lines go offscreen, make them transparent - var yVal = y(average(d)); - if (yVal < 0 || yVal > availableHeight) return 0; - return 1; - }) - .attr('x1',0) - .attr('x2',availableWidth) - .attr('y1', getAvgLineY) - .attr('y2', getAvgLineY); - - avgLines.exit().remove(); - - //Create index line - var indexLine = linesWrap.selectAll('.nv-indexLine') - .data([index]); - indexLine.enter().append('rect').attr('class', 'nv-indexLine') - .attr('width', 3) - .attr('x', -2) - .attr('fill', 'red') - .attr('fill-opacity', .5) - .style("pointer-events","all") - .call(indexDrag); - - indexLine - .attr('transform', function(d) { return 'translate(' + dx(d.i) + ',0)' }) - .attr('height', availableHeight); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/70, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + y.range()[0] + ')'); - g.select('.nv-x.nv-axis') - .call(xAxis); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis') - .call(yAxis); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - function updateZero() { - indexLine - .data([index]); - - //When dragging the index line, turn off line transitions. - // Then turn them back on when done dragging. - var oldDuration = chart.duration(); - chart.duration(0); - chart.update(); - chart.duration(oldDuration); - } - - g.select('.nv-background rect') - .on('click', function() { - index.x = d3.mouse(this)[0]; - index.i = Math.round(dx.invert(index.x)); - - // update state and send stateChange with new index - state.index = index.i; - dispatch.stateChange(state); - - updateZero(); - }); - - lines.dispatch.on('elementClick', function(e) { - index.i = e.pointIndex; - index.x = dx(index.i); - - // update state and send stateChange with new index - state.index = index.i; - dispatch.stateChange(state); - - updateZero(); - }); - - controls.dispatch.on('legendClick', function(d,i) { - d.disabled = !d.disabled; - rescaleY = !d.disabled; - - state.rescaleY = rescaleY; - dispatch.stateChange(state); - chart.update(); - }); - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - interactiveLayer.dispatch.on('elementMousemove', function(e) { - lines.clearHighlights(); - var singlePoint, pointIndex, pointXLocation, allData = []; - - data - .filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }) - .forEach(function(series,i) { - pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); - lines.highlightPoint(i, pointIndex, true); - var point = series.values[pointIndex]; - if (typeof point === 'undefined') return; - if (typeof singlePoint === 'undefined') singlePoint = point; - if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - allData.push({ - key: series.key, - value: chart.y()(point, pointIndex), - color: color(series,series.seriesIndex) - }); - }); - - //Highlight the tooltip entry based on which point the mouse is closest to. - if (allData.length > 2) { - var yValue = chart.yScale().invert(e.mouseY); - var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); - var threshold = 0.03 * domainExtent; - var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); - if (indexToHighlight !== null) - allData[indexToHighlight].highlight = true; - } - - var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex), pointIndex); - interactiveLayer.tooltip - .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) - .chartContainer(that.parentNode) - .valueFormatter(function(d,i) { - return yAxis.tickFormat()(d); - }) - .data( - { - value: xValue, - series: allData - } - )(); - - interactiveLayer.renderGuideLine(pointXLocation); - }); - - interactiveLayer.dispatch.on("elementMouseout",function(e) { - lines.clearHighlights(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - - state.disabled = e.disabled; - } - - if (typeof e.index !== 'undefined') { - index.i = e.index; - index.x = dx(index.i); - - state.index = e.index; - - indexLine - .data([index]); - } - - if (typeof e.rescaleY !== 'undefined') { - rescaleY = e.rescaleY; - } - - chart.update(); - }); - - }); - - renderWatch.renderEnd('cumulativeLineChart immediate'); - - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - lines.dispatch.on('elementMouseover.tooltip', function(evt) { - var point = { - x: chart.x()(evt.point), - y: chart.y()(evt.point), - color: evt.point.color - }; - evt.point = point; - tooltip.data(evt).position(evt.pos).hidden(false); - }); - - lines.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - //============================================================ - // Functions - //------------------------------------------------------------ - - var indexifyYGetter = null; - /* Normalize the data according to an index point. */ - function indexify(idx, data) { - if (!indexifyYGetter) indexifyYGetter = lines.y(); - return data.map(function(line, i) { - if (!line.values) { - return line; - } - var indexValue = line.values[idx]; - if (indexValue == null) { - return line; - } - var v = indexifyYGetter(indexValue, idx); - - //TODO: implement check below, and disable series if series loses 100% or more cause divide by 0 issue - if (v < -.95 && !noErrorCheck) { - //if a series loses more than 100%, calculations fail.. anything close can cause major distortion (but is mathematically correct till it hits 100) - - line.tempDisabled = true; - return line; - } - - line.tempDisabled = false; - - line.values = line.values.map(function(point, pointIndex) { - point.display = {'y': (indexifyYGetter(point, pointIndex) - v) / (1 + v) }; - return point; - }); - - return line; - }) - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.lines = lines; - chart.legend = legend; - chart.controls = controls; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.interactiveLayer = interactiveLayer; - chart.state = state; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - rescaleY: {get: function(){return rescaleY;}, set: function(_){rescaleY=_;}}, - showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - average: {get: function(){return average;}, set: function(_){average=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - noErrorCheck: {get: function(){return noErrorCheck;}, set: function(_){noErrorCheck=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - }}, - useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ - useInteractiveGuideline = _; - if (_ === true) { - chart.interactive(false); - chart.useVoronoi(false); - } - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( (_) ? 'right' : 'left'); - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - lines.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - renderWatch.reset(duration); - }} - }); - - nv.utils.inheritOptions(chart, lines); - nv.utils.initOptions(chart); - - return chart; -}; -//TODO: consider deprecating by adding necessary features to multiBar model -nv.models.discreteBar = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container - , x = d3.scale.ordinal() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove - , color = nv.utils.defaultColor() - , showValues = false - , valueFormat = d3.format(',.2f') - , xDomain - , yDomain - , xRange - , yRange - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - , rectClass = 'discreteBar' - , duration = 250 - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0; - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - //add series index to each data point for reference - data.forEach(function(series, i) { - series.values.forEach(function(point) { - point.series = i; - }); - }); - - // Setup Scales - // remap and flatten the data for use in calculating the scales' domains - var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate - data.map(function(d) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i), y0: d.y0 } - }) - }); - - x .domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) - .rangeBands(xRange || [0, availableWidth], .1); - y .domain(yDomain || d3.extent(d3.merge(seriesData).map(function(d) { return d.y }).concat(forceY))); - - // If showValues, pad the Y axis range to account for label height - if (showValues) y.range(yRange || [availableHeight - (y.domain()[0] < 0 ? 12 : 0), y.domain()[1] > 0 ? 12 : 0]); - else y.range(yRange || [availableHeight, 0]); - - //store old scales if they exist - x0 = x0 || x; - y0 = y0 || y.copy().range([y(0),y(0)]); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-groups'); - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - //TODO: by definition, the discrete bar should not have multiple groups, will modify/remove later - var groups = wrap.select('.nv-groups').selectAll('.nv-group') - .data(function(d) { return d }, function(d) { return d.key }); - groups.enter().append('g') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6); - groups.exit() - .watchTransition(renderWatch, 'discreteBar: exit groups') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6) - .remove(); - groups - .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) - .classed('hover', function(d) { return d.hover }); - groups - .watchTransition(renderWatch, 'discreteBar: groups') - .style('stroke-opacity', 1) - .style('fill-opacity', .75); - - var bars = groups.selectAll('g.nv-bar') - .data(function(d) { return d.values }); - bars.exit().remove(); - - var barsEnter = bars.enter().append('g') - .attr('transform', function(d,i,j) { - return 'translate(' + (x(getX(d,i)) + x.rangeBand() * .05 ) + ', ' + y(0) + ')' - }) - .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mouseout', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('click', function(d,i) { - dispatch.elementClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }) - .on('dblclick', function(d,i) { - dispatch.elementDblClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }); - - barsEnter.append('rect') - .attr('height', 0) - .attr('width', x.rangeBand() * .9 / data.length ) - - if (showValues) { - barsEnter.append('text') - .attr('text-anchor', 'middle') - ; - - bars.select('text') - .text(function(d,i) { return valueFormat(getY(d,i)) }) - .watchTransition(renderWatch, 'discreteBar: bars text') - .attr('x', x.rangeBand() * .9 / 2) - .attr('y', function(d,i) { return getY(d,i) < 0 ? y(getY(d,i)) - y(0) + 12 : -4 }) - - ; - } else { - bars.selectAll('text').remove(); - } - - bars - .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive' }) - .style('fill', function(d,i) { return d.color || color(d,i) }) - .style('stroke', function(d,i) { return d.color || color(d,i) }) - .select('rect') - .attr('class', rectClass) - .watchTransition(renderWatch, 'discreteBar: bars rect') - .attr('width', x.rangeBand() * .9 / data.length); - bars.watchTransition(renderWatch, 'discreteBar: bars') - //.delay(function(d,i) { return i * 1200 / data[0].values.length }) - .attr('transform', function(d,i) { - var left = x(getX(d,i)) + x.rangeBand() * .05, - top = getY(d,i) < 0 ? - y(0) : - y(0) - y(getY(d,i)) < 1 ? - y(0) - 1 : //make 1 px positive bars show up above y=0 - y(getY(d,i)); - - return 'translate(' + left + ', ' + top + ')' - }) - .select('rect') - .attr('height', function(d,i) { - return Math.max(Math.abs(y(getY(d,i)) - y((yDomain && yDomain[0]) || 0)) || 1) - }); - - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - - }); - - renderWatch.renderEnd('discreteBar immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - rectClass: {get: function(){return rectClass;}, set: function(_){rectClass=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.discreteBarChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var discretebar = nv.models.discreteBar() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 15, right: 10, bottom: 50, left: 60} - , width = null - , height = null - , color = nv.utils.getColor() - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , staggerLabels = false - , x - , y - , noData = null - , dispatch = d3.dispatch('beforeUpdate','renderEnd') - , duration = 250 - ; - - xAxis - .orient('bottom') - .showMaxMin(false) - .tickFormat(function(d) { return d }) - ; - yAxis - .orient((rightAlignYAxis) ? 'right' : 'left') - .tickFormat(d3.format(',.1f')) - ; - - tooltip - .duration(0) - .headerEnabled(false) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }) - .keyFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(discretebar); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - dispatch.beforeUpdate(); - container.transition().duration(duration).call(chart); - }; - chart.container = this; - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container); - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = discretebar.xScale(); - y = discretebar.yScale().clamp(true); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g'); - var defsEnter = gEnter.append('defs'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis') - .append('g').attr('class', 'nv-zeroLine') - .append('line'); - - gEnter.append('g').attr('class', 'nv-barsWrap'); - - g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - // Main Chart Component(s) - discretebar - .width(availableWidth) - .height(availableHeight); - - var barsWrap = g.select('.nv-barsWrap') - .datum(data.filter(function(d) { return !d.disabled })); - - barsWrap.transition().call(discretebar); - - - defsEnter.append('clipPath') - .attr('id', 'nv-x-label-clip-' + discretebar.id()) - .append('rect'); - - g.select('#nv-x-label-clip-' + discretebar.id() + ' rect') - .attr('width', x.rangeBand() * (staggerLabels ? 2 : 1)) - .attr('height', 16) - .attr('x', -x.rangeBand() / (staggerLabels ? 1 : 2 )); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + (y.range()[0] + ((discretebar.showValues() && y.domain()[0] < 0) ? 16 : 0)) + ')'); - g.select('.nv-x.nv-axis').call(xAxis); - - var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); - if (staggerLabels) { - xTicks - .selectAll('text') - .attr('transform', function(d,i,j) { return 'translate(0,' + (j % 2 == 0 ? '5' : '17') + ')' }) - } - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis').call(yAxis); - } - - // Zero line - g.select(".nv-zeroLine line") - .attr("x1",0) - .attr("x2",availableWidth) - .attr("y1", y(0)) - .attr("y2", y(0)) - ; - }); - - renderWatch.renderEnd('discreteBar chart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - discretebar.dispatch.on('elementMouseover.tooltip', function(evt) { - evt['series'] = { - key: chart.x()(evt.data), - value: chart.y()(evt.data), - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - discretebar.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - discretebar.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.discretebar = discretebar; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - discretebar.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - discretebar.color(color); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( (_) ? 'right' : 'left'); - }} - }); - - nv.utils.inheritOptions(chart, discretebar); - nv.utils.initOptions(chart); - - return chart; -} - -nv.models.distribution = function() { - "use strict"; - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 400 //technically width or height depending on x or y.... - , size = 8 - , axis = 'x' // 'x' or 'y'... horizontal or vertical - , getData = function(d) { return d[axis] } // defaults d.x or d.y - , color = nv.utils.defaultColor() - , scale = d3.scale.linear() - , domain - , duration = 250 - , dispatch = d3.dispatch('renderEnd') - ; - - //============================================================ - - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var scale0; - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - //============================================================ - - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableLength = width - (axis === 'x' ? margin.left + margin.right : margin.top + margin.bottom), - naxis = axis == 'x' ? 'y' : 'x', - container = d3.select(this); - nv.utils.initSVG(container); - - //------------------------------------------------------------ - // Setup Scales - - scale0 = scale0 || scale; - - //------------------------------------------------------------ - - - //------------------------------------------------------------ - // Setup containers and skeleton of chart - - var wrap = container.selectAll('g.nv-distribution').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-distribution'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') - - //------------------------------------------------------------ - - - var distWrap = g.selectAll('g.nv-dist') - .data(function(d) { return d }, function(d) { return d.key }); - - distWrap.enter().append('g'); - distWrap - .attr('class', function(d,i) { return 'nv-dist nv-series-' + i }) - .style('stroke', function(d,i) { return color(d, i) }); - - var dist = distWrap.selectAll('line.nv-dist' + axis) - .data(function(d) { return d.values }) - dist.enter().append('line') - .attr(axis + '1', function(d,i) { return scale0(getData(d,i)) }) - .attr(axis + '2', function(d,i) { return scale0(getData(d,i)) }) - renderWatch.transition(distWrap.exit().selectAll('line.nv-dist' + axis), 'dist exit') - // .transition() - .attr(axis + '1', function(d,i) { return scale(getData(d,i)) }) - .attr(axis + '2', function(d,i) { return scale(getData(d,i)) }) - .style('stroke-opacity', 0) - .remove(); - dist - .attr('class', function(d,i) { return 'nv-dist' + axis + ' nv-dist' + axis + '-' + i }) - .attr(naxis + '1', 0) - .attr(naxis + '2', size); - renderWatch.transition(dist, 'dist') - // .transition() - .attr(axis + '1', function(d,i) { return scale(getData(d,i)) }) - .attr(axis + '2', function(d,i) { return scale(getData(d,i)) }) - - - scale0 = scale.copy(); - - }); - renderWatch.renderEnd('distribution immediate'); - return chart; - } - - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - chart.options = nv.utils.optionsFunc.bind(chart); - chart.dispatch = dispatch; - - chart.margin = function(_) { - if (!arguments.length) return margin; - margin.top = typeof _.top != 'undefined' ? _.top : margin.top; - margin.right = typeof _.right != 'undefined' ? _.right : margin.right; - margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom; - margin.left = typeof _.left != 'undefined' ? _.left : margin.left; - return chart; - }; - - chart.width = function(_) { - if (!arguments.length) return width; - width = _; - return chart; - }; - - chart.axis = function(_) { - if (!arguments.length) return axis; - axis = _; - return chart; - }; - - chart.size = function(_) { - if (!arguments.length) return size; - size = _; - return chart; - }; - - chart.getData = function(_) { - if (!arguments.length) return getData; - getData = d3.functor(_); - return chart; - }; - - chart.scale = function(_) { - if (!arguments.length) return scale; - scale = _; - return chart; - }; - - chart.color = function(_) { - if (!arguments.length) return color; - color = nv.utils.getColor(_); - return chart; - }; - - chart.duration = function(_) { - if (!arguments.length) return duration; - duration = _; - renderWatch.reset(duration); - return chart; - }; - //============================================================ - - - return chart; -} -nv.models.furiousLegend = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 5, right: 0, bottom: 5, left: 0} - , width = 400 - , height = 20 - , getKey = function(d) { return d.key } - , color = nv.utils.getColor() - , align = true - , padding = 28 //define how much space between legend items. - recommend 32 for furious version - , rightAlign = true - , updateState = true //If true, legend will update data.disabled and trigger a 'stateChange' dispatch. - , radioButtonMode = false //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time) - , expanded = false - , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange') - , vers = 'classic' //Options are "classic" and "furious" - ; - - function chart(selection) { - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - container = d3.select(this); - nv.utils.initSVG(container); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-legend').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g'); - var g = wrap.select('g'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var series = g.selectAll('.nv-series') - .data(function(d) { - if(vers != 'furious') return d; - - return d.filter(function(n) { - return expanded ? true : !n.disengaged; - }); - }); - var seriesEnter = series.enter().append('g').attr('class', 'nv-series') - - var seriesShape; - - if(vers == 'classic') { - seriesEnter.append('circle') - .style('stroke-width', 2) - .attr('class','nv-legend-symbol') - .attr('r', 5); - - seriesShape = series.select('circle'); - } else if (vers == 'furious') { - seriesEnter.append('rect') - .style('stroke-width', 2) - .attr('class','nv-legend-symbol') - .attr('rx', 3) - .attr('ry', 3); - - seriesShape = series.select('rect'); - - seriesEnter.append('g') - .attr('class', 'nv-check-box') - .property('innerHTML','') - .attr('transform', 'translate(-10,-8)scale(0.5)'); - - var seriesCheckbox = series.select('.nv-check-box'); - - seriesCheckbox.each(function(d,i) { - d3.select(this).selectAll('path') - .attr('stroke', setTextColor(d,i)); - }); - } - - seriesEnter.append('text') - .attr('text-anchor', 'start') - .attr('class','nv-legend-text') - .attr('dy', '.32em') - .attr('dx', '8'); - - var seriesText = series.select('text.nv-legend-text'); - - series - .on('mouseover', function(d,i) { - dispatch.legendMouseover(d,i); //TODO: Make consistent with other event objects - }) - .on('mouseout', function(d,i) { - dispatch.legendMouseout(d,i); - }) - .on('click', function(d,i) { - dispatch.legendClick(d,i); - // make sure we re-get data in case it was modified - var data = series.data(); - if (updateState) { - if(vers =='classic') { - if (radioButtonMode) { - //Radio button mode: set every series to disabled, - // and enable the clicked series. - data.forEach(function(series) { series.disabled = true}); - d.disabled = false; - } - else { - d.disabled = !d.disabled; - if (data.every(function(series) { return series.disabled})) { - //the default behavior of NVD3 legends is, if every single series - // is disabled, turn all series' back on. - data.forEach(function(series) { series.disabled = false}); - } - } - } else if(vers == 'furious') { - if(expanded) { - d.disengaged = !d.disengaged; - d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled; - d.disabled = d.disengaged || d.userDisabled; - } else if (!expanded) { - d.disabled = !d.disabled; - d.userDisabled = d.disabled; - var engaged = data.filter(function(d) { return !d.disengaged; }); - if (engaged.every(function(series) { return series.userDisabled })) { - //the default behavior of NVD3 legends is, if every single series - // is disabled, turn all series' back on. - data.forEach(function(series) { - series.disabled = series.userDisabled = false; - }); - } - } - } - dispatch.stateChange({ - disabled: data.map(function(d) { return !!d.disabled }), - disengaged: data.map(function(d) { return !!d.disengaged }) - }); - - } - }) - .on('dblclick', function(d,i) { - if(vers == 'furious' && expanded) return; - dispatch.legendDblclick(d,i); - if (updateState) { - // make sure we re-get data in case it was modified - var data = series.data(); - //the default behavior of NVD3 legends, when double clicking one, - // is to set all other series' to false, and make the double clicked series enabled. - data.forEach(function(series) { - series.disabled = true; - if(vers == 'furious') series.userDisabled = series.disabled; - }); - d.disabled = false; - if(vers == 'furious') d.userDisabled = d.disabled; - dispatch.stateChange({ - disabled: data.map(function(d) { return !!d.disabled }) - }); - } - }); - - series.classed('nv-disabled', function(d) { return d.userDisabled }); - series.exit().remove(); - - seriesText - .attr('fill', setTextColor) - .text(getKey); - - //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option) - // NEW ALIGNING CODE, TODO: clean up - - var versPadding; - switch(vers) { - case 'furious' : - versPadding = 23; - break; - case 'classic' : - versPadding = 20; - } - - if (align) { - - var seriesWidths = []; - series.each(function(d,i) { - var legendText = d3.select(this).select('text'); - var nodeTextLength; - try { - nodeTextLength = legendText.node().getComputedTextLength(); - // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead - if(nodeTextLength <= 0) throw Error(); - } - catch(e) { - nodeTextLength = nv.utils.calcApproxTextWidth(legendText); - } - - seriesWidths.push(nodeTextLength + padding); - }); - - var seriesPerRow = 0; - var legendWidth = 0; - var columnWidths = []; - - while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) { - columnWidths[seriesPerRow] = seriesWidths[seriesPerRow]; - legendWidth += seriesWidths[seriesPerRow++]; - } - if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row - - while ( legendWidth > availableWidth && seriesPerRow > 1 ) { - columnWidths = []; - seriesPerRow--; - - for (var k = 0; k < seriesWidths.length; k++) { - if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) ) - columnWidths[k % seriesPerRow] = seriesWidths[k]; - } - - legendWidth = columnWidths.reduce(function(prev, cur, index, array) { - return prev + cur; - }); - } - - var xPositions = []; - for (var i = 0, curX = 0; i < seriesPerRow; i++) { - xPositions[i] = curX; - curX += columnWidths[i]; - } - - series - .attr('transform', function(d, i) { - return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')'; - }); - - //position legend as far right as possible within the total width - if (rightAlign) { - g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')'); - } - else { - g.attr('transform', 'translate(0' + ',' + margin.top + ')'); - } - - height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding); - - } else { - - var ypos = 5, - newxpos = 5, - maxwidth = 0, - xpos; - series - .attr('transform', function(d, i) { - var length = d3.select(this).select('text').node().getComputedTextLength() + padding; - xpos = newxpos; - - if (width < margin.left + margin.right + xpos + length) { - newxpos = xpos = 5; - ypos += versPadding; - } - - newxpos += length; - if (newxpos > maxwidth) maxwidth = newxpos; - - return 'translate(' + xpos + ',' + ypos + ')'; - }); - - //position legend as far right as possible within the total width - g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')'); - - height = margin.top + margin.bottom + ypos + 15; - } - - if(vers == 'furious') { - // Size rectangles after text is placed - seriesShape - .attr('width', function(d,i) { - return seriesText[0][i].getComputedTextLength() + 27; - }) - .attr('height', 18) - .attr('y', -9) - .attr('x', -15) - } - - seriesShape - .style('fill', setBGColor) - .style('stroke', function(d,i) { return d.color || color(d, i) }); - }); - - function setTextColor(d,i) { - if(vers != 'furious') return '#000'; - if(expanded) { - return d.disengaged ? color(d,i) : '#fff'; - } else if (!expanded) { - return !!d.disabled ? color(d,i) : '#fff'; - } - } - - function setBGColor(d,i) { - if(expanded && vers == 'furious') { - return d.disengaged ? '#fff' : color(d,i); - } else { - return !!d.disabled ? '#fff' : color(d,i); - } - } - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - key: {get: function(){return getKey;}, set: function(_){getKey=_;}}, - align: {get: function(){return align;}, set: function(_){align=_;}}, - rightAlign: {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}}, - padding: {get: function(){return padding;}, set: function(_){padding=_;}}, - updateState: {get: function(){return updateState;}, set: function(_){updateState=_;}}, - radioButtonMode: {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}}, - expanded: {get: function(){return expanded;}, set: function(_){expanded=_;}}, - vers: {get: function(){return vers;}, set: function(_){vers=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; -//TODO: consider deprecating and using multibar with single series for this -nv.models.historicalBar = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = null - , height = null - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , x = d3.scale.linear() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , forceX = [] - , forceY = [0] - , padData = false - , clipEdge = true - , color = nv.utils.defaultColor() - , xDomain - , yDomain - , xRange - , yRange - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - , interactive = true - ; - - var renderWatch = nv.utils.renderWatch(dispatch, 0); - - function chart(selection) { - selection.each(function(data) { - renderWatch.reset(); - - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - nv.utils.initSVG(container); - - // Setup Scales - x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); - - if (padData) - x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); - else - x.range(xRange || [0, availableWidth]); - - y.domain(yDomain || d3.extent(data[0].values.map(getY).concat(forceY) )) - .range(yRange || [availableHeight, 0]); - - // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point - if (x.domain()[0] === x.domain()[1]) - x.domain()[0] ? - x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) - : x.domain([-1,1]); - - if (y.domain()[0] === y.domain()[1]) - y.domain()[0] ? - y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) - : y.domain([-1,1]); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-historicalBar-' + id).data([data[0].values]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBar-' + id); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-bars'); - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - container - .on('click', function(d,i) { - dispatch.chartClick({ - data: d, - index: i, - pos: d3.event, - id: id - }); - }); - - defsEnter.append('clipPath') - .attr('id', 'nv-chart-clip-path-' + id) - .append('rect'); - - wrap.select('#nv-chart-clip-path-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - g.attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); - - var bars = wrap.select('.nv-bars').selectAll('.nv-bar') - .data(function(d) { return d }, function(d,i) {return getX(d,i)}); - bars.exit().remove(); - - bars.enter().append('rect') - .attr('x', 0 ) - .attr('y', function(d,i) { return nv.utils.NaNtoZero(y(Math.max(0, getY(d,i)))) }) - .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.abs(y(getY(d,i)) - y(0))) }) - .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) - .on('mouseover', function(d,i) { - if (!interactive) return; - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - - }) - .on('mouseout', function(d,i) { - if (!interactive) return; - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mousemove', function(d,i) { - if (!interactive) return; - dispatch.elementMousemove({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('click', function(d,i) { - if (!interactive) return; - dispatch.elementClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }) - .on('dblclick', function(d,i) { - if (!interactive) return; - dispatch.elementDblClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }); - - bars - .attr('fill', function(d,i) { return color(d, i); }) - .attr('class', function(d,i,j) { return (getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive') + ' nv-bar-' + j + '-' + i }) - .watchTransition(renderWatch, 'bars') - .attr('transform', function(d,i) { return 'translate(' + (x(getX(d,i)) - availableWidth / data[0].values.length * .45) + ',0)'; }) - //TODO: better width calculations that don't assume always uniform data spacing;w - .attr('width', (availableWidth / data[0].values.length) * .9 ); - - bars.watchTransition(renderWatch, 'bars') - .attr('y', function(d,i) { - var rval = getY(d,i) < 0 ? - y(0) : - y(0) - y(getY(d,i)) < 1 ? - y(0) - 1 : - y(getY(d,i)); - return nv.utils.NaNtoZero(rval); - }) - .attr('height', function(d,i) { return nv.utils.NaNtoZero(Math.max(Math.abs(y(getY(d,i)) - y(0)),1)) }); - - }); - - renderWatch.renderEnd('historicalBar immediate'); - return chart; - } - - //Create methods to allow outside functions to highlight a specific bar. - chart.highlightPoint = function(pointIndex, isHoverOver) { - container - .select(".nv-bars .nv-bar-0-" + pointIndex) - .classed("hover", isHoverOver) - ; - }; - - chart.clearHighlights = function() { - container - .select(".nv-bars .nv-bar.hover") - .classed("hover", false) - ; - }; - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - padData: {get: function(){return padData;}, set: function(_){padData=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.historicalBarChart = function(bar_model) { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var bars = bar_model || nv.models.historicalBar() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , interactiveLayer = nv.interactiveGuideline() - , tooltip = nv.models.tooltip() - ; - - - var margin = {top: 30, right: 90, bottom: 50, left: 90} - , color = nv.utils.defaultColor() - , width = null - , height = null - , showLegend = false - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , useInteractiveGuideline = false - , x - , y - , state = {} - , defaultState = null - , noData = null - , dispatch = d3.dispatch('tooltipHide', 'stateChange', 'changeState', 'renderEnd') - , transitionDuration = 250 - ; - - xAxis.orient('bottom').tickPadding(7); - yAxis.orient( (rightAlignYAxis) ? 'right' : 'left'); - tooltip - .duration(0) - .headerEnabled(false) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }) - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch, 0); - - function chart(selection) { - selection.each(function(data) { - renderWatch.reset(); - renderWatch.models(bars); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { container.transition().duration(transitionDuration).call(chart) }; - chart.container = this; - - //set state.disabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display noData message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = bars.xScale(); - y = bars.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-historicalBarChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-historicalBarChart').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-barsWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-interactive'); - - // Legend - if (showLegend) { - legend.width(availableWidth); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - wrap.select('.nv-legendWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')') - } - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - //Set up interactive layer - if (useInteractiveGuideline) { - interactiveLayer - .width(availableWidth) - .height(availableHeight) - .margin({left:margin.left, top:margin.top}) - .svgContainer(container) - .xScale(x); - wrap.select(".nv-interactive").call(interactiveLayer); - } - bars - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - - var barsWrap = g.select('.nv-barsWrap') - .datum(data.filter(function(d) { return !d.disabled })); - barsWrap.transition().call(bars); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + y.range()[0] + ')'); - g.select('.nv-x.nv-axis') - .transition() - .call(xAxis); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis') - .transition() - .call(yAxis); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - interactiveLayer.dispatch.on('elementMousemove', function(e) { - bars.clearHighlights(); - - var singlePoint, pointIndex, pointXLocation, allData = []; - data - .filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }) - .forEach(function(series,i) { - pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); - bars.highlightPoint(pointIndex,true); - var point = series.values[pointIndex]; - if (point === undefined) return; - if (singlePoint === undefined) singlePoint = point; - if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - allData.push({ - key: series.key, - value: chart.y()(point, pointIndex), - color: color(series,series.seriesIndex), - data: series.values[pointIndex] - }); - }); - - var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); - interactiveLayer.tooltip - .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) - .chartContainer(that.parentNode) - .valueFormatter(function(d,i) { - return yAxis.tickFormat()(d); - }) - .data({ - value: xValue, - index: pointIndex, - series: allData - })(); - - interactiveLayer.renderGuideLine(pointXLocation); - - }); - - interactiveLayer.dispatch.on("elementMouseout",function(e) { - dispatch.tooltipHide(); - bars.clearHighlights(); - }); - - legend.dispatch.on('legendClick', function(d,i) { - d.disabled = !d.disabled; - - if (!data.filter(function(d) { return !d.disabled }).length) { - data.map(function(d) { - d.disabled = false; - wrap.selectAll('.nv-series').classed('disabled', false); - return d; - }); - } - - state.disabled = data.map(function(d) { return !!d.disabled }); - dispatch.stateChange(state); - - selection.transition().call(chart); - }); - - legend.dispatch.on('legendDblclick', function(d) { - //Double clicking should always enable current series, and disabled all others. - data.forEach(function(d) { - d.disabled = true; - }); - d.disabled = false; - - state.disabled = data.map(function(d) { return !!d.disabled }); - dispatch.stateChange(state); - chart.update(); - }); - - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - - state.disabled = e.disabled; - } - - chart.update(); - }); - }); - - renderWatch.renderEnd('historicalBarChart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - bars.dispatch.on('elementMouseover.tooltip', function(evt) { - evt['series'] = { - key: chart.x()(evt.data), - value: chart.y()(evt.data), - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - bars.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - bars.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.bars = bars; - chart.legend = legend; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.interactiveLayer = interactiveLayer; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - bars.color(color); - }}, - duration: {get: function(){return transitionDuration;}, set: function(_){ - transitionDuration=_; - renderWatch.reset(transitionDuration); - yAxis.duration(transitionDuration); - xAxis.duration(transitionDuration); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( (_) ? 'right' : 'left'); - }}, - useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ - useInteractiveGuideline = _; - if (_ === true) { - chart.interactive(false); - } - }} - }); - - nv.utils.inheritOptions(chart, bars); - nv.utils.initOptions(chart); - - return chart; -}; - - -// ohlcChart is just a historical chart with ohlc bars and some tweaks -nv.models.ohlcBarChart = function() { - var chart = nv.models.historicalBarChart(nv.models.ohlcBar()); - - // special default tooltip since we show multiple values per x - chart.useInteractiveGuideline(true); - chart.interactiveLayer.tooltip.contentGenerator(function(data) { - // we assume only one series exists for this chart - var d = data.series[0].data; - // match line colors as defined in nv.d3.css - var color = d.open < d.close ? "2ca02c" : "d62728"; - return '' + - '

' + data.value + '

' + - '' + - '' + - '' + - '' + - '' + - '
open:' + chart.yAxis.tickFormat()(d.open) + '
close:' + chart.yAxis.tickFormat()(d.close) + '
high' + chart.yAxis.tickFormat()(d.high) + '
low:' + chart.yAxis.tickFormat()(d.low) + '
'; - }); - return chart; -}; - -// candlestickChart is just a historical chart with candlestick bars and some tweaks -nv.models.candlestickBarChart = function() { - var chart = nv.models.historicalBarChart(nv.models.candlestickBar()); - - // special default tooltip since we show multiple values per x - chart.useInteractiveGuideline(true); - chart.interactiveLayer.tooltip.contentGenerator(function(data) { - // we assume only one series exists for this chart - var d = data.series[0].data; - // match line colors as defined in nv.d3.css - var color = d.open < d.close ? "2ca02c" : "d62728"; - return '' + - '

' + data.value + '

' + - '' + - '' + - '' + - '' + - '' + - '
open:' + chart.yAxis.tickFormat()(d.open) + '
close:' + chart.yAxis.tickFormat()(d.close) + '
high' + chart.yAxis.tickFormat()(d.high) + '
low:' + chart.yAxis.tickFormat()(d.low) + '
'; - }); - return chart; -}; -nv.models.legend = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 5, right: 0, bottom: 5, left: 0} - , width = 400 - , height = 20 - , getKey = function(d) { return d.key } - , color = nv.utils.getColor() - , align = true - , padding = 32 //define how much space between legend items. - recommend 32 for furious version - , rightAlign = true - , updateState = true //If true, legend will update data.disabled and trigger a 'stateChange' dispatch. - , radioButtonMode = false //If true, clicking legend items will cause it to behave like a radio button. (only one can be selected at a time) - , expanded = false - , dispatch = d3.dispatch('legendClick', 'legendDblclick', 'legendMouseover', 'legendMouseout', 'stateChange') - , vers = 'classic' //Options are "classic" and "furious" - ; - - function chart(selection) { - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - container = d3.select(this); - nv.utils.initSVG(container); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-legend').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-legend').append('g'); - var g = wrap.select('g'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var series = g.selectAll('.nv-series') - .data(function(d) { - if(vers != 'furious') return d; - - return d.filter(function(n) { - return expanded ? true : !n.disengaged; - }); - }); - - var seriesEnter = series.enter().append('g').attr('class', 'nv-series'); - var seriesShape; - - var versPadding; - switch(vers) { - case 'furious' : - versPadding = 23; - break; - case 'classic' : - versPadding = 20; - } - - if(vers == 'classic') { - seriesEnter.append('circle') - .style('stroke-width', 2) - .attr('class','nv-legend-symbol') - .attr('r', 5); - - seriesShape = series.select('circle'); - } else if (vers == 'furious') { - seriesEnter.append('rect') - .style('stroke-width', 2) - .attr('class','nv-legend-symbol') - .attr('rx', 3) - .attr('ry', 3); - - seriesShape = series.select('.nv-legend-symbol'); - - seriesEnter.append('g') - .attr('class', 'nv-check-box') - .property('innerHTML','') - .attr('transform', 'translate(-10,-8)scale(0.5)'); - - var seriesCheckbox = series.select('.nv-check-box'); - - seriesCheckbox.each(function(d,i) { - d3.select(this).selectAll('path') - .attr('stroke', setTextColor(d,i)); - }); - } - - seriesEnter.append('text') - .attr('text-anchor', 'start') - .attr('class','nv-legend-text') - .attr('dy', '.32em') - .attr('dx', '8'); - - var seriesText = series.select('text.nv-legend-text'); - - series - .on('mouseover', function(d,i) { - dispatch.legendMouseover(d,i); //TODO: Make consistent with other event objects - }) - .on('mouseout', function(d,i) { - dispatch.legendMouseout(d,i); - }) - .on('click', function(d,i) { - dispatch.legendClick(d,i); - // make sure we re-get data in case it was modified - var data = series.data(); - if (updateState) { - if(vers =='classic') { - if (radioButtonMode) { - //Radio button mode: set every series to disabled, - // and enable the clicked series. - data.forEach(function(series) { series.disabled = true}); - d.disabled = false; - } - else { - d.disabled = !d.disabled; - if (data.every(function(series) { return series.disabled})) { - //the default behavior of NVD3 legends is, if every single series - // is disabled, turn all series' back on. - data.forEach(function(series) { series.disabled = false}); - } - } - } else if(vers == 'furious') { - if(expanded) { - d.disengaged = !d.disengaged; - d.userDisabled = d.userDisabled == undefined ? !!d.disabled : d.userDisabled; - d.disabled = d.disengaged || d.userDisabled; - } else if (!expanded) { - d.disabled = !d.disabled; - d.userDisabled = d.disabled; - var engaged = data.filter(function(d) { return !d.disengaged; }); - if (engaged.every(function(series) { return series.userDisabled })) { - //the default behavior of NVD3 legends is, if every single series - // is disabled, turn all series' back on. - data.forEach(function(series) { - series.disabled = series.userDisabled = false; - }); - } - } - } - dispatch.stateChange({ - disabled: data.map(function(d) { return !!d.disabled }), - disengaged: data.map(function(d) { return !!d.disengaged }) - }); - - } - }) - .on('dblclick', function(d,i) { - if(vers == 'furious' && expanded) return; - dispatch.legendDblclick(d,i); - if (updateState) { - // make sure we re-get data in case it was modified - var data = series.data(); - //the default behavior of NVD3 legends, when double clicking one, - // is to set all other series' to false, and make the double clicked series enabled. - data.forEach(function(series) { - series.disabled = true; - if(vers == 'furious') series.userDisabled = series.disabled; - }); - d.disabled = false; - if(vers == 'furious') d.userDisabled = d.disabled; - dispatch.stateChange({ - disabled: data.map(function(d) { return !!d.disabled }) - }); - } - }); - - series.classed('nv-disabled', function(d) { return d.userDisabled }); - series.exit().remove(); - - seriesText - .attr('fill', setTextColor) - .text(getKey); - - //TODO: implement fixed-width and max-width options (max-width is especially useful with the align option) - // NEW ALIGNING CODE, TODO: clean up - var legendWidth = 0; - if (align) { - - var seriesWidths = []; - series.each(function(d,i) { - var legendText = d3.select(this).select('text'); - var nodeTextLength; - try { - nodeTextLength = legendText.node().getComputedTextLength(); - // If the legendText is display:none'd (nodeTextLength == 0), simulate an error so we approximate, instead - if(nodeTextLength <= 0) throw Error(); - } - catch(e) { - nodeTextLength = nv.utils.calcApproxTextWidth(legendText); - } - - seriesWidths.push(nodeTextLength + padding); - }); - - var seriesPerRow = 0; - var columnWidths = []; - legendWidth = 0; - - while ( legendWidth < availableWidth && seriesPerRow < seriesWidths.length) { - columnWidths[seriesPerRow] = seriesWidths[seriesPerRow]; - legendWidth += seriesWidths[seriesPerRow++]; - } - if (seriesPerRow === 0) seriesPerRow = 1; //minimum of one series per row - - while ( legendWidth > availableWidth && seriesPerRow > 1 ) { - columnWidths = []; - seriesPerRow--; - - for (var k = 0; k < seriesWidths.length; k++) { - if (seriesWidths[k] > (columnWidths[k % seriesPerRow] || 0) ) - columnWidths[k % seriesPerRow] = seriesWidths[k]; - } - - legendWidth = columnWidths.reduce(function(prev, cur, index, array) { - return prev + cur; - }); - } - - var xPositions = []; - for (var i = 0, curX = 0; i < seriesPerRow; i++) { - xPositions[i] = curX; - curX += columnWidths[i]; - } - - series - .attr('transform', function(d, i) { - return 'translate(' + xPositions[i % seriesPerRow] + ',' + (5 + Math.floor(i / seriesPerRow) * versPadding) + ')'; - }); - - //position legend as far right as possible within the total width - if (rightAlign) { - g.attr('transform', 'translate(' + (width - margin.right - legendWidth) + ',' + margin.top + ')'); - } - else { - g.attr('transform', 'translate(0' + ',' + margin.top + ')'); - } - - height = margin.top + margin.bottom + (Math.ceil(seriesWidths.length / seriesPerRow) * versPadding); - - } else { - - var ypos = 5, - newxpos = 5, - maxwidth = 0, - xpos; - series - .attr('transform', function(d, i) { - var length = d3.select(this).select('text').node().getComputedTextLength() + padding; - xpos = newxpos; - - if (width < margin.left + margin.right + xpos + length) { - newxpos = xpos = 5; - ypos += versPadding; - } - - newxpos += length; - if (newxpos > maxwidth) maxwidth = newxpos; - - if(legendWidth < xpos + maxwidth) { - legendWidth = xpos + maxwidth; - } - return 'translate(' + xpos + ',' + ypos + ')'; - }); - - //position legend as far right as possible within the total width - g.attr('transform', 'translate(' + (width - margin.right - maxwidth) + ',' + margin.top + ')'); - - height = margin.top + margin.bottom + ypos + 15; - } - - if(vers == 'furious') { - // Size rectangles after text is placed - seriesShape - .attr('width', function(d,i) { - return seriesText[0][i].getComputedTextLength() + 27; - }) - .attr('height', 18) - .attr('y', -9) - .attr('x', -15); - - // The background for the expanded legend (UI) - gEnter.insert('rect',':first-child') - .attr('class', 'nv-legend-bg') - .attr('fill', '#eee') - // .attr('stroke', '#444') - .attr('opacity',0); - - var seriesBG = g.select('.nv-legend-bg'); - - seriesBG - .transition().duration(300) - .attr('x', -versPadding ) - .attr('width', legendWidth + versPadding - 12) - .attr('height', height + 10) - .attr('y', -margin.top - 10) - .attr('opacity', expanded ? 1 : 0); - - - } - - seriesShape - .style('fill', setBGColor) - .style('fill-opacity', setBGOpacity) - .style('stroke', setBGColor); - }); - - function setTextColor(d,i) { - if(vers != 'furious') return '#000'; - if(expanded) { - return d.disengaged ? '#000' : '#fff'; - } else if (!expanded) { - if(!d.color) d.color = color(d,i); - return !!d.disabled ? d.color : '#fff'; - } - } - - function setBGColor(d,i) { - if(expanded && vers == 'furious') { - return d.disengaged ? '#eee' : d.color || color(d,i); - } else { - return d.color || color(d,i); - } - } - - - function setBGOpacity(d,i) { - if(expanded && vers == 'furious') { - return 1; - } else { - return !!d.disabled ? 0 : 1; - } - } - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - key: {get: function(){return getKey;}, set: function(_){getKey=_;}}, - align: {get: function(){return align;}, set: function(_){align=_;}}, - rightAlign: {get: function(){return rightAlign;}, set: function(_){rightAlign=_;}}, - padding: {get: function(){return padding;}, set: function(_){padding=_;}}, - updateState: {get: function(){return updateState;}, set: function(_){updateState=_;}}, - radioButtonMode: {get: function(){return radioButtonMode;}, set: function(_){radioButtonMode=_;}}, - expanded: {get: function(){return expanded;}, set: function(_){expanded=_;}}, - vers: {get: function(){return vers;}, set: function(_){vers=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.line = function() { - "use strict"; - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var scatter = nv.models.scatter() - ; - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , container = null - , strokeWidth = 1.5 - , color = nv.utils.defaultColor() // a function that returns a color - , getX = function(d) { return d.x } // accessor to get the x value from a data point - , getY = function(d) { return d.y } // accessor to get the y value from a data point - , defined = function(d,i) { return !isNaN(getY(d,i)) && getY(d,i) !== null } // allows a line to be not continuous when it is not defined - , isArea = function(d) { return d.area } // decides if a line is an area or just a line - , clipEdge = false // if true, masks lines within x and y scale - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , interpolate = "linear" // controls the line interpolation - , duration = 250 - , dispatch = d3.dispatch('elementClick', 'elementMouseover', 'elementMouseout', 'renderEnd') - ; - - scatter - .pointSize(16) // default size - .pointDomain([16,256]) //set to speed up calculation, needs to be unset if there is a custom size accessor - ; - - //============================================================ - - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0 //used to store previous scales - , renderWatch = nv.utils.renderWatch(dispatch, duration) - ; - - //============================================================ - - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(scatter); - selection.each(function(data) { - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - nv.utils.initSVG(container); - - // Setup Scales - x = scatter.xScale(); - y = scatter.yScale(); - - x0 = x0 || x; - y0 = y0 || y; - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-line').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-line'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-groups'); - gEnter.append('g').attr('class', 'nv-scatterWrap'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - scatter - .width(availableWidth) - .height(availableHeight); - - var scatterWrap = wrap.select('.nv-scatterWrap'); - scatterWrap.call(scatter); - - defsEnter.append('clipPath') - .attr('id', 'nv-edge-clip-' + scatter.id()) - .append('rect'); - - wrap.select('#nv-edge-clip-' + scatter.id() + ' rect') - .attr('width', availableWidth) - .attr('height', (availableHeight > 0) ? availableHeight : 0); - - g .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : ''); - scatterWrap - .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : ''); - - var groups = wrap.select('.nv-groups').selectAll('.nv-group') - .data(function(d) { return d }, function(d) { return d.key }); - groups.enter().append('g') - .style('stroke-opacity', 1e-6) - .style('stroke-width', function(d) { return d.strokeWidth || strokeWidth }) - .style('fill-opacity', 1e-6); - - groups.exit().remove(); - - groups - .attr('class', function(d,i) { - return (d.classed || '') + ' nv-group nv-series-' + i; - }) - .classed('hover', function(d) { return d.hover }) - .style('fill', function(d,i){ return color(d, i) }) - .style('stroke', function(d,i){ return color(d, i)}); - groups.watchTransition(renderWatch, 'line: groups') - .style('stroke-opacity', 1) - .style('fill-opacity', function(d) { return d.fillOpacity || .5}); - - var areaPaths = groups.selectAll('path.nv-area') - .data(function(d) { return isArea(d) ? [d] : [] }); // this is done differently than lines because I need to check if series is an area - areaPaths.enter().append('path') - .attr('class', 'nv-area') - .attr('d', function(d) { - return d3.svg.area() - .interpolate(interpolate) - .defined(defined) - .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) }) - .y0(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) }) - .y1(function(d,i) { return y0( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) }) - //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this - .apply(this, [d.values]) - }); - groups.exit().selectAll('path.nv-area') - .remove(); - - areaPaths.watchTransition(renderWatch, 'line: areaPaths') - .attr('d', function(d) { - return d3.svg.area() - .interpolate(interpolate) - .defined(defined) - .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) }) - .y0(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) }) - .y1(function(d,i) { return y( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) }) - //.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this - .apply(this, [d.values]) - }); - - var linePaths = groups.selectAll('path.nv-line') - .data(function(d) { return [d.values] }); - - linePaths.enter().append('path') - .attr('class', 'nv-line') - .attr('d', - d3.svg.line() - .interpolate(interpolate) - .defined(defined) - .x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) }) - .y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) }) - ); - - linePaths.watchTransition(renderWatch, 'line: linePaths') - .attr('d', - d3.svg.line() - .interpolate(interpolate) - .defined(defined) - .x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) }) - .y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) }) - ); - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - }); - renderWatch.renderEnd('line immediate'); - return chart; - } - - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.scatter = scatter; - // Pass through events - scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); }); - scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); }); - scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); }); - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - defined: {get: function(){return defined;}, set: function(_){defined=_;}}, - interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - scatter.duration(duration); - }}, - isArea: {get: function(){return isArea;}, set: function(_){ - isArea = d3.functor(_); - }}, - x: {get: function(){return getX;}, set: function(_){ - getX = _; - scatter.x(_); - }}, - y: {get: function(){return getY;}, set: function(_){ - getY = _; - scatter.y(_); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - scatter.color(color); - }} - }); - - nv.utils.inheritOptions(chart, scatter); - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.lineChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var lines = nv.models.line() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , interactiveLayer = nv.interactiveGuideline() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 20, bottom: 50, left: 60} - , color = nv.utils.defaultColor() - , width = null - , height = null - , showLegend = true - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , useInteractiveGuideline = false - , x - , y - , state = nv.utils.state() - , defaultState = null - , noData = null - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd') - , duration = 250 - ; - - // set options on sub-objects for this chart - xAxis.orient('bottom').tickPadding(7); - yAxis.orient(rightAlignYAxis ? 'right' : 'left'); - tooltip.valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }).headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }) - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(lines); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - if (duration === 0) - container.call(chart); - else - container.transition().duration(duration).call(chart) - }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display noData message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - - // Setup Scales - x = lines.xScale(); - y = lines.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-lineChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineChart').append('g'); - var g = wrap.select('g'); - - gEnter.append("rect").style("opacity",0); - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-linesWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-interactive'); - - g.select("rect") - .attr("width",availableWidth) - .attr("height",(availableHeight > 0) ? availableHeight : 0); - - // Legend - if (showLegend) { - legend.width(availableWidth); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - wrap.select('.nv-legendWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')') - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - //Set up interactive layer - if (useInteractiveGuideline) { - interactiveLayer - .width(availableWidth) - .height(availableHeight) - .margin({left:margin.left, top:margin.top}) - .svgContainer(container) - .xScale(x); - wrap.select(".nv-interactive").call(interactiveLayer); - } - - lines - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - - - var linesWrap = g.select('.nv-linesWrap') - .datum(data.filter(function(d) { return !d.disabled })); - - linesWrap.call(lines); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks(nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + y.range()[0] + ')'); - g.select('.nv-x.nv-axis') - .call(xAxis); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks(nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis') - .call(yAxis); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - interactiveLayer.dispatch.on('elementMousemove', function(e) { - lines.clearHighlights(); - var singlePoint, pointIndex, pointXLocation, allData = []; - data - .filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }) - .forEach(function(series,i) { - pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); - var point = series.values[pointIndex]; - var pointYValue = chart.y()(point, pointIndex); - if (pointYValue != null) { - lines.highlightPoint(i, pointIndex, true); - } - if (point === undefined) return; - if (singlePoint === undefined) singlePoint = point; - if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - allData.push({ - key: series.key, - value: pointYValue, - color: color(series,series.seriesIndex) - }); - }); - //Highlight the tooltip entry based on which point the mouse is closest to. - if (allData.length > 2) { - var yValue = chart.yScale().invert(e.mouseY); - var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); - var threshold = 0.03 * domainExtent; - var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); - if (indexToHighlight !== null) - allData[indexToHighlight].highlight = true; - } - - var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); - interactiveLayer.tooltip - .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top}) - .chartContainer(that.parentNode) - .valueFormatter(function(d,i) { - return d == null ? "N/A" : yAxis.tickFormat()(d); - }) - .data({ - value: xValue, - index: pointIndex, - series: allData - })(); - - interactiveLayer.renderGuideLine(pointXLocation); - - }); - - interactiveLayer.dispatch.on('elementClick', function(e) { - var pointXLocation, allData = []; - - data.filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }).forEach(function(series) { - var pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); - var point = series.values[pointIndex]; - if (typeof point === 'undefined') return; - if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - var yPos = chart.yScale()(chart.y()(point,pointIndex)); - allData.push({ - point: point, - pointIndex: pointIndex, - pos: [pointXLocation, yPos], - seriesIndex: series.seriesIndex, - series: series - }); - }); - - lines.dispatch.elementClick(allData); - }); - - interactiveLayer.dispatch.on("elementMouseout",function(e) { - lines.clearHighlights(); - }); - - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - - state.disabled = e.disabled; - } - - chart.update(); - }); - - }); - - renderWatch.renderEnd('lineChart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - lines.dispatch.on('elementMouseover.tooltip', function(evt) { - tooltip.data(evt).position(evt.pos).hidden(false); - }); - - lines.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.lines = lines; - chart.legend = legend; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.interactiveLayer = interactiveLayer; - chart.tooltip = tooltip; - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - lines.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - lines.color(color); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( rightAlignYAxis ? 'right' : 'left'); - }}, - useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ - useInteractiveGuideline = _; - if (useInteractiveGuideline) { - lines.interactive(false); - lines.useVoronoi(false); - } - }} - }); - - nv.utils.inheritOptions(chart, lines); - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.linePlusBarChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var lines = nv.models.line() - , lines2 = nv.models.line() - , bars = nv.models.historicalBar() - , bars2 = nv.models.historicalBar() - , xAxis = nv.models.axis() - , x2Axis = nv.models.axis() - , y1Axis = nv.models.axis() - , y2Axis = nv.models.axis() - , y3Axis = nv.models.axis() - , y4Axis = nv.models.axis() - , legend = nv.models.legend() - , brush = d3.svg.brush() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 30, bottom: 30, left: 60} - , margin2 = {top: 0, right: 30, bottom: 20, left: 60} - , width = null - , height = null - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , color = nv.utils.defaultColor() - , showLegend = true - , focusEnable = true - , focusShowAxisY = false - , focusShowAxisX = true - , focusHeight = 50 - , extent - , brushExtent = null - , x - , x2 - , y1 - , y2 - , y3 - , y4 - , noData = null - , dispatch = d3.dispatch('brush', 'stateChange', 'changeState') - , transitionDuration = 0 - , state = nv.utils.state() - , defaultState = null - , legendLeftAxisHint = ' (left axis)' - , legendRightAxisHint = ' (right axis)' - ; - - lines.clipEdge(true); - lines2.interactive(false); - xAxis.orient('bottom').tickPadding(5); - y1Axis.orient('left'); - y2Axis.orient('right'); - x2Axis.orient('bottom').tickPadding(5); - y3Axis.orient('left'); - y4Axis.orient('right'); - - tooltip.headerEnabled(true).headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }) - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight1 = nv.utils.availableHeight(height, container, margin) - - (focusEnable ? focusHeight : 0), - availableHeight2 = focusHeight - margin2.top - margin2.bottom; - - chart.update = function() { container.transition().duration(transitionDuration).call(chart); }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - var dataBars = data.filter(function(d) { return !d.disabled && d.bar }); - var dataLines = data.filter(function(d) { return !d.bar }); // removed the !d.disabled clause here to fix Issue #240 - - x = bars.xScale(); - x2 = x2Axis.scale(); - y1 = bars.yScale(); - y2 = lines.yScale(); - y3 = bars2.yScale(); - y4 = lines2.yScale(); - - var series1 = data - .filter(function(d) { return !d.disabled && d.bar }) - .map(function(d) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i) } - }) - }); - - var series2 = data - .filter(function(d) { return !d.disabled && !d.bar }) - .map(function(d) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i) } - }) - }); - - x.range([0, availableWidth]); - - x2 .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } )) - .range([0, availableWidth]); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-linePlusBar').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-linePlusBar').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-legendWrap'); - - // this is the main chart - var focusEnter = gEnter.append('g').attr('class', 'nv-focus'); - focusEnter.append('g').attr('class', 'nv-x nv-axis'); - focusEnter.append('g').attr('class', 'nv-y1 nv-axis'); - focusEnter.append('g').attr('class', 'nv-y2 nv-axis'); - focusEnter.append('g').attr('class', 'nv-barsWrap'); - focusEnter.append('g').attr('class', 'nv-linesWrap'); - - // context chart is where you can focus in - var contextEnter = gEnter.append('g').attr('class', 'nv-context'); - contextEnter.append('g').attr('class', 'nv-x nv-axis'); - contextEnter.append('g').attr('class', 'nv-y1 nv-axis'); - contextEnter.append('g').attr('class', 'nv-y2 nv-axis'); - contextEnter.append('g').attr('class', 'nv-barsWrap'); - contextEnter.append('g').attr('class', 'nv-linesWrap'); - contextEnter.append('g').attr('class', 'nv-brushBackground'); - contextEnter.append('g').attr('class', 'nv-x nv-brush'); - - //============================================================ - // Legend - //------------------------------------------------------------ - - if (showLegend) { - var legendWidth = legend.align() ? availableWidth / 2 : availableWidth; - var legendXPosition = legend.align() ? legendWidth : 0; - - legend.width(legendWidth); - - g.select('.nv-legendWrap') - .datum(data.map(function(series) { - series.originalKey = series.originalKey === undefined ? series.key : series.originalKey; - series.key = series.originalKey + (series.bar ? legendLeftAxisHint : legendRightAxisHint); - return series; - })) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - // FIXME: shouldn't this be "- (focusEnabled ? focusHeight : 0)"? - availableHeight1 = nv.utils.availableHeight(height, container, margin) - focusHeight; - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')'); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - //============================================================ - // Context chart (focus chart) components - //------------------------------------------------------------ - - // hide or show the focus context chart - g.select('.nv-context').style('display', focusEnable ? 'initial' : 'none'); - - bars2 - .width(availableWidth) - .height(availableHeight2) - .color(data.map(function (d, i) { - return d.color || color(d, i); - }).filter(function (d, i) { - return !data[i].disabled && data[i].bar - })); - lines2 - .width(availableWidth) - .height(availableHeight2) - .color(data.map(function (d, i) { - return d.color || color(d, i); - }).filter(function (d, i) { - return !data[i].disabled && !data[i].bar - })); - - var bars2Wrap = g.select('.nv-context .nv-barsWrap') - .datum(dataBars.length ? dataBars : [ - {values: []} - ]); - var lines2Wrap = g.select('.nv-context .nv-linesWrap') - .datum(!dataLines[0].disabled ? dataLines : [ - {values: []} - ]); - - g.select('.nv-context') - .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')'); - - bars2Wrap.transition().call(bars2); - lines2Wrap.transition().call(lines2); - - // context (focus chart) axis controls - if (focusShowAxisX) { - x2Axis - ._ticks( nv.utils.calcTicksX(availableWidth / 100, data)) - .tickSize(-availableHeight2, 0); - g.select('.nv-context .nv-x.nv-axis') - .attr('transform', 'translate(0,' + y3.range()[0] + ')'); - g.select('.nv-context .nv-x.nv-axis').transition() - .call(x2Axis); - } - - if (focusShowAxisY) { - y3Axis - .scale(y3) - ._ticks( availableHeight2 / 36 ) - .tickSize( -availableWidth, 0); - y4Axis - .scale(y4) - ._ticks( availableHeight2 / 36 ) - .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none - - g.select('.nv-context .nv-y3.nv-axis') - .style('opacity', dataBars.length ? 1 : 0) - .attr('transform', 'translate(0,' + x2.range()[0] + ')'); - g.select('.nv-context .nv-y2.nv-axis') - .style('opacity', dataLines.length ? 1 : 0) - .attr('transform', 'translate(' + x2.range()[1] + ',0)'); - - g.select('.nv-context .nv-y1.nv-axis').transition() - .call(y3Axis); - g.select('.nv-context .nv-y2.nv-axis').transition() - .call(y4Axis); - } - - // Setup Brush - brush.x(x2).on('brush', onBrush); - - if (brushExtent) brush.extent(brushExtent); - - var brushBG = g.select('.nv-brushBackground').selectAll('g') - .data([brushExtent || brush.extent()]); - - var brushBGenter = brushBG.enter() - .append('g'); - - brushBGenter.append('rect') - .attr('class', 'left') - .attr('x', 0) - .attr('y', 0) - .attr('height', availableHeight2); - - brushBGenter.append('rect') - .attr('class', 'right') - .attr('x', 0) - .attr('y', 0) - .attr('height', availableHeight2); - - var gBrush = g.select('.nv-x.nv-brush') - .call(brush); - gBrush.selectAll('rect') - //.attr('y', -5) - .attr('height', availableHeight2); - gBrush.selectAll('.resize').append('path').attr('d', resizePath); - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - state.disabled = e.disabled; - } - chart.update(); - }); - - //============================================================ - // Functions - //------------------------------------------------------------ - - // Taken from crossfilter (http://square.github.com/crossfilter/) - function resizePath(d) { - var e = +(d == 'e'), - x = e ? 1 : -1, - y = availableHeight2 / 3; - return 'M' + (.5 * x) + ',' + y - + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) - + 'V' + (2 * y - 6) - + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y) - + 'Z' - + 'M' + (2.5 * x) + ',' + (y + 8) - + 'V' + (2 * y - 8) - + 'M' + (4.5 * x) + ',' + (y + 8) - + 'V' + (2 * y - 8); - } - - - function updateBrushBG() { - if (!brush.empty()) brush.extent(brushExtent); - brushBG - .data([brush.empty() ? x2.domain() : brushExtent]) - .each(function(d,i) { - var leftWidth = x2(d[0]) - x2.range()[0], - rightWidth = x2.range()[1] - x2(d[1]); - d3.select(this).select('.left') - .attr('width', leftWidth < 0 ? 0 : leftWidth); - - d3.select(this).select('.right') - .attr('x', x2(d[1])) - .attr('width', rightWidth < 0 ? 0 : rightWidth); - }); - } - - function onBrush() { - brushExtent = brush.empty() ? null : brush.extent(); - extent = brush.empty() ? x2.domain() : brush.extent(); - dispatch.brush({extent: extent, brush: brush}); - updateBrushBG(); - - // Prepare Main (Focus) Bars and Lines - bars - .width(availableWidth) - .height(availableHeight1) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled && data[i].bar })); - - lines - .width(availableWidth) - .height(availableHeight1) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled && !data[i].bar })); - - var focusBarsWrap = g.select('.nv-focus .nv-barsWrap') - .datum(!dataBars.length ? [{values:[]}] : - dataBars - .map(function(d,i) { - return { - key: d.key, - values: d.values.filter(function(d,i) { - return bars.x()(d,i) >= extent[0] && bars.x()(d,i) <= extent[1]; - }) - } - }) - ); - - var focusLinesWrap = g.select('.nv-focus .nv-linesWrap') - .datum(dataLines[0].disabled ? [{values:[]}] : - dataLines - .map(function(d,i) { - return { - area: d.area, - fillOpacity: d.fillOpacity, - key: d.key, - values: d.values.filter(function(d,i) { - return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; - }) - } - }) - ); - - // Update Main (Focus) X Axis - if (dataBars.length) { - x = bars.xScale(); - } else { - x = lines.xScale(); - } - - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight1, 0); - - xAxis.domain([Math.ceil(extent[0]), Math.floor(extent[1])]); - - g.select('.nv-x.nv-axis').transition().duration(transitionDuration) - .call(xAxis); - - // Update Main (Focus) Bars and Lines - focusBarsWrap.transition().duration(transitionDuration).call(bars); - focusLinesWrap.transition().duration(transitionDuration).call(lines); - - // Setup and Update Main (Focus) Y Axes - g.select('.nv-focus .nv-x.nv-axis') - .attr('transform', 'translate(0,' + y1.range()[0] + ')'); - - y1Axis - .scale(y1) - ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) - .tickSize(-availableWidth, 0); - y2Axis - .scale(y2) - ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) - .tickSize(dataBars.length ? 0 : -availableWidth, 0); // Show the y2 rules only if y1 has none - - g.select('.nv-focus .nv-y1.nv-axis') - .style('opacity', dataBars.length ? 1 : 0); - g.select('.nv-focus .nv-y2.nv-axis') - .style('opacity', dataLines.length && !dataLines[0].disabled ? 1 : 0) - .attr('transform', 'translate(' + x.range()[1] + ',0)'); - - g.select('.nv-focus .nv-y1.nv-axis').transition().duration(transitionDuration) - .call(y1Axis); - g.select('.nv-focus .nv-y2.nv-axis').transition().duration(transitionDuration) - .call(y2Axis); - } - - onBrush(); - - }); - - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - lines.dispatch.on('elementMouseover.tooltip', function(evt) { - tooltip - .duration(100) - .valueFormatter(function(d, i) { - return y2Axis.tickFormat()(d, i); - }) - .data(evt) - .position(evt.pos) - .hidden(false); - }); - - lines.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - bars.dispatch.on('elementMouseover.tooltip', function(evt) { - evt.value = chart.x()(evt.data); - evt['series'] = { - value: chart.y()(evt.data), - color: evt.color - }; - tooltip - .duration(0) - .valueFormatter(function(d, i) { - return y1Axis.tickFormat()(d, i); - }) - .data(evt) - .hidden(false); - }); - - bars.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - bars.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.legend = legend; - chart.lines = lines; - chart.lines2 = lines2; - chart.bars = bars; - chart.bars2 = bars2; - chart.xAxis = xAxis; - chart.x2Axis = x2Axis; - chart.y1Axis = y1Axis; - chart.y2Axis = y2Axis; - chart.y3Axis = y3Axis; - chart.y4Axis = y4Axis; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - focusEnable: {get: function(){return focusEnable;}, set: function(_){focusEnable=_;}}, - focusHeight: {get: function(){return focusHeight;}, set: function(_){focusHeight=_;}}, - focusShowAxisX: {get: function(){return focusShowAxisX;}, set: function(_){focusShowAxisX=_;}}, - focusShowAxisY: {get: function(){return focusShowAxisY;}, set: function(_){focusShowAxisY=_;}}, - legendLeftAxisHint: {get: function(){return legendLeftAxisHint;}, set: function(_){legendLeftAxisHint=_;}}, - legendRightAxisHint: {get: function(){return legendRightAxisHint;}, set: function(_){legendRightAxisHint=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return transitionDuration;}, set: function(_){ - transitionDuration = _; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - }}, - x: {get: function(){return getX;}, set: function(_){ - getX = _; - lines.x(_); - lines2.x(_); - bars.x(_); - bars2.x(_); - }}, - y: {get: function(){return getY;}, set: function(_){ - getY = _; - lines.y(_); - lines2.y(_); - bars.y(_); - bars2.y(_); - }} - }); - - nv.utils.inheritOptions(chart, lines); - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.lineWithFocusChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var lines = nv.models.line() - , lines2 = nv.models.line() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , x2Axis = nv.models.axis() - , y2Axis = nv.models.axis() - , legend = nv.models.legend() - , brush = d3.svg.brush() - , tooltip = nv.models.tooltip() - , interactiveLayer = nv.interactiveGuideline() - ; - - var margin = {top: 30, right: 30, bottom: 30, left: 60} - , margin2 = {top: 0, right: 30, bottom: 20, left: 60} - , color = nv.utils.defaultColor() - , width = null - , height = null - , height2 = 50 - , useInteractiveGuideline = false - , x - , y - , x2 - , y2 - , showLegend = true - , brushExtent = null - , noData = null - , dispatch = d3.dispatch('brush', 'stateChange', 'changeState') - , transitionDuration = 250 - , state = nv.utils.state() - , defaultState = null - ; - - lines.clipEdge(true).duration(0); - lines2.interactive(false); - xAxis.orient('bottom').tickPadding(5); - yAxis.orient('left'); - x2Axis.orient('bottom').tickPadding(5); - y2Axis.orient('left'); - - tooltip.valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }).headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }) - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2, - availableHeight2 = height2 - margin2.top - margin2.bottom; - - chart.update = function() { container.transition().duration(transitionDuration).call(chart) }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = lines.xScale(); - y = lines.yScale(); - x2 = lines2.xScale(); - y2 = lines2.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-lineWithFocusChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-lineWithFocusChart').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-legendWrap'); - - var focusEnter = gEnter.append('g').attr('class', 'nv-focus'); - focusEnter.append('g').attr('class', 'nv-x nv-axis'); - focusEnter.append('g').attr('class', 'nv-y nv-axis'); - focusEnter.append('g').attr('class', 'nv-linesWrap'); - focusEnter.append('g').attr('class', 'nv-interactive'); - - var contextEnter = gEnter.append('g').attr('class', 'nv-context'); - contextEnter.append('g').attr('class', 'nv-x nv-axis'); - contextEnter.append('g').attr('class', 'nv-y nv-axis'); - contextEnter.append('g').attr('class', 'nv-linesWrap'); - contextEnter.append('g').attr('class', 'nv-brushBackground'); - contextEnter.append('g').attr('class', 'nv-x nv-brush'); - - // Legend - if (showLegend) { - legend.width(availableWidth); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight1 = nv.utils.availableHeight(height, container, margin) - height2; - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')') - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - - //Set up interactive layer - if (useInteractiveGuideline) { - interactiveLayer - .width(availableWidth) - .height(availableHeight1) - .margin({left:margin.left, top:margin.top}) - .svgContainer(container) - .xScale(x); - wrap.select(".nv-interactive").call(interactiveLayer); - } - - // Main Chart Component(s) - lines - .width(availableWidth) - .height(availableHeight1) - .color( - data - .map(function(d,i) { - return d.color || color(d, i); - }) - .filter(function(d,i) { - return !data[i].disabled; - }) - ); - - lines2 - .defined(lines.defined()) - .width(availableWidth) - .height(availableHeight2) - .color( - data - .map(function(d,i) { - return d.color || color(d, i); - }) - .filter(function(d,i) { - return !data[i].disabled; - }) - ); - - g.select('.nv-context') - .attr('transform', 'translate(0,' + ( availableHeight1 + margin.bottom + margin2.top) + ')') - - var contextLinesWrap = g.select('.nv-context .nv-linesWrap') - .datum(data.filter(function(d) { return !d.disabled })) - - d3.transition(contextLinesWrap).call(lines2); - - // Setup Main (Focus) Axes - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight1, 0); - - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight1/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-focus .nv-x.nv-axis') - .attr('transform', 'translate(0,' + availableHeight1 + ')'); - - // Setup Brush - brush - .x(x2) - .on('brush', function() { - onBrush(); - }); - - if (brushExtent) brush.extent(brushExtent); - - var brushBG = g.select('.nv-brushBackground').selectAll('g') - .data([brushExtent || brush.extent()]) - - var brushBGenter = brushBG.enter() - .append('g'); - - brushBGenter.append('rect') - .attr('class', 'left') - .attr('x', 0) - .attr('y', 0) - .attr('height', availableHeight2); - - brushBGenter.append('rect') - .attr('class', 'right') - .attr('x', 0) - .attr('y', 0) - .attr('height', availableHeight2); - - var gBrush = g.select('.nv-x.nv-brush') - .call(brush); - gBrush.selectAll('rect') - .attr('height', availableHeight2); - gBrush.selectAll('.resize').append('path').attr('d', resizePath); - - onBrush(); - - // Setup Secondary (Context) Axes - x2Axis - .scale(x2) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight2, 0); - - g.select('.nv-context .nv-x.nv-axis') - .attr('transform', 'translate(0,' + y2.range()[0] + ')'); - d3.transition(g.select('.nv-context .nv-x.nv-axis')) - .call(x2Axis); - - y2Axis - .scale(y2) - ._ticks( nv.utils.calcTicksY(availableHeight2/36, data) ) - .tickSize( -availableWidth, 0); - - d3.transition(g.select('.nv-context .nv-y.nv-axis')) - .call(y2Axis); - - g.select('.nv-context .nv-x.nv-axis') - .attr('transform', 'translate(0,' + y2.range()[0] + ')'); - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - interactiveLayer.dispatch.on('elementMousemove', function(e) { - lines.clearHighlights(); - var singlePoint, pointIndex, pointXLocation, allData = []; - data - .filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }) - .forEach(function(series,i) { - var extent = brush.empty() ? x2.domain() : brush.extent(); - var currentValues = series.values.filter(function(d,i) { - return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; - }); - - pointIndex = nv.interactiveBisect(currentValues, e.pointXValue, lines.x()); - var point = currentValues[pointIndex]; - var pointYValue = chart.y()(point, pointIndex); - if (pointYValue != null) { - lines.highlightPoint(i, pointIndex, true); - } - if (point === undefined) return; - if (singlePoint === undefined) singlePoint = point; - if (pointXLocation === undefined) pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - allData.push({ - key: series.key, - value: chart.y()(point, pointIndex), - color: color(series,series.seriesIndex) - }); - }); - //Highlight the tooltip entry based on which point the mouse is closest to. - if (allData.length > 2) { - var yValue = chart.yScale().invert(e.mouseY); - var domainExtent = Math.abs(chart.yScale().domain()[0] - chart.yScale().domain()[1]); - var threshold = 0.03 * domainExtent; - var indexToHighlight = nv.nearestValueIndex(allData.map(function(d){return d.value}),yValue,threshold); - if (indexToHighlight !== null) - allData[indexToHighlight].highlight = true; - } - - var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); - interactiveLayer.tooltip - .position({left: e.mouseX + margin.left, top: e.mouseY + margin.top}) - .chartContainer(that.parentNode) - .valueFormatter(function(d,i) { - return d == null ? "N/A" : yAxis.tickFormat()(d); - }) - .data({ - value: xValue, - index: pointIndex, - series: allData - })(); - - interactiveLayer.renderGuideLine(pointXLocation); - - }); - - interactiveLayer.dispatch.on("elementMouseout",function(e) { - lines.clearHighlights(); - }); - - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - } - chart.update(); - }); - - //============================================================ - // Functions - //------------------------------------------------------------ - - // Taken from crossfilter (http://square.github.com/crossfilter/) - function resizePath(d) { - var e = +(d == 'e'), - x = e ? 1 : -1, - y = availableHeight2 / 3; - return 'M' + (.5 * x) + ',' + y - + 'A6,6 0 0 ' + e + ' ' + (6.5 * x) + ',' + (y + 6) - + 'V' + (2 * y - 6) - + 'A6,6 0 0 ' + e + ' ' + (.5 * x) + ',' + (2 * y) - + 'Z' - + 'M' + (2.5 * x) + ',' + (y + 8) - + 'V' + (2 * y - 8) - + 'M' + (4.5 * x) + ',' + (y + 8) - + 'V' + (2 * y - 8); - } - - - function updateBrushBG() { - if (!brush.empty()) brush.extent(brushExtent); - brushBG - .data([brush.empty() ? x2.domain() : brushExtent]) - .each(function(d,i) { - var leftWidth = x2(d[0]) - x.range()[0], - rightWidth = availableWidth - x2(d[1]); - d3.select(this).select('.left') - .attr('width', leftWidth < 0 ? 0 : leftWidth); - - d3.select(this).select('.right') - .attr('x', x2(d[1])) - .attr('width', rightWidth < 0 ? 0 : rightWidth); - }); - } - - - function onBrush() { - brushExtent = brush.empty() ? null : brush.extent(); - var extent = brush.empty() ? x2.domain() : brush.extent(); - - //The brush extent cannot be less than one. If it is, don't update the line chart. - if (Math.abs(extent[0] - extent[1]) <= 1) { - return; - } - - dispatch.brush({extent: extent, brush: brush}); - - - updateBrushBG(); - - // Update Main (Focus) - var focusLinesWrap = g.select('.nv-focus .nv-linesWrap') - .datum( - data - .filter(function(d) { return !d.disabled }) - .map(function(d,i) { - return { - key: d.key, - area: d.area, - values: d.values.filter(function(d,i) { - return lines.x()(d,i) >= extent[0] && lines.x()(d,i) <= extent[1]; - }) - } - }) - ); - focusLinesWrap.transition().duration(transitionDuration).call(lines); - - - // Update Main (Focus) Axes - g.select('.nv-focus .nv-x.nv-axis').transition().duration(transitionDuration) - .call(xAxis); - g.select('.nv-focus .nv-y.nv-axis').transition().duration(transitionDuration) - .call(yAxis); - } - }); - - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - lines.dispatch.on('elementMouseover.tooltip', function(evt) { - tooltip.data(evt).position(evt.pos).hidden(false); - }); - - lines.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.legend = legend; - chart.lines = lines; - chart.lines2 = lines2; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.x2Axis = x2Axis; - chart.y2Axis = y2Axis; - chart.interactiveLayer = interactiveLayer; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - focusHeight: {get: function(){return height2;}, set: function(_){height2=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - brushExtent: {get: function(){return brushExtent;}, set: function(_){brushExtent=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - // line color is handled above? - }}, - interpolate: {get: function(){return lines.interpolate();}, set: function(_){ - lines.interpolate(_); - lines2.interpolate(_); - }}, - xTickFormat: {get: function(){return xAxis.tickFormat();}, set: function(_){ - xAxis.tickFormat(_); - x2Axis.tickFormat(_); - }}, - yTickFormat: {get: function(){return yAxis.tickFormat();}, set: function(_){ - yAxis.tickFormat(_); - y2Axis.tickFormat(_); - }}, - duration: {get: function(){return transitionDuration;}, set: function(_){ - transitionDuration=_; - yAxis.duration(transitionDuration); - y2Axis.duration(transitionDuration); - xAxis.duration(transitionDuration); - x2Axis.duration(transitionDuration); - }}, - x: {get: function(){return lines.x();}, set: function(_){ - lines.x(_); - lines2.x(_); - }}, - y: {get: function(){return lines.y();}, set: function(_){ - lines.y(_); - lines2.y(_); - }}, - useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ - useInteractiveGuideline = _; - if (useInteractiveGuideline) { - lines.interactive(false); - lines.useVoronoi(false); - } - }} - }); - - nv.utils.inheritOptions(chart, lines); - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.multiBar = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , x = d3.scale.ordinal() - , y = d3.scale.linear() - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , getYerr = function(d) { return d.yErr } - , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove - , clipEdge = true - , stacked = false - , stackOffset = 'zero' // options include 'silhouette', 'wiggle', 'expand', 'zero', or a custom function - , color = nv.utils.defaultColor() - , errorBarColor = nv.utils.defaultColor() - , hideable = false - , barColor = null // adding the ability to set the color for each rather than the whole group - , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled - , duration = 500 - , xDomain - , yDomain - , xRange - , yRange - , groupSpacing = 0.1 - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0 //used to store previous scales - , renderWatch = nv.utils.renderWatch(dispatch, duration) - ; - - var last_datalength = 0; - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - var nonStackableCount = 0; - // This function defines the requirements for render complete - var endFn = function(d, i) { - if (d.series === data.length - 1 && i === data[0].values.length - 1) - return true; - return false; - }; - - if(hideable && data.length) hideable = [{ - values: data[0].values.map(function(d) { - return { - x: d.x, - y: 0, - series: d.series, - size: 0.01 - };} - )}]; - - if (stacked) { - var parsed = d3.layout.stack() - .offset(stackOffset) - .values(function(d){ return d.values }) - .y(getY) - (!data.length && hideable ? hideable : data); - - parsed.forEach(function(series, i){ - // if series is non-stackable, use un-parsed data - if (series.nonStackable) { - data[i].nonStackableSeries = nonStackableCount++; - parsed[i] = data[i]; - } else { - // don't stack this seires on top of the nonStackable seriees - if (i > 0 && parsed[i - 1].nonStackable){ - parsed[i].values.map(function(d,j){ - d.y0 -= parsed[i - 1].values[j].y; - d.y1 = d.y0 + d.y; - }); - } - } - }); - data = parsed; - } - //add series index and key to each data point for reference - data.forEach(function(series, i) { - series.values.forEach(function(point) { - point.series = i; - point.key = series.key; - }); - }); - - // HACK for negative value stacking - if (stacked) { - data[0].values.map(function(d,i) { - var posBase = 0, negBase = 0; - data.map(function(d, idx) { - if (!data[idx].nonStackable) { - var f = d.values[i] - f.size = Math.abs(f.y); - if (f.y<0) { - f.y1 = negBase; - negBase = negBase - f.size; - } else - { - f.y1 = f.size + posBase; - posBase = posBase + f.size; - } - } - - }); - }); - } - // Setup Scales - // remap and flatten the data for use in calculating the scales' domains - var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate - data.map(function(d, idx) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1, idx:idx, yErr: getYerr(d,i)} - }) - }); - - x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) - .rangeBands(xRange || [0, availableWidth], groupSpacing); - - y.domain(yDomain || d3.extent(d3.merge( - d3.merge(seriesData).map(function(d) { - var domain = d.y; - // increase the domain range if this series is stackable - if (stacked && !data[d.idx].nonStackable) { - if (d.y > 0){ - domain = d.y1 - } else { - domain = d.y1 + d.y - } - } - var yerr = d.yErr; - if (yerr) { - if (yerr.length) { - return [domain + yerr[0], domain + yerr[1]]; - } else { - yerr = Math.abs(yerr) - return [domain - yerr, domain + yerr]; - } - } else { - return [domain]; - } - })).concat(forceY))) - .range(yRange || [availableHeight, 0]); - - // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point - if (x.domain()[0] === x.domain()[1]) - x.domain()[0] ? - x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) - : x.domain([-1,1]); - - if (y.domain()[0] === y.domain()[1]) - y.domain()[0] ? - y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) - : y.domain([-1,1]); - - x0 = x0 || x; - y0 = y0 || y; - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-multibar').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibar'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-groups'); - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - defsEnter.append('clipPath') - .attr('id', 'nv-edge-clip-' + id) - .append('rect'); - wrap.select('#nv-edge-clip-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); - - var groups = wrap.select('.nv-groups').selectAll('.nv-group') - .data(function(d) { return d }, function(d,i) { return i }); - groups.enter().append('g') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6); - - var exitTransition = renderWatch - .transition(groups.exit().selectAll('g.nv-bar'), 'multibarExit', Math.min(100, duration)) - .attr('y', function(d, i, j) { - var yVal = y0(0) || 0; - if (stacked) { - if (data[d.series] && !data[d.series].nonStackable) { - yVal = y0(d.y0); - } - } - return yVal; - }) - .attr('height', 0) - .remove(); - if (exitTransition.delay) - exitTransition.delay(function(d,i) { - var delay = i * (duration / (last_datalength + 1)) - i; - return delay; - }); - groups - .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) - .classed('hover', function(d) { return d.hover }) - .style('fill', function(d,i){ return color(d, i) }) - .style('stroke', function(d,i){ return color(d, i) }); - groups - .style('stroke-opacity', 1) - .style('fill-opacity', 0.75); - - var bars = groups.selectAll('g.nv-bar') - .data(function(d) { return (hideable && !data.length) ? hideable.values : d.values }); - bars.exit().remove(); - - var barsEnter = bars.enter().append('g') - .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) - .attr('transform', function(d,i,j) { - var _x = stacked && !data[j].nonStackable ? 0 : (j * x.rangeBand() / data.length ); - var _y = y0(stacked && !data[j].nonStackable ? d.y0 : 0) || 0; - return 'translate(' + _x + ',' + _y + ')'; - }) - ; - - barsEnter.append('rect') - .attr('height', 0) - .attr('width', function(d,i,j) { return x.rangeBand() / (stacked && !data[j].nonStackable ? 1 : data.length) }) - .style('fill', function(d,i,j){ return color(d, j, i); }) - .style('stroke', function(d,i,j){ return color(d, j, i); }) - ; - bars - .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mouseout', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('click', function(d,i) { - dispatch.elementClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }) - .on('dblclick', function(d,i) { - dispatch.elementDblClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }); - - if (getYerr(data[0].values[0], 0)) { - barsEnter.append('polyline'); - - bars.select('polyline') - .attr('fill', 'none') - .attr('stroke', 'black') - //.attr('stroke', function(d, i, j) { return errorBarColor(d, j, i); }) - .attr('points', function(d,i) { - var yerr = getYerr(d,i) - , mid = 0.8 * x.rangeBand() / ((stacked ? 1 : data.length) * 2); - yerr = yerr.length ? yerr : [-Math.abs(yerr), Math.abs(yerr)]; - yerr = yerr.map(function(e) { return y(e) - y(0); }); - var a = [[-mid, yerr[0]], [mid, yerr[0]], [0, yerr[0]], [0, yerr[1]], [-mid, yerr[1]], [mid, yerr[1]]]; - return a.map(function (path) { return path.join(',') }).join(' '); - }) - .attr('transform', function(d, i) { - var xOffset = x.rangeBand() / ((stacked ? 1 : data.length) * 2); - var yOffset = getY(d,i) < 0 ? y(getY(d, i)) - y(0) : 0; - return 'translate(' + xOffset + ', ' + yOffset + ')'; - }) - } - - bars - .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) - - if (barColor) { - if (!disabled) disabled = data.map(function() { return true }); - bars.select('rect') - .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }) - .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }); - } - - var barSelection = - bars.watchTransition(renderWatch, 'multibar', Math.min(250, duration)) - .delay(function(d,i) { - return i * duration / data[0].values.length; - }); - if (stacked){ - barSelection - .attr('transform', function(d,i,j) { - var yVal = 0; - // if stackable, stack it on top of the previous series - if (!data[j].nonStackable) { - yVal = y(d.y1); - } else { - if (getY(d,i) < 0){ - yVal = y(0); - } else { - if (y(0) - y(getY(d,i)) < -1){ - yVal = y(0) - 1; - } else { - yVal = y(getY(d, i)) || 0; - } - } - } - var width = 0; - if (data[j].nonStackable) { - width = d.series * x.rangeBand() / data.length; - if (data.length !== nonStackableCount){ - width = data[j].nonStackableSeries * x.rangeBand()/(nonStackableCount*2); - } - } - var xVal = width + x(getX(d, i)); - return 'translate(' + xVal + ',' + yVal + ')'; - }) - .select('rect') - .attr('height', function(d,i,j) { - if (!data[j].nonStackable) { - return Math.max(Math.abs(y(d.y+d.y0) - y(d.y0)), 1); - } else { - return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0; - } - }) - .attr('width', function(d,i,j){ - if (!data[j].nonStackable) { - return x.rangeBand(); - } else { - // if all series are nonStacable, take the full width - var width = (x.rangeBand() / nonStackableCount); - // otherwise, nonStackable graph will be only taking the half-width - // of the x rangeBand - if (data.length !== nonStackableCount) { - width = x.rangeBand()/(nonStackableCount*2); - } - return width; - } - }); - } - else { - barSelection.attr('transform', function(d,i) { - var xVal = d.series * x.rangeBand() / data.length + x(getX(d, i)); - var yVal = getY(d,i) < 0 ? - y(0) : - y(0) - y(getY(d,i)) < 1 ? - y(0) - 1 : - y(getY(d,i)) || 0; - return 'translate(' + xVal + ',' + yVal + ')'; - }) - .select('rect') - .attr('width', x.rangeBand() / data.length) - .attr('height', function(d,i) { - return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) || 0; - }); - } - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - - // keep track of the last data value length for transition calculations - if (data[0] && data[0].values) { - last_datalength = data[0].values.length; - } - - }); - - renderWatch.renderEnd('multibar immediate'); - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - yErr: {get: function(){return getYerr;}, set: function(_){getYerr=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}}, - stackOffset: {get: function(){return stackOffset;}, set: function(_){stackOffset=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - hideable: {get: function(){return hideable;}, set: function(_){hideable=_;}}, - groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - barColor: {get: function(){return barColor;}, set: function(_){ - barColor = _ ? nv.utils.getColor(_) : null; - }}, - errorBarColor: {get: function(){return errorBarColor;}, set: function(_){ - errorBarColor = _ ? nv.utils.getColor(_) : null; - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.multiBarChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var multibar = nv.models.multiBar() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , controls = nv.models.legend() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 20, bottom: 50, left: 60} - , width = null - , height = null - , color = nv.utils.defaultColor() - , showControls = true - , controlLabels = {} - , showLegend = true - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , reduceXTicks = true // if false a tick will show for every data point - , staggerLabels = false - , rotateLabels = 0 - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , state = nv.utils.state() - , defaultState = null - , noData = null - , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') - , controlWidth = function() { return showControls ? 180 : 0 } - , duration = 250 - ; - - state.stacked = false // DEPRECATED Maintained for backward compatibility - - multibar.stacked(false); - xAxis - .orient('bottom') - .tickPadding(7) - .showMaxMin(false) - .tickFormat(function(d) { return d }) - ; - yAxis - .orient((rightAlignYAxis) ? 'right' : 'left') - .tickFormat(d3.format(',.1f')) - ; - - tooltip - .duration(0) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }) - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - controls.updateState(false); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - var stacked = false; - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }), - stacked: stacked - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.stacked !== undefined) - stacked = state.stacked; - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(multibar); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - if (duration === 0) - container.call(chart); - else - container.transition() - .duration(duration) - .call(chart); - }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display noData message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = multibar.xScale(); - y = multibar.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-multiBarWithLegend').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarWithLegend').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-barsWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-controlsWrap'); - - // Legend - if (showLegend) { - legend.width(availableWidth - controlWidth()); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')'); - } - - // Controls - if (showControls) { - var controlsData = [ - { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() }, - { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() } - ]; - - controls.width(controlWidth()).color(['#444', '#444', '#444']); - g.select('.nv-controlsWrap') - .datum(controlsData) - .attr('transform', 'translate(0,' + (-margin.top) +')') - .call(controls); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - // Main Chart Component(s) - multibar - .disabled(data.map(function(series) { return series.disabled })) - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - - - var barsWrap = g.select('.nv-barsWrap') - .datum(data.filter(function(d) { return !d.disabled })); - - barsWrap.call(multibar); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + y.range()[0] + ')'); - g.select('.nv-x.nv-axis') - .call(xAxis); - - var xTicks = g.select('.nv-x.nv-axis > g').selectAll('g'); - - xTicks - .selectAll('line, text') - .style('opacity', 1) - - if (staggerLabels) { - var getTranslate = function(x,y) { - return "translate(" + x + "," + y + ")"; - }; - - var staggerUp = 5, staggerDown = 17; //pixels to stagger by - // Issue #140 - xTicks - .selectAll("text") - .attr('transform', function(d,i,j) { - return getTranslate(0, (j % 2 == 0 ? staggerUp : staggerDown)); - }); - - var totalInBetweenTicks = d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length; - g.selectAll(".nv-x.nv-axis .nv-axisMaxMin text") - .attr("transform", function(d,i) { - return getTranslate(0, (i === 0 || totalInBetweenTicks % 2 !== 0) ? staggerDown : staggerUp); - }); - } - - if (reduceXTicks) - xTicks - .filter(function(d,i) { - return i % Math.ceil(data[0].values.length / (availableWidth / 100)) !== 0; - }) - .selectAll('text, line') - .style('opacity', 0); - - if(rotateLabels) - xTicks - .selectAll('.tick text') - .attr('transform', 'rotate(' + rotateLabels + ' 0,0)') - .style('text-anchor', rotateLabels > 0 ? 'start' : 'end'); - - g.select('.nv-x.nv-axis').selectAll('g.nv-axisMaxMin text') - .style('opacity', 1); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis') - .call(yAxis); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - controls.dispatch.on('legendClick', function(d,i) { - if (!d.disabled) return; - controlsData = controlsData.map(function(s) { - s.disabled = true; - return s; - }); - d.disabled = false; - - switch (d.key) { - case 'Grouped': - case controlLabels.grouped: - multibar.stacked(false); - break; - case 'Stacked': - case controlLabels.stacked: - multibar.stacked(true); - break; - } - - state.stacked = multibar.stacked(); - dispatch.stateChange(state); - chart.update(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - state.disabled = e.disabled; - } - if (typeof e.stacked !== 'undefined') { - multibar.stacked(e.stacked); - state.stacked = e.stacked; - stacked = e.stacked; - } - chart.update(); - }); - }); - - renderWatch.renderEnd('multibarchart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - multibar.dispatch.on('elementMouseover.tooltip', function(evt) { - evt.value = chart.x()(evt.data); - evt['series'] = { - key: evt.data.key, - value: chart.y()(evt.data), - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - multibar.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - multibar.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.multibar = multibar; - chart.legend = legend; - chart.controls = controls; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.state = state; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, - controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - reduceXTicks: {get: function(){return reduceXTicks;}, set: function(_){reduceXTicks=_;}}, - rotateLabels: {get: function(){return rotateLabels;}, set: function(_){rotateLabels=_;}}, - staggerLabels: {get: function(){return staggerLabels;}, set: function(_){staggerLabels=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - multibar.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - renderWatch.reset(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( rightAlignYAxis ? 'right' : 'left'); - }}, - barColor: {get: function(){return multibar.barColor;}, set: function(_){ - multibar.barColor(_); - legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();}) - }} - }); - - nv.utils.inheritOptions(chart, multibar); - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.multiBarHorizontal = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , x = d3.scale.ordinal() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , getYerr = function(d) { return d.yErr } - , forceY = [0] // 0 is forced by default.. this makes sense for the majority of bar graphs... user can always do chart.forceY([]) to remove - , color = nv.utils.defaultColor() - , barColor = null // adding the ability to set the color for each rather than the whole group - , errorBarColor = nv.utils.defaultColor() - , disabled // used in conjunction with barColor to communicate from multiBarHorizontalChart what series are disabled - , stacked = false - , showValues = false - , showBarLabels = false - , valuePadding = 60 - , groupSpacing = 0.1 - , valueFormat = d3.format(',.2f') - , delay = 1200 - , xDomain - , yDomain - , xRange - , yRange - , duration = 250 - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0; //used to store previous scales - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - if (stacked) - data = d3.layout.stack() - .offset('zero') - .values(function(d){ return d.values }) - .y(getY) - (data); - - //add series index and key to each data point for reference - data.forEach(function(series, i) { - series.values.forEach(function(point) { - point.series = i; - point.key = series.key; - }); - }); - - // HACK for negative value stacking - if (stacked) - data[0].values.map(function(d,i) { - var posBase = 0, negBase = 0; - data.map(function(d) { - var f = d.values[i] - f.size = Math.abs(f.y); - if (f.y<0) { - f.y1 = negBase - f.size; - negBase = negBase - f.size; - } else - { - f.y1 = posBase; - posBase = posBase + f.size; - } - }); - }); - - // Setup Scales - // remap and flatten the data for use in calculating the scales' domains - var seriesData = (xDomain && yDomain) ? [] : // if we know xDomain and yDomain, no need to calculate - data.map(function(d) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i), y0: d.y0, y1: d.y1, yErr: getYerr(d,i) } - }) - }); - - x.domain(xDomain || d3.merge(seriesData).map(function(d) { return d.x })) - .rangeBands(xRange || [0, availableHeight], groupSpacing); - - y.domain(yDomain || d3.extent(d3.merge( - d3.merge(seriesData).map(function(d) { - var domain = d.y; - if (stacked) { - if (d.y > 0){ - domain = d.y1 + d.y - } else { - domain = d.y1 - } - } - var yerr = d.yErr; - if (yerr) { - if (yerr.length) { - return [domain + yerr[0], domain + yerr[1]]; - } else { - yerr = Math.abs(yerr) - return [domain - yerr, domain + yerr]; - } - } else { - return [domain]; - } - })).concat(forceY))) - - if (showValues && !stacked) - y.range(yRange || [(y.domain()[0] < 0 ? valuePadding : 0), availableWidth - (y.domain()[1] > 0 ? valuePadding : 0) ]); - else - y.range(yRange || [0, availableWidth]); - - x0 = x0 || x; - y0 = y0 || d3.scale.linear().domain(y.domain()).range([y(0),y(0)]); - - // Setup containers and skeleton of chart - var wrap = d3.select(this).selectAll('g.nv-wrap.nv-multibarHorizontal').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multibarHorizontal'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-groups'); - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var groups = wrap.select('.nv-groups').selectAll('.nv-group') - .data(function(d) { return d }, function(d,i) { return i }); - groups.enter().append('g') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6); - groups.exit().watchTransition(renderWatch, 'multibarhorizontal: exit groups') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6) - .remove(); - groups - .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) - .classed('hover', function(d) { return d.hover }) - .style('fill', function(d,i){ return color(d, i) }) - .style('stroke', function(d,i){ return color(d, i) }); - groups.watchTransition(renderWatch, 'multibarhorizontal: groups') - .style('stroke-opacity', 1) - .style('fill-opacity', .75); - - var bars = groups.selectAll('g.nv-bar') - .data(function(d) { return d.values }); - bars.exit().remove(); - - var barsEnter = bars.enter().append('g') - .attr('transform', function(d,i,j) { - return 'translate(' + y0(stacked ? d.y0 : 0) + ',' + (stacked ? 0 : (j * x.rangeBand() / data.length ) + x(getX(d,i))) + ')' - }); - - barsEnter.append('rect') - .attr('width', 0) - .attr('height', x.rangeBand() / (stacked ? 1 : data.length) ) - - bars - .on('mouseover', function(d,i) { //TODO: figure out why j works above, but not here - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mouseout', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mouseout', function(d,i) { - dispatch.elementMouseout({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('mousemove', function(d,i) { - dispatch.elementMousemove({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - }) - .on('click', function(d,i) { - dispatch.elementClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }) - .on('dblclick', function(d,i) { - dispatch.elementDblClick({ - data: d, - index: i, - color: d3.select(this).style("fill") - }); - d3.event.stopPropagation(); - }); - - if (getYerr(data[0].values[0], 0)) { - barsEnter.append('polyline'); - - bars.select('polyline') - .attr('fill', 'none') - .attr('stroke', function(d,i,j) { return errorBarColor(d, j, i); }) - .attr('points', function(d,i) { - var xerr = getYerr(d,i) - , mid = 0.8 * x.rangeBand() / ((stacked ? 1 : data.length) * 2); - xerr = xerr.length ? xerr : [-Math.abs(xerr), Math.abs(xerr)]; - xerr = xerr.map(function(e) { return y(e) - y(0); }); - var a = [[xerr[0],-mid], [xerr[0],mid], [xerr[0],0], [xerr[1],0], [xerr[1],-mid], [xerr[1],mid]]; - return a.map(function (path) { return path.join(',') }).join(' '); - }) - .attr('transform', function(d,i) { - var mid = x.rangeBand() / ((stacked ? 1 : data.length) * 2); - return 'translate(' + (getY(d,i) < 0 ? 0 : y(getY(d,i)) - y(0)) + ', ' + mid + ')' - }); - } - - barsEnter.append('text'); - - if (showValues && !stacked) { - bars.select('text') - .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'end' : 'start' }) - .attr('y', x.rangeBand() / (data.length * 2)) - .attr('dy', '.32em') - .text(function(d,i) { - var t = valueFormat(getY(d,i)) - , yerr = getYerr(d,i); - if (yerr === undefined) - return t; - if (!yerr.length) - return t + '±' + valueFormat(Math.abs(yerr)); - return t + '+' + valueFormat(Math.abs(yerr[1])) + '-' + valueFormat(Math.abs(yerr[0])); - }); - bars.watchTransition(renderWatch, 'multibarhorizontal: bars') - .select('text') - .attr('x', function(d,i) { return getY(d,i) < 0 ? -4 : y(getY(d,i)) - y(0) + 4 }) - } else { - bars.selectAll('text').text(''); - } - - if (showBarLabels && !stacked) { - barsEnter.append('text').classed('nv-bar-label',true); - bars.select('text.nv-bar-label') - .attr('text-anchor', function(d,i) { return getY(d,i) < 0 ? 'start' : 'end' }) - .attr('y', x.rangeBand() / (data.length * 2)) - .attr('dy', '.32em') - .text(function(d,i) { return getX(d,i) }); - bars.watchTransition(renderWatch, 'multibarhorizontal: bars') - .select('text.nv-bar-label') - .attr('x', function(d,i) { return getY(d,i) < 0 ? y(0) - y(getY(d,i)) + 4 : -4 }); - } - else { - bars.selectAll('text.nv-bar-label').text(''); - } - - bars - .attr('class', function(d,i) { return getY(d,i) < 0 ? 'nv-bar negative' : 'nv-bar positive'}) - - if (barColor) { - if (!disabled) disabled = data.map(function() { return true }); - bars - .style('fill', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }) - .style('stroke', function(d,i,j) { return d3.rgb(barColor(d,i)).darker( disabled.map(function(d,i) { return i }).filter(function(d,i){ return !disabled[i] })[j] ).toString(); }); - } - - if (stacked) - bars.watchTransition(renderWatch, 'multibarhorizontal: bars') - .attr('transform', function(d,i) { - return 'translate(' + y(d.y1) + ',' + x(getX(d,i)) + ')' - }) - .select('rect') - .attr('width', function(d,i) { - return Math.abs(y(getY(d,i) + d.y0) - y(d.y0)) - }) - .attr('height', x.rangeBand() ); - else - bars.watchTransition(renderWatch, 'multibarhorizontal: bars') - .attr('transform', function(d,i) { - //TODO: stacked must be all positive or all negative, not both? - return 'translate(' + - (getY(d,i) < 0 ? y(getY(d,i)) : y(0)) - + ',' + - (d.series * x.rangeBand() / data.length - + - x(getX(d,i)) ) - + ')' - }) - .select('rect') - .attr('height', x.rangeBand() / data.length ) - .attr('width', function(d,i) { - return Math.max(Math.abs(y(getY(d,i)) - y(0)),1) - }); - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - - }); - - renderWatch.renderEnd('multibarHorizontal immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - yErr: {get: function(){return getYerr;}, set: function(_){getYerr=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - stacked: {get: function(){return stacked;}, set: function(_){stacked=_;}}, - showValues: {get: function(){return showValues;}, set: function(_){showValues=_;}}, - // this shows the group name, seems pointless? - //showBarLabels: {get: function(){return showBarLabels;}, set: function(_){showBarLabels=_;}}, - disabled: {get: function(){return disabled;}, set: function(_){disabled=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, - valuePadding: {get: function(){return valuePadding;}, set: function(_){valuePadding=_;}}, - groupSpacing:{get: function(){return groupSpacing;}, set: function(_){groupSpacing=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - barColor: {get: function(){return barColor;}, set: function(_){ - barColor = _ ? nv.utils.getColor(_) : null; - }}, - errorBarColor: {get: function(){return errorBarColor;}, set: function(_){ - errorBarColor = _ ? nv.utils.getColor(_) : null; - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.multiBarHorizontalChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var multibar = nv.models.multiBarHorizontal() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend().height(30) - , controls = nv.models.legend().height(30) - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 20, bottom: 50, left: 60} - , width = null - , height = null - , color = nv.utils.defaultColor() - , showControls = true - , controlLabels = {} - , showLegend = true - , showXAxis = true - , showYAxis = true - , stacked = false - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , state = nv.utils.state() - , defaultState = null - , noData = null - , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd') - , controlWidth = function() { return showControls ? 180 : 0 } - , duration = 250 - ; - - state.stacked = false; // DEPRECATED Maintained for backward compatibility - - multibar.stacked(stacked); - - xAxis - .orient('left') - .tickPadding(5) - .showMaxMin(false) - .tickFormat(function(d) { return d }) - ; - yAxis - .orient('bottom') - .tickFormat(d3.format(',.1f')) - ; - - tooltip - .duration(0) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }) - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }); - - controls.updateState(false); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }), - stacked: stacked - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.stacked !== undefined) - stacked = state.stacked; - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(multibar); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { container.transition().duration(duration).call(chart) }; - chart.container = this; - - stacked = multibar.stacked(); - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = multibar.xScale(); - y = multibar.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-multiBarHorizontalChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-multiBarHorizontalChart').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis') - .append('g').attr('class', 'nv-zeroLine') - .append('line'); - gEnter.append('g').attr('class', 'nv-barsWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-controlsWrap'); - - // Legend - if (showLegend) { - legend.width(availableWidth - controlWidth()); - - g.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(' + controlWidth() + ',' + (-margin.top) +')'); - } - - // Controls - if (showControls) { - var controlsData = [ - { key: controlLabels.grouped || 'Grouped', disabled: multibar.stacked() }, - { key: controlLabels.stacked || 'Stacked', disabled: !multibar.stacked() } - ]; - - controls.width(controlWidth()).color(['#444', '#444', '#444']); - g.select('.nv-controlsWrap') - .datum(controlsData) - .attr('transform', 'translate(0,' + (-margin.top) +')') - .call(controls); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Main Chart Component(s) - multibar - .disabled(data.map(function(series) { return series.disabled })) - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - - var barsWrap = g.select('.nv-barsWrap') - .datum(data.filter(function(d) { return !d.disabled })); - - barsWrap.transition().call(multibar); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksY(availableHeight/24, data) ) - .tickSize(-availableWidth, 0); - - g.select('.nv-x.nv-axis').call(xAxis); - - var xTicks = g.select('.nv-x.nv-axis').selectAll('g'); - - xTicks - .selectAll('line, text'); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize( -availableHeight, 0); - - g.select('.nv-y.nv-axis') - .attr('transform', 'translate(0,' + availableHeight + ')'); - g.select('.nv-y.nv-axis').call(yAxis); - } - - // Zero line - g.select(".nv-zeroLine line") - .attr("x1", y(0)) - .attr("x2", y(0)) - .attr("y1", 0) - .attr("y2", -availableHeight) - ; - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - controls.dispatch.on('legendClick', function(d,i) { - if (!d.disabled) return; - controlsData = controlsData.map(function(s) { - s.disabled = true; - return s; - }); - d.disabled = false; - - switch (d.key) { - case 'Grouped': - multibar.stacked(false); - break; - case 'Stacked': - multibar.stacked(true); - break; - } - - state.stacked = multibar.stacked(); - dispatch.stateChange(state); - stacked = multibar.stacked(); - - chart.update(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - - state.disabled = e.disabled; - } - - if (typeof e.stacked !== 'undefined') { - multibar.stacked(e.stacked); - state.stacked = e.stacked; - stacked = e.stacked; - } - - chart.update(); - }); - }); - renderWatch.renderEnd('multibar horizontal chart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - multibar.dispatch.on('elementMouseover.tooltip', function(evt) { - evt.value = chart.x()(evt.data); - evt['series'] = { - key: evt.data.key, - value: chart.y()(evt.data), - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - multibar.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - multibar.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.multibar = multibar; - chart.legend = legend; - chart.controls = controls; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.state = state; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, - controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - multibar.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - }}, - barColor: {get: function(){return multibar.barColor;}, set: function(_){ - multibar.barColor(_); - legend.color(function(d,i) {return d3.rgb('#ccc').darker(i * 1.5).toString();}) - }} - }); - - nv.utils.inheritOptions(chart, multibar); - nv.utils.initOptions(chart); - - return chart; -}; -nv.models.multiChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 30, right: 20, bottom: 50, left: 60}, - color = nv.utils.defaultColor(), - width = null, - height = null, - showLegend = true, - noData = null, - yDomain1, - yDomain2, - getX = function(d) { return d.x }, - getY = function(d) { return d.y}, - interpolate = 'monotone', - useVoronoi = true - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x = d3.scale.linear(), - yScale1 = d3.scale.linear(), - yScale2 = d3.scale.linear(), - - lines1 = nv.models.line().yScale(yScale1), - lines2 = nv.models.line().yScale(yScale2), - - bars1 = nv.models.multiBar().stacked(false).yScale(yScale1), - bars2 = nv.models.multiBar().stacked(false).yScale(yScale2), - - stack1 = nv.models.stackedArea().yScale(yScale1), - stack2 = nv.models.stackedArea().yScale(yScale2), - - xAxis = nv.models.axis().scale(x).orient('bottom').tickPadding(5), - yAxis1 = nv.models.axis().scale(yScale1).orient('left'), - yAxis2 = nv.models.axis().scale(yScale2).orient('right'), - - legend = nv.models.legend().height(30), - tooltip = nv.models.tooltip(), - dispatch = d3.dispatch(); - - function chart(selection) { - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - - chart.update = function() { container.transition().call(chart); }; - chart.container = this; - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - var dataLines1 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 1}); - var dataLines2 = data.filter(function(d) {return d.type == 'line' && d.yAxis == 2}); - var dataBars1 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 1}); - var dataBars2 = data.filter(function(d) {return d.type == 'bar' && d.yAxis == 2}); - var dataStack1 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 1}); - var dataStack2 = data.filter(function(d) {return d.type == 'area' && d.yAxis == 2}); - - // Display noData message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container); - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - var series1 = data.filter(function(d) {return !d.disabled && d.yAxis == 1}) - .map(function(d) { - return d.values.map(function(d,i) { - return { x: d.x, y: d.y } - }) - }); - - var series2 = data.filter(function(d) {return !d.disabled && d.yAxis == 2}) - .map(function(d) { - return d.values.map(function(d,i) { - return { x: d.x, y: d.y } - }) - }); - - x .domain(d3.extent(d3.merge(series1.concat(series2)), function(d) { return d.x } )) - .range([0, availableWidth]); - - var wrap = container.selectAll('g.wrap.multiChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'wrap nvd3 multiChart').append('g'); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y1 nv-axis'); - gEnter.append('g').attr('class', 'nv-y2 nv-axis'); - gEnter.append('g').attr('class', 'lines1Wrap'); - gEnter.append('g').attr('class', 'lines2Wrap'); - gEnter.append('g').attr('class', 'bars1Wrap'); - gEnter.append('g').attr('class', 'bars2Wrap'); - gEnter.append('g').attr('class', 'stack1Wrap'); - gEnter.append('g').attr('class', 'stack2Wrap'); - gEnter.append('g').attr('class', 'legendWrap'); - - var g = wrap.select('g'); - - var color_array = data.map(function(d,i) { - return data[i].color || color(d, i); - }); - - if (showLegend) { - var legendWidth = legend.align() ? availableWidth / 2 : availableWidth; - var legendXPosition = legend.align() ? legendWidth : 0; - - legend.width(legendWidth); - legend.color(color_array); - - g.select('.legendWrap') - .datum(data.map(function(series) { - series.originalKey = series.originalKey === undefined ? series.key : series.originalKey; - series.key = series.originalKey + (series.yAxis == 1 ? '' : ' (right axis)'); - return series; - })) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.legendWrap') - .attr('transform', 'translate(' + legendXPosition + ',' + (-margin.top) +')'); - } - - lines1 - .width(availableWidth) - .height(availableHeight) - .interpolate(interpolate) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'line'})); - lines2 - .width(availableWidth) - .height(availableHeight) - .interpolate(interpolate) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'line'})); - bars1 - .width(availableWidth) - .height(availableHeight) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'bar'})); - bars2 - .width(availableWidth) - .height(availableHeight) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'bar'})); - stack1 - .width(availableWidth) - .height(availableHeight) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 1 && data[i].type == 'area'})); - stack2 - .width(availableWidth) - .height(availableHeight) - .color(color_array.filter(function(d,i) { return !data[i].disabled && data[i].yAxis == 2 && data[i].type == 'area'})); - - g.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var lines1Wrap = g.select('.lines1Wrap') - .datum(dataLines1.filter(function(d){return !d.disabled})); - var bars1Wrap = g.select('.bars1Wrap') - .datum(dataBars1.filter(function(d){return !d.disabled})); - var stack1Wrap = g.select('.stack1Wrap') - .datum(dataStack1.filter(function(d){return !d.disabled})); - var lines2Wrap = g.select('.lines2Wrap') - .datum(dataLines2.filter(function(d){return !d.disabled})); - var bars2Wrap = g.select('.bars2Wrap') - .datum(dataBars2.filter(function(d){return !d.disabled})); - var stack2Wrap = g.select('.stack2Wrap') - .datum(dataStack2.filter(function(d){return !d.disabled})); - - var extraValue1 = dataStack1.length ? dataStack1.map(function(a){return a.values}).reduce(function(a,b){ - return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}}) - }).concat([{x:0, y:0}]) : []; - var extraValue2 = dataStack2.length ? dataStack2.map(function(a){return a.values}).reduce(function(a,b){ - return a.map(function(aVal,i){return {x: aVal.x, y: aVal.y + b[i].y}}) - }).concat([{x:0, y:0}]) : []; - - yScale1 .domain(yDomain1 || d3.extent(d3.merge(series1).concat(extraValue1), function(d) { return d.y } )) - .range([0, availableHeight]); - - yScale2 .domain(yDomain2 || d3.extent(d3.merge(series2).concat(extraValue2), function(d) { return d.y } )) - .range([0, availableHeight]); - - lines1.yDomain(yScale1.domain()); - bars1.yDomain(yScale1.domain()); - stack1.yDomain(yScale1.domain()); - - lines2.yDomain(yScale2.domain()); - bars2.yDomain(yScale2.domain()); - stack2.yDomain(yScale2.domain()); - - if(dataStack1.length){d3.transition(stack1Wrap).call(stack1);} - if(dataStack2.length){d3.transition(stack2Wrap).call(stack2);} - - if(dataBars1.length){d3.transition(bars1Wrap).call(bars1);} - if(dataBars2.length){d3.transition(bars2Wrap).call(bars2);} - - if(dataLines1.length){d3.transition(lines1Wrap).call(lines1);} - if(dataLines2.length){d3.transition(lines2Wrap).call(lines2);} - - xAxis - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize(-availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + availableHeight + ')'); - d3.transition(g.select('.nv-x.nv-axis')) - .call(xAxis); - - yAxis1 - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - - d3.transition(g.select('.nv-y1.nv-axis')) - .call(yAxis1); - - yAxis2 - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - d3.transition(g.select('.nv-y2.nv-axis')) - .call(yAxis2); - - g.select('.nv-y1.nv-axis') - .classed('nv-disabled', series1.length ? false : true) - .attr('transform', 'translate(' + x.range()[0] + ',0)'); - - g.select('.nv-y2.nv-axis') - .classed('nv-disabled', series2.length ? false : true) - .attr('transform', 'translate(' + x.range()[1] + ',0)'); - - legend.dispatch.on('stateChange', function(newState) { - chart.update(); - }); - - //============================================================ - // Event Handling/Dispatching - //------------------------------------------------------------ - - function mouseover_line(evt) { - var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1; - evt.value = evt.point.x; - evt.series = { - value: evt.point.y, - color: evt.point.color - }; - tooltip - .duration(100) - .valueFormatter(function(d, i) { - return yaxis.tickFormat()(d, i); - }) - .data(evt) - .position(evt.pos) - .hidden(false); - } - - function mouseover_stack(evt) { - var yaxis = data[evt.seriesIndex].yAxis === 2 ? yAxis2 : yAxis1; - evt.point['x'] = stack1.x()(evt.point); - evt.point['y'] = stack1.y()(evt.point); - tooltip - .duration(100) - .valueFormatter(function(d, i) { - return yaxis.tickFormat()(d, i); - }) - .data(evt) - .position(evt.pos) - .hidden(false); - } - - function mouseover_bar(evt) { - var yaxis = data[evt.data.series].yAxis === 2 ? yAxis2 : yAxis1; - - evt.value = bars1.x()(evt.data); - evt['series'] = { - value: bars1.y()(evt.data), - color: evt.color - }; - tooltip - .duration(0) - .valueFormatter(function(d, i) { - return yaxis.tickFormat()(d, i); - }) - .data(evt) - .hidden(false); - } - - lines1.dispatch.on('elementMouseover.tooltip', mouseover_line); - lines2.dispatch.on('elementMouseover.tooltip', mouseover_line); - lines1.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - lines2.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - stack1.dispatch.on('elementMouseover.tooltip', mouseover_stack); - stack2.dispatch.on('elementMouseover.tooltip', mouseover_stack); - stack1.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - stack2.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - bars1.dispatch.on('elementMouseover.tooltip', mouseover_bar); - bars2.dispatch.on('elementMouseover.tooltip', mouseover_bar); - - bars1.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - bars2.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - bars1.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - bars2.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - }); - - return chart; - } - - //============================================================ - // Global getters and setters - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.lines1 = lines1; - chart.lines2 = lines2; - chart.bars1 = bars1; - chart.bars2 = bars2; - chart.stack1 = stack1; - chart.stack2 = stack2; - chart.xAxis = xAxis; - chart.yAxis1 = yAxis1; - chart.yAxis2 = yAxis2; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - yDomain1: {get: function(){return yDomain1;}, set: function(_){yDomain1=_;}}, - yDomain2: {get: function(){return yDomain2;}, set: function(_){yDomain2=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - x: {get: function(){return getX;}, set: function(_){ - getX = _; - lines1.x(_); - lines2.x(_); - bars1.x(_); - bars2.x(_); - stack1.x(_); - stack2.x(_); - }}, - y: {get: function(){return getY;}, set: function(_){ - getY = _; - lines1.y(_); - lines2.y(_); - stack1.y(_); - stack2.y(_); - bars1.y(_); - bars2.y(_); - }}, - useVoronoi: {get: function(){return useVoronoi;}, set: function(_){ - useVoronoi=_; - lines1.useVoronoi(_); - lines2.useVoronoi(_); - stack1.useVoronoi(_); - stack2.useVoronoi(_); - }} - }); - - nv.utils.initOptions(chart); - - return chart; -}; - - -nv.models.ohlcBar = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = null - , height = null - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , x = d3.scale.linear() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , getOpen = function(d) { return d.open } - , getClose = function(d) { return d.close } - , getHigh = function(d) { return d.high } - , getLow = function(d) { return d.low } - , forceX = [] - , forceY = [] - , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart - , clipEdge = true - , color = nv.utils.defaultColor() - , interactive = false - , xDomain - , yDomain - , xRange - , yRange - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState', 'renderEnd', 'chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - function chart(selection) { - selection.each(function(data) { - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - nv.utils.initSVG(container); - - // ohlc bar width. - var w = (availableWidth / data[0].values.length) * .9; - - // Setup Scales - x.domain(xDomain || d3.extent(data[0].values.map(getX).concat(forceX) )); - - if (padData) - x.range(xRange || [availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); - else - x.range(xRange || [5 + w/2, availableWidth - w/2 - 5]); - - y.domain(yDomain || [ - d3.min(data[0].values.map(getLow).concat(forceY)), - d3.max(data[0].values.map(getHigh).concat(forceY)) - ] - ).range(yRange || [availableHeight, 0]); - - // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point - if (x.domain()[0] === x.domain()[1]) - x.domain()[0] ? - x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) - : x.domain([-1,1]); - - if (y.domain()[0] === y.domain()[1]) - y.domain()[0] ? - y.domain([y.domain()[0] + y.domain()[0] * 0.01, y.domain()[1] - y.domain()[1] * 0.01]) - : y.domain([-1,1]); - - // Setup containers and skeleton of chart - var wrap = d3.select(this).selectAll('g.nv-wrap.nv-ohlcBar').data([data[0].values]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-ohlcBar'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-ticks'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - container - .on('click', function(d,i) { - dispatch.chartClick({ - data: d, - index: i, - pos: d3.event, - id: id - }); - }); - - defsEnter.append('clipPath') - .attr('id', 'nv-chart-clip-path-' + id) - .append('rect'); - - wrap.select('#nv-chart-clip-path-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - g .attr('clip-path', clipEdge ? 'url(#nv-chart-clip-path-' + id + ')' : ''); - - var ticks = wrap.select('.nv-ticks').selectAll('.nv-tick') - .data(function(d) { return d }); - ticks.exit().remove(); - - ticks.enter().append('path') - .attr('class', function(d,i,j) { return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i }) - .attr('d', function(d,i) { - return 'm0,0l0,' - + (y(getOpen(d,i)) - - y(getHigh(d,i))) - + 'l' - + (-w/2) - + ',0l' - + (w/2) - + ',0l0,' - + (y(getLow(d,i)) - y(getOpen(d,i))) - + 'l0,' - + (y(getClose(d,i)) - - y(getLow(d,i))) - + 'l' - + (w/2) - + ',0l' - + (-w/2) - + ',0z'; - }) - .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; }) - .attr('fill', function(d,i) { return color[0]; }) - .attr('stroke', function(d,i) { return color[0]; }) - .attr('x', 0 ) - .attr('y', function(d,i) { return y(Math.max(0, getY(d,i))) }) - .attr('height', function(d,i) { return Math.abs(y(getY(d,i)) - y(0)) }); - - // the bar colors are controlled by CSS currently - ticks.attr('class', function(d,i,j) { - return (getOpen(d,i) > getClose(d,i) ? 'nv-tick negative' : 'nv-tick positive') + ' nv-tick-' + j + '-' + i; - }); - - d3.transition(ticks) - .attr('transform', function(d,i) { return 'translate(' + x(getX(d,i)) + ',' + y(getHigh(d,i)) + ')'; }) - .attr('d', function(d,i) { - var w = (availableWidth / data[0].values.length) * .9; - return 'm0,0l0,' - + (y(getOpen(d,i)) - - y(getHigh(d,i))) - + 'l' - + (-w/2) - + ',0l' - + (w/2) - + ',0l0,' - + (y(getLow(d,i)) - - y(getOpen(d,i))) - + 'l0,' - + (y(getClose(d,i)) - - y(getLow(d,i))) - + 'l' - + (w/2) - + ',0l' - + (-w/2) - + ',0z'; - }); - }); - - return chart; - } - - - //Create methods to allow outside functions to highlight a specific bar. - chart.highlightPoint = function(pointIndex, isHoverOver) { - chart.clearHighlights(); - container.select(".nv-ohlcBar .nv-tick-0-" + pointIndex) - .classed("hover", isHoverOver) - ; - }; - - chart.clearHighlights = function() { - container.select(".nv-ohlcBar .nv-tick.hover") - .classed("hover", false) - ; - }; - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - padData: {get: function(){return padData;}, set: function(_){padData=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, - - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - y: {get: function(){return getY;}, set: function(_){getY=_;}}, - open: {get: function(){return getOpen();}, set: function(_){getOpen=_;}}, - close: {get: function(){return getClose();}, set: function(_){getClose=_;}}, - high: {get: function(){return getHigh;}, set: function(_){getHigh=_;}}, - low: {get: function(){return getLow;}, set: function(_){getLow=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top != undefined ? _.top : margin.top; - margin.right = _.right != undefined ? _.right : margin.right; - margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; - margin.left = _.left != undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; -// Code adapted from Jason Davies' "Parallel Coordinates" -// http://bl.ocks.org/jasondavies/1341281 -nv.models.parallelCoordinates = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 30, right: 0, bottom: 10, left: 0} - , width = null - , height = null - , x = d3.scale.ordinal() - , y = {} - , dimensionNames = [] - , dimensionFormats = [] - , color = nv.utils.defaultColor() - , filters = [] - , active = [] - , dragging = [] - , lineTension = 1 - , dispatch = d3.dispatch('brush', 'elementMouseover', 'elementMouseout') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - function chart(selection) { - selection.each(function(data) { - var container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - nv.utils.initSVG(container); - - active = data; //set all active before first brush call - - // Setup Scales - x.rangePoints([0, availableWidth], 1).domain(dimensionNames); - - //Set as true if all values on an axis are missing. - var onlyNanValues = {}; - // Extract the list of dimensions and create a scale for each. - dimensionNames.forEach(function(d) { - var extent = d3.extent(data, function(p) { return +p[d]; }); - onlyNanValues[d] = false; - //If there is no values to display on an axis, set the extent to 0 - if (extent[0] === undefined) { - onlyNanValues[d] = true; - extent[0] = 0; - extent[1] = 0; - } - //Scale axis if there is only one value - if (extent[0] === extent[1]) { - extent[0] = extent[0] - 1; - extent[1] = extent[1] + 1; - } - //Use 90% of (availableHeight - 12) for the axis range, 12 reprensenting the space necessary to display "undefined values" text. - //The remaining 10% are used to display the missingValue line. - y[d] = d3.scale.linear() - .domain(extent) - .range([(availableHeight - 12) * 0.9, 0]); - - y[d].brush = d3.svg.brush().y(y[d]).on('brush', brush); - - return d != 'name'; - }); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-parallelCoordinates').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-parallelCoordinates'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-parallelCoordinates background'); - gEnter.append('g').attr('class', 'nv-parallelCoordinates foreground'); - gEnter.append('g').attr('class', 'nv-parallelCoordinates missingValuesline'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - var line = d3.svg.line().interpolate('cardinal').tension(lineTension), - axis = d3.svg.axis().orient('left'), - axisDrag = d3.behavior.drag() - .on('dragstart', dragStart) - .on('drag', dragMove) - .on('dragend', dragEnd); - - //Add missing value line at the bottom of the chart - var missingValuesline, missingValueslineText; - var step = x.range()[1] - x.range()[0]; - var axisWithMissingValues = []; - var lineData = [0 + step / 2, availableHeight - 12, availableWidth - step / 2, availableHeight - 12]; - missingValuesline = wrap.select('.missingValuesline').selectAll('line').data([lineData]); - missingValuesline.enter().append('line'); - missingValuesline.exit().remove(); - missingValuesline.attr("x1", function(d) { return d[0]; }) - .attr("y1", function(d) { return d[1]; }) - .attr("x2", function(d) { return d[2]; }) - .attr("y2", function(d) { return d[3]; }); - - //Add the text "undefined values" under the missing value line - missingValueslineText = wrap.select('.missingValuesline').selectAll('text').data(["undefined values"]); - missingValueslineText.append('text').data(["undefined values"]); - missingValueslineText.enter().append('text'); - missingValueslineText.exit().remove(); - missingValueslineText.attr("y", availableHeight) - //To have the text right align with the missingValues line, substract 92 representing the text size. - .attr("x", availableWidth - 92 - step / 2) - .text(function(d) { return d; }); - - // Add grey background lines for context. - var background = wrap.select('.background').selectAll('path').data(data); - background.enter().append('path'); - background.exit().remove(); - background.attr('d', path); - - // Add blue foreground lines for focus. - var foreground = wrap.select('.foreground').selectAll('path').data(data); - foreground.enter().append('path') - foreground.exit().remove(); - foreground.attr('d', path).attr('stroke', color); - foreground.on("mouseover", function (d, i) { - d3.select(this).classed('hover', true); - dispatch.elementMouseover({ - label: d.name, - data: d.data, - index: i, - pos: [d3.mouse(this.parentNode)[0], d3.mouse(this.parentNode)[1]] - }); - - }); - foreground.on("mouseout", function (d, i) { - d3.select(this).classed('hover', false); - dispatch.elementMouseout({ - label: d.name, - data: d.data, - index: i - }); - }); - - // Add a group element for each dimension. - var dimensions = g.selectAll('.dimension').data(dimensionNames); - var dimensionsEnter = dimensions.enter().append('g').attr('class', 'nv-parallelCoordinates dimension'); - dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates nv-axis'); - dimensionsEnter.append('g').attr('class', 'nv-parallelCoordinates-brush'); - dimensionsEnter.append('text').attr('class', 'nv-parallelCoordinates nv-label'); - - dimensions.attr('transform', function(d) { return 'translate(' + x(d) + ',0)'; }); - dimensions.exit().remove(); - - // Add an axis and title. - dimensions.select('.nv-label') - .style("cursor", "move") - .attr('dy', '-1em') - .attr('text-anchor', 'middle') - .text(String) - .on("mouseover", function(d, i) { - dispatch.elementMouseover({ - dim: d, - pos: [d3.mouse(this.parentNode.parentNode)[0], d3.mouse(this.parentNode.parentNode)[1]] - }); - }) - .on("mouseout", function(d, i) { - dispatch.elementMouseout({ - dim: d - }); - }) - .call(axisDrag); - - dimensions.select('.nv-axis') - .each(function (d, i) { - d3.select(this).call(axis.scale(y[d]).tickFormat(d3.format(dimensionFormats[i]))); - }); - - dimensions.select('.nv-parallelCoordinates-brush') - .each(function (d) { - d3.select(this).call(y[d].brush); - }) - .selectAll('rect') - .attr('x', -8) - .attr('width', 16); - - // Returns the path for a given data point. - function path(d) { - return line(dimensionNames.map(function (p) { - //If value if missing, put the value on the missing value line - if(isNaN(d[p]) || isNaN(parseFloat(d[p]))) { - var domain = y[p].domain(); - var range = y[p].range(); - var min = domain[0] - (domain[1] - domain[0]) / 9; - - //If it's not already the case, allow brush to select undefined values - if(axisWithMissingValues.indexOf(p) < 0) { - - var newscale = d3.scale.linear().domain([min, domain[1]]).range([availableHeight - 12, range[1]]); - y[p].brush.y(newscale); - axisWithMissingValues.push(p); - } - - return [x(p), y[p](min)]; - } - - //If parallelCoordinate contain missing values show the missing values line otherwise, hide it. - if(axisWithMissingValues.length > 0) { - missingValuesline.style("display", "inline"); - missingValueslineText.style("display", "inline"); - } else { - missingValuesline.style("display", "none"); - missingValueslineText.style("display", "none"); - } - - return [x(p), y[p](d[p])]; - })); - } - - // Handles a brush event, toggling the display of foreground lines. - function brush() { - var actives = dimensionNames.filter(function(p) { return !y[p].brush.empty(); }), - extents = actives.map(function(p) { return y[p].brush.extent(); }); - - filters = []; //erase current filters - actives.forEach(function(d,i) { - filters[i] = { - dimension: d, - extent: extents[i] - } - }); - - active = []; //erase current active list - foreground.style('display', function(d) { - var isActive = actives.every(function(p, i) { - if(isNaN(d[p]) && extents[i][0] == y[p].brush.y().domain()[0]) return true; - return extents[i][0] <= d[p] && d[p] <= extents[i][1]; - }); - if (isActive) active.push(d); - return isActive ? null : 'none'; - }); - - dispatch.brush({ - filters: filters, - active: active - }); - } - - function dragStart(d, i) { - dragging[d] = this.parentNode.__origin__ = x(d); - background.attr("visibility", "hidden"); - - } - - function dragMove(d, i) { - dragging[d] = Math.min(availableWidth, Math.max(0, this.parentNode.__origin__ += d3.event.x)); - foreground.attr("d", path); - dimensionNames.sort(function (a, b) { return position(a) - position(b); }); - x.domain(dimensionNames); - dimensions.attr("transform", function(d) { return "translate(" + position(d) + ")"; }); - } - - function dragEnd(d, i) { - delete this.parentNode.__origin__; - delete dragging[d]; - d3.select(this.parentNode).attr("transform", "translate(" + x(d) + ")"); - foreground - .attr("d", path); - background - .attr("d", path) - .attr("visibility", null); - - } - - function position(d) { - var v = dragging[d]; - return v == null ? x(d) : v; - } - }); - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width= _;}}, - height: {get: function(){return height;}, set: function(_){height= _;}}, - dimensionNames: {get: function() { return dimensionNames;}, set: function(_){dimensionNames= _;}}, - dimensionFormats : {get: function(){return dimensionFormats;}, set: function (_){dimensionFormats=_;}}, - lineTension: {get: function(){return lineTension;}, set: function(_){lineTension = _;}}, - - // deprecated options - dimensions: {get: function (){return dimensionNames;}, set: function(_){ - // deprecated after 1.8.1 - nv.deprecated('dimensions', 'use dimensionNames instead'); - dimensionNames = _; - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; -nv.models.pie = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 500 - , height = 500 - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , color = nv.utils.defaultColor() - , valueFormat = d3.format(',.2f') - , showLabels = true - , labelsOutside = false - , labelType = "key" - , labelThreshold = .02 //if slice percentage is under this, don't show label - , donut = false - , title = false - , growOnHover = true - , titleOffset = 0 - , labelSunbeamLayout = false - , startAngle = false - , padAngle = false - , endAngle = false - , cornerRadius = 0 - , donutRatio = 0.5 - , arcsRadius = [] - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - ; - - var arcs = []; - var arcsOver = []; - - //============================================================ - // chart function - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right - , availableHeight = height - margin.top - margin.bottom - , radius = Math.min(availableWidth, availableHeight) / 2 - , arcsRadiusOuter = [] - , arcsRadiusInner = [] - ; - - container = d3.select(this) - if (arcsRadius.length === 0) { - var outer = radius - radius / 5; - var inner = donutRatio * radius; - for (var i = 0; i < data[0].length; i++) { - arcsRadiusOuter.push(outer); - arcsRadiusInner.push(inner); - } - } else { - arcsRadiusOuter = arcsRadius.map(function (d) { return (d.outer - d.outer / 5) * radius; }); - arcsRadiusInner = arcsRadius.map(function (d) { return (d.inner - d.inner / 5) * radius; }); - donutRatio = d3.min(arcsRadius.map(function (d) { return (d.inner - d.inner / 5); })); - } - nv.utils.initSVG(container); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('.nv-wrap.nv-pie').data(data); - var wrapEnter = wrap.enter().append('g').attr('class','nvd3 nv-wrap nv-pie nv-chart-' + id); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - var g_pie = gEnter.append('g').attr('class', 'nv-pie'); - gEnter.append('g').attr('class', 'nv-pieLabels'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - g.select('.nv-pie').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); - g.select('.nv-pieLabels').attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); - - // - container.on('click', function(d,i) { - dispatch.chartClick({ - data: d, - index: i, - pos: d3.event, - id: id - }); - }); - - arcs = []; - arcsOver = []; - for (var i = 0; i < data[0].length; i++) { - - var arc = d3.svg.arc().outerRadius(arcsRadiusOuter[i]); - var arcOver = d3.svg.arc().outerRadius(arcsRadiusOuter[i] + 5); - - if (startAngle !== false) { - arc.startAngle(startAngle); - arcOver.startAngle(startAngle); - } - if (endAngle !== false) { - arc.endAngle(endAngle); - arcOver.endAngle(endAngle); - } - if (donut) { - arc.innerRadius(arcsRadiusInner[i]); - arcOver.innerRadius(arcsRadiusInner[i]); - } - - if (arc.cornerRadius && cornerRadius) { - arc.cornerRadius(cornerRadius); - arcOver.cornerRadius(cornerRadius); - } - - arcs.push(arc); - arcsOver.push(arcOver); - } - - // Setup the Pie chart and choose the data element - var pie = d3.layout.pie() - .sort(null) - .value(function(d) { return d.disabled ? 0 : getY(d) }); - - // padAngle added in d3 3.5 - if (pie.padAngle && padAngle) { - pie.padAngle(padAngle); - } - - // if title is specified and donut, put it in the middle - if (donut && title) { - g_pie.append("text").attr('class', 'nv-pie-title'); - - wrap.select('.nv-pie-title') - .style("text-anchor", "middle") - .text(function (d) { - return title; - }) - .style("font-size", (Math.min(availableWidth, availableHeight)) * donutRatio * 2 / (title.length + 2) + "px") - .attr("dy", "0.35em") // trick to vertically center text - .attr('transform', function(d, i) { - return 'translate(0, '+ titleOffset + ')'; - }); - } - - var slices = wrap.select('.nv-pie').selectAll('.nv-slice').data(pie); - var pieLabels = wrap.select('.nv-pieLabels').selectAll('.nv-label').data(pie); - - slices.exit().remove(); - pieLabels.exit().remove(); - - var ae = slices.enter().append('g'); - ae.attr('class', 'nv-slice'); - ae.on('mouseover', function(d, i) { - d3.select(this).classed('hover', true); - if (growOnHover) { - d3.select(this).select("path").transition() - .duration(70) - .attr("d", arcsOver[i]); - } - dispatch.elementMouseover({ - data: d.data, - index: i, - color: d3.select(this).style("fill") - }); - }); - ae.on('mouseout', function(d, i) { - d3.select(this).classed('hover', false); - if (growOnHover) { - d3.select(this).select("path").transition() - .duration(50) - .attr("d", arcs[i]); - } - dispatch.elementMouseout({data: d.data, index: i}); - }); - ae.on('mousemove', function(d, i) { - dispatch.elementMousemove({data: d.data, index: i}); - }); - ae.on('click', function(d, i) { - dispatch.elementClick({ - data: d.data, - index: i, - color: d3.select(this).style("fill") - }); - }); - ae.on('dblclick', function(d, i) { - dispatch.elementDblClick({ - data: d.data, - index: i, - color: d3.select(this).style("fill") - }); - }); - - slices.attr('fill', function(d,i) { return color(d.data, i); }); - slices.attr('stroke', function(d,i) { return color(d.data, i); }); - - var paths = ae.append('path').each(function(d) { - this._current = d; - }); - - slices.select('path') - .transition() - .attr('d', function (d, i) { return arcs[i](d); }) - .attrTween('d', arcTween); - - if (showLabels) { - // This does the normal label - var labelsArc = []; - for (var i = 0; i < data[0].length; i++) { - labelsArc.push(arcs[i]); - - if (labelsOutside) { - if (donut) { - labelsArc[i] = d3.svg.arc().outerRadius(arcs[i].outerRadius()); - if (startAngle !== false) labelsArc[i].startAngle(startAngle); - if (endAngle !== false) labelsArc[i].endAngle(endAngle); - } - } else if (!donut) { - labelsArc[i].innerRadius(0); - } - } - - pieLabels.enter().append("g").classed("nv-label",true).each(function(d,i) { - var group = d3.select(this); - - group.attr('transform', function (d, i) { - if (labelSunbeamLayout) { - d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate - d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate - var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI); - if ((d.startAngle + d.endAngle) / 2 < Math.PI) { - rotateAngle -= 90; - } else { - rotateAngle += 90; - } - return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')'; - } else { - d.outerRadius = radius + 10; // Set Outer Coordinate - d.innerRadius = radius + 15; // Set Inner Coordinate - return 'translate(' + labelsArc[i].centroid(d) + ')' - } - }); - - group.append('rect') - .style('stroke', '#fff') - .style('fill', '#fff') - .attr("rx", 3) - .attr("ry", 3); - - group.append('text') - .style('text-anchor', labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle') //center the text on it's origin or begin/end if orthogonal aligned - .style('fill', '#000') - }); - - var labelLocationHash = {}; - var avgHeight = 14; - var avgWidth = 140; - var createHashKey = function(coordinates) { - return Math.floor(coordinates[0]/avgWidth) * avgWidth + ',' + Math.floor(coordinates[1]/avgHeight) * avgHeight; - }; - - pieLabels.watchTransition(renderWatch, 'pie labels').attr('transform', function (d, i) { - if (labelSunbeamLayout) { - d.outerRadius = arcsRadiusOuter[i] + 10; // Set Outer Coordinate - d.innerRadius = arcsRadiusOuter[i] + 15; // Set Inner Coordinate - var rotateAngle = (d.startAngle + d.endAngle) / 2 * (180 / Math.PI); - if ((d.startAngle + d.endAngle) / 2 < Math.PI) { - rotateAngle -= 90; - } else { - rotateAngle += 90; - } - return 'translate(' + labelsArc[i].centroid(d) + ') rotate(' + rotateAngle + ')'; - } else { - d.outerRadius = radius + 10; // Set Outer Coordinate - d.innerRadius = radius + 15; // Set Inner Coordinate - - /* - Overlapping pie labels are not good. What this attempts to do is, prevent overlapping. - Each label location is hashed, and if a hash collision occurs, we assume an overlap. - Adjust the label's y-position to remove the overlap. - */ - var center = labelsArc[i].centroid(d); - if (d.value) { - var hashKey = createHashKey(center); - if (labelLocationHash[hashKey]) { - center[1] -= avgHeight; - } - labelLocationHash[createHashKey(center)] = true; - } - return 'translate(' + center + ')' - } - }); - - pieLabels.select(".nv-label text") - .style('text-anchor', function(d,i) { - //center the text on it's origin or begin/end if orthogonal aligned - return labelSunbeamLayout ? ((d.startAngle + d.endAngle) / 2 < Math.PI ? 'start' : 'end') : 'middle'; - }) - .text(function(d, i) { - var percent = (d.endAngle - d.startAngle) / (2 * Math.PI); - var label = ''; - if (!d.value || percent < labelThreshold) return ''; - - if(typeof labelType === 'function') { - label = labelType(d, i, { - 'key': getX(d.data), - 'value': getY(d.data), - 'percent': valueFormat(percent) - }); - } else { - switch (labelType) { - case 'key': - label = getX(d.data); - break; - case 'value': - label = valueFormat(getY(d.data)); - break; - case 'percent': - label = d3.format('%')(percent); - break; - } - } - return label; - }) - ; - } - - - // Computes the angle of an arc, converting from radians to degrees. - function angle(d) { - var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90; - return a > 90 ? a - 180 : a; - } - - function arcTween(a, idx) { - a.endAngle = isNaN(a.endAngle) ? 0 : a.endAngle; - a.startAngle = isNaN(a.startAngle) ? 0 : a.startAngle; - if (!donut) a.innerRadius = 0; - var i = d3.interpolate(this._current, a); - this._current = i(0); - return function (t) { - return arcs[idx](i(t)); - }; - } - }); - - renderWatch.renderEnd('pie immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - arcsRadius: { get: function () { return arcsRadius; }, set: function (_) { arcsRadius = _; } }, - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLabels: {get: function(){return showLabels;}, set: function(_){showLabels=_;}}, - title: {get: function(){return title;}, set: function(_){title=_;}}, - titleOffset: {get: function(){return titleOffset;}, set: function(_){titleOffset=_;}}, - labelThreshold: {get: function(){return labelThreshold;}, set: function(_){labelThreshold=_;}}, - valueFormat: {get: function(){return valueFormat;}, set: function(_){valueFormat=_;}}, - x: {get: function(){return getX;}, set: function(_){getX=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - endAngle: {get: function(){return endAngle;}, set: function(_){endAngle=_;}}, - startAngle: {get: function(){return startAngle;}, set: function(_){startAngle=_;}}, - padAngle: {get: function(){return padAngle;}, set: function(_){padAngle=_;}}, - cornerRadius: {get: function(){return cornerRadius;}, set: function(_){cornerRadius=_;}}, - donutRatio: {get: function(){return donutRatio;}, set: function(_){donutRatio=_;}}, - labelsOutside: {get: function(){return labelsOutside;}, set: function(_){labelsOutside=_;}}, - labelSunbeamLayout: {get: function(){return labelSunbeamLayout;}, set: function(_){labelSunbeamLayout=_;}}, - donut: {get: function(){return donut;}, set: function(_){donut=_;}}, - growOnHover: {get: function(){return growOnHover;}, set: function(_){growOnHover=_;}}, - - // depreciated after 1.7.1 - pieLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){ - labelsOutside=_; - nv.deprecated('pieLabelsOutside', 'use labelsOutside instead'); - }}, - // depreciated after 1.7.1 - donutLabelsOutside: {get: function(){return labelsOutside;}, set: function(_){ - labelsOutside=_; - nv.deprecated('donutLabelsOutside', 'use labelsOutside instead'); - }}, - // deprecated after 1.7.1 - labelFormat: {get: function(){ return valueFormat;}, set: function(_) { - valueFormat=_; - nv.deprecated('labelFormat','use valueFormat instead'); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = typeof _.top != 'undefined' ? _.top : margin.top; - margin.right = typeof _.right != 'undefined' ? _.right : margin.right; - margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom; - margin.left = typeof _.left != 'undefined' ? _.left : margin.left; - }}, - y: {get: function(){return getY;}, set: function(_){ - getY=d3.functor(_); - }}, - color: {get: function(){return color;}, set: function(_){ - color=nv.utils.getColor(_); - }}, - labelType: {get: function(){return labelType;}, set: function(_){ - labelType= _ || 'key'; - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; -nv.models.pieChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var pie = nv.models.pie(); - var legend = nv.models.legend(); - var tooltip = nv.models.tooltip(); - - var margin = {top: 30, right: 20, bottom: 20, left: 20} - , width = null - , height = null - , showLegend = true - , legendPosition = "top" - , color = nv.utils.defaultColor() - , state = nv.utils.state() - , defaultState = null - , noData = null - , duration = 250 - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd') - ; - - tooltip - .headerEnabled(false) - .duration(0) - .valueFormatter(function(d, i) { - return pie.valueFormat()(d, i); - }); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }) - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.active !== undefined) { - data.forEach(function (series, i) { - series.disabled = !state.active[i]; - }); - } - } - }; - - //============================================================ - // Chart function - //------------------------------------------------------------ - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(pie); - - selection.each(function(data) { - var container = d3.select(this); - nv.utils.initSVG(container); - - var that = this; - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { container.transition().call(chart); }; - chart.container = this; - - state.setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - //set state.disabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length) { - nv.utils.noData(chart, container); - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-pieChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-pieChart').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-pieWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - - // Legend - if (showLegend) { - if (legendPosition === "top") { - legend.width( availableWidth ).key(pie.x()); - - wrap.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - wrap.select('.nv-legendWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')'); - } else if (legendPosition === "right") { - var legendWidth = nv.models.legend().width(); - if (availableWidth / 2 < legendWidth) { - legendWidth = (availableWidth / 2) - } - legend.height(availableHeight).key(pie.x()); - legend.width(legendWidth); - availableWidth -= legend.width(); - - wrap.select('.nv-legendWrap') - .datum(data) - .call(legend) - .attr('transform', 'translate(' + (availableWidth) +',0)'); - } - } - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Main Chart Component(s) - pie.width(availableWidth).height(availableHeight); - var pieWrap = g.select('.nv-pieWrap').datum([data]); - d3.transition(pieWrap).call(pie); - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) { - state[key] = newState[key]; - } - dispatch.stateChange(state); - chart.update(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - state.disabled = e.disabled; - } - chart.update(); - }); - }); - - renderWatch.renderEnd('pieChart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - pie.dispatch.on('elementMouseover.tooltip', function(evt) { - evt['series'] = { - key: chart.x()(evt.data), - value: chart.y()(evt.data), - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - pie.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - pie.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.legend = legend; - chart.dispatch = dispatch; - chart.pie = pie; - chart.tooltip = tooltip; - chart.options = nv.utils.optionsFunc.bind(chart); - - // use Object get/set functionality to map between vars and chart functions - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - legendPosition: {get: function(){return legendPosition;}, set: function(_){legendPosition=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - color: {get: function(){return color;}, set: function(_){ - color = _; - legend.color(color); - pie.color(color); - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }}, - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }} - }); - nv.utils.inheritOptions(chart, pie); - nv.utils.initOptions(chart); - return chart; -}; - -nv.models.scatter = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = null - , height = null - , color = nv.utils.defaultColor() // chooses color - , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't select one - , container = null - , x = d3.scale.linear() - , y = d3.scale.linear() - , z = d3.scale.linear() //linear because d3.svg.shape.size is treated as area - , getX = function(d) { return d.x } // accessor to get the x value - , getY = function(d) { return d.y } // accessor to get the y value - , getSize = function(d) { return d.size || 1} // accessor to get the point size - , getShape = function(d) { return d.shape || 'circle' } // accessor to get point shape - , forceX = [] // List of numbers to Force into the X scale (ie. 0, or a max / min, etc.) - , forceY = [] // List of numbers to Force into the Y scale - , forceSize = [] // List of numbers to Force into the Size scale - , interactive = true // If true, plots a voronoi overlay for advanced point intersection - , pointActive = function(d) { return !d.notActive } // any points that return false will be filtered out - , padData = false // If true, adds half a data points width to front and back, for lining up a line chart with a bar chart - , padDataOuter = .1 //outerPadding to imitate ordinal scale outer padding - , clipEdge = false // if true, masks points within x and y scale - , clipVoronoi = true // if true, masks each point with a circle... can turn off to slightly increase performance - , showVoronoi = false // display the voronoi areas - , clipRadius = function() { return 25 } // function to get the radius for voronoi point clips - , xDomain = null // Override x domain (skips the calculation from data) - , yDomain = null // Override y domain - , xRange = null // Override x range - , yRange = null // Override y range - , sizeDomain = null // Override point size domain - , sizeRange = null - , singlePoint = false - , dispatch = d3.dispatch('elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'renderEnd') - , useVoronoi = true - , duration = 250 - ; - - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0, z0 // used to store previous scales - , timeoutID - , needsUpdate = false // Flag for when the points are visually updating, but the interactive layer is behind, to disable tooltips - , renderWatch = nv.utils.renderWatch(dispatch, duration) - , _sizeRange_def = [16, 256] - ; - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - nv.utils.initSVG(container); - - //add series index to each data point for reference - data.forEach(function(series, i) { - series.values.forEach(function(point) { - point.series = i; - }); - }); - - // Setup Scales - // remap and flatten the data for use in calculating the scales' domains - var seriesData = (xDomain && yDomain && sizeDomain) ? [] : // if we know xDomain and yDomain and sizeDomain, no need to calculate.... if Size is constant remember to set sizeDomain to speed up performance - d3.merge( - data.map(function(d) { - return d.values.map(function(d,i) { - return { x: getX(d,i), y: getY(d,i), size: getSize(d,i) } - }) - }) - ); - - x .domain(xDomain || d3.extent(seriesData.map(function(d) { return d.x; }).concat(forceX))) - - if (padData && data[0]) - x.range(xRange || [(availableWidth * padDataOuter + availableWidth) / (2 *data[0].values.length), availableWidth - availableWidth * (1 + padDataOuter) / (2 * data[0].values.length) ]); - //x.range([availableWidth * .5 / data[0].values.length, availableWidth * (data[0].values.length - .5) / data[0].values.length ]); - else - x.range(xRange || [0, availableWidth]); - - y .domain(yDomain || d3.extent(seriesData.map(function(d) { return d.y }).concat(forceY))) - .range(yRange || [availableHeight, 0]); - - z .domain(sizeDomain || d3.extent(seriesData.map(function(d) { return d.size }).concat(forceSize))) - .range(sizeRange || _sizeRange_def); - - // If scale's domain don't have a range, slightly adjust to make one... so a chart can show a single data point - singlePoint = x.domain()[0] === x.domain()[1] || y.domain()[0] === y.domain()[1]; - - if (x.domain()[0] === x.domain()[1]) - x.domain()[0] ? - x.domain([x.domain()[0] - x.domain()[0] * 0.01, x.domain()[1] + x.domain()[1] * 0.01]) - : x.domain([-1,1]); - - if (y.domain()[0] === y.domain()[1]) - y.domain()[0] ? - y.domain([y.domain()[0] - y.domain()[0] * 0.01, y.domain()[1] + y.domain()[1] * 0.01]) - : y.domain([-1,1]); - - if ( isNaN(x.domain()[0])) { - x.domain([-1,1]); - } - - if ( isNaN(y.domain()[0])) { - y.domain([-1,1]); - } - - x0 = x0 || x; - y0 = y0 || y; - z0 = z0 || z; - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-scatter').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatter nv-chart-' + id); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - wrap.classed('nv-single-point', singlePoint); - gEnter.append('g').attr('class', 'nv-groups'); - gEnter.append('g').attr('class', 'nv-point-paths'); - wrapEnter.append('g').attr('class', 'nv-point-clips'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - defsEnter.append('clipPath') - .attr('id', 'nv-edge-clip-' + id) - .append('rect'); - - wrap.select('#nv-edge-clip-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', (availableHeight > 0) ? availableHeight : 0); - - g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); - - function updateInteractiveLayer() { - // Always clear needs-update flag regardless of whether or not - // we will actually do anything (avoids needless invocations). - needsUpdate = false; - - if (!interactive) return false; - - // inject series and point index for reference into voronoi - if (useVoronoi === true) { - var vertices = d3.merge(data.map(function(group, groupIndex) { - return group.values - .map(function(point, pointIndex) { - // *Adding noise to make duplicates very unlikely - // *Injecting series and point index for reference - /* *Adding a 'jitter' to the points, because there's an issue in d3.geom.voronoi. - */ - var pX = getX(point,pointIndex); - var pY = getY(point,pointIndex); - - return [x(pX)+ Math.random() * 1e-4, - y(pY)+ Math.random() * 1e-4, - groupIndex, - pointIndex, point]; //temp hack to add noise until I think of a better way so there are no duplicates - }) - .filter(function(pointArray, pointIndex) { - return pointActive(pointArray[4], pointIndex); // Issue #237.. move filter to after map, so pointIndex is correct! - }) - }) - ); - - if (vertices.length == 0) return false; // No active points, we're done - if (vertices.length < 3) { - // Issue #283 - Adding 2 dummy points to the voronoi b/c voronoi requires min 3 points to work - vertices.push([x.range()[0] - 20, y.range()[0] - 20, null, null]); - vertices.push([x.range()[1] + 20, y.range()[1] + 20, null, null]); - vertices.push([x.range()[0] - 20, y.range()[0] + 20, null, null]); - vertices.push([x.range()[1] + 20, y.range()[1] - 20, null, null]); - } - - // keep voronoi sections from going more than 10 outside of graph - // to avoid overlap with other things like legend etc - var bounds = d3.geom.polygon([ - [-10,-10], - [-10,height + 10], - [width + 10,height + 10], - [width + 10,-10] - ]); - - var voronoi = d3.geom.voronoi(vertices).map(function(d, i) { - return { - 'data': bounds.clip(d), - 'series': vertices[i][2], - 'point': vertices[i][3] - } - }); - - // nuke all voronoi paths on reload and recreate them - wrap.select('.nv-point-paths').selectAll('path').remove(); - var pointPaths = wrap.select('.nv-point-paths').selectAll('path').data(voronoi); - var vPointPaths = pointPaths - .enter().append("svg:path") - .attr("d", function(d) { - if (!d || !d.data || d.data.length === 0) - return 'M 0 0'; - else - return "M" + d.data.join(",") + "Z"; - }) - .attr("id", function(d,i) { - return "nv-path-"+i; }) - .attr("clip-path", function(d,i) { return "url(#nv-clip-"+i+")"; }) - ; - - // good for debugging point hover issues - if (showVoronoi) { - vPointPaths.style("fill", d3.rgb(230, 230, 230)) - .style('fill-opacity', 0.4) - .style('stroke-opacity', 1) - .style("stroke", d3.rgb(200,200,200)); - } - - if (clipVoronoi) { - // voronoi sections are already set to clip, - // just create the circles with the IDs they expect - wrap.select('.nv-point-clips').selectAll('clipPath').remove(); - wrap.select('.nv-point-clips').selectAll("clipPath") - .data(vertices) - .enter().append("svg:clipPath") - .attr("id", function(d, i) { return "nv-clip-"+i;}) - .append("svg:circle") - .attr('cx', function(d) { return d[0]; }) - .attr('cy', function(d) { return d[1]; }) - .attr('r', clipRadius); - } - - var mouseEventCallback = function(d, mDispatch) { - if (needsUpdate) return 0; - var series = data[d.series]; - if (series === undefined) return; - var point = series.values[d.point]; - point['color'] = color(series, d.series); - - // standardize attributes for tooltip. - point['x'] = getX(point); - point['y'] = getY(point); - - // can't just get box of event node since it's actually a voronoi polygon - var box = container.node().getBoundingClientRect(); - var scrollTop = window.pageYOffset || document.documentElement.scrollTop; - var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; - - var pos = { - left: x(getX(point, d.point)) + box.left + scrollLeft + margin.left + 10, - top: y(getY(point, d.point)) + box.top + scrollTop + margin.top + 10 - }; - - mDispatch({ - point: point, - series: series, - pos: pos, - seriesIndex: d.series, - pointIndex: d.point - }); - }; - - pointPaths - .on('click', function(d) { - mouseEventCallback(d, dispatch.elementClick); - }) - .on('dblclick', function(d) { - mouseEventCallback(d, dispatch.elementDblClick); - }) - .on('mouseover', function(d) { - mouseEventCallback(d, dispatch.elementMouseover); - }) - .on('mouseout', function(d, i) { - mouseEventCallback(d, dispatch.elementMouseout); - }); - - } else { - // add event handlers to points instead voronoi paths - wrap.select('.nv-groups').selectAll('.nv-group') - .selectAll('.nv-point') - //.data(dataWithPoints) - //.style('pointer-events', 'auto') // recativate events, disabled by css - .on('click', function(d,i) { - //nv.log('test', d, i); - if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point - var series = data[d.series], - point = series.values[i]; - - dispatch.elementClick({ - point: point, - series: series, - pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], - seriesIndex: d.series, - pointIndex: i - }); - }) - .on('dblclick', function(d,i) { - if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point - var series = data[d.series], - point = series.values[i]; - - dispatch.elementDblClick({ - point: point, - series: series, - pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], - seriesIndex: d.series, - pointIndex: i - }); - }) - .on('mouseover', function(d,i) { - if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point - var series = data[d.series], - point = series.values[i]; - - dispatch.elementMouseover({ - point: point, - series: series, - pos: [x(getX(point, i)) + margin.left, y(getY(point, i)) + margin.top], - seriesIndex: d.series, - pointIndex: i, - color: color(d, i) - }); - }) - .on('mouseout', function(d,i) { - if (needsUpdate || !data[d.series]) return 0; //check if this is a dummy point - var series = data[d.series], - point = series.values[i]; - - dispatch.elementMouseout({ - point: point, - series: series, - seriesIndex: d.series, - pointIndex: i, - color: color(d, i) - }); - }); - } - } - - needsUpdate = true; - var groups = wrap.select('.nv-groups').selectAll('.nv-group') - .data(function(d) { return d }, function(d) { return d.key }); - groups.enter().append('g') - .style('stroke-opacity', 1e-6) - .style('fill-opacity', 1e-6); - groups.exit() - .remove(); - groups - .attr('class', function(d,i) { return 'nv-group nv-series-' + i }) - .classed('hover', function(d) { return d.hover }); - groups.watchTransition(renderWatch, 'scatter: groups') - .style('fill', function(d,i) { return color(d, i) }) - .style('stroke', function(d,i) { return color(d, i) }) - .style('stroke-opacity', 1) - .style('fill-opacity', .5); - - // create the points, maintaining their IDs from the original data set - var points = groups.selectAll('path.nv-point') - .data(function(d) { - return d.values.map( - function (point, pointIndex) { - return [point, pointIndex] - }).filter( - function(pointArray, pointIndex) { - return pointActive(pointArray[0], pointIndex) - }) - }); - points.enter().append('path') - .style('fill', function (d) { return d.color }) - .style('stroke', function (d) { return d.color }) - .attr('transform', function(d) { - return 'translate(' + x0(getX(d[0],d[1])) + ',' + y0(getY(d[0],d[1])) + ')' - }) - .attr('d', - nv.utils.symbol() - .type(function(d) { return getShape(d[0]); }) - .size(function(d) { return z(getSize(d[0],d[1])) }) - ); - points.exit().remove(); - groups.exit().selectAll('path.nv-point') - .watchTransition(renderWatch, 'scatter exit') - .attr('transform', function(d) { - return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')' - }) - .remove(); - points.each(function(d) { - d3.select(this) - .classed('nv-point', true) - .classed('nv-point-' + d[1], true) - .classed('nv-noninteractive', !interactive) - .classed('hover',false) - ; - }); - points - .watchTransition(renderWatch, 'scatter points') - .attr('transform', function(d) { - //nv.log(d, getX(d[0],d[1]), x(getX(d[0],d[1]))); - return 'translate(' + x(getX(d[0],d[1])) + ',' + y(getY(d[0],d[1])) + ')' - }) - .attr('d', - nv.utils.symbol() - .type(function(d) { return getShape(d[0]); }) - .size(function(d) { return z(getSize(d[0],d[1])) }) - ); - - // Delay updating the invisible interactive layer for smoother animation - clearTimeout(timeoutID); // stop repeat calls to updateInteractiveLayer - timeoutID = setTimeout(updateInteractiveLayer, 300); - //updateInteractiveLayer(); - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - z0 = z.copy(); - - }); - renderWatch.renderEnd('scatter immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - // utility function calls provided by this chart - chart._calls = new function() { - this.clearHighlights = function () { - nv.dom.write(function() { - container.selectAll(".nv-point.hover").classed("hover", false); - }); - return null; - }; - this.highlightPoint = function (seriesIndex, pointIndex, isHoverOver) { - nv.dom.write(function() { - container.select(" .nv-series-" + seriesIndex + " .nv-point-" + pointIndex) - .classed("hover", isHoverOver); - }); - }; - }; - - // trigger calls from events too - dispatch.on('elementMouseover.point', function(d) { - if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,true); - }); - - dispatch.on('elementMouseout.point', function(d) { - if (interactive) chart._calls.highlightPoint(d.seriesIndex,d.pointIndex,false); - }); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - pointScale: {get: function(){return z;}, set: function(_){z=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - pointDomain: {get: function(){return sizeDomain;}, set: function(_){sizeDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - pointRange: {get: function(){return sizeRange;}, set: function(_){sizeRange=_;}}, - forceX: {get: function(){return forceX;}, set: function(_){forceX=_;}}, - forceY: {get: function(){return forceY;}, set: function(_){forceY=_;}}, - forcePoint: {get: function(){return forceSize;}, set: function(_){forceSize=_;}}, - interactive: {get: function(){return interactive;}, set: function(_){interactive=_;}}, - pointActive: {get: function(){return pointActive;}, set: function(_){pointActive=_;}}, - padDataOuter: {get: function(){return padDataOuter;}, set: function(_){padDataOuter=_;}}, - padData: {get: function(){return padData;}, set: function(_){padData=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - clipVoronoi: {get: function(){return clipVoronoi;}, set: function(_){clipVoronoi=_;}}, - clipRadius: {get: function(){return clipRadius;}, set: function(_){clipRadius=_;}}, - showVoronoi: {get: function(){return showVoronoi;}, set: function(_){showVoronoi=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - - - // simple functor options - x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}}, - y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}}, - pointSize: {get: function(){return getSize;}, set: function(_){getSize = d3.functor(_);}}, - pointShape: {get: function(){return getShape;}, set: function(_){getShape = d3.functor(_);}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - useVoronoi: {get: function(){return useVoronoi;}, set: function(_){ - useVoronoi = _; - if (useVoronoi === false) { - clipVoronoi = false; - } - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; - -nv.models.scatterChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var scatter = nv.models.scatter() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , distX = nv.models.distribution() - , distY = nv.models.distribution() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 20, bottom: 50, left: 75} - , width = null - , height = null - , container = null - , color = nv.utils.defaultColor() - , x = scatter.xScale() - , y = scatter.yScale() - , showDistX = false - , showDistY = false - , showLegend = true - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , state = nv.utils.state() - , defaultState = null - , dispatch = d3.dispatch('stateChange', 'changeState', 'renderEnd') - , noData = null - , duration = 250 - ; - - scatter.xScale(x).yScale(y); - xAxis.orient('bottom').tickPadding(10); - yAxis - .orient((rightAlignYAxis) ? 'right' : 'left') - .tickPadding(10) - ; - distX.axis('x'); - distY.axis('y'); - tooltip - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var x0, y0 - , renderWatch = nv.utils.renderWatch(dispatch, duration); - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }) - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(scatter); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - if (showDistX) renderWatch.models(distX); - if (showDistY) renderWatch.models(distY); - - selection.each(function(data) { - var that = this; - - container = d3.select(this); - nv.utils.initSVG(container); - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - if (duration === 0) - container.call(chart); - else - container.transition().duration(duration).call(chart); - }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disableddisabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display noData message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container); - renderWatch.renderEnd('scatter immediate'); - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = scatter.xScale(); - y = scatter.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-scatterChart').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-scatterChart nv-chart-' + scatter.id()); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - // background for pointer events - gEnter.append('rect').attr('class', 'nvd3 nv-background').style("pointer-events","none"); - - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-scatterWrap'); - gEnter.append('g').attr('class', 'nv-regressionLinesWrap'); - gEnter.append('g').attr('class', 'nv-distWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - // Legend - if (showLegend) { - var legendWidth = availableWidth; - legend.width(legendWidth); - - wrap.select('.nv-legendWrap') - .datum(data) - .call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - wrap.select('.nv-legendWrap') - .attr('transform', 'translate(0' + ',' + (-margin.top) +')'); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Main Chart Component(s) - scatter - .width(availableWidth) - .height(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - - wrap.select('.nv-scatterWrap') - .datum(data.filter(function(d) { return !d.disabled })) - .call(scatter); - - - wrap.select('.nv-regressionLinesWrap') - .attr('clip-path', 'url(#nv-edge-clip-' + scatter.id() + ')'); - - var regWrap = wrap.select('.nv-regressionLinesWrap').selectAll('.nv-regLines') - .data(function (d) { - return d; - }); - - regWrap.enter().append('g').attr('class', 'nv-regLines'); - - var regLine = regWrap.selectAll('.nv-regLine') - .data(function (d) { - return [d] - }); - - regLine.enter() - .append('line').attr('class', 'nv-regLine') - .style('stroke-opacity', 0); - - // don't add lines unless we have slope and intercept to use - regLine.filter(function(d) { - return d.intercept && d.slope; - }) - .watchTransition(renderWatch, 'scatterPlusLineChart: regline') - .attr('x1', x.range()[0]) - .attr('x2', x.range()[1]) - .attr('y1', function (d, i) { - return y(x.domain()[0] * d.slope + d.intercept) - }) - .attr('y2', function (d, i) { - return y(x.domain()[1] * d.slope + d.intercept) - }) - .style('stroke', function (d, i, j) { - return color(d, j) - }) - .style('stroke-opacity', function (d, i) { - return (d.disabled || typeof d.slope === 'undefined' || typeof d.intercept === 'undefined') ? 0 : 1 - }); - - // Setup Axes - if (showXAxis) { - xAxis - .scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize( -availableHeight , 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + y.range()[0] + ')') - .call(xAxis); - } - - if (showYAxis) { - yAxis - .scale(y) - ._ticks( nv.utils.calcTicksY(availableHeight/36, data) ) - .tickSize( -availableWidth, 0); - - g.select('.nv-y.nv-axis') - .call(yAxis); - } - - - if (showDistX) { - distX - .getData(scatter.x()) - .scale(x) - .width(availableWidth) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - gEnter.select('.nv-distWrap').append('g') - .attr('class', 'nv-distributionX'); - g.select('.nv-distributionX') - .attr('transform', 'translate(0,' + y.range()[0] + ')') - .datum(data.filter(function(d) { return !d.disabled })) - .call(distX); - } - - if (showDistY) { - distY - .getData(scatter.y()) - .scale(y) - .width(availableHeight) - .color(data.map(function(d,i) { - return d.color || color(d, i); - }).filter(function(d,i) { return !data[i].disabled })); - gEnter.select('.nv-distWrap').append('g') - .attr('class', 'nv-distributionY'); - g.select('.nv-distributionY') - .attr('transform', 'translate(' + (rightAlignYAxis ? availableWidth : -distY.size() ) + ',0)') - .datum(data.filter(function(d) { return !d.disabled })) - .call(distY); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - if (typeof e.disabled !== 'undefined') { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - state.disabled = e.disabled; - } - chart.update(); - }); - - // mouseover needs availableHeight so we just keep scatter mouse events inside the chart block - scatter.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex) - .attr('y1', 0); - container.select('.nv-chart-' + scatter.id() + ' .nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex) - .attr('x2', distY.size()); - }); - - scatter.dispatch.on('elementMouseover.tooltip', function(evt) { - container.select('.nv-series-' + evt.seriesIndex + ' .nv-distx-' + evt.pointIndex) - .attr('y1', evt.pos.top - availableHeight - margin.top); - container.select('.nv-series-' + evt.seriesIndex + ' .nv-disty-' + evt.pointIndex) - .attr('x2', evt.pos.left + distX.size() - margin.left); - tooltip.position(evt.pos).data(evt).hidden(false); - }); - - //store old scales for use in transitions on update - x0 = x.copy(); - y0 = y.copy(); - - }); - - renderWatch.renderEnd('scatter with line immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.scatter = scatter; - chart.legend = legend; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.distX = distX; - chart.distY = distY; - chart.tooltip = tooltip; - - chart.options = nv.utils.optionsFunc.bind(chart); - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - container: {get: function(){return container;}, set: function(_){container=_;}}, - showDistX: {get: function(){return showDistX;}, set: function(_){showDistX=_;}}, - showDistY: {get: function(){return showDistY;}, set: function(_){showDistY=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - duration: {get: function(){return duration;}, set: function(_){duration=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - tooltipXContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.'); - }}, - tooltipYContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'This option is removed, put values into main tooltip.'); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( (_) ? 'right' : 'left'); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - distX.color(color); - distY.color(color); - }} - }); - - nv.utils.inheritOptions(chart, scatter); - nv.utils.initOptions(chart); - return chart; -}; - -nv.models.sparkline = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 2, right: 0, bottom: 2, left: 0} - , width = 400 - , height = 32 - , container = null - , animate = true - , x = d3.scale.linear() - , y = d3.scale.linear() - , getX = function(d) { return d.x } - , getY = function(d) { return d.y } - , color = nv.utils.getColor(['#000']) - , xDomain - , yDomain - , xRange - , yRange - ; - - function chart(selection) { - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - // Setup Scales - x .domain(xDomain || d3.extent(data, getX )) - .range(xRange || [0, availableWidth]); - - y .domain(yDomain || d3.extent(data, getY )) - .range(yRange || [availableHeight, 0]); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-sparkline').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparkline'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') - - var paths = wrap.selectAll('path') - .data(function(d) { return [d] }); - paths.enter().append('path'); - paths.exit().remove(); - paths - .style('stroke', function(d,i) { return d.color || color(d, i) }) - .attr('d', d3.svg.line() - .x(function(d,i) { return x(getX(d,i)) }) - .y(function(d,i) { return y(getY(d,i)) }) - ); - - // TODO: Add CURRENT data point (Need Min, Mac, Current / Most recent) - var points = wrap.selectAll('circle.nv-point') - .data(function(data) { - var yValues = data.map(function(d, i) { return getY(d,i); }); - function pointIndex(index) { - if (index != -1) { - var result = data[index]; - result.pointIndex = index; - return result; - } else { - return null; - } - } - var maxPoint = pointIndex(yValues.lastIndexOf(y.domain()[1])), - minPoint = pointIndex(yValues.indexOf(y.domain()[0])), - currentPoint = pointIndex(yValues.length - 1); - return [minPoint, maxPoint, currentPoint].filter(function (d) {return d != null;}); - }); - points.enter().append('circle'); - points.exit().remove(); - points - .attr('cx', function(d,i) { return x(getX(d,d.pointIndex)) }) - .attr('cy', function(d,i) { return y(getY(d,d.pointIndex)) }) - .attr('r', 2) - .attr('class', function(d,i) { - return getX(d, d.pointIndex) == x.domain()[1] ? 'nv-point nv-currentValue' : - getY(d, d.pointIndex) == y.domain()[0] ? 'nv-point nv-minValue' : 'nv-point nv-maxValue' - }); - }); - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - xDomain: {get: function(){return xDomain;}, set: function(_){xDomain=_;}}, - yDomain: {get: function(){return yDomain;}, set: function(_){yDomain=_;}}, - xRange: {get: function(){return xRange;}, set: function(_){xRange=_;}}, - yRange: {get: function(){return yRange;}, set: function(_){yRange=_;}}, - xScale: {get: function(){return x;}, set: function(_){x=_;}}, - yScale: {get: function(){return y;}, set: function(_){y=_;}}, - animate: {get: function(){return animate;}, set: function(_){animate=_;}}, - - //functor options - x: {get: function(){return getX;}, set: function(_){getX=d3.functor(_);}}, - y: {get: function(){return getY;}, set: function(_){getY=d3.functor(_);}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; - -nv.models.sparklinePlus = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var sparkline = nv.models.sparkline(); - - var margin = {top: 15, right: 100, bottom: 10, left: 50} - , width = null - , height = null - , x - , y - , index = [] - , paused = false - , xTickFormat = d3.format(',r') - , yTickFormat = d3.format(',.2f') - , showLastValue = true - , alignValue = true - , rightAlignValue = false - , noData = null - ; - - function chart(selection) { - selection.each(function(data) { - var container = d3.select(this); - nv.utils.initSVG(container); - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { chart(selection) }; - chart.container = this; - - // Display No Data message if there's nothing to show. - if (!data || !data.length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - var currentValue = sparkline.y()(data[data.length-1], data.length-1); - - // Setup Scales - x = sparkline.xScale(); - y = sparkline.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-sparklineplus').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sparklineplus'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-sparklineWrap'); - gEnter.append('g').attr('class', 'nv-valueWrap'); - gEnter.append('g').attr('class', 'nv-hoverArea'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Main Chart Component(s) - var sparklineWrap = g.select('.nv-sparklineWrap'); - - sparkline.width(availableWidth).height(availableHeight); - sparklineWrap.call(sparkline); - - if (showLastValue) { - var valueWrap = g.select('.nv-valueWrap'); - var value = valueWrap.selectAll('.nv-currentValue') - .data([currentValue]); - - value.enter().append('text').attr('class', 'nv-currentValue') - .attr('dx', rightAlignValue ? -8 : 8) - .attr('dy', '.9em') - .style('text-anchor', rightAlignValue ? 'end' : 'start'); - - value - .attr('x', availableWidth + (rightAlignValue ? margin.right : 0)) - .attr('y', alignValue ? function (d) { - return y(d) - } : 0) - .style('fill', sparkline.color()(data[data.length - 1], data.length - 1)) - .text(yTickFormat(currentValue)); - } - - gEnter.select('.nv-hoverArea').append('rect') - .on('mousemove', sparklineHover) - .on('click', function() { paused = !paused }) - .on('mouseout', function() { index = []; updateValueLine(); }); - - g.select('.nv-hoverArea rect') - .attr('transform', function(d) { return 'translate(' + -margin.left + ',' + -margin.top + ')' }) - .attr('width', availableWidth + margin.left + margin.right) - .attr('height', availableHeight + margin.top); - - //index is currently global (within the chart), may or may not keep it that way - function updateValueLine() { - if (paused) return; - - var hoverValue = g.selectAll('.nv-hoverValue').data(index); - - var hoverEnter = hoverValue.enter() - .append('g').attr('class', 'nv-hoverValue') - .style('stroke-opacity', 0) - .style('fill-opacity', 0); - - hoverValue.exit() - .transition().duration(250) - .style('stroke-opacity', 0) - .style('fill-opacity', 0) - .remove(); - - hoverValue - .attr('transform', function(d) { return 'translate(' + x(sparkline.x()(data[d],d)) + ',0)' }) - .transition().duration(250) - .style('stroke-opacity', 1) - .style('fill-opacity', 1); - - if (!index.length) return; - - hoverEnter.append('line') - .attr('x1', 0) - .attr('y1', -margin.top) - .attr('x2', 0) - .attr('y2', availableHeight); - - hoverEnter.append('text').attr('class', 'nv-xValue') - .attr('x', -6) - .attr('y', -margin.top) - .attr('text-anchor', 'end') - .attr('dy', '.9em'); - - g.select('.nv-hoverValue .nv-xValue') - .text(xTickFormat(sparkline.x()(data[index[0]], index[0]))); - - hoverEnter.append('text').attr('class', 'nv-yValue') - .attr('x', 6) - .attr('y', -margin.top) - .attr('text-anchor', 'start') - .attr('dy', '.9em'); - - g.select('.nv-hoverValue .nv-yValue') - .text(yTickFormat(sparkline.y()(data[index[0]], index[0]))); - } - - function sparklineHover() { - if (paused) return; - - var pos = d3.mouse(this)[0] - margin.left; - - function getClosestIndex(data, x) { - var distance = Math.abs(sparkline.x()(data[0], 0) - x); - var closestIndex = 0; - for (var i = 0; i < data.length; i++){ - if (Math.abs(sparkline.x()(data[i], i) - x) < distance) { - distance = Math.abs(sparkline.x()(data[i], i) - x); - closestIndex = i; - } - } - return closestIndex; - } - - index = [getClosestIndex(data, Math.round(x.invert(pos)))]; - updateValueLine(); - } - - }); - - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.sparkline = sparkline; - - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - xTickFormat: {get: function(){return xTickFormat;}, set: function(_){xTickFormat=_;}}, - yTickFormat: {get: function(){return yTickFormat;}, set: function(_){yTickFormat=_;}}, - showLastValue: {get: function(){return showLastValue;}, set: function(_){showLastValue=_;}}, - alignValue: {get: function(){return alignValue;}, set: function(_){alignValue=_;}}, - rightAlignValue: {get: function(){return rightAlignValue;}, set: function(_){rightAlignValue=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }} - }); - - nv.utils.inheritOptions(chart, sparkline); - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.stackedArea = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = 960 - , height = 500 - , color = nv.utils.defaultColor() // a function that computes the color - , id = Math.floor(Math.random() * 100000) //Create semi-unique ID incase user doesn't selet one - , container = null - , getX = function(d) { return d.x } // accessor to get the x value from a data point - , getY = function(d) { return d.y } // accessor to get the y value from a data point - , style = 'stack' - , offset = 'zero' - , order = 'default' - , interpolate = 'linear' // controls the line interpolation - , clipEdge = false // if true, masks lines within x and y scale - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , scatter = nv.models.scatter() - , duration = 250 - , dispatch = d3.dispatch('areaClick', 'areaMouseover', 'areaMouseout','renderEnd', 'elementClick', 'elementMouseover', 'elementMouseout') - ; - - scatter - .pointSize(2.2) // default size - .pointDomain([2.2, 2.2]) // all the same size by default - ; - - /************************************ - * offset: - * 'wiggle' (stream) - * 'zero' (stacked) - * 'expand' (normalize to 100%) - * 'silhouette' (simple centered) - * - * order: - * 'inside-out' (stream) - * 'default' (input order) - ************************************/ - - var renderWatch = nv.utils.renderWatch(dispatch, duration); - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(scatter); - selection.each(function(data) { - var availableWidth = width - margin.left - margin.right, - availableHeight = height - margin.top - margin.bottom; - - container = d3.select(this); - nv.utils.initSVG(container); - - // Setup Scales - x = scatter.xScale(); - y = scatter.yScale(); - - var dataRaw = data; - // Injecting point index into each point because d3.layout.stack().out does not give index - data.forEach(function(aseries, i) { - aseries.seriesIndex = i; - aseries.values = aseries.values.map(function(d, j) { - d.index = j; - d.seriesIndex = i; - return d; - }); - }); - - var dataFiltered = data.filter(function(series) { - return !series.disabled; - }); - - data = d3.layout.stack() - .order(order) - .offset(offset) - .values(function(d) { return d.values }) //TODO: make values customizeable in EVERY model in this fashion - .x(getX) - .y(getY) - .out(function(d, y0, y) { - d.display = { - y: y, - y0: y0 - }; - }) - (dataFiltered); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-stackedarea').data([data]); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedarea'); - var defsEnter = wrapEnter.append('defs'); - var gEnter = wrapEnter.append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-areaWrap'); - gEnter.append('g').attr('class', 'nv-scatterWrap'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // If the user has not specified forceY, make sure 0 is included in the domain - // Otherwise, use user-specified values for forceY - if (scatter.forceY().length == 0) { - scatter.forceY().push(0); - } - - scatter - .width(availableWidth) - .height(availableHeight) - .x(getX) - .y(function(d) { return d.display.y + d.display.y0 }) - .forceY([0]) - .color(data.map(function(d,i) { - return d.color || color(d, d.seriesIndex); - })); - - var scatterWrap = g.select('.nv-scatterWrap') - .datum(data); - - scatterWrap.call(scatter); - - defsEnter.append('clipPath') - .attr('id', 'nv-edge-clip-' + id) - .append('rect'); - - wrap.select('#nv-edge-clip-' + id + ' rect') - .attr('width', availableWidth) - .attr('height', availableHeight); - - g.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + id + ')' : ''); - - var area = d3.svg.area() - .x(function(d,i) { return x(getX(d,i)) }) - .y0(function(d) { - return y(d.display.y0) - }) - .y1(function(d) { - return y(d.display.y + d.display.y0) - }) - .interpolate(interpolate); - - var zeroArea = d3.svg.area() - .x(function(d,i) { return x(getX(d,i)) }) - .y0(function(d) { return y(d.display.y0) }) - .y1(function(d) { return y(d.display.y0) }); - - var path = g.select('.nv-areaWrap').selectAll('path.nv-area') - .data(function(d) { return d }); - - path.enter().append('path').attr('class', function(d,i) { return 'nv-area nv-area-' + i }) - .attr('d', function(d,i){ - return zeroArea(d.values, d.seriesIndex); - }) - .on('mouseover', function(d,i) { - d3.select(this).classed('hover', true); - dispatch.areaMouseover({ - point: d, - series: d.key, - pos: [d3.event.pageX, d3.event.pageY], - seriesIndex: d.seriesIndex - }); - }) - .on('mouseout', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.areaMouseout({ - point: d, - series: d.key, - pos: [d3.event.pageX, d3.event.pageY], - seriesIndex: d.seriesIndex - }); - }) - .on('click', function(d,i) { - d3.select(this).classed('hover', false); - dispatch.areaClick({ - point: d, - series: d.key, - pos: [d3.event.pageX, d3.event.pageY], - seriesIndex: d.seriesIndex - }); - }); - - path.exit().remove(); - path.style('fill', function(d,i){ - return d.color || color(d, d.seriesIndex) - }) - .style('stroke', function(d,i){ return d.color || color(d, d.seriesIndex) }); - path.watchTransition(renderWatch,'stackedArea path') - .attr('d', function(d,i) { - return area(d.values,i) - }); - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - scatter.dispatch.on('elementMouseover.area', function(e) { - g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', true); - }); - scatter.dispatch.on('elementMouseout.area', function(e) { - g.select('.nv-chart-' + id + ' .nv-area-' + e.seriesIndex).classed('hover', false); - }); - - //Special offset functions - chart.d3_stackedOffset_stackPercent = function(stackData) { - var n = stackData.length, //How many series - m = stackData[0].length, //how many points per series - i, - j, - o, - y0 = []; - - for (j = 0; j < m; ++j) { //Looping through all points - for (i = 0, o = 0; i < dataRaw.length; i++) { //looping through all series - o += getY(dataRaw[i].values[j]); //total y value of all series at a certian point in time. - } - - if (o) for (i = 0; i < n; i++) { //(total y value of all series at point in time i) != 0 - stackData[i][j][1] /= o; - } else { //(total y value of all series at point in time i) == 0 - for (i = 0; i < n; i++) { - stackData[i][j][1] = 0; - } - } - } - for (j = 0; j < m; ++j) y0[j] = 0; - return y0; - }; - - }); - - renderWatch.renderEnd('stackedArea immediate'); - return chart; - } - - //============================================================ - // Global getters and setters - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.scatter = scatter; - - scatter.dispatch.on('elementClick', function(){ dispatch.elementClick.apply(this, arguments); }); - scatter.dispatch.on('elementMouseover', function(){ dispatch.elementMouseover.apply(this, arguments); }); - scatter.dispatch.on('elementMouseout', function(){ dispatch.elementMouseout.apply(this, arguments); }); - - chart.interpolate = function(_) { - if (!arguments.length) return interpolate; - interpolate = _; - return chart; - }; - - chart.duration = function(_) { - if (!arguments.length) return duration; - duration = _; - renderWatch.reset(duration); - scatter.duration(duration); - return chart; - }; - - chart.dispatch = dispatch; - chart.scatter = scatter; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - clipEdge: {get: function(){return clipEdge;}, set: function(_){clipEdge=_;}}, - offset: {get: function(){return offset;}, set: function(_){offset=_;}}, - order: {get: function(){return order;}, set: function(_){order=_;}}, - interpolate: {get: function(){return interpolate;}, set: function(_){interpolate=_;}}, - - // simple functor options - x: {get: function(){return getX;}, set: function(_){getX = d3.functor(_);}}, - y: {get: function(){return getY;}, set: function(_){getY = d3.functor(_);}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - }}, - style: {get: function(){return style;}, set: function(_){ - style = _; - switch (style) { - case 'stack': - chart.offset('zero'); - chart.order('default'); - break; - case 'stream': - chart.offset('wiggle'); - chart.order('inside-out'); - break; - case 'stream-center': - chart.offset('silhouette'); - chart.order('inside-out'); - break; - case 'expand': - chart.offset('expand'); - chart.order('default'); - break; - case 'stack_percent': - chart.offset(chart.d3_stackedOffset_stackPercent); - chart.order('default'); - break; - } - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - scatter.duration(duration); - }} - }); - - nv.utils.inheritOptions(chart, scatter); - nv.utils.initOptions(chart); - - return chart; -}; - -nv.models.stackedAreaChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var stacked = nv.models.stackedArea() - , xAxis = nv.models.axis() - , yAxis = nv.models.axis() - , legend = nv.models.legend() - , controls = nv.models.legend() - , interactiveLayer = nv.interactiveGuideline() - , tooltip = nv.models.tooltip() - ; - - var margin = {top: 30, right: 25, bottom: 50, left: 60} - , width = null - , height = null - , color = nv.utils.defaultColor() - , showControls = true - , showLegend = true - , showXAxis = true - , showYAxis = true - , rightAlignYAxis = false - , useInteractiveGuideline = false - , x //can be accessed via chart.xScale() - , y //can be accessed via chart.yScale() - , state = nv.utils.state() - , defaultState = null - , noData = null - , dispatch = d3.dispatch('stateChange', 'changeState','renderEnd') - , controlWidth = 250 - , controlOptions = ['Stacked','Stream','Expanded'] - , controlLabels = {} - , duration = 250 - ; - - state.style = stacked.style(); - xAxis.orient('bottom').tickPadding(7); - yAxis.orient((rightAlignYAxis) ? 'right' : 'left'); - - tooltip - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }); - - interactiveLayer.tooltip - .headerFormatter(function(d, i) { - return xAxis.tickFormat()(d, i); - }) - .valueFormatter(function(d, i) { - return yAxis.tickFormat()(d, i); - }); - - var oldYTickFormat = null, - oldValueFormatter = null; - - controls.updateState(false); - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - var style = stacked.style(); - - var stateGetter = function(data) { - return function(){ - return { - active: data.map(function(d) { return !d.disabled }), - style: stacked.style() - }; - } - }; - - var stateSetter = function(data) { - return function(state) { - if (state.style !== undefined) - style = state.style; - if (state.active !== undefined) - data.forEach(function(series,i) { - series.disabled = !state.active[i]; - }); - } - }; - - var percentFormatter = d3.format('%'); - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(stacked); - if (showXAxis) renderWatch.models(xAxis); - if (showYAxis) renderWatch.models(yAxis); - - selection.each(function(data) { - var container = d3.select(this), - that = this; - nv.utils.initSVG(container); - - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { container.transition().duration(duration).call(chart); }; - chart.container = this; - - state - .setter(stateSetter(data), chart.update) - .getter(stateGetter(data)) - .update(); - - // DEPRECATED set state.disabled - state.disabled = data.map(function(d) { return !!d.disabled }); - - if (!defaultState) { - var key; - defaultState = {}; - for (key in state) { - if (state[key] instanceof Array) - defaultState[key] = state[key].slice(0); - else - defaultState[key] = state[key]; - } - } - - // Display No Data message if there's nothing to show. - if (!data || !data.length || !data.filter(function(d) { return d.values.length }).length) { - nv.utils.noData(chart, container) - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup Scales - x = stacked.xScale(); - y = stacked.yScale(); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-stackedAreaChart').data([data]); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-stackedAreaChart').append('g'); - var g = wrap.select('g'); - - gEnter.append("rect").style("opacity",0); - gEnter.append('g').attr('class', 'nv-x nv-axis'); - gEnter.append('g').attr('class', 'nv-y nv-axis'); - gEnter.append('g').attr('class', 'nv-stackedWrap'); - gEnter.append('g').attr('class', 'nv-legendWrap'); - gEnter.append('g').attr('class', 'nv-controlsWrap'); - gEnter.append('g').attr('class', 'nv-interactive'); - - g.select("rect").attr("width",availableWidth).attr("height",availableHeight); - - // Legend - if (showLegend) { - var legendWidth = (showControls) ? availableWidth - controlWidth : availableWidth; - - legend.width(legendWidth); - g.select('.nv-legendWrap').datum(data).call(legend); - - if ( margin.top != legend.height()) { - margin.top = legend.height(); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.nv-legendWrap') - .attr('transform', 'translate(' + (availableWidth-legendWidth) + ',' + (-margin.top) +')'); - } - - // Controls - if (showControls) { - var controlsData = [ - { - key: controlLabels.stacked || 'Stacked', - metaKey: 'Stacked', - disabled: stacked.style() != 'stack', - style: 'stack' - }, - { - key: controlLabels.stream || 'Stream', - metaKey: 'Stream', - disabled: stacked.style() != 'stream', - style: 'stream' - }, - { - key: controlLabels.expanded || 'Expanded', - metaKey: 'Expanded', - disabled: stacked.style() != 'expand', - style: 'expand' - }, - { - key: controlLabels.stack_percent || 'Stack %', - metaKey: 'Stack_Percent', - disabled: stacked.style() != 'stack_percent', - style: 'stack_percent' - } - ]; - - controlWidth = (controlOptions.length/3) * 260; - controlsData = controlsData.filter(function(d) { - return controlOptions.indexOf(d.metaKey) !== -1; - }); - - controls - .width( controlWidth ) - .color(['#444', '#444', '#444']); - - g.select('.nv-controlsWrap') - .datum(controlsData) - .call(controls); - - if ( margin.top != Math.max(controls.height(), legend.height()) ) { - margin.top = Math.max(controls.height(), legend.height()); - availableHeight = nv.utils.availableHeight(height, container, margin); - } - - g.select('.nv-controlsWrap') - .attr('transform', 'translate(0,' + (-margin.top) +')'); - } - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - if (rightAlignYAxis) { - g.select(".nv-y.nv-axis") - .attr("transform", "translate(" + availableWidth + ",0)"); - } - - //Set up interactive layer - if (useInteractiveGuideline) { - interactiveLayer - .width(availableWidth) - .height(availableHeight) - .margin({left: margin.left, top: margin.top}) - .svgContainer(container) - .xScale(x); - wrap.select(".nv-interactive").call(interactiveLayer); - } - - stacked - .width(availableWidth) - .height(availableHeight); - - var stackedWrap = g.select('.nv-stackedWrap') - .datum(data); - - stackedWrap.transition().call(stacked); - - // Setup Axes - if (showXAxis) { - xAxis.scale(x) - ._ticks( nv.utils.calcTicksX(availableWidth/100, data) ) - .tickSize( -availableHeight, 0); - - g.select('.nv-x.nv-axis') - .attr('transform', 'translate(0,' + availableHeight + ')'); - - g.select('.nv-x.nv-axis') - .transition().duration(0) - .call(xAxis); - } - - if (showYAxis) { - var ticks; - if (stacked.offset() === 'wiggle') { - ticks = 0; - } - else { - ticks = nv.utils.calcTicksY(availableHeight/36, data); - } - yAxis.scale(y) - ._ticks(ticks) - .tickSize(-availableWidth, 0); - - if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') { - var currentFormat = yAxis.tickFormat(); - - if ( !oldYTickFormat || currentFormat !== percentFormatter ) - oldYTickFormat = currentFormat; - - //Forces the yAxis to use percentage in 'expand' mode. - yAxis.tickFormat(percentFormatter); - } - else { - if (oldYTickFormat) { - yAxis.tickFormat(oldYTickFormat); - oldYTickFormat = null; - } - } - - g.select('.nv-y.nv-axis') - .transition().duration(0) - .call(yAxis); - } - - //============================================================ - // Event Handling/Dispatching (in chart's scope) - //------------------------------------------------------------ - - stacked.dispatch.on('areaClick.toggle', function(e) { - if (data.filter(function(d) { return !d.disabled }).length === 1) - data.forEach(function(d) { - d.disabled = false; - }); - else - data.forEach(function(d,i) { - d.disabled = (i != e.seriesIndex); - }); - - state.disabled = data.map(function(d) { return !!d.disabled }); - dispatch.stateChange(state); - - chart.update(); - }); - - legend.dispatch.on('stateChange', function(newState) { - for (var key in newState) - state[key] = newState[key]; - dispatch.stateChange(state); - chart.update(); - }); - - controls.dispatch.on('legendClick', function(d,i) { - if (!d.disabled) return; - - controlsData = controlsData.map(function(s) { - s.disabled = true; - return s; - }); - d.disabled = false; - - stacked.style(d.style); - - - state.style = stacked.style(); - dispatch.stateChange(state); - - chart.update(); - }); - - interactiveLayer.dispatch.on('elementMousemove', function(e) { - stacked.clearHighlights(); - var singlePoint, pointIndex, pointXLocation, allData = []; - data - .filter(function(series, i) { - series.seriesIndex = i; - return !series.disabled; - }) - .forEach(function(series,i) { - pointIndex = nv.interactiveBisect(series.values, e.pointXValue, chart.x()); - var point = series.values[pointIndex]; - var pointYValue = chart.y()(point, pointIndex); - if (pointYValue != null) { - stacked.highlightPoint(i, pointIndex, true); - } - if (typeof point === 'undefined') return; - if (typeof singlePoint === 'undefined') singlePoint = point; - if (typeof pointXLocation === 'undefined') pointXLocation = chart.xScale()(chart.x()(point,pointIndex)); - - //If we are in 'expand' mode, use the stacked percent value instead of raw value. - var tooltipValue = (stacked.style() == 'expand') ? point.display.y : chart.y()(point,pointIndex); - allData.push({ - key: series.key, - value: tooltipValue, - color: color(series,series.seriesIndex), - stackedValue: point.display - }); - }); - - allData.reverse(); - - //Highlight the tooltip entry based on which stack the mouse is closest to. - if (allData.length > 2) { - var yValue = chart.yScale().invert(e.mouseY); - var yDistMax = Infinity, indexToHighlight = null; - allData.forEach(function(series,i) { - - //To handle situation where the stacked area chart is negative, we need to use absolute values - //when checking if the mouse Y value is within the stack area. - yValue = Math.abs(yValue); - var stackedY0 = Math.abs(series.stackedValue.y0); - var stackedY = Math.abs(series.stackedValue.y); - if ( yValue >= stackedY0 && yValue <= (stackedY + stackedY0)) - { - indexToHighlight = i; - return; - } - }); - if (indexToHighlight != null) - allData[indexToHighlight].highlight = true; - } - - var xValue = xAxis.tickFormat()(chart.x()(singlePoint,pointIndex)); - - var valueFormatter = interactiveLayer.tooltip.valueFormatter(); - // Keeps track of the tooltip valueFormatter if the chart changes to expanded view - if (stacked.style() === 'expand' || stacked.style() === 'stack_percent') { - if ( !oldValueFormatter ) { - oldValueFormatter = valueFormatter; - } - //Forces the tooltip to use percentage in 'expand' mode. - valueFormatter = d3.format(".1%"); - } - else { - if (oldValueFormatter) { - valueFormatter = oldValueFormatter; - oldValueFormatter = null; - } - } - - interactiveLayer.tooltip - .position({left: pointXLocation + margin.left, top: e.mouseY + margin.top}) - .chartContainer(that.parentNode) - .valueFormatter(valueFormatter) - .data( - { - value: xValue, - series: allData - } - )(); - - interactiveLayer.renderGuideLine(pointXLocation); - - }); - - interactiveLayer.dispatch.on("elementMouseout",function(e) { - stacked.clearHighlights(); - }); - - // Update chart from a state object passed to event handler - dispatch.on('changeState', function(e) { - - if (typeof e.disabled !== 'undefined' && data.length === e.disabled.length) { - data.forEach(function(series,i) { - series.disabled = e.disabled[i]; - }); - - state.disabled = e.disabled; - } - - if (typeof e.style !== 'undefined') { - stacked.style(e.style); - style = e.style; - } - - chart.update(); - }); - - }); - - renderWatch.renderEnd('stacked Area chart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - stacked.dispatch.on('elementMouseover.tooltip', function(evt) { - evt.point['x'] = stacked.x()(evt.point); - evt.point['y'] = stacked.y()(evt.point); - tooltip.data(evt).position(evt.pos).hidden(false); - }); - - stacked.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true) - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.stacked = stacked; - chart.legend = legend; - chart.controls = controls; - chart.xAxis = xAxis; - chart.yAxis = yAxis; - chart.interactiveLayer = interactiveLayer; - chart.tooltip = tooltip; - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - showLegend: {get: function(){return showLegend;}, set: function(_){showLegend=_;}}, - showXAxis: {get: function(){return showXAxis;}, set: function(_){showXAxis=_;}}, - showYAxis: {get: function(){return showYAxis;}, set: function(_){showYAxis=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - showControls: {get: function(){return showControls;}, set: function(_){showControls=_;}}, - controlLabels: {get: function(){return controlLabels;}, set: function(_){controlLabels=_;}}, - controlOptions: {get: function(){return controlOptions;}, set: function(_){controlOptions=_;}}, - - // deprecated options - tooltips: {get: function(){return tooltip.enabled();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltips', 'use chart.tooltip.enabled() instead'); - tooltip.enabled(!!_); - }}, - tooltipContent: {get: function(){return tooltip.contentGenerator();}, set: function(_){ - // deprecated after 1.7.1 - nv.deprecated('tooltipContent', 'use chart.tooltip.contentGenerator() instead'); - tooltip.contentGenerator(_); - }}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - stacked.duration(duration); - xAxis.duration(duration); - yAxis.duration(duration); - }}, - color: {get: function(){return color;}, set: function(_){ - color = nv.utils.getColor(_); - legend.color(color); - stacked.color(color); - }}, - rightAlignYAxis: {get: function(){return rightAlignYAxis;}, set: function(_){ - rightAlignYAxis = _; - yAxis.orient( rightAlignYAxis ? 'right' : 'left'); - }}, - useInteractiveGuideline: {get: function(){return useInteractiveGuideline;}, set: function(_){ - useInteractiveGuideline = !!_; - chart.interactive(!_); - chart.useVoronoi(!_); - stacked.scatter.interactive(!_); - }} - }); - - nv.utils.inheritOptions(chart, stacked); - nv.utils.initOptions(chart); - - return chart; -}; -// based on http://bl.ocks.org/kerryrodden/477c1bfb081b783f80ad -nv.models.sunburst = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var margin = {top: 0, right: 0, bottom: 0, left: 0} - , width = null - , height = null - , mode = "count" - , modes = {count: function(d) { return 1; }, size: function(d) { return d.size }} - , id = Math.floor(Math.random() * 10000) //Create semi-unique ID in case user doesn't select one - , container = null - , color = nv.utils.defaultColor() - , duration = 500 - , dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMousemove', 'elementMouseover', 'elementMouseout', 'renderEnd') - ; - - var x = d3.scale.linear().range([0, 2 * Math.PI]); - var y = d3.scale.sqrt(); - - var partition = d3.layout.partition() - .sort(null) - .value(function(d) { return 1; }); - - var arc = d3.svg.arc() - .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); }) - .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); }) - .innerRadius(function(d) { return Math.max(0, y(d.y)); }) - .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); }); - - // Keep track of the current and previous node being displayed as the root. - var node, prevNode; - // Keep track of the root node - var rootNode; - - //============================================================ - // chart function - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - - function chart(selection) { - renderWatch.reset(); - selection.each(function(data) { - container = d3.select(this); - var availableWidth = nv.utils.availableWidth(width, container, margin); - var availableHeight = nv.utils.availableHeight(height, container, margin); - var radius = Math.min(availableWidth, availableHeight) / 2; - var path; - - nv.utils.initSVG(container); - - // Setup containers and skeleton of chart - var wrap = container.selectAll('.nv-wrap.nv-sunburst').data(data); - var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburst nv-chart-' + id); - - var g = wrapEnter.selectAll('nv-sunburst'); - - wrap.attr('transform', 'translate(' + availableWidth / 2 + ',' + availableHeight / 2 + ')'); - - container.on('click', function (d, i) { - dispatch.chartClick({ - data: d, - index: i, - pos: d3.event, - id: id - }); - }); - - y.range([0, radius]); - - node = node || data; - rootNode = data[0]; - partition.value(modes[mode] || modes["count"]); - path = g.data(partition.nodes).enter() - .append("path") - .attr("d", arc) - .style("fill", function (d) { - return color((d.children ? d : d.parent).name); - }) - .style("stroke", "#FFF") - .on("click", function(d) { - if (prevNode !== node && node !== d) prevNode = node; - node = d; - path.transition() - .duration(duration) - .attrTween("d", arcTweenZoom(d)); - }) - .each(stash) - .on("dblclick", function(d) { - if (prevNode.parent == d) { - path.transition() - .duration(duration) - .attrTween("d", arcTweenZoom(rootNode)); - } - }) - .each(stash) - .on('mouseover', function(d,i){ - d3.select(this).classed('hover', true).style('opacity', 0.8); - dispatch.elementMouseover({ - data: d, - color: d3.select(this).style("fill") - }); - }) - .on('mouseout', function(d,i){ - d3.select(this).classed('hover', false).style('opacity', 1); - dispatch.elementMouseout({ - data: d - }); - }) - .on('mousemove', function(d,i){ - dispatch.elementMousemove({ - data: d - }); - }); - - - - // Setup for switching data: stash the old values for transition. - function stash(d) { - d.x0 = d.x; - d.dx0 = d.dx; - } - - // When switching data: interpolate the arcs in data space. - function arcTweenData(a, i) { - var oi = d3.interpolate({x: a.x0, dx: a.dx0}, a); - - function tween(t) { - var b = oi(t); - a.x0 = b.x; - a.dx0 = b.dx; - return arc(b); - } - - if (i == 0) { - // If we are on the first arc, adjust the x domain to match the root node - // at the current zoom level. (We only need to do this once.) - var xd = d3.interpolate(x.domain(), [node.x, node.x + node.dx]); - return function (t) { - x.domain(xd(t)); - return tween(t); - }; - } else { - return tween; - } - } - - // When zooming: interpolate the scales. - function arcTweenZoom(d) { - var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]), - yd = d3.interpolate(y.domain(), [d.y, 1]), - yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]); - return function (d, i) { - return i - ? function (t) { - return arc(d); - } - : function (t) { - x.domain(xd(t)); - y.domain(yd(t)).range(yr(t)); - return arc(d); - }; - }; - } - - }); - - renderWatch.renderEnd('sunburst immediate'); - return chart; - } - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - chart.dispatch = dispatch; - chart.options = nv.utils.optionsFunc.bind(chart); - - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - width: {get: function(){return width;}, set: function(_){width=_;}}, - height: {get: function(){return height;}, set: function(_){height=_;}}, - mode: {get: function(){return mode;}, set: function(_){mode=_;}}, - id: {get: function(){return id;}, set: function(_){id=_;}}, - duration: {get: function(){return duration;}, set: function(_){duration=_;}}, - - // options that require extra logic in the setter - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top != undefined ? _.top : margin.top; - margin.right = _.right != undefined ? _.right : margin.right; - margin.bottom = _.bottom != undefined ? _.bottom : margin.bottom; - margin.left = _.left != undefined ? _.left : margin.left; - }}, - color: {get: function(){return color;}, set: function(_){ - color=nv.utils.getColor(_); - }} - }); - - nv.utils.initOptions(chart); - return chart; -}; -nv.models.sunburstChart = function() { - "use strict"; - - //============================================================ - // Public Variables with Default Settings - //------------------------------------------------------------ - - var sunburst = nv.models.sunburst(); - var tooltip = nv.models.tooltip(); - - var margin = {top: 30, right: 20, bottom: 20, left: 20} - , width = null - , height = null - , color = nv.utils.defaultColor() - , id = Math.round(Math.random() * 100000) - , defaultState = null - , noData = null - , duration = 250 - , dispatch = d3.dispatch('tooltipShow', 'tooltipHide', 'stateChange', 'changeState','renderEnd') - ; - - //============================================================ - // Private Variables - //------------------------------------------------------------ - - var renderWatch = nv.utils.renderWatch(dispatch); - tooltip.headerEnabled(false).duration(0).valueFormatter(function(d, i) { - return d; - }); - - //============================================================ - // Chart function - //------------------------------------------------------------ - - function chart(selection) { - renderWatch.reset(); - renderWatch.models(sunburst); - - selection.each(function(data) { - var container = d3.select(this); - nv.utils.initSVG(container); - - var that = this; - var availableWidth = nv.utils.availableWidth(width, container, margin), - availableHeight = nv.utils.availableHeight(height, container, margin); - - chart.update = function() { - if (duration === 0) - container.call(chart); - else - container.transition().duration(duration).call(chart) - }; - chart.container = this; - - // Display No Data message if there's nothing to show. - if (!data || !data.length) { - nv.utils.noData(chart, container); - return chart; - } else { - container.selectAll('.nv-noData').remove(); - } - - // Setup containers and skeleton of chart - var wrap = container.selectAll('g.nv-wrap.nv-sunburstChart').data(data); - var gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-sunburstChart').append('g'); - var g = wrap.select('g'); - - gEnter.append('g').attr('class', 'nv-sunburstWrap'); - - wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); - - // Main Chart Component(s) - sunburst.width(availableWidth).height(availableHeight); - var sunWrap = g.select('.nv-sunburstWrap').datum(data); - d3.transition(sunWrap).call(sunburst); - - }); - - renderWatch.renderEnd('sunburstChart immediate'); - return chart; - } - - //============================================================ - // Event Handling/Dispatching (out of chart's scope) - //------------------------------------------------------------ - - sunburst.dispatch.on('elementMouseover.tooltip', function(evt) { - evt['series'] = { - key: evt.data.name, - value: evt.data.size, - color: evt.color - }; - tooltip.data(evt).hidden(false); - }); - - sunburst.dispatch.on('elementMouseout.tooltip', function(evt) { - tooltip.hidden(true); - }); - - sunburst.dispatch.on('elementMousemove.tooltip', function(evt) { - tooltip.position({top: d3.event.pageY, left: d3.event.pageX})(); - }); - - //============================================================ - // Expose Public Variables - //------------------------------------------------------------ - - // expose chart's sub-components - chart.dispatch = dispatch; - chart.sunburst = sunburst; - chart.tooltip = tooltip; - chart.options = nv.utils.optionsFunc.bind(chart); - - // use Object get/set functionality to map between vars and chart functions - chart._options = Object.create({}, { - // simple options, just get/set the necessary values - noData: {get: function(){return noData;}, set: function(_){noData=_;}}, - defaultState: {get: function(){return defaultState;}, set: function(_){defaultState=_;}}, - - // options that require extra logic in the setter - color: {get: function(){return color;}, set: function(_){ - color = _; - sunburst.color(color); - }}, - duration: {get: function(){return duration;}, set: function(_){ - duration = _; - renderWatch.reset(duration); - sunburst.duration(duration); - }}, - margin: {get: function(){return margin;}, set: function(_){ - margin.top = _.top !== undefined ? _.top : margin.top; - margin.right = _.right !== undefined ? _.right : margin.right; - margin.bottom = _.bottom !== undefined ? _.bottom : margin.bottom; - margin.left = _.left !== undefined ? _.left : margin.left; - }} - }); - nv.utils.inheritOptions(chart, sunburst); - nv.utils.initOptions(chart); - return chart; -}; - -nv.version = "1.8.1"; -})(); \ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.css b/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.css deleted file mode 100644 index 7a6f7fe9..00000000 --- a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.css +++ /dev/null @@ -1 +0,0 @@ -.nvd3 .nv-axis{pointer-events:none;opacity:1}.nvd3 .nv-axis path{fill:none;stroke:#000;stroke-opacity:.75;shape-rendering:crispEdges}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{fill:none;stroke:#e5e5e5;shape-rendering:crispEdges}.nvd3 .nv-axis .zero line,.nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nvd3 .nv-axis.nv-disabled{opacity:0}.nvd3 .nv-bars rect{fill-opacity:.75;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:rgba(0,0,0,0)}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect,.nvd3 .nv-discretebar .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,.nvd3 .nv-candlestickBar .nv-ticks rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:rgba(0,0,0,0)}.nvd3 .nv-boxplot circle{fill-opacity:.5}.nvd3 .nv-boxplot circle:hover{fill-opacity:1}.nvd3 .nv-boxplot rect:hover{fill-opacity:1}.nvd3 line.nv-boxplot-median{stroke:#000}.nv-boxplot-tick:hover{stroke-width:2.5px}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-candlestickBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.positive rect{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-candlestickBar .nv-ticks .nv-tick.negative rect{stroke:#d62728;fill:#d62728}.with-transitions .nv-candlestickBar .nv-ticks .nv-tick{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-candlestickBar .nv-ticks line{stroke:#333}.nvd3 .nv-legend .nv-disabled rect{}.nvd3 .nv-check-box .nv-box{fill-opacity:0;stroke-width:2}.nvd3 .nv-check-box .nv-check{fill-opacity:0;stroke-width:4}.nvd3 .nv-series.nv-disabled .nv-check-box .nv-check{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-controlsWrap .nv-legend .nv-check-box .nv-check{opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3 .nv-groups path.nv-line{fill:none}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-scatter .nv-groups .nv-point.hover,.nvd3 .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}svg.nvd3-svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-ms-user-select:none;-moz-user-select:none;user-select:none;display:block;width:100%;height:100%}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nvd3 text{font:400 12px Arial}.nvd3 .title{font:700 14px Arial}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125;shape-rendering:crispEdges}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .nv-disabled circle{fill-opacity:0}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:1px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3 .background path{fill:none;stroke:#EEE;stroke-opacity:.4;shape-rendering:crispEdges}.nvd3 .foreground path{fill:none;stroke-opacity:.7}.nvd3 .nv-parallelCoordinates-brush .extent{fill:#fff;fill-opacity:.6;stroke:gray;shape-rendering:crispEdges}.nvd3 .nv-parallelCoordinates .hover{fill-opacity:1;stroke-width:3px}.nvd3 .missingValuesline line{fill:none;stroke:#000;stroke-width:1;stroke-opacity:1;stroke-dasharray:5,5}.nvd3.nv-pie path{stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-pie .nv-pie-title{font-size:24px;fill:rgba(19,196,249,.59)}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{stroke:#fff;stroke-width:1px;stroke-opacity:1}.nvd3.nv-pie .hover path{fill-opacity:.7}.nvd3.nv-pie .nv-label{pointer-events:none}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nv-noninteractive{pointer-events:none}.nv-distx,.nv-disty{pointer-events:none}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-hoverArea{fill-opacity:0;stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvtooltip{position:absolute;background-color:rgba(255,255,255,1);color:rgba(0,0,0,1);padding:1px;border:1px solid rgba(0,0,0,.2);z-index:10000;display:block;font-family:Arial;font-size:13px;text-align:left;pointer-events:none;white-space:nowrap;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.nvtooltip{background:rgba(255,255,255,.8);border:1px solid rgba(0,0,0,.5);border-radius:4px}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 50ms linear;-moz-transition:opacity 50ms linear;-webkit-transition:opacity 50ms linear;transition-delay:200ms;-moz-transition-delay:200ms;-webkit-transition-delay:200ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{margin:0;padding:4px 14px;line-height:18px;font-weight:400;background-color:rgba(247,247,247,.75);color:rgba(0,0,0,1);text-align:center;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.nvtooltip p{margin:0;padding:5px 14px;text-align:center}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key{font-weight:400}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{width:8px;height:8px;vertical-align:middle}.nvtooltip table td.legend-color-guide div{width:12px;height:12px;border:1px solid #999}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{pointer-events:none;display:none}.nvd3 .nv-interactiveGuideLine{pointer-events:none}.nvd3 line.nv-guideline{stroke:#ccc} \ No newline at end of file diff --git a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.js b/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.js deleted file mode 100644 index ab17e9fe..00000000 --- a/wqflask/wqflask/static/new/packages/nvd3/nv.d3.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/* nvd3 version 1.8.1 (https://github.com/novus/nvd3) 2015-05-25 */ -!function(){var a={};a.dev=!1,a.tooltip=a.tooltip||{},a.utils=a.utils||{},a.models=a.models||{},a.charts={},a.logs={},a.dom={},a.dispatch=d3.dispatch("render_start","render_end"),Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),a.dev&&(a.dispatch.on("render_start",function(b){a.logs.startTime=+new Date}),a.dispatch.on("render_end",function(b){a.logs.endTime=+new Date,a.logs.totalTime=a.logs.endTime-a.logs.startTime,a.log("total",a.logs.totalTime)})),a.log=function(){if(a.dev&&window.console&&console.log&&console.log.apply)console.log.apply(console,arguments);else if(a.dev&&window.console&&"function"==typeof console.log&&Function.prototype.bind){var b=Function.prototype.bind.call(console.log,console);b.apply(console,arguments)}return arguments[arguments.length-1]},a.deprecated=function(a,b){console&&console.warn&&console.warn("nvd3 warning: `"+a+"` has been deprecated. ",b||"")},a.render=function(b){b=b||1,a.render.active=!0,a.dispatch.render_start();var c=function(){for(var d,e,f=0;b>f&&(e=a.render.queue[f]);f++)d=e.generate(),typeof e.callback==typeof Function&&e.callback(d);a.render.queue.splice(0,f),a.render.queue.length?setTimeout(c):(a.dispatch.render_end(),a.render.active=!1)};setTimeout(c)},a.render.active=!1,a.render.queue=[],a.addGraph=function(b){typeof arguments[0]==typeof Function&&(b={generate:arguments[0],callback:arguments[1]}),a.render.queue.push(b),a.render.active||a.render()},"undefined"!=typeof module&&"undefined"!=typeof exports&&(module.exports=a),"undefined"!=typeof window&&(window.nv=a),a.dom.write=function(a){return void 0!==window.fastdom?fastdom.write(a):a()},a.dom.read=function(a){return void 0!==window.fastdom?fastdom.read(a):a()},a.interactiveGuideline=function(){"use strict";function b(l){l.each(function(l){function m(){var a=d3.mouse(this),d=a[0],e=a[1],i=!0,j=!1;if(k&&(d=d3.event.offsetX,e=d3.event.offsetY,"svg"!==d3.event.target.tagName&&(i=!1),d3.event.target.className.baseVal.match("nv-legend")&&(j=!0)),i&&(d-=f.left,e-=f.top),0>d||0>e||d>o||e>p||d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement||j){if(k&&d3.event.relatedTarget&&void 0===d3.event.relatedTarget.ownerSVGElement&&(void 0===d3.event.relatedTarget.className||d3.event.relatedTarget.className.match(c.nvPointerEventsClass)))return;return h.elementMouseout({mouseX:d,mouseY:e}),b.renderGuideLine(null),void c.hidden(!0)}c.hidden(!1);var l=g.invert(d);h.elementMousemove({mouseX:d,mouseY:e,pointXValue:l}),"dblclick"===d3.event.type&&h.elementDblclick({mouseX:d,mouseY:e,pointXValue:l}),"click"===d3.event.type&&h.elementClick({mouseX:d,mouseY:e,pointXValue:l})}var n=d3.select(this),o=d||960,p=e||400,q=n.selectAll("g.nv-wrap.nv-interactiveLineLayer").data([l]),r=q.enter().append("g").attr("class"," nv-wrap nv-interactiveLineLayer");r.append("g").attr("class","nv-interactiveGuideLine"),j&&(j.on("touchmove",m).on("mousemove",m,!0).on("mouseout",m,!0).on("dblclick",m).on("click",m),b.guideLine=null,b.renderGuideLine=function(c){i&&(b.guideLine&&b.guideLine.attr("x1")===c||a.dom.write(function(){var b=q.select(".nv-interactiveGuideLine").selectAll("line").data(null!=c?[a.utils.NaNtoZero(c)]:[],String);b.enter().append("line").attr("class","nv-guideline").attr("x1",function(a){return a}).attr("x2",function(a){return a}).attr("y1",p).attr("y2",0),b.exit().remove()}))})})}var c=a.models.tooltip();c.duration(0).hideDelay(0)._isInteractiveLayer(!0).hidden(!1);var d=null,e=null,f={left:0,top:0},g=d3.scale.linear(),h=d3.dispatch("elementMousemove","elementMouseout","elementClick","elementDblclick"),i=!0,j=null,k="ActiveXObject"in window;return b.dispatch=h,b.tooltip=c,b.margin=function(a){return arguments.length?(f.top="undefined"!=typeof a.top?a.top:f.top,f.left="undefined"!=typeof a.left?a.left:f.left,b):f},b.width=function(a){return arguments.length?(d=a,b):d},b.height=function(a){return arguments.length?(e=a,b):e},b.xScale=function(a){return arguments.length?(g=a,b):g},b.showGuideLine=function(a){return arguments.length?(i=a,b):i},b.svgContainer=function(a){return arguments.length?(j=a,b):j},b},a.interactiveBisect=function(a,b,c){"use strict";if(!(a instanceof Array))return null;var d;d="function"!=typeof c?function(a){return a.x}:c;var e=function(a,b){return d(a)-b},f=d3.bisector(e).left,g=d3.max([0,f(a,b)-1]),h=d(a[g]);if("undefined"==typeof h&&(h=g),h===b)return g;var i=d3.min([g+1,a.length-1]),j=d(a[i]);return"undefined"==typeof j&&(j=i),Math.abs(j-b)>=Math.abs(h-b)?g:i},a.nearestValueIndex=function(a,b,c){"use strict";var d=1/0,e=null;return a.forEach(function(a,f){var g=Math.abs(b-a);null!=a&&d>=g&&c>g&&(d=g,e=f)}),e},function(){"use strict";a.models.tooltip=function(){function b(){if(k){var a=d3.select(k);"svg"!==a.node().tagName&&(a=a.select("svg"));var b=a.node()?a.attr("viewBox"):null;if(b){b=b.split(" ");var c=parseInt(a.style("width"),10)/b[2];p.left=p.left*c,p.top=p.top*c}}}function c(){if(!n){var a;a=k?k:document.body,n=d3.select(a).append("div").attr("class","nvtooltip "+(j?j:"xy-tooltip")).attr("id",v),n.style("top",0).style("left",0),n.style("opacity",0),n.selectAll("div, table, td, tr").classed(w,!0),n.classed(w,!0),o=n.node()}}function d(){if(r&&B(e)){b();var f=p.left,g=null!==i?i:p.top;return a.dom.write(function(){c();var b=A(e);b&&(o.innerHTML=b),k&&u?a.dom.read(function(){var a=k.getElementsByTagName("svg")[0],b={left:0,top:0};if(a){var c=a.getBoundingClientRect(),d=k.getBoundingClientRect(),e=c.top;if(0>e){var i=k.getBoundingClientRect();e=Math.abs(e)>i.height?0:e}b.top=Math.abs(e-d.top),b.left=Math.abs(c.left-d.left)}f+=k.offsetLeft+b.left-2*k.scrollLeft,g+=k.offsetTop+b.top-2*k.scrollTop,h&&h>0&&(g=Math.floor(g/h)*h),C([f,g])}):C([f,g])}),d}}var e=null,f="w",g=25,h=0,i=null,j=null,k=null,l=!0,m=400,n=null,o=null,p={left:null,top:null},q={left:0,top:0},r=!0,s=100,t=!0,u=!1,v="nvtooltip-"+Math.floor(1e5*Math.random()),w="nv-pointer-events-none",x=function(a,b){return a},y=function(a){return a},z=function(a,b){return a},A=function(a){if(null===a)return"";var b=d3.select(document.createElement("table"));if(t){var c=b.selectAll("thead").data([a]).enter().append("thead");c.append("tr").append("td").attr("colspan",3).append("strong").classed("x-value",!0).html(y(a.value))}var d=b.selectAll("tbody").data([a]).enter().append("tbody"),e=d.selectAll("tr").data(function(a){return a.series}).enter().append("tr").classed("highlight",function(a){return a.highlight});e.append("td").classed("legend-color-guide",!0).append("div").style("background-color",function(a){return a.color}),e.append("td").classed("key",!0).html(function(a,b){return z(a.key,b)}),e.append("td").classed("value",!0).html(function(a,b){return x(a.value,b)}),e.selectAll("td").each(function(a){if(a.highlight){var b=d3.scale.linear().domain([0,1]).range(["#fff",a.color]),c=.6;d3.select(this).style("border-bottom-color",b(c)).style("border-top-color",b(c))}});var f=b.node().outerHTML;return void 0!==a.footer&&(f+=""),f},B=function(a){if(a&&a.series){if(a.series instanceof Array)return!!a.series.length;if(a.series instanceof Object)return a.series=[a.series],!0}return!1},C=function(b){o&&a.dom.read(function(){var c,d,e=parseInt(o.offsetHeight,10),h=parseInt(o.offsetWidth,10),i=a.utils.windowSize().width,j=a.utils.windowSize().height,k=window.pageYOffset,p=window.pageXOffset;j=window.innerWidth>=document.body.scrollWidth?j:j-16,i=window.innerHeight>=document.body.scrollHeight?i:i-16;var r,t,u=function(a){var b=d;do isNaN(a.offsetTop)||(b+=a.offsetTop),a=a.offsetParent;while(a);return b},v=function(a){var b=c;do isNaN(a.offsetLeft)||(b+=a.offsetLeft),a=a.offsetParent;while(a);return b};switch(f){case"e":c=b[0]-h-g,d=b[1]-e/2,r=v(o),t=u(o),p>r&&(c=b[0]+g>p?b[0]+g:p-r+c),k>t&&(d=k-t+d),t+e>k+j&&(d=k+j-t+d-e);break;case"w":c=b[0]+g,d=b[1]-e/2,r=v(o),t=u(o),r+h>i&&(c=b[0]-h-g),k>t&&(d=k+5),t+e>k+j&&(d=k+j-t+d-e);break;case"n":c=b[0]-h/2-5,d=b[1]+g,r=v(o),t=u(o),p>r&&(c=p+5),r+h>i&&(c=c-h/2+5),t+e>k+j&&(d=k+j-t+d-e);break;case"s":c=b[0]-h/2,d=b[1]-e-g,r=v(o),t=u(o),p>r&&(c=p+5),r+h>i&&(c=c-h/2+5),k>t&&(d=k);break;case"none":c=b[0],d=b[1]-g,r=v(o),t=u(o)}c-=q.left,d-=q.top;var w=o.getBoundingClientRect(),k=window.pageYOffset||document.documentElement.scrollTop,p=window.pageXOffset||document.documentElement.scrollLeft,x="translate("+(w.left+p)+"px, "+(w.top+k)+"px)",y="translate("+c+"px, "+d+"px)",z=d3.interpolateString(x,y),A=n.style("opacity")<.1;l?n.transition().delay(m).duration(0).style("opacity",0):n.interrupt().transition().duration(A?0:s).styleTween("transform",function(a){return z},"important").style("-webkit-transform",y).style("opacity",1)})};return d.nvPointerEventsClass=w,d.options=a.utils.optionsFunc.bind(d),d._options=Object.create({},{duration:{get:function(){return s},set:function(a){s=a}},gravity:{get:function(){return f},set:function(a){f=a}},distance:{get:function(){return g},set:function(a){g=a}},snapDistance:{get:function(){return h},set:function(a){h=a}},classes:{get:function(){return j},set:function(a){j=a}},chartContainer:{get:function(){return k},set:function(a){k=a}},fixedTop:{get:function(){return i},set:function(a){i=a}},enabled:{get:function(){return r},set:function(a){r=a}},hideDelay:{get:function(){return m},set:function(a){m=a}},contentGenerator:{get:function(){return A},set:function(a){A=a}},valueFormatter:{get:function(){return x},set:function(a){x=a}},headerFormatter:{get:function(){return y},set:function(a){y=a}},keyFormatter:{get:function(){return z},set:function(a){z=a}},headerEnabled:{get:function(){return t},set:function(a){t=a}},_isInteractiveLayer:{get:function(){return u},set:function(a){u=!!a}},position:{get:function(){return p},set:function(a){p.left=void 0!==a.left?a.left:p.left,p.top=void 0!==a.top?a.top:p.top}},offset:{get:function(){return q},set:function(a){q.left=void 0!==a.left?a.left:q.left,q.top=void 0!==a.top?a.top:q.top}},hidden:{get:function(){return l},set:function(a){l!=a&&(l=!!a,d())}},data:{get:function(){return e},set:function(a){a.point&&(a.value=a.point.x,a.series=a.series||{},a.series.value=a.point.y,a.series.color=a.point.color||a.series.color),e=a}},tooltipElem:{get:function(){return o},set:function(a){}},id:{get:function(){return v},set:function(a){}}}),a.utils.initOptions(d),d}}(),a.utils.windowSize=function(){var a={width:640,height:480};return window.innerWidth&&window.innerHeight?(a.width=window.innerWidth,a.height=window.innerHeight,a):"CSS1Compat"==document.compatMode&&document.documentElement&&document.documentElement.offsetWidth?(a.width=document.documentElement.offsetWidth,a.height=document.documentElement.offsetHeight,a):document.body&&document.body.offsetWidth?(a.width=document.body.offsetWidth,a.height=document.body.offsetHeight,a):a},a.utils.windowResize=function(b){return window.addEventListener?window.addEventListener("resize",b):a.log("ERROR: Failed to bind to window.resize with: ",b),{callback:b,clear:function(){window.removeEventListener("resize",b)}}},a.utils.getColor=function(b){if(void 0===b)return a.utils.defaultColor();if(Array.isArray(b)){var c=d3.scale.ordinal().range(b);return function(a,b){var d=void 0===b?a:b;return a.color||c(d)}}return b},a.utils.defaultColor=function(){return a.utils.getColor(d3.scale.category20().range())},a.utils.customTheme=function(a,b,c){b=b||function(a){return a.key},c=c||d3.scale.category20().range();var d=c.length;return function(e,f){var g=b(e);return"function"==typeof a[g]?a[g]():void 0!==a[g]?a[g]:(d||(d=c.length),d-=1,c[d])}},a.utils.pjax=function(b,c){var d=function(d){d3.html(d,function(d){var e=d3.select(c).node();e.parentNode.replaceChild(d3.select(d).select(c).node(),e),a.utils.pjax(b,c)})};d3.selectAll(b).on("click",function(){history.pushState(this.href,this.textContent,this.href),d(this.href),d3.event.preventDefault()}),d3.select(window).on("popstate",function(){d3.event.state&&d(d3.event.state)})},a.utils.calcApproxTextWidth=function(a){if("function"==typeof a.style&&"function"==typeof a.text){var b=parseInt(a.style("font-size").replace("px",""),10),c=a.text().length;return c*b*.5}return 0},a.utils.NaNtoZero=function(a){return"number"!=typeof a||isNaN(a)||null===a||a===1/0||a===-(1/0)?0:a},d3.selection.prototype.watchTransition=function(a){var b=[this].concat([].slice.call(arguments,1));return a.transition.apply(a,b)},a.utils.renderWatch=function(b,c){if(!(this instanceof a.utils.renderWatch))return new a.utils.renderWatch(b,c);var d=void 0!==c?c:250,e=[],f=this;this.models=function(a){return a=[].slice.call(arguments,0),a.forEach(function(a){a.__rendered=!1,function(a){a.dispatch.on("renderEnd",function(b){a.__rendered=!0,f.renderEnd("model")})}(a),e.indexOf(a)<0&&e.push(a)}),this},this.reset=function(a){void 0!==a&&(d=a),e=[]},this.transition=function(a,b,c){if(b=arguments.length>1?[].slice.call(arguments,1):[],c=b.length>1?b.pop():void 0!==d?d:250,a.__rendered=!1,e.indexOf(a)<0&&e.push(a),0===c)return a.__rendered=!0,a.delay=function(){return this},a.duration=function(){return this},a;0===a.length?a.__rendered=!0:a.every(function(a){return!a.length})?a.__rendered=!0:a.__rendered=!1;var g=0;return a.transition().duration(c).each(function(){++g}).each("end",function(c,d){0===--g&&(a.__rendered=!0,f.renderEnd.apply(this,b))})},this.renderEnd=function(){e.every(function(a){return a.__rendered})&&(e.forEach(function(a){a.__rendered=!1}),b.renderEnd.apply(this,arguments))}},a.utils.deepExtend=function(b){var c=arguments.length>1?[].slice.call(arguments,1):[];c.forEach(function(c){for(var d in c){var e=b[d]instanceof Array,f="object"==typeof b[d],g="object"==typeof c[d];f&&!e&&g?a.utils.deepExtend(b[d],c[d]):b[d]=c[d]}})},a.utils.state=function(){if(!(this instanceof a.utils.state))return new a.utils.state;var b={},c=function(){},d=function(){return{}},e=null,f=null;this.dispatch=d3.dispatch("change","set"),this.dispatch.on("set",function(a){c(a,!0)}),this.getter=function(a){return d=a,this},this.setter=function(a,b){return b||(b=function(){}),c=function(c,d){a(c),d&&b()},this},this.init=function(b){e=e||{},a.utils.deepExtend(e,b)};var g=function(){var a=d();if(JSON.stringify(a)===JSON.stringify(b))return!1;for(var c in a)void 0===b[c]&&(b[c]={}),b[c]=a[c],f=!0;return!0};this.update=function(){e&&(c(e,!1),e=null),g.call(this)&&this.dispatch.change(b)}},a.utils.optionsFunc=function(a){return a&&d3.map(a).forEach(function(a,b){"function"==typeof this[a]&&this[a](b)}.bind(this)),this},a.utils.calcTicksX=function(b,c){var d=1,e=0;for(e;ed?f:d}return a.log("Requested number of ticks: ",b),a.log("Calculated max values to be: ",d),b=b>d?b=d-1:b,b=1>b?1:b,b=Math.floor(b),a.log("Calculating tick count as: ",b),b},a.utils.calcTicksY=function(b,c){return a.utils.calcTicksX(b,c)},a.utils.initOption=function(a,b){a._calls&&a._calls[b]?a[b]=a._calls[b]:(a[b]=function(c){return arguments.length?(a._overrides[b]=!0,a._options[b]=c,a):a._options[b]},a["_"+b]=function(c){return arguments.length?(a._overrides[b]||(a._options[b]=c),a):a._options[b]})},a.utils.initOptions=function(b){b._overrides=b._overrides||{};var c=Object.getOwnPropertyNames(b._options||{}),d=Object.getOwnPropertyNames(b._calls||{});c=c.concat(d);for(var e in c)a.utils.initOption(b,c[e])},a.utils.inheritOptionsD3=function(a,b,c){a._d3options=c.concat(a._d3options||[]),c.unshift(b),c.unshift(a),d3.rebind.apply(this,c)},a.utils.arrayUnique=function(a){return a.sort().filter(function(b,c){return!c||b!=a[c-1]})},a.utils.symbolMap=d3.map(),a.utils.symbol=function(){function b(b,e){var f=c.call(this,b,e),g=d.call(this,b,e);return-1!==d3.svg.symbolTypes.indexOf(f)?d3.svg.symbol().type(f).size(g)():a.utils.symbolMap.get(f)(g)}var c,d=64;return b.type=function(a){return arguments.length?(c=d3.functor(a),b):c},b.size=function(a){return arguments.length?(d=d3.functor(a),b):d},b},a.utils.inheritOptions=function(b,c){var d=Object.getOwnPropertyNames(c._options||{}),e=Object.getOwnPropertyNames(c._calls||{}),f=c._inherited||[],g=c._d3options||[],h=d.concat(e).concat(f).concat(g);h.unshift(c),h.unshift(b),d3.rebind.apply(this,h),b._inherited=a.utils.arrayUnique(d.concat(e).concat(f).concat(d).concat(b._inherited||[])),b._d3options=a.utils.arrayUnique(g.concat(b._d3options||[]))},a.utils.initSVG=function(a){a.classed({"nvd3-svg":!0})},a.utils.sanitizeHeight=function(a,b){return a||parseInt(b.style("height"),10)||400},a.utils.sanitizeWidth=function(a,b){return a||parseInt(b.style("width"),10)||960},a.utils.availableHeight=function(b,c,d){return a.utils.sanitizeHeight(b,c)-d.top-d.bottom},a.utils.availableWidth=function(b,c,d){return a.utils.sanitizeWidth(b,c)-d.left-d.right},a.utils.noData=function(b,c){var d=b.options(),e=d.margin(),f=d.noData(),g=null==f?["No Data Available."]:[f],h=a.utils.availableHeight(d.height(),c,e),i=a.utils.availableWidth(d.width(),c,e),j=e.left+i/2,k=e.top+h/2;c.selectAll("g").remove();var l=c.selectAll(".nv-noData").data(g);l.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),l.attr("x",j).attr("y",k).text(function(a){return a})},a.models.axis=function(){"use strict";function b(g){return s.reset(),g.each(function(b){var g=d3.select(this);a.utils.initSVG(g);var p=g.selectAll("g.nv-wrap.nv-axis").data([b]),q=p.enter().append("g").attr("class","nvd3 nv-wrap nv-axis"),t=(q.append("g"),p.select("g"));null!==n?c.ticks(n):("top"==c.orient()||"bottom"==c.orient())&&c.ticks(Math.abs(d.range()[1]-d.range()[0])/100),t.watchTransition(s,"axis").call(c),r=r||c.scale();var u=c.tickFormat();null==u&&(u=r.tickFormat());var v=t.selectAll("text.nv-axislabel").data([h||null]);v.exit().remove();var w,x,y;switch(c.orient()){case"top":v.enter().append("text").attr("class","nv-axislabel"),y=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),v.attr("text-anchor","middle").attr("y",0).attr("x",y/2),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-x",0==b?"nv-axisMin-x":"nv-axisMax-x"].join(" ")}).append("text"),x.exit().remove(),x.attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d(b))+",0)"}).select("text").attr("dy","-0.5em").attr("y",-c.tickPadding()).attr("text-anchor","middle").text(function(a,b){var c=u(a);return(""+c).match("NaN")?"":c}),x.watchTransition(s,"min-max top").attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d.range()[c])+",0)"}));break;case"bottom":w=o+36;var z=30,A=0,B=t.selectAll("g").select("text"),C="";if(j%360){B.each(function(a,b){var c=this.getBoundingClientRect(),d=c.width;A=c.height,d>z&&(z=d)}),C="rotate("+j+" 0,"+(A/2+c.tickPadding())+")";var D=Math.abs(Math.sin(j*Math.PI/180));w=(D?D*z:z)+30,B.attr("transform",C).style("text-anchor",j%360>0?"start":"end")}v.enter().append("text").attr("class","nv-axislabel"),y=d.range().length<2?0:2===d.range().length?d.range()[1]:d.range()[d.range().length-1]+(d.range()[1]-d.range()[0]),v.attr("text-anchor","middle").attr("y",w).attr("x",y/2),i&&(x=p.selectAll("g.nv-axisMaxMin").data([d.domain()[0],d.domain()[d.domain().length-1]]),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-x",0==b?"nv-axisMin-x":"nv-axisMax-x"].join(" ")}).append("text"),x.exit().remove(),x.attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d(b)+(m?d.rangeBand()/2:0))+",0)"}).select("text").attr("dy",".71em").attr("y",c.tickPadding()).attr("transform",C).style("text-anchor",j?j%360>0?"start":"end":"middle").text(function(a,b){var c=u(a);return(""+c).match("NaN")?"":c}),x.watchTransition(s,"min-max bottom").attr("transform",function(b,c){return"translate("+a.utils.NaNtoZero(d(b)+(m?d.rangeBand()/2:0))+",0)"})),l&&B.attr("transform",function(a,b){return"translate(0,"+(b%2==0?"0":"12")+")"});break;case"right":v.enter().append("text").attr("class","nv-axislabel"),v.style("text-anchor",k?"middle":"begin").attr("transform",k?"rotate(90)":"").attr("y",k?-Math.max(e.right,f)+12:-10).attr("x",k?d3.max(d.range())/2:c.tickPadding()),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-y",0==b?"nv-axisMin-y":"nv-axisMax-y"].join(" ")}).append("text").style("opacity",0),x.exit().remove(),x.attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",c.tickPadding()).style("text-anchor","start").text(function(a,b){var c=u(a);return(""+c).match("NaN")?"":c}),x.watchTransition(s,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1));break;case"left":v.enter().append("text").attr("class","nv-axislabel"),v.style("text-anchor",k?"middle":"end").attr("transform",k?"rotate(-90)":"").attr("y",k?-Math.max(e.left,f)+25-(o||0):-10).attr("x",k?-d3.max(d.range())/2:-c.tickPadding()),i&&(x=p.selectAll("g.nv-axisMaxMin").data(d.domain()),x.enter().append("g").attr("class",function(a,b){return["nv-axisMaxMin","nv-axisMaxMin-y",0==b?"nv-axisMin-y":"nv-axisMax-y"].join(" ")}).append("text").style("opacity",0),x.exit().remove(),x.attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(r(b))+")"}).select("text").attr("dy",".32em").attr("y",0).attr("x",-c.tickPadding()).attr("text-anchor","end").text(function(a,b){var c=u(a);return(""+c).match("NaN")?"":c}),x.watchTransition(s,"min-max right").attr("transform",function(b,c){return"translate(0,"+a.utils.NaNtoZero(d.range()[c])+")"}).select("text").style("opacity",1))}if(v.text(function(a){return a}),!i||"left"!==c.orient()&&"right"!==c.orient()||(t.selectAll("g").each(function(a,b){d3.select(this).select("text").attr("opacity",1),(d(a)d.range()[0]-10)&&((a>1e-10||-1e-10>a)&&d3.select(this).attr("opacity",0),d3.select(this).select("text").attr("opacity",0))}),d.domain()[0]==d.domain()[1]&&0==d.domain()[0]&&p.selectAll("g.nv-axisMaxMin").style("opacity",function(a,b){return b?0:1})),i&&("top"===c.orient()||"bottom"===c.orient())){var E=[];p.selectAll("g.nv-axisMaxMin").each(function(a,b){try{b?E.push(d(a)-this.getBoundingClientRect().width-4):E.push(d(a)+this.getBoundingClientRect().width+4)}catch(c){b?E.push(d(a)-4):E.push(d(a)+4)}}),t.selectAll("g").each(function(a,b){(d(a)E[1])&&(a>1e-10||-1e-10>a?d3.select(this).remove():d3.select(this).select("text").remove())})}t.selectAll(".tick").filter(function(a){return!parseFloat(Math.round(1e5*a)/1e6)&&void 0!==a}).classed("zero",!0),r=d.copy()}),s.renderEnd("axis immediate"),b}var c=d3.svg.axis(),d=d3.scale.linear(),e={top:0,right:0,bottom:0,left:0},f=75,g=60,h=null,i=!0,j=0,k=!0,l=!1,m=!1,n=null,o=0,p=250,q=d3.dispatch("renderEnd");c.scale(d).orient("bottom").tickFormat(function(a){return a});var r,s=a.utils.renderWatch(q,p);return b.axis=c,b.dispatch=q,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{axisLabelDistance:{get:function(){return o},set:function(a){o=a}},staggerLabels:{get:function(){return l},set:function(a){l=a}},rotateLabels:{get:function(){return j},set:function(a){j=a}},rotateYLabel:{get:function(){return k},set:function(a){k=a}},showMaxMin:{get:function(){return i},set:function(a){i=a}},axisLabel:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return g},set:function(a){g=a}},ticks:{get:function(){return n},set:function(a){n=a}},width:{get:function(){return f},set:function(a){f=a}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},duration:{get:function(){return p},set:function(a){p=a,s.reset(p)}},scale:{get:function(){return d},set:function(e){d=e,c.scale(d),m="function"==typeof d.rangeBands,a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"])}}}),a.utils.initOptions(b),a.utils.inheritOptionsD3(b,c,["orient","tickValues","tickSubdivide","tickSize","tickPadding","tickFormat"]),a.utils.inheritOptionsD3(b,d,["domain","range","rangeBand","rangeBands"]),b},a.models.boxPlot=function(){"use strict";function b(l){return v.reset(),l.each(function(b){var l=j-i.left-i.right,p=k-i.top-i.bottom;r=d3.select(this),a.utils.initSVG(r),m.domain(c||b.map(function(a,b){return o(a,b)})).rangeBands(e||[0,l],.1);var w=[];if(!d){var x=d3.min(b.map(function(a){var b=[];return b.push(a.values.Q1),a.values.hasOwnProperty("whisker_low")&&null!==a.values.whisker_low&&b.push(a.values.whisker_low),a.values.hasOwnProperty("outliers")&&null!==a.values.outliers&&(b=b.concat(a.values.outliers)),d3.min(b)})),y=d3.max(b.map(function(a){var b=[];return b.push(a.values.Q3),a.values.hasOwnProperty("whisker_high")&&null!==a.values.whisker_high&&b.push(a.values.whisker_high),a.values.hasOwnProperty("outliers")&&null!==a.values.outliers&&(b=b.concat(a.values.outliers)),d3.max(b)}));w=[x,y]}n.domain(d||w),n.range(f||[p,0]),g=g||m,h=h||n.copy().range([n(0),n(0)]);var z=r.selectAll("g.nv-wrap").data([b]);z.enter().append("g").attr("class","nvd3 nv-wrap");z.attr("transform","translate("+i.left+","+i.top+")");var A=z.selectAll(".nv-boxplot").data(function(a){return a}),B=A.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);A.attr("class","nv-boxplot").attr("transform",function(a,b,c){return"translate("+(m(o(a,b))+.05*m.rangeBand())+", 0)"}).classed("hover",function(a){return a.hover}),A.watchTransition(v,"nv-boxplot: boxplots").style("stroke-opacity",1).style("fill-opacity",.75).delay(function(a,c){return c*t/b.length}).attr("transform",function(a,b){return"translate("+(m(o(a,b))+.05*m.rangeBand())+", 0)"}),A.exit().remove(),B.each(function(a,b){var c=d3.select(this);["low","high"].forEach(function(d){a.values.hasOwnProperty("whisker_"+d)&&null!==a.values["whisker_"+d]&&(c.append("line").style("stroke",a.color?a.color:q(a,b)).attr("class","nv-boxplot-whisker nv-boxplot-"+d),c.append("line").style("stroke",a.color?a.color:q(a,b)).attr("class","nv-boxplot-tick nv-boxplot-"+d))})});var C=A.selectAll(".nv-boxplot-outlier").data(function(a){return a.values.hasOwnProperty("outliers")&&null!==a.values.outliers?a.values.outliers:[]});C.enter().append("circle").style("fill",function(a,b,c){return q(a,c)}).style("stroke",function(a,b,c){return q(a,c)}).on("mouseover",function(a,b,c){d3.select(this).classed("hover",!0),s.elementMouseover({series:{key:a,color:q(a,c)},e:d3.event})}).on("mouseout",function(a,b,c){d3.select(this).classed("hover",!1),s.elementMouseout({series:{key:a,color:q(a,c)},e:d3.event})}).on("mousemove",function(a,b){s.elementMousemove({e:d3.event})}),C.attr("class","nv-boxplot-outlier"),C.watchTransition(v,"nv-boxplot: nv-boxplot-outlier").attr("cx",.45*m.rangeBand()).attr("cy",function(a,b,c){return n(a)}).attr("r","3"),C.exit().remove();var D=function(){return null===u?.9*m.rangeBand():Math.min(75,.9*m.rangeBand())},E=function(){return.45*m.rangeBand()-D()/2},F=function(){return.45*m.rangeBand()+D()/2};["low","high"].forEach(function(a){var b="low"===a?"Q1":"Q3";A.select("line.nv-boxplot-whisker.nv-boxplot-"+a).watchTransition(v,"nv-boxplot: boxplots").attr("x1",.45*m.rangeBand()).attr("y1",function(b,c){return n(b.values["whisker_"+a])}).attr("x2",.45*m.rangeBand()).attr("y2",function(a,c){return n(a.values[b])}),A.select("line.nv-boxplot-tick.nv-boxplot-"+a).watchTransition(v,"nv-boxplot: boxplots").attr("x1",E).attr("y1",function(b,c){return n(b.values["whisker_"+a])}).attr("x2",F).attr("y2",function(b,c){return n(b.values["whisker_"+a])})}),["low","high"].forEach(function(a){B.selectAll(".nv-boxplot-"+a).on("mouseover",function(b,c,d){d3.select(this).classed("hover",!0),s.elementMouseover({series:{key:b.values["whisker_"+a],color:q(b,d)},e:d3.event})}).on("mouseout",function(b,c,d){d3.select(this).classed("hover",!1),s.elementMouseout({series:{key:b.values["whisker_"+a],color:q(b,d)},e:d3.event})}).on("mousemove",function(a,b){s.elementMousemove({e:d3.event})})}),B.append("rect").attr("class","nv-boxplot-box").on("mouseover",function(a,b){d3.select(this).classed("hover",!0),s.elementMouseover({key:a.label,value:a.label,series:[{key:"Q3",value:a.values.Q3,color:a.color||q(a,b)},{key:"Q2",value:a.values.Q2,color:a.color||q(a,b)},{key:"Q1",value:a.values.Q1,color:a.color||q(a,b)}],data:a,index:b,e:d3.event})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),s.elementMouseout({key:a.label,value:a.label,series:[{key:"Q3",value:a.values.Q3,color:a.color||q(a,b)},{key:"Q2",value:a.values.Q2,color:a.color||q(a,b)},{key:"Q1",value:a.values.Q1,color:a.color||q(a,b)}],data:a,index:b,e:d3.event})}).on("mousemove",function(a,b){s.elementMousemove({e:d3.event})}),A.select("rect.nv-boxplot-box").watchTransition(v,"nv-boxplot: boxes").attr("y",function(a,b){return n(a.values.Q3)}).attr("width",D).attr("x",E).attr("height",function(a,b){return Math.abs(n(a.values.Q3)-n(a.values.Q1))||1}).style("fill",function(a,b){return a.color||q(a,b)}).style("stroke",function(a,b){return a.color||q(a,b)}),B.append("line").attr("class","nv-boxplot-median"),A.select("line.nv-boxplot-median").watchTransition(v,"nv-boxplot: boxplots line").attr("x1",E).attr("y1",function(a,b){return n(a.values.Q2)}).attr("x2",F).attr("y2",function(a,b){return n(a.values.Q2)}),g=m.copy(),h=n.copy()}),v.renderEnd("nv-boxplot immediate"),b}var c,d,e,f,g,h,i={top:0,right:0,bottom:0,left:0},j=960,k=500,l=Math.floor(1e4*Math.random()),m=d3.scale.ordinal(),n=d3.scale.linear(),o=function(a){return a.x},p=function(a){return a.y},q=a.utils.defaultColor(),r=null,s=d3.dispatch("elementMouseover","elementMouseout","elementMousemove","renderEnd"),t=250,u=null,v=a.utils.renderWatch(s,t);return b.dispatch=s,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},maxBoxWidth:{get:function(){return u},set:function(a){u=a}},x:{get:function(){return o},set:function(a){o=a}},y:{get:function(){return p},set:function(a){p=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},id:{get:function(){return l},set:function(a){l=a}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},color:{get:function(){return q},set:function(b){q=a.utils.getColor(b)}},duration:{get:function(){return t},set:function(a){t=a,v.reset(t)}}}),a.utils.initOptions(b),b},a.models.boxPlotChart=function(){"use strict";function b(k){return t.reset(),t.models(e),l&&t.models(f),m&&t.models(g),k.each(function(k){var p=d3.select(this);a.utils.initSVG(p);var t=(i||parseInt(p.style("width"))||960)-h.left-h.right,u=(j||parseInt(p.style("height"))||400)-h.top-h.bottom;if(b.update=function(){r.beforeUpdate(),p.transition().duration(s).call(b)},b.container=this,!(k&&k.length&&k.filter(function(a){return a.values.hasOwnProperty("Q1")&&a.values.hasOwnProperty("Q2")&&a.values.hasOwnProperty("Q3")}).length)){var v=p.selectAll(".nv-noData").data([q]);return v.enter().append("text").attr("class","nvd3 nv-noData").attr("dy","-.7em").style("text-anchor","middle"),v.attr("x",h.left+t/2).attr("y",h.top+u/2).text(function(a){return a}),b}p.selectAll(".nv-noData").remove(), -c=e.xScale(),d=e.yScale().clamp(!0);var w=p.selectAll("g.nv-wrap.nv-boxPlotWithAxes").data([k]),x=w.enter().append("g").attr("class","nvd3 nv-wrap nv-boxPlotWithAxes").append("g"),y=x.append("defs"),z=w.select("g");x.append("g").attr("class","nv-x nv-axis"),x.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),x.append("g").attr("class","nv-barsWrap"),z.attr("transform","translate("+h.left+","+h.top+")"),n&&z.select(".nv-y.nv-axis").attr("transform","translate("+t+",0)"),e.width(t).height(u);var A=z.select(".nv-barsWrap").datum(k.filter(function(a){return!a.disabled}));if(A.transition().call(e),y.append("clipPath").attr("id","nv-x-label-clip-"+e.id()).append("rect"),z.select("#nv-x-label-clip-"+e.id()+" rect").attr("width",c.rangeBand()*(o?2:1)).attr("height",16).attr("x",-c.rangeBand()/(o?1:2)),l){f.scale(c).ticks(a.utils.calcTicksX(t/100,k)).tickSize(-u,0),z.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),z.select(".nv-x.nv-axis").call(f);var B=z.select(".nv-x.nv-axis").selectAll("g");o&&B.selectAll("text").attr("transform",function(a,b,c){return"translate(0,"+(c%2==0?"5":"17")+")"})}m&&(g.scale(d).ticks(Math.floor(u/36)).tickSize(-t,0),z.select(".nv-y.nv-axis").call(g)),z.select(".nv-zeroLine line").attr("x1",0).attr("x2",t).attr("y1",d(0)).attr("y2",d(0))}),t.renderEnd("nv-boxplot chart immediate"),b}var c,d,e=a.models.boxPlot(),f=a.models.axis(),g=a.models.axis(),h={top:15,right:10,bottom:50,left:60},i=null,j=null,k=a.utils.getColor(),l=!0,m=!0,n=!1,o=!1,p=a.models.tooltip(),q="No Data Available.",r=d3.dispatch("tooltipShow","tooltipHide","beforeUpdate","renderEnd"),s=250;f.orient("bottom").showMaxMin(!1).tickFormat(function(a){return a}),g.orient(n?"right":"left").tickFormat(d3.format(",.1f")),p.duration(0);var t=a.utils.renderWatch(r,s);return e.dispatch.on("elementMouseover.tooltip",function(a){p.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){p.data(a).hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(a){p.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=r,b.boxplot=e,b.xAxis=f,b.yAxis=g,b.tooltip=p,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return i},set:function(a){i=a}},height:{get:function(){return j},set:function(a){j=a}},staggerLabels:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return l},set:function(a){l=a}},showYAxis:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return tooltips},set:function(a){tooltips=a}},tooltipContent:{get:function(){return p},set:function(a){p=a}},noData:{get:function(){return q},set:function(a){q=a}},margin:{get:function(){return h},set:function(a){h.top=void 0!==a.top?a.top:h.top,h.right=void 0!==a.right?a.right:h.right,h.bottom=void 0!==a.bottom?a.bottom:h.bottom,h.left=void 0!==a.left?a.left:h.left}},duration:{get:function(){return s},set:function(a){s=a,t.reset(s),e.duration(s),f.duration(s),g.duration(s)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),e.color(k)}},rightAlignYAxis:{get:function(){return n},set:function(a){n=a,g.orient(a?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.bullet=function(){"use strict";function b(d){return d.each(function(b,d){var p=m-c.left-c.right,s=n-c.top-c.bottom;o=d3.select(this),a.utils.initSVG(o);var t=f.call(this,b,d).slice().sort(d3.descending),u=g.call(this,b,d).slice().sort(d3.descending),v=h.call(this,b,d).slice().sort(d3.descending),w=i.call(this,b,d).slice(),x=j.call(this,b,d).slice(),y=k.call(this,b,d).slice(),z=d3.scale.linear().domain(d3.extent(d3.merge([l,t]))).range(e?[p,0]:[0,p]);this.__chart__||d3.scale.linear().domain([0,1/0]).range(z.range());this.__chart__=z;var A=d3.min(t),B=d3.max(t),C=t[1],D=o.selectAll("g.nv-wrap.nv-bullet").data([b]),E=D.enter().append("g").attr("class","nvd3 nv-wrap nv-bullet"),F=E.append("g"),G=D.select("g");F.append("rect").attr("class","nv-range nv-rangeMax"),F.append("rect").attr("class","nv-range nv-rangeAvg"),F.append("rect").attr("class","nv-range nv-rangeMin"),F.append("rect").attr("class","nv-measure"),D.attr("transform","translate("+c.left+","+c.top+")");var H=function(a){return Math.abs(z(a)-z(0))},I=function(a){return z(0>a?a:0)};G.select("rect.nv-rangeMax").attr("height",s).attr("width",H(B>0?B:A)).attr("x",I(B>0?B:A)).datum(B>0?B:A),G.select("rect.nv-rangeAvg").attr("height",s).attr("width",H(C)).attr("x",I(C)).datum(C),G.select("rect.nv-rangeMin").attr("height",s).attr("width",H(B)).attr("x",I(B)).attr("width",H(B>0?A:B)).attr("x",I(B>0?A:B)).datum(B>0?A:B),G.select("rect.nv-measure").style("fill",q).attr("height",s/3).attr("y",s/3).attr("width",0>v?z(0)-z(v[0]):z(v[0])-z(0)).attr("x",I(v)).on("mouseover",function(){r.elementMouseover({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})}).on("mousemove",function(){r.elementMousemove({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})}).on("mouseout",function(){r.elementMouseout({value:v[0],label:y[0]||"Current",color:d3.select(this).style("fill")})});var J=s/6,K=u.map(function(a,b){return{value:a,label:x[b]}});F.selectAll("path.nv-markerTriangle").data(K).enter().append("path").attr("class","nv-markerTriangle").attr("transform",function(a){return"translate("+z(a.value)+","+s/2+")"}).attr("d","M0,"+J+"L"+J+","+-J+" "+-J+","+-J+"Z").on("mouseover",function(a){r.elementMouseover({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill"),pos:[z(a.value),s/2]})}).on("mousemove",function(a){r.elementMousemove({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){r.elementMouseout({value:a.value,label:a.label||"Previous",color:d3.select(this).style("fill")})}),D.selectAll(".nv-range").on("mouseover",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");r.elementMouseover({value:a,label:c,color:d3.select(this).style("fill")})}).on("mousemove",function(){r.elementMousemove({value:v[0],label:y[0]||"Previous",color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){var c=w[b]||(b?1==b?"Mean":"Minimum":"Maximum");r.elementMouseout({value:a,label:c,color:d3.select(this).style("fill")})})}),b}var c={top:0,right:0,bottom:0,left:0},d="left",e=!1,f=function(a){return a.ranges},g=function(a){return a.markers?a.markers:[0]},h=function(a){return a.measures},i=function(a){return a.rangeLabels?a.rangeLabels:[]},j=function(a){return a.markerLabels?a.markerLabels:[]},k=function(a){return a.measureLabels?a.measureLabels:[]},l=[0],m=380,n=30,o=null,p=null,q=a.utils.getColor(["#1f77b4"]),r=d3.dispatch("elementMouseover","elementMouseout","elementMousemove");return b.dispatch=r,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return f},set:function(a){f=a}},markers:{get:function(){return g},set:function(a){g=a}},measures:{get:function(){return h},set:function(a){h=a}},forceX:{get:function(){return l},set:function(a){l=a}},width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},tickFormat:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},orient:{get:function(){return d},set:function(a){d=a,e="right"==d||"bottom"==d}},color:{get:function(){return q},set:function(b){q=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.bulletChart=function(){"use strict";function b(d){return d.each(function(e,o){var p=d3.select(this);a.utils.initSVG(p);var q=a.utils.availableWidth(k,p,g),r=l-g.top-g.bottom;if(b.update=function(){b(d)},b.container=this,!e||!h.call(this,e,o))return a.utils.noData(b,p),b;p.selectAll(".nv-noData").remove();var s=h.call(this,e,o).slice().sort(d3.descending),t=i.call(this,e,o).slice().sort(d3.descending),u=j.call(this,e,o).slice().sort(d3.descending),v=p.selectAll("g.nv-wrap.nv-bulletChart").data([e]),w=v.enter().append("g").attr("class","nvd3 nv-wrap nv-bulletChart"),x=w.append("g"),y=v.select("g");x.append("g").attr("class","nv-bulletWrap"),x.append("g").attr("class","nv-titles"),v.attr("transform","translate("+g.left+","+g.top+")");var z=d3.scale.linear().domain([0,Math.max(s[0],t[0],u[0])]).range(f?[q,0]:[0,q]),A=this.__chart__||d3.scale.linear().domain([0,1/0]).range(z.range());this.__chart__=z;var B=x.select(".nv-titles").append("g").attr("text-anchor","end").attr("transform","translate(-6,"+(l-g.top-g.bottom)/2+")");B.append("text").attr("class","nv-title").text(function(a){return a.title}),B.append("text").attr("class","nv-subtitle").attr("dy","1em").text(function(a){return a.subtitle}),c.width(q).height(r);var C=y.select(".nv-bulletWrap");d3.transition(C).call(c);var D=m||z.tickFormat(q/100),E=y.selectAll("g.nv-tick").data(z.ticks(n?n:q/50),function(a){return this.textContent||D(a)}),F=E.enter().append("g").attr("class","nv-tick").attr("transform",function(a){return"translate("+A(a)+",0)"}).style("opacity",1e-6);F.append("line").attr("y1",r).attr("y2",7*r/6),F.append("text").attr("text-anchor","middle").attr("dy","1em").attr("y",7*r/6).text(D);var G=d3.transition(E).attr("transform",function(a){return"translate("+z(a)+",0)"}).style("opacity",1);G.select("line").attr("y1",r).attr("y2",7*r/6),G.select("text").attr("y",7*r/6),d3.transition(E.exit()).attr("transform",function(a){return"translate("+z(a)+",0)"}).style("opacity",1e-6).remove()}),d3.timer.flush(),b}var c=a.models.bullet(),d=a.models.tooltip(),e="left",f=!1,g={top:5,right:40,bottom:20,left:120},h=function(a){return a.ranges},i=function(a){return a.markers?a.markers:[0]},j=function(a){return a.measures},k=null,l=55,m=null,n=null,o=null,p=d3.dispatch("tooltipShow","tooltipHide");return d.duration(0).headerEnabled(!1),c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:a.label,value:a.value,color:a.color},d.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(a){d.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(a){d.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.bullet=c,b.dispatch=p,b.tooltip=d,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{ranges:{get:function(){return h},set:function(a){h=a}},markers:{get:function(){return i},set:function(a){i=a}},measures:{get:function(){return j},set:function(a){j=a}},width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},tickFormat:{get:function(){return m},set:function(a){m=a}},ticks:{get:function(){return n},set:function(a){n=a}},noData:{get:function(){return o},set:function(a){o=a}},tooltips:{get:function(){return d.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),d.enabled(!!b)}},tooltipContent:{get:function(){return d.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),d.contentGenerator(b)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},orient:{get:function(){return e},set:function(a){e=a,f="right"==e||"bottom"==e}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.candlestickBar=function(){"use strict";function b(x){return x.each(function(b){c=d3.select(this);var x=a.utils.availableWidth(i,c,h),y=a.utils.availableHeight(j,c,h);a.utils.initSVG(c);var A=x/b[0].values.length*.45;l.domain(d||d3.extent(b[0].values.map(n).concat(t))),v?l.range(f||[.5*x/b[0].values.length,x*(b[0].values.length-.5)/b[0].values.length]):l.range(f||[5+A/2,x-A/2-5]),m.domain(e||[d3.min(b[0].values.map(s).concat(u)),d3.max(b[0].values.map(r).concat(u))]).range(g||[y,0]),l.domain()[0]===l.domain()[1]&&(l.domain()[0]?l.domain([l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]):l.domain([-1,1])),m.domain()[0]===m.domain()[1]&&(m.domain()[0]?m.domain([m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]):m.domain([-1,1]));var B=d3.select(this).selectAll("g.nv-wrap.nv-candlestickBar").data([b[0].values]),C=B.enter().append("g").attr("class","nvd3 nv-wrap nv-candlestickBar"),D=C.append("defs"),E=C.append("g"),F=B.select("g");E.append("g").attr("class","nv-ticks"),B.attr("transform","translate("+h.left+","+h.top+")"),c.on("click",function(a,b){z.chartClick({data:a,index:b,pos:d3.event,id:k})}),D.append("clipPath").attr("id","nv-chart-clip-path-"+k).append("rect"),B.select("#nv-chart-clip-path-"+k+" rect").attr("width",x).attr("height",y),F.attr("clip-path",w?"url(#nv-chart-clip-path-"+k+")":"");var G=B.select(".nv-ticks").selectAll(".nv-tick").data(function(a){return a});G.exit().remove();var H=G.enter().append("g").attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b});H.append("line").attr("class","nv-candlestick-lines").attr("transform",function(a,b){return"translate("+l(n(a,b))+",0)"}).attr("x1",0).attr("y1",function(a,b){return m(r(a,b))}).attr("x2",0).attr("y2",function(a,b){return m(s(a,b))}),H.append("rect").attr("class","nv-candlestick-rects nv-bars").attr("transform",function(a,b){return"translate("+(l(n(a,b))-A/2)+","+(m(o(a,b))-(p(a,b)>q(a,b)?m(q(a,b))-m(p(a,b)):0))+")"}).attr("x",0).attr("y",0).attr("width",A).attr("height",function(a,b){var c=p(a,b),d=q(a,b);return c>d?m(d)-m(c):m(c)-m(d)});c.selectAll(".nv-candlestick-lines").transition().attr("transform",function(a,b){return"translate("+l(n(a,b))+",0)"}).attr("x1",0).attr("y1",function(a,b){return m(r(a,b))}).attr("x2",0).attr("y2",function(a,b){return m(s(a,b))}),c.selectAll(".nv-candlestick-rects").transition().attr("transform",function(a,b){return"translate("+(l(n(a,b))-A/2)+","+(m(o(a,b))-(p(a,b)>q(a,b)?m(q(a,b))-m(p(a,b)):0))+")"}).attr("x",0).attr("y",0).attr("width",A).attr("height",function(a,b){var c=p(a,b),d=q(a,b);return c>d?m(d)-m(c):m(c)-m(d)})}),b}var c,d,e,f,g,h={top:0,right:0,bottom:0,left:0},i=null,j=null,k=Math.floor(1e4*Math.random()),l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=function(a){return a.open},q=function(a){return a.close},r=function(a){return a.high},s=function(a){return a.low},t=[],u=[],v=!1,w=!0,x=a.utils.defaultColor(),y=!1,z=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove");return b.highlightPoint=function(a,d){b.clearHighlights(),c.select(".nv-candlestickBar .nv-tick-0-"+a).classed("hover",d)},b.clearHighlights=function(){c.select(".nv-candlestickBar .nv-tick.hover").classed("hover",!1)},b.dispatch=z,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return i},set:function(a){i=a}},height:{get:function(){return j},set:function(a){j=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},padData:{get:function(){return v},set:function(a){v=a}},clipEdge:{get:function(){return w},set:function(a){w=a}},id:{get:function(){return k},set:function(a){k=a}},interactive:{get:function(){return y},set:function(a){y=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},open:{get:function(){return p()},set:function(a){p=a}},close:{get:function(){return q()},set:function(a){q=a}},high:{get:function(){return r},set:function(a){r=a}},low:{get:function(){return s},set:function(a){s=a}},margin:{get:function(){return h},set:function(a){h.top=void 0!=a.top?a.top:h.top,h.right=void 0!=a.right?a.right:h.right,h.bottom=void 0!=a.bottom?a.bottom:h.bottom,h.left=void 0!=a.left?a.left:h.left}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.cumulativeLineChart=function(){"use strict";function b(l){return H.reset(),H.models(f),r&&H.models(g),s&&H.models(h),l.each(function(l){function A(a,c){d3.select(b.container).style("cursor","ew-resize")}function E(a,b){G.x=d3.event.x,G.i=Math.round(F.invert(G.x)),K()}function H(a,c){d3.select(b.container).style("cursor","auto"),y.index=G.i,C.stateChange(y)}function K(){ba.data([G]);var a=b.duration();b.duration(0),b.update(),b.duration(a)}var L=d3.select(this);a.utils.initSVG(L),L.classed("nv-chart-"+x,!0);var M=this,N=a.utils.availableWidth(o,L,m),O=a.utils.availableHeight(p,L,m);if(b.update=function(){0===D?L.call(b):L.transition().duration(D).call(b)},b.container=this,y.setter(J(l),b.update).getter(I(l)).update(),y.disabled=l.map(function(a){return!!a.disabled}),!z){var P;z={};for(P in y)y[P]instanceof Array?z[P]=y[P].slice(0):z[P]=y[P]}var Q=d3.behavior.drag().on("dragstart",A).on("drag",E).on("dragend",H);if(!(l&&l.length&&l.filter(function(a){return a.values.length}).length))return a.utils.noData(b,L),b;if(L.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale(),w)f.yDomain(null);else{var R=l.filter(function(a){return!a.disabled}).map(function(a,b){var c=d3.extent(a.values,f.y());return c[0]<-.95&&(c[0]=-.95),[(c[0]-c[1])/(1+c[1]),(c[1]-c[0])/(1+c[0])]}),S=[d3.min(R,function(a){return a[0]}),d3.max(R,function(a){return a[1]})];f.yDomain(S)}F.domain([0,l[0].values.length-1]).range([0,N]).clamp(!0);var l=c(G.i,l),T=v?"none":"all",U=L.selectAll("g.nv-wrap.nv-cumulativeLine").data([l]),V=U.enter().append("g").attr("class","nvd3 nv-wrap nv-cumulativeLine").append("g"),W=U.select("g");if(V.append("g").attr("class","nv-interactive"),V.append("g").attr("class","nv-x nv-axis").style("pointer-events","none"),V.append("g").attr("class","nv-y nv-axis"),V.append("g").attr("class","nv-background"),V.append("g").attr("class","nv-linesWrap").style("pointer-events",T),V.append("g").attr("class","nv-avgLinesWrap").style("pointer-events","none"),V.append("g").attr("class","nv-legendWrap"),V.append("g").attr("class","nv-controlsWrap"),q&&(i.width(N),W.select(".nv-legendWrap").datum(l).call(i),m.top!=i.height()&&(m.top=i.height(),O=a.utils.availableHeight(p,L,m)),W.select(".nv-legendWrap").attr("transform","translate(0,"+-m.top+")")),u){var X=[{key:"Re-scale y-axis",disabled:!w}];j.width(140).color(["#444","#444","#444"]).rightAlign(!1).margin({top:5,right:0,bottom:5,left:20}),W.select(".nv-controlsWrap").datum(X).attr("transform","translate(0,"+-m.top+")").call(j)}U.attr("transform","translate("+m.left+","+m.top+")"),t&&W.select(".nv-y.nv-axis").attr("transform","translate("+N+",0)");var Y=l.filter(function(a){return a.tempDisabled});U.select(".tempDisabled").remove(),Y.length&&U.append("text").attr("class","tempDisabled").attr("x",N/2).attr("y","-.71em").style("text-anchor","end").text(Y.map(function(a){return a.key}).join(", ")+" values cannot be calculated for this time period."),v&&(k.width(N).height(O).margin({left:m.left,top:m.top}).svgContainer(L).xScale(d),U.select(".nv-interactive").call(k)),V.select(".nv-background").append("rect"),W.select(".nv-background rect").attr("width",N).attr("height",O),f.y(function(a){return a.display.y}).width(N).height(O).color(l.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!l[b].disabled&&!l[b].tempDisabled}));var Z=W.select(".nv-linesWrap").datum(l.filter(function(a){return!a.disabled&&!a.tempDisabled}));Z.call(f),l.forEach(function(a,b){a.seriesIndex=b});var $=l.filter(function(a){return!a.disabled&&!!B(a)}),_=W.select(".nv-avgLinesWrap").selectAll("line").data($,function(a){return a.key}),aa=function(a){var b=e(B(a));return 0>b?0:b>O?O:b};_.enter().append("line").style("stroke-width",2).style("stroke-dasharray","10,10").style("stroke",function(a,b){return f.color()(a,a.seriesIndex)}).attr("x1",0).attr("x2",N).attr("y1",aa).attr("y2",aa),_.style("stroke-opacity",function(a){var b=e(B(a));return 0>b||b>O?0:1}).attr("x1",0).attr("x2",N).attr("y1",aa).attr("y2",aa),_.exit().remove();var ba=Z.selectAll(".nv-indexLine").data([G]);ba.enter().append("rect").attr("class","nv-indexLine").attr("width",3).attr("x",-2).attr("fill","red").attr("fill-opacity",.5).style("pointer-events","all").call(Q),ba.attr("transform",function(a){return"translate("+F(a.i)+",0)"}).attr("height",O),r&&(g.scale(d)._ticks(a.utils.calcTicksX(N/70,l)).tickSize(-O,0),W.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),W.select(".nv-x.nv-axis").call(g)),s&&(h.scale(e)._ticks(a.utils.calcTicksY(O/36,l)).tickSize(-N,0),W.select(".nv-y.nv-axis").call(h)),W.select(".nv-background rect").on("click",function(){G.x=d3.mouse(this)[0],G.i=Math.round(F.invert(G.x)),y.index=G.i,C.stateChange(y),K()}),f.dispatch.on("elementClick",function(a){G.i=a.pointIndex,G.x=F(G.i),y.index=G.i,C.stateChange(y),K()}),j.dispatch.on("legendClick",function(a,c){a.disabled=!a.disabled,w=!a.disabled,y.rescaleY=w,C.stateChange(y),b.update()}),i.dispatch.on("stateChange",function(a){for(var c in a)y[c]=a[c];C.stateChange(y),b.update()}),k.dispatch.on("elementMousemove",function(c){f.clearHighlights();var d,e,i,j=[];if(l.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g,h){e=a.interactiveBisect(g.values,c.pointXValue,b.x()),f.highlightPoint(h,e,!0);var k=g.values[e];"undefined"!=typeof k&&("undefined"==typeof d&&(d=k),"undefined"==typeof i&&(i=b.xScale()(b.x()(k,e))),j.push({key:g.key,value:b.y()(k,e),color:n(g,g.seriesIndex)}))}),j.length>2){var o=b.yScale().invert(c.mouseY),p=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),q=.03*p,r=a.nearestValueIndex(j.map(function(a){return a.value}),o,q);null!==r&&(j[r].highlight=!0)}var s=g.tickFormat()(b.x()(d,e),e);k.tooltip.position({left:i+m.left,top:c.mouseY+m.top}).chartContainer(M.parentNode).valueFormatter(function(a,b){return h.tickFormat()(a)}).data({value:s,series:j})(),k.renderGuideLine(i)}),k.dispatch.on("elementMouseout",function(a){f.clearHighlights()}),C.on("changeState",function(a){"undefined"!=typeof a.disabled&&(l.forEach(function(b,c){b.disabled=a.disabled[c]}),y.disabled=a.disabled),"undefined"!=typeof a.index&&(G.i=a.index,G.x=F(G.i),y.index=a.index,ba.data([G])),"undefined"!=typeof a.rescaleY&&(w=a.rescaleY),b.update()})}),H.renderEnd("cumulativeLineChart immediate"),b}function c(a,b){return K||(K=f.y()),b.map(function(b,c){if(!b.values)return b;var d=b.values[a];if(null==d)return b;var e=K(d,a);return-.95>e&&!E?(b.tempDisabled=!0,b):(b.tempDisabled=!1,b.values=b.values.map(function(a,b){return a.display={y:(K(a,b)-e)/(1+e)},a}),b)})}var d,e,f=a.models.line(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.models.legend(),k=a.interactiveGuideline(),l=a.models.tooltip(),m={top:30,right:30,bottom:50,left:60},n=a.utils.defaultColor(),o=null,p=null,q=!0,r=!0,s=!0,t=!1,u=!0,v=!1,w=!0,x=f.id(),y=a.utils.state(),z=null,A=null,B=function(a){return a.average},C=d3.dispatch("stateChange","changeState","renderEnd"),D=250,E=!1;y.index=0,y.rescaleY=w,g.orient("bottom").tickPadding(7),h.orient(t?"right":"left"),l.valueFormatter(function(a,b){return h.tickFormat()(a,b)}).headerFormatter(function(a,b){return g.tickFormat()(a,b)}),j.updateState(!1);var F=d3.scale.linear(),G={i:0,x:0},H=a.utils.renderWatch(C,D),I=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),index:G.i,rescaleY:w}}},J=function(a){return function(b){void 0!==b.index&&(G.i=b.index),void 0!==b.rescaleY&&(w=b.rescaleY),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};f.dispatch.on("elementMouseover.tooltip",function(a){var c={x:b.x()(a.point),y:b.y()(a.point),color:a.point.color};a.point=c,l.data(a).position(a.pos).hidden(!1)}),f.dispatch.on("elementMouseout.tooltip",function(a){l.hidden(!0)});var K=null;return b.dispatch=C,b.lines=f,b.legend=i,b.controls=j,b.xAxis=g,b.yAxis=h,b.interactiveLayer=k,b.state=y,b.tooltip=l,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return o},set:function(a){o=a}},height:{get:function(){return p},set:function(a){p=a}},rescaleY:{get:function(){return w},set:function(a){w=a}},showControls:{get:function(){return u},set:function(a){u=a}},showLegend:{get:function(){return q},set:function(a){q=a}},average:{get:function(){return B},set:function(a){B=a}},defaultState:{get:function(){return z},set:function(a){z=a}},noData:{get:function(){return A},set:function(a){A=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},noErrorCheck:{get:function(){return E},set:function(a){E=a}},tooltips:{get:function(){return l.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),l.enabled(!!b)}},tooltipContent:{get:function(){return l.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),l.contentGenerator(b)}},margin:{get:function(){return m},set:function(a){m.top=void 0!==a.top?a.top:m.top,m.right=void 0!==a.right?a.right:m.right,m.bottom=void 0!==a.bottom?a.bottom:m.bottom,m.left=void 0!==a.left?a.left:m.left}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),i.color(n)}},useInteractiveGuideline:{get:function(){return v},set:function(a){v=a,a===!0&&(b.interactive(!1),b.useVoronoi(!1))}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,h.orient(a?"right":"left")}},duration:{get:function(){return D},set:function(a){D=a,f.duration(D),g.duration(D),h.duration(D),H.reset(D)}}}),a.utils.inheritOptions(b,f),a.utils.initOptions(b),b},a.models.discreteBar=function(){"use strict";function b(m){return y.reset(),m.each(function(b){var m=k-j.left-j.right,x=l-j.top-j.bottom;c=d3.select(this),a.utils.initSVG(c),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var z=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),y0:a.y0}})});n.domain(d||d3.merge(z).map(function(a){return a.x})).rangeBands(f||[0,m],.1),o.domain(e||d3.extent(d3.merge(z).map(function(a){return a.y}).concat(r))),t?o.range(g||[x-(o.domain()[0]<0?12:0),o.domain()[1]>0?12:0]):o.range(g||[x,0]),h=h||n,i=i||o.copy().range([o(0),o(0)]);var A=c.selectAll("g.nv-wrap.nv-discretebar").data([b]),B=A.enter().append("g").attr("class","nvd3 nv-wrap nv-discretebar"),C=B.append("g");A.select("g");C.append("g").attr("class","nv-groups"),A.attr("transform","translate("+j.left+","+j.top+")");var D=A.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});D.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),D.exit().watchTransition(y,"discreteBar: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),D.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),D.watchTransition(y,"discreteBar: groups").style("stroke-opacity",1).style("fill-opacity",.75);var E=D.selectAll("g.nv-bar").data(function(a){return a.values});E.exit().remove();var F=E.enter().append("g").attr("transform",function(a,b,c){return"translate("+(n(p(a,b))+.05*n.rangeBand())+", "+o(0)+")"}).on("mouseover",function(a,b){d3.select(this).classed("hover",!0),v.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),v.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){v.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){v.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){v.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()});F.append("rect").attr("height",0).attr("width",.9*n.rangeBand()/b.length),t?(F.append("text").attr("text-anchor","middle"),E.select("text").text(function(a,b){return u(q(a,b))}).watchTransition(y,"discreteBar: bars text").attr("x",.9*n.rangeBand()/2).attr("y",function(a,b){return q(a,b)<0?o(q(a,b))-o(0)+12:-4})):E.selectAll("text").remove(),E.attr("class",function(a,b){return q(a,b)<0?"nv-bar negative":"nv-bar positive"}).style("fill",function(a,b){return a.color||s(a,b)}).style("stroke",function(a,b){return a.color||s(a,b)}).select("rect").attr("class",w).watchTransition(y,"discreteBar: bars rect").attr("width",.9*n.rangeBand()/b.length),E.watchTransition(y,"discreteBar: bars").attr("transform",function(a,b){var c=n(p(a,b))+.05*n.rangeBand(),d=q(a,b)<0?o(0):o(0)-o(q(a,b))<1?o(0)-1:o(q(a,b));return"translate("+c+", "+d+")"}).select("rect").attr("height",function(a,b){return Math.max(Math.abs(o(q(a,b))-o(e&&e[0]||0))||1)}),h=n.copy(),i=o.copy()}),y.renderEnd("discreteBar immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=Math.floor(1e4*Math.random()),n=d3.scale.ordinal(),o=d3.scale.linear(),p=function(a){return a.x},q=function(a){return a.y},r=[0],s=a.utils.defaultColor(),t=!1,u=d3.format(",.2f"),v=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),w="discreteBar",x=250,y=a.utils.renderWatch(v,x);return b.dispatch=v,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},forceY:{get:function(){return r},set:function(a){r=a}},showValues:{get:function(){return t},set:function(a){t=a}},x:{get:function(){return p},set:function(a){p=a}},y:{get:function(){return q},set:function(a){q=a}},xScale:{get:function(){return n},set:function(a){n=a}},yScale:{get:function(){return o},set:function(a){o=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},valueFormat:{get:function(){return u},set:function(a){u=a}},id:{get:function(){return m},set:function(a){m=a}},rectClass:{get:function(){return w},set:function(a){w=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},color:{get:function(){return s},set:function(b){s=a.utils.getColor(b)}},duration:{get:function(){return x},set:function(a){x=a,y.reset(x)}}}),a.utils.initOptions(b),b},a.models.discreteBarChart=function(){"use strict";function b(h){return t.reset(),t.models(e),m&&t.models(f),n&&t.models(g),h.each(function(h){var l=d3.select(this);a.utils.initSVG(l);var q=a.utils.availableWidth(j,l,i),t=a.utils.availableHeight(k,l,i);if(b.update=function(){r.beforeUpdate(),l.transition().duration(s).call(b)},b.container=this,!(h&&h.length&&h.filter(function(a){return a.values.length}).length))return a.utils.noData(b,l),b;l.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale().clamp(!0);var u=l.selectAll("g.nv-wrap.nv-discreteBarWithAxes").data([h]),v=u.enter().append("g").attr("class","nvd3 nv-wrap nv-discreteBarWithAxes").append("g"),w=v.append("defs"),x=u.select("g");v.append("g").attr("class","nv-x nv-axis"),v.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),v.append("g").attr("class","nv-barsWrap"),x.attr("transform","translate("+i.left+","+i.top+")"),o&&x.select(".nv-y.nv-axis").attr("transform","translate("+q+",0)"),e.width(q).height(t);var y=x.select(".nv-barsWrap").datum(h.filter(function(a){return!a.disabled}));if(y.transition().call(e),w.append("clipPath").attr("id","nv-x-label-clip-"+e.id()).append("rect"), -x.select("#nv-x-label-clip-"+e.id()+" rect").attr("width",c.rangeBand()*(p?2:1)).attr("height",16).attr("x",-c.rangeBand()/(p?1:2)),m){f.scale(c)._ticks(a.utils.calcTicksX(q/100,h)).tickSize(-t,0),x.select(".nv-x.nv-axis").attr("transform","translate(0,"+(d.range()[0]+(e.showValues()&&d.domain()[0]<0?16:0))+")"),x.select(".nv-x.nv-axis").call(f);var z=x.select(".nv-x.nv-axis").selectAll("g");p&&z.selectAll("text").attr("transform",function(a,b,c){return"translate(0,"+(c%2==0?"5":"17")+")"})}n&&(g.scale(d)._ticks(a.utils.calcTicksY(t/36,h)).tickSize(-q,0),x.select(".nv-y.nv-axis").call(g)),x.select(".nv-zeroLine line").attr("x1",0).attr("x2",q).attr("y1",d(0)).attr("y2",d(0))}),t.renderEnd("discreteBar chart immediate"),b}var c,d,e=a.models.discreteBar(),f=a.models.axis(),g=a.models.axis(),h=a.models.tooltip(),i={top:15,right:10,bottom:50,left:60},j=null,k=null,l=a.utils.getColor(),m=!0,n=!0,o=!1,p=!1,q=null,r=d3.dispatch("beforeUpdate","renderEnd"),s=250;f.orient("bottom").showMaxMin(!1).tickFormat(function(a){return a}),g.orient(o?"right":"left").tickFormat(d3.format(",.1f")),h.duration(0).headerEnabled(!1).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).keyFormatter(function(a,b){return f.tickFormat()(a,b)});var t=a.utils.renderWatch(r,s);return e.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:b.x()(a.data),value:b.y()(a.data),color:a.color},h.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){h.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(a){h.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=r,b.discretebar=e,b.xAxis=f,b.yAxis=g,b.tooltip=h,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return j},set:function(a){j=a}},height:{get:function(){return k},set:function(a){k=a}},staggerLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return m},set:function(a){m=a}},showYAxis:{get:function(){return n},set:function(a){n=a}},noData:{get:function(){return q},set:function(a){q=a}},tooltips:{get:function(){return h.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),h.enabled(!!b)}},tooltipContent:{get:function(){return h.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),h.contentGenerator(b)}},margin:{get:function(){return i},set:function(a){i.top=void 0!==a.top?a.top:i.top,i.right=void 0!==a.right?a.right:i.right,i.bottom=void 0!==a.bottom?a.bottom:i.bottom,i.left=void 0!==a.left?a.left:i.left}},duration:{get:function(){return s},set:function(a){s=a,t.reset(s),e.duration(s),f.duration(s),g.duration(s)}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),e.color(l)}},rightAlignYAxis:{get:function(){return o},set:function(a){o=a,g.orient(a?"right":"left")}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.distribution=function(){"use strict";function b(k){return m.reset(),k.each(function(b){var k=(e-("x"===g?d.left+d.right:d.top+d.bottom),"x"==g?"y":"x"),l=d3.select(this);a.utils.initSVG(l),c=c||j;var n=l.selectAll("g.nv-distribution").data([b]),o=n.enter().append("g").attr("class","nvd3 nv-distribution"),p=(o.append("g"),n.select("g"));n.attr("transform","translate("+d.left+","+d.top+")");var q=p.selectAll("g.nv-dist").data(function(a){return a},function(a){return a.key});q.enter().append("g"),q.attr("class",function(a,b){return"nv-dist nv-series-"+b}).style("stroke",function(a,b){return i(a,b)});var r=q.selectAll("line.nv-dist"+g).data(function(a){return a.values});r.enter().append("line").attr(g+"1",function(a,b){return c(h(a,b))}).attr(g+"2",function(a,b){return c(h(a,b))}),m.transition(q.exit().selectAll("line.nv-dist"+g),"dist exit").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}).style("stroke-opacity",0).remove(),r.attr("class",function(a,b){return"nv-dist"+g+" nv-dist"+g+"-"+b}).attr(k+"1",0).attr(k+"2",f),m.transition(r,"dist").attr(g+"1",function(a,b){return j(h(a,b))}).attr(g+"2",function(a,b){return j(h(a,b))}),c=j.copy()}),m.renderEnd("distribution immediate"),b}var c,d={top:0,right:0,bottom:0,left:0},e=400,f=8,g="x",h=function(a){return a[g]},i=a.utils.defaultColor(),j=d3.scale.linear(),k=250,l=d3.dispatch("renderEnd"),m=a.utils.renderWatch(l,k);return b.options=a.utils.optionsFunc.bind(b),b.dispatch=l,b.margin=function(a){return arguments.length?(d.top="undefined"!=typeof a.top?a.top:d.top,d.right="undefined"!=typeof a.right?a.right:d.right,d.bottom="undefined"!=typeof a.bottom?a.bottom:d.bottom,d.left="undefined"!=typeof a.left?a.left:d.left,b):d},b.width=function(a){return arguments.length?(e=a,b):e},b.axis=function(a){return arguments.length?(g=a,b):g},b.size=function(a){return arguments.length?(f=a,b):f},b.getData=function(a){return arguments.length?(h=d3.functor(a),b):h},b.scale=function(a){return arguments.length?(j=a,b):j},b.color=function(c){return arguments.length?(i=a.utils.getColor(c),b):i},b.duration=function(a){return arguments.length?(k=a,m.reset(k),b):k},b},a.models.furiousLegend=function(){"use strict";function b(p){function q(a,b){return"furious"!=o?"#000":m?a.disengaged?g(a,b):"#fff":m?void 0:a.disabled?g(a,b):"#fff"}function r(a,b){return m&&"furious"==o?a.disengaged?"#fff":g(a,b):a.disabled?"#fff":g(a,b)}return p.each(function(b){var p=d-c.left-c.right,s=d3.select(this);a.utils.initSVG(s);var t=s.selectAll("g.nv-legend").data([b]),u=(t.enter().append("g").attr("class","nvd3 nv-legend").append("g"),t.select("g"));t.attr("transform","translate("+c.left+","+c.top+")");var v,w=u.selectAll(".nv-series").data(function(a){return"furious"!=o?a:a.filter(function(a){return m?!0:!a.disengaged})}),x=w.enter().append("g").attr("class","nv-series");if("classic"==o)x.append("circle").style("stroke-width",2).attr("class","nv-legend-symbol").attr("r",5),v=w.select("circle");else if("furious"==o){x.append("rect").style("stroke-width",2).attr("class","nv-legend-symbol").attr("rx",3).attr("ry",3),v=w.select("rect"),x.append("g").attr("class","nv-check-box").property("innerHTML",'').attr("transform","translate(-10,-8)scale(0.5)");var y=w.select(".nv-check-box");y.each(function(a,b){d3.select(this).selectAll("path").attr("stroke",q(a,b))})}x.append("text").attr("text-anchor","start").attr("class","nv-legend-text").attr("dy",".32em").attr("dx","8");var z=w.select("text.nv-legend-text");w.on("mouseover",function(a,b){n.legendMouseover(a,b)}).on("mouseout",function(a,b){n.legendMouseout(a,b)}).on("click",function(a,b){n.legendClick(a,b);var c=w.data();if(k){if("classic"==o)l?(c.forEach(function(a){a.disabled=!0}),a.disabled=!1):(a.disabled=!a.disabled,c.every(function(a){return a.disabled})&&c.forEach(function(a){a.disabled=!1}));else if("furious"==o)if(m)a.disengaged=!a.disengaged,a.userDisabled=void 0==a.userDisabled?!!a.disabled:a.userDisabled,a.disabled=a.disengaged||a.userDisabled;else if(!m){a.disabled=!a.disabled,a.userDisabled=a.disabled;var d=c.filter(function(a){return!a.disengaged});d.every(function(a){return a.userDisabled})&&c.forEach(function(a){a.disabled=a.userDisabled=!1})}n.stateChange({disabled:c.map(function(a){return!!a.disabled}),disengaged:c.map(function(a){return!!a.disengaged})})}}).on("dblclick",function(a,b){if(("furious"!=o||!m)&&(n.legendDblclick(a,b),k)){var c=w.data();c.forEach(function(a){a.disabled=!0,"furious"==o&&(a.userDisabled=a.disabled)}),a.disabled=!1,"furious"==o&&(a.userDisabled=a.disabled),n.stateChange({disabled:c.map(function(a){return!!a.disabled})})}}),w.classed("nv-disabled",function(a){return a.userDisabled}),w.exit().remove(),z.attr("fill",q).text(f);var A;switch(o){case"furious":A=23;break;case"classic":A=20}if(h){var B=[];w.each(function(b,c){var d,e=d3.select(this).select("text");try{if(d=e.node().getComputedTextLength(),0>=d)throw Error()}catch(f){d=a.utils.calcApproxTextWidth(e)}B.push(d+i)});for(var C=0,D=0,E=[];p>D&&Cp&&C>1;){E=[],C--;for(var F=0;F(E[F%C]||0)&&(E[F%C]=B[F]);D=E.reduce(function(a,b,c,d){return a+b})}for(var G=[],H=0,I=0;C>H;H++)G[H]=I,I+=E[H];w.attr("transform",function(a,b){return"translate("+G[b%C]+","+(5+Math.floor(b/C)*A)+")"}),j?u.attr("transform","translate("+(d-c.right-D)+","+c.top+")"):u.attr("transform","translate(0,"+c.top+")"),e=c.top+c.bottom+Math.ceil(B.length/C)*A}else{var J,K=5,L=5,M=0;w.attr("transform",function(a,b){var e=d3.select(this).select("text").node().getComputedTextLength()+i;return J=L,dM&&(M=L),"translate("+J+","+K+")"}),u.attr("transform","translate("+(d-c.right-M)+","+c.top+")"),e=c.top+c.bottom+K+15}"furious"==o&&v.attr("width",function(a,b){return z[0][b].getComputedTextLength()+27}).attr("height",18).attr("y",-9).attr("x",-15),v.style("fill",r).style("stroke",function(a,b){return a.color||g(a,b)})}),b}var c={top:5,right:0,bottom:5,left:0},d=400,e=20,f=function(a){return a.key},g=a.utils.getColor(),h=!0,i=28,j=!0,k=!0,l=!1,m=!1,n=d3.dispatch("legendClick","legendDblclick","legendMouseover","legendMouseout","stateChange"),o="classic";return b.dispatch=n,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},key:{get:function(){return f},set:function(a){f=a}},align:{get:function(){return h},set:function(a){h=a}},rightAlign:{get:function(){return j},set:function(a){j=a}},padding:{get:function(){return i},set:function(a){i=a}},updateState:{get:function(){return k},set:function(a){k=a}},radioButtonMode:{get:function(){return l},set:function(a){l=a}},expanded:{get:function(){return m},set:function(a){m=a}},vers:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.historicalBar=function(){"use strict";function b(x){return x.each(function(b){w.reset(),k=d3.select(this);var x=a.utils.availableWidth(h,k,g),y=a.utils.availableHeight(i,k,g);a.utils.initSVG(k),l.domain(c||d3.extent(b[0].values.map(n).concat(p))),r?l.range(e||[.5*x/b[0].values.length,x*(b[0].values.length-.5)/b[0].values.length]):l.range(e||[0,x]),m.domain(d||d3.extent(b[0].values.map(o).concat(q))).range(f||[y,0]),l.domain()[0]===l.domain()[1]&&(l.domain()[0]?l.domain([l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]):l.domain([-1,1])),m.domain()[0]===m.domain()[1]&&(m.domain()[0]?m.domain([m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]):m.domain([-1,1]));var z=k.selectAll("g.nv-wrap.nv-historicalBar-"+j).data([b[0].values]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBar-"+j),B=A.append("defs"),C=A.append("g"),D=z.select("g");C.append("g").attr("class","nv-bars"),z.attr("transform","translate("+g.left+","+g.top+")"),k.on("click",function(a,b){u.chartClick({data:a,index:b,pos:d3.event,id:j})}),B.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),z.select("#nv-chart-clip-path-"+j+" rect").attr("width",x).attr("height",y),D.attr("clip-path",s?"url(#nv-chart-clip-path-"+j+")":"");var E=z.select(".nv-bars").selectAll(".nv-bar").data(function(a){return a},function(a,b){return n(a,b)});E.exit().remove(),E.enter().append("rect").attr("x",0).attr("y",function(b,c){return a.utils.NaNtoZero(m(Math.max(0,o(b,c))))}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.abs(m(o(b,c))-m(0)))}).attr("transform",function(a,c){return"translate("+(l(n(a,c))-x/b[0].values.length*.45)+",0)"}).on("mouseover",function(a,b){v&&(d3.select(this).classed("hover",!0),u.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")}))}).on("mouseout",function(a,b){v&&(d3.select(this).classed("hover",!1),u.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")}))}).on("mousemove",function(a,b){v&&u.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){v&&(u.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation())}).on("dblclick",function(a,b){v&&(u.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation())}),E.attr("fill",function(a,b){return t(a,b)}).attr("class",function(a,b,c){return(o(a,b)<0?"nv-bar negative":"nv-bar positive")+" nv-bar-"+c+"-"+b}).watchTransition(w,"bars").attr("transform",function(a,c){return"translate("+(l(n(a,c))-x/b[0].values.length*.45)+",0)"}).attr("width",x/b[0].values.length*.9),E.watchTransition(w,"bars").attr("y",function(b,c){var d=o(b,c)<0?m(0):m(0)-m(o(b,c))<1?m(0)-1:m(o(b,c));return a.utils.NaNtoZero(d)}).attr("height",function(b,c){return a.utils.NaNtoZero(Math.max(Math.abs(m(o(b,c))-m(0)),1))})}),w.renderEnd("historicalBar immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=null,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=[],q=[0],r=!1,s=!0,t=a.utils.defaultColor(),u=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),v=!0,w=a.utils.renderWatch(u,0);return b.highlightPoint=function(a,b){k.select(".nv-bars .nv-bar-0-"+a).classed("hover",b)},b.clearHighlights=function(){k.select(".nv-bars .nv-bar.hover").classed("hover",!1)},b.dispatch=u,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},forceX:{get:function(){return p},set:function(a){p=a}},forceY:{get:function(){return q},set:function(a){q=a}},padData:{get:function(){return r},set:function(a){r=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},clipEdge:{get:function(){return s},set:function(a){s=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return v},set:function(a){v=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return t},set:function(b){t=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.historicalBarChart=function(b){"use strict";function c(b){return b.each(function(k){z.reset(),z.models(f),q&&z.models(g),r&&z.models(h);var w=d3.select(this),A=this;a.utils.initSVG(w);var B=a.utils.availableWidth(n,w,l),C=a.utils.availableHeight(o,w,l);if(c.update=function(){w.transition().duration(y).call(c)},c.container=this,u.disabled=k.map(function(a){return!!a.disabled}),!v){var D;v={};for(D in u)u[D]instanceof Array?v[D]=u[D].slice(0):v[D]=u[D]}if(!(k&&k.length&&k.filter(function(a){return a.values.length}).length))return a.utils.noData(c,w),c;w.selectAll(".nv-noData").remove(),d=f.xScale(),e=f.yScale();var E=w.selectAll("g.nv-wrap.nv-historicalBarChart").data([k]),F=E.enter().append("g").attr("class","nvd3 nv-wrap nv-historicalBarChart").append("g"),G=E.select("g");F.append("g").attr("class","nv-x nv-axis"),F.append("g").attr("class","nv-y nv-axis"),F.append("g").attr("class","nv-barsWrap"),F.append("g").attr("class","nv-legendWrap"),F.append("g").attr("class","nv-interactive"),p&&(i.width(B),G.select(".nv-legendWrap").datum(k).call(i),l.top!=i.height()&&(l.top=i.height(),C=a.utils.availableHeight(o,w,l)),E.select(".nv-legendWrap").attr("transform","translate(0,"+-l.top+")")),E.attr("transform","translate("+l.left+","+l.top+")"),s&&G.select(".nv-y.nv-axis").attr("transform","translate("+B+",0)"),t&&(j.width(B).height(C).margin({left:l.left,top:l.top}).svgContainer(w).xScale(d),E.select(".nv-interactive").call(j)),f.width(B).height(C).color(k.map(function(a,b){return a.color||m(a,b)}).filter(function(a,b){return!k[b].disabled}));var H=G.select(".nv-barsWrap").datum(k.filter(function(a){return!a.disabled}));H.transition().call(f),q&&(g.scale(d)._ticks(a.utils.calcTicksX(B/100,k)).tickSize(-C,0),G.select(".nv-x.nv-axis").attr("transform","translate(0,"+e.range()[0]+")"),G.select(".nv-x.nv-axis").transition().call(g)),r&&(h.scale(e)._ticks(a.utils.calcTicksY(C/36,k)).tickSize(-B,0),G.select(".nv-y.nv-axis").transition().call(h)),j.dispatch.on("elementMousemove",function(b){f.clearHighlights();var d,e,i,n=[];k.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(g,h){e=a.interactiveBisect(g.values,b.pointXValue,c.x()),f.highlightPoint(e,!0);var j=g.values[e];void 0!==j&&(void 0===d&&(d=j),void 0===i&&(i=c.xScale()(c.x()(j,e))),n.push({key:g.key,value:c.y()(j,e),color:m(g,g.seriesIndex),data:g.values[e]}))});var o=g.tickFormat()(c.x()(d,e));j.tooltip.position({left:i+l.left,top:b.mouseY+l.top}).chartContainer(A.parentNode).valueFormatter(function(a,b){return h.tickFormat()(a)}).data({value:o,index:e,series:n})(),j.renderGuideLine(i)}),j.dispatch.on("elementMouseout",function(a){x.tooltipHide(),f.clearHighlights()}),i.dispatch.on("legendClick",function(a,d){a.disabled=!a.disabled,k.filter(function(a){return!a.disabled}).length||k.map(function(a){return a.disabled=!1,E.selectAll(".nv-series").classed("disabled",!1),a}),u.disabled=k.map(function(a){return!!a.disabled}),x.stateChange(u),b.transition().call(c)}),i.dispatch.on("legendDblclick",function(a){k.forEach(function(a){a.disabled=!0}),a.disabled=!1,u.disabled=k.map(function(a){return!!a.disabled}),x.stateChange(u),c.update()}),x.on("changeState",function(a){"undefined"!=typeof a.disabled&&(k.forEach(function(b,c){b.disabled=a.disabled[c]}),u.disabled=a.disabled),c.update()})}),z.renderEnd("historicalBarChart immediate"),c}var d,e,f=b||a.models.historicalBar(),g=a.models.axis(),h=a.models.axis(),i=a.models.legend(),j=a.interactiveGuideline(),k=a.models.tooltip(),l={top:30,right:90,bottom:50,left:90},m=a.utils.defaultColor(),n=null,o=null,p=!1,q=!0,r=!0,s=!1,t=!1,u={},v=null,w=null,x=d3.dispatch("tooltipHide","stateChange","changeState","renderEnd"),y=250;g.orient("bottom").tickPadding(7),h.orient(s?"right":"left"),k.duration(0).headerEnabled(!1).valueFormatter(function(a,b){return h.tickFormat()(a,b)}).headerFormatter(function(a,b){return g.tickFormat()(a,b)});var z=a.utils.renderWatch(x,0);return f.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:c.x()(a.data),value:c.y()(a.data),color:a.color},k.data(a).hidden(!1)}),f.dispatch.on("elementMouseout.tooltip",function(a){k.hidden(!0)}),f.dispatch.on("elementMousemove.tooltip",function(a){k.position({top:d3.event.pageY,left:d3.event.pageX})()}),c.dispatch=x,c.bars=f,c.legend=i,c.xAxis=g,c.yAxis=h,c.interactiveLayer=j,c.tooltip=k,c.options=a.utils.optionsFunc.bind(c),c._options=Object.create({},{width:{get:function(){return n},set:function(a){n=a}},height:{get:function(){return o},set:function(a){o=a}},showLegend:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return q},set:function(a){q=a}},showYAxis:{get:function(){return r},set:function(a){r=a}},defaultState:{get:function(){return v},set:function(a){v=a}},noData:{get:function(){return w},set:function(a){w=a}},tooltips:{get:function(){return k.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),k.enabled(!!b)}},tooltipContent:{get:function(){return k.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),k.contentGenerator(b)}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b),i.color(m),f.color(m)}},duration:{get:function(){return y},set:function(a){y=a,z.reset(y),h.duration(y),g.duration(y)}},rightAlignYAxis:{get:function(){return s},set:function(a){s=a,h.orient(a?"right":"left")}},useInteractiveGuideline:{get:function(){return t},set:function(a){t=a,a===!0&&c.interactive(!1)}}}),a.utils.inheritOptions(c,f),a.utils.initOptions(c),c},a.models.ohlcBarChart=function(){var b=a.models.historicalBarChart(a.models.ohlcBar());return b.useInteractiveGuideline(!0),b.interactiveLayer.tooltip.contentGenerator(function(a){var c=a.series[0].data,d=c.open'+a.value+"
open:"+b.yAxis.tickFormat()(c.open)+"
close:"+b.yAxis.tickFormat()(c.close)+"
high"+b.yAxis.tickFormat()(c.high)+"
low:"+b.yAxis.tickFormat()(c.low)+"
"}),b},a.models.candlestickBarChart=function(){var b=a.models.historicalBarChart(a.models.candlestickBar());return b.useInteractiveGuideline(!0),b.interactiveLayer.tooltip.contentGenerator(function(a){var c=a.series[0].data,d=c.open'+a.value+"
open:"+b.yAxis.tickFormat()(c.open)+"
close:"+b.yAxis.tickFormat()(c.close)+"
high"+b.yAxis.tickFormat()(c.high)+"
low:"+b.yAxis.tickFormat()(c.low)+"
"}),b},a.models.legend=function(){"use strict";function b(p){function q(a,b){return"furious"!=o?"#000":m?a.disengaged?"#000":"#fff":m?void 0:(a.color||(a.color=g(a,b)),a.disabled?a.color:"#fff")}function r(a,b){return m&&"furious"==o&&a.disengaged?"#eee":a.color||g(a,b)}function s(a,b){return m&&"furious"==o?1:a.disabled?0:1}return p.each(function(b){var g=d-c.left-c.right,p=d3.select(this);a.utils.initSVG(p);var t=p.selectAll("g.nv-legend").data([b]),u=t.enter().append("g").attr("class","nvd3 nv-legend").append("g"),v=t.select("g");t.attr("transform","translate("+c.left+","+c.top+")");var w,x,y=v.selectAll(".nv-series").data(function(a){return"furious"!=o?a:a.filter(function(a){return m?!0:!a.disengaged})}),z=y.enter().append("g").attr("class","nv-series");switch(o){case"furious":x=23;break;case"classic":x=20}if("classic"==o)z.append("circle").style("stroke-width",2).attr("class","nv-legend-symbol").attr("r",5),w=y.select("circle");else if("furious"==o){z.append("rect").style("stroke-width",2).attr("class","nv-legend-symbol").attr("rx",3).attr("ry",3),w=y.select(".nv-legend-symbol"),z.append("g").attr("class","nv-check-box").property("innerHTML",'').attr("transform","translate(-10,-8)scale(0.5)");var A=y.select(".nv-check-box");A.each(function(a,b){d3.select(this).selectAll("path").attr("stroke",q(a,b))})}z.append("text").attr("text-anchor","start").attr("class","nv-legend-text").attr("dy",".32em").attr("dx","8");var B=y.select("text.nv-legend-text");y.on("mouseover",function(a,b){n.legendMouseover(a,b)}).on("mouseout",function(a,b){n.legendMouseout(a,b)}).on("click",function(a,b){n.legendClick(a,b);var c=y.data();if(k){if("classic"==o)l?(c.forEach(function(a){a.disabled=!0}),a.disabled=!1):(a.disabled=!a.disabled,c.every(function(a){return a.disabled})&&c.forEach(function(a){a.disabled=!1}));else if("furious"==o)if(m)a.disengaged=!a.disengaged,a.userDisabled=void 0==a.userDisabled?!!a.disabled:a.userDisabled,a.disabled=a.disengaged||a.userDisabled;else if(!m){a.disabled=!a.disabled,a.userDisabled=a.disabled;var d=c.filter(function(a){return!a.disengaged});d.every(function(a){return a.userDisabled})&&c.forEach(function(a){a.disabled=a.userDisabled=!1})}n.stateChange({disabled:c.map(function(a){return!!a.disabled}),disengaged:c.map(function(a){return!!a.disengaged})})}}).on("dblclick",function(a,b){if(("furious"!=o||!m)&&(n.legendDblclick(a,b),k)){var c=y.data();c.forEach(function(a){a.disabled=!0,"furious"==o&&(a.userDisabled=a.disabled)}),a.disabled=!1,"furious"==o&&(a.userDisabled=a.disabled),n.stateChange({disabled:c.map(function(a){return!!a.disabled})})}}),y.classed("nv-disabled",function(a){return a.userDisabled}),y.exit().remove(),B.attr("fill",q).text(f);var C=0;if(h){var D=[];y.each(function(b,c){var d,e=d3.select(this).select("text");try{if(d=e.node().getComputedTextLength(),0>=d)throw Error()}catch(f){d=a.utils.calcApproxTextWidth(e)}D.push(d+i)});var E=0,F=[];for(C=0;g>C&&Eg&&E>1;){F=[],E--;for(var G=0;G(F[G%E]||0)&&(F[G%E]=D[G]);C=F.reduce(function(a,b,c,d){return a+b})}for(var H=[],I=0,J=0;E>I;I++)H[I]=J,J+=F[I];y.attr("transform",function(a,b){return"translate("+H[b%E]+","+(5+Math.floor(b/E)*x)+")"}),j?v.attr("transform","translate("+(d-c.right-C)+","+c.top+")"):v.attr("transform","translate(0,"+c.top+")"),e=c.top+c.bottom+Math.ceil(D.length/E)*x}else{var K,L=5,M=5,N=0;y.attr("transform",function(a,b){var e=d3.select(this).select("text").node().getComputedTextLength()+i;return K=M,dN&&(N=M),K+N>C&&(C=K+N),"translate("+K+","+L+")"}),v.attr("transform","translate("+(d-c.right-N)+","+c.top+")"),e=c.top+c.bottom+L+15}if("furious"==o){w.attr("width",function(a,b){return B[0][b].getComputedTextLength()+27}).attr("height",18).attr("y",-9).attr("x",-15),u.insert("rect",":first-child").attr("class","nv-legend-bg").attr("fill","#eee").attr("opacity",0);var O=v.select(".nv-legend-bg");O.transition().duration(300).attr("x",-x).attr("width",C+x-12).attr("height",e+10).attr("y",-c.top-10).attr("opacity",m?1:0)}w.style("fill",r).style("fill-opacity",s).style("stroke",r)}),b}var c={top:5,right:0,bottom:5,left:0},d=400,e=20,f=function(a){return a.key},g=a.utils.getColor(),h=!0,i=32,j=!0,k=!0,l=!1,m=!1,n=d3.dispatch("legendClick","legendDblclick","legendMouseover","legendMouseout","stateChange"),o="classic";return b.dispatch=n,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},key:{get:function(){return f},set:function(a){f=a}},align:{get:function(){return h},set:function(a){h=a}},rightAlign:{get:function(){return j},set:function(a){j=a}},padding:{get:function(){return i},set:function(a){i=a}},updateState:{get:function(){return k},set:function(a){k=a}},radioButtonMode:{get:function(){return l},set:function(a){l=a}},expanded:{get:function(){return m},set:function(a){m=a}},vers:{get:function(){return o},set:function(a){o=a}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return g},set:function(b){g=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.line=function(){"use strict";function b(r){return v.reset(),v.models(e),r.each(function(b){i=d3.select(this);var r=a.utils.availableWidth(g,i,f),s=a.utils.availableHeight(h,i,f);a.utils.initSVG(i),c=e.xScale(),d=e.yScale(),t=t||c,u=u||d;var w=i.selectAll("g.nv-wrap.nv-line").data([b]),x=w.enter().append("g").attr("class","nvd3 nv-wrap nv-line"),y=x.append("defs"),z=x.append("g"),A=w.select("g");z.append("g").attr("class","nv-groups"),z.append("g").attr("class","nv-scatterWrap"),w.attr("transform","translate("+f.left+","+f.top+")"),e.width(r).height(s);var B=w.select(".nv-scatterWrap");B.call(e),y.append("clipPath").attr("id","nv-edge-clip-"+e.id()).append("rect"),w.select("#nv-edge-clip-"+e.id()+" rect").attr("width",r).attr("height",s>0?s:0),A.attr("clip-path",p?"url(#nv-edge-clip-"+e.id()+")":""),B.attr("clip-path",p?"url(#nv-edge-clip-"+e.id()+")":"");var C=w.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});C.enter().append("g").style("stroke-opacity",1e-6).style("stroke-width",function(a){return a.strokeWidth||j}).style("fill-opacity",1e-6),C.exit().remove(),C.attr("class",function(a,b){return(a.classed||"")+" nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return k(a,b)}).style("stroke",function(a,b){return k(a,b)}),C.watchTransition(v,"line: groups").style("stroke-opacity",1).style("fill-opacity",function(a){return a.fillOpacity||.5});var D=C.selectAll("path.nv-area").data(function(a){return o(a)?[a]:[]});D.enter().append("path").attr("class","nv-area").attr("d",function(b){return d3.svg.area().interpolate(q).defined(n).x(function(b,c){return a.utils.NaNtoZero(t(l(b,c)))}).y0(function(b,c){return a.utils.NaNtoZero(u(m(b,c)))}).y1(function(a,b){return u(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])}),C.exit().selectAll("path.nv-area").remove(),D.watchTransition(v,"line: areaPaths").attr("d",function(b){return d3.svg.area().interpolate(q).defined(n).x(function(b,d){return a.utils.NaNtoZero(c(l(b,d)))}).y0(function(b,c){return a.utils.NaNtoZero(d(m(b,c)))}).y1(function(a,b){return d(d.domain()[0]<=0?d.domain()[1]>=0?0:d.domain()[1]:d.domain()[0])}).apply(this,[b.values])});var E=C.selectAll("path.nv-line").data(function(a){return[a.values]});E.enter().append("path").attr("class","nv-line").attr("d",d3.svg.line().interpolate(q).defined(n).x(function(b,c){return a.utils.NaNtoZero(t(l(b,c)))}).y(function(b,c){return a.utils.NaNtoZero(u(m(b,c)))})),E.watchTransition(v,"line: linePaths").attr("d",d3.svg.line().interpolate(q).defined(n).x(function(b,d){return a.utils.NaNtoZero(c(l(b,d)))}).y(function(b,c){return a.utils.NaNtoZero(d(m(b,c)))})),t=c.copy(),u=d.copy()}),v.renderEnd("line immediate"),b}var c,d,e=a.models.scatter(),f={top:0,right:0,bottom:0,left:0},g=960,h=500,i=null,j=1.5,k=a.utils.defaultColor(),l=function(a){return a.x},m=function(a){return a.y},n=function(a,b){return!isNaN(m(a,b))&&null!==m(a,b)},o=function(a){return a.area},p=!1,q="linear",r=250,s=d3.dispatch("elementClick","elementMouseover","elementMouseout","renderEnd");e.pointSize(16).pointDomain([16,256]);var t,u,v=a.utils.renderWatch(s,r);return b.dispatch=s,b.scatter=e,e.dispatch.on("elementClick",function(){s.elementClick.apply(this,arguments)}),e.dispatch.on("elementMouseover",function(){s.elementMouseover.apply(this,arguments)}),e.dispatch.on("elementMouseout",function(){s.elementMouseout.apply(this,arguments)}),b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},defined:{get:function(){return n},set:function(a){n=a}},interpolate:{get:function(){return q},set:function(a){q=a}},clipEdge:{get:function(){return p},set:function(a){p=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}},duration:{get:function(){return r},set:function(a){r=a,v.reset(r),e.duration(r)}},isArea:{get:function(){return o},set:function(a){o=d3.functor(a)}},x:{get:function(){return l},set:function(a){l=a,e.x(a)}},y:{get:function(){return m},set:function(a){m=a,e.y(a)}},color:{get:function(){return k},set:function(b){k=a.utils.getColor(b),e.color(k)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.lineChart=function(){"use strict";function b(j){return y.reset(),y.models(e), -p&&y.models(f),q&&y.models(g),j.each(function(j){var v=d3.select(this),y=this;a.utils.initSVG(v);var B=a.utils.availableWidth(m,v,k),C=a.utils.availableHeight(n,v,k);if(b.update=function(){0===x?v.call(b):v.transition().duration(x).call(b)},b.container=this,t.setter(A(j),b.update).getter(z(j)).update(),t.disabled=j.map(function(a){return!!a.disabled}),!u){var D;u={};for(D in t)t[D]instanceof Array?u[D]=t[D].slice(0):u[D]=t[D]}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,v),b;v.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var E=v.selectAll("g.nv-wrap.nv-lineChart").data([j]),F=E.enter().append("g").attr("class","nvd3 nv-wrap nv-lineChart").append("g"),G=E.select("g");F.append("rect").style("opacity",0),F.append("g").attr("class","nv-x nv-axis"),F.append("g").attr("class","nv-y nv-axis"),F.append("g").attr("class","nv-linesWrap"),F.append("g").attr("class","nv-legendWrap"),F.append("g").attr("class","nv-interactive"),G.select("rect").attr("width",B).attr("height",C>0?C:0),o&&(h.width(B),G.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),C=a.utils.availableHeight(n,v,k)),E.select(".nv-legendWrap").attr("transform","translate(0,"+-k.top+")")),E.attr("transform","translate("+k.left+","+k.top+")"),r&&G.select(".nv-y.nv-axis").attr("transform","translate("+B+",0)"),s&&(i.width(B).height(C).margin({left:k.left,top:k.top}).svgContainer(v).xScale(c),E.select(".nv-interactive").call(i)),e.width(B).height(C).color(j.map(function(a,b){return a.color||l(a,b)}).filter(function(a,b){return!j[b].disabled}));var H=G.select(".nv-linesWrap").datum(j.filter(function(a){return!a.disabled}));H.call(e),p&&(f.scale(c)._ticks(a.utils.calcTicksX(B/100,j)).tickSize(-C,0),G.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),G.select(".nv-x.nv-axis").call(f)),q&&(g.scale(d)._ticks(a.utils.calcTicksY(C/36,j)).tickSize(-B,0),G.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)t[c]=a[c];w.stateChange(t),b.update()}),i.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,h,m,n=[];if(j.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,g){h=a.interactiveBisect(f.values,c.pointXValue,b.x());var i=f.values[h],j=b.y()(i,h);null!=j&&e.highlightPoint(g,h,!0),void 0!==i&&(void 0===d&&(d=i),void 0===m&&(m=b.xScale()(b.x()(i,h))),n.push({key:f.key,value:j,color:l(f,f.seriesIndex)}))}),n.length>2){var o=b.yScale().invert(c.mouseY),p=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),q=.03*p,r=a.nearestValueIndex(n.map(function(a){return a.value}),o,q);null!==r&&(n[r].highlight=!0)}var s=f.tickFormat()(b.x()(d,h));i.tooltip.position({left:c.mouseX+k.left,top:c.mouseY+k.top}).chartContainer(y.parentNode).valueFormatter(function(a,b){return null==a?"N/A":g.tickFormat()(a)}).data({value:s,index:h,series:n})(),i.renderGuideLine(m)}),i.dispatch.on("elementClick",function(c){var d,f=[];j.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(e){var g=a.interactiveBisect(e.values,c.pointXValue,b.x()),h=e.values[g];if("undefined"!=typeof h){"undefined"==typeof d&&(d=b.xScale()(b.x()(h,g)));var i=b.yScale()(b.y()(h,g));f.push({point:h,pointIndex:g,pos:[d,i],seriesIndex:e.seriesIndex,series:e})}}),e.dispatch.elementClick(f)}),i.dispatch.on("elementMouseout",function(a){e.clearHighlights()}),w.on("changeState",function(a){"undefined"!=typeof a.disabled&&j.length===a.disabled.length&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),t.disabled=a.disabled),b.update()})}),y.renderEnd("lineChart immediate"),b}var c,d,e=a.models.line(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.interactiveGuideline(),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=a.utils.defaultColor(),m=null,n=null,o=!0,p=!0,q=!0,r=!1,s=!1,t=a.utils.state(),u=null,v=null,w=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),x=250;f.orient("bottom").tickPadding(7),g.orient(r?"right":"left"),j.valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)});var y=a.utils.renderWatch(w,x),z=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},A=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){j.data(a).position(a.pos).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){j.hidden(!0)}),b.dispatch=w,b.lines=e,b.legend=h,b.xAxis=f,b.yAxis=g,b.interactiveLayer=i,b.tooltip=j,b.dispatch=w,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return o},set:function(a){o=a}},showXAxis:{get:function(){return p},set:function(a){p=a}},showYAxis:{get:function(){return q},set:function(a){q=a}},defaultState:{get:function(){return u},set:function(a){u=a}},noData:{get:function(){return v},set:function(a){v=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return x},set:function(a){x=a,y.reset(x),e.duration(x),f.duration(x),g.duration(x)}},color:{get:function(){return l},set:function(b){l=a.utils.getColor(b),h.color(l),e.color(l)}},rightAlignYAxis:{get:function(){return r},set:function(a){r=a,g.orient(r?"right":"left")}},useInteractiveGuideline:{get:function(){return s},set:function(a){s=a,s&&(e.interactive(!1),e.useVoronoi(!1))}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.linePlusBarChart=function(){"use strict";function b(v){return v.each(function(v){function J(a){var b=+("e"==a),c=b?1:-1,d=X/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function S(){u.empty()||u.extent(I),ka.data([u.empty()?e.domain():I]).each(function(a,b){var c=e(a[0])-e.range()[0],d=e.range()[1]-e(a[1]);d3.select(this).select(".left").attr("width",0>c?0:c),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>d?0:d)})}function T(){I=u.empty()?null:u.extent(),c=u.empty()?e.domain():u.extent(),K.brush({extent:c,brush:u}),S(),l.width(V).height(W).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),j.width(V).height(W).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var b=da.select(".nv-focus .nv-barsWrap").datum(Z.length?Z.map(function(a,b){return{key:a.key,values:a.values.filter(function(a,b){return l.x()(a,b)>=c[0]&&l.x()(a,b)<=c[1]})}}):[{values:[]}]),h=da.select(".nv-focus .nv-linesWrap").datum($[0].disabled?[{values:[]}]:$.map(function(a,b){return{area:a.area,fillOpacity:a.fillOpacity,key:a.key,values:a.values.filter(function(a,b){return j.x()(a,b)>=c[0]&&j.x()(a,b)<=c[1]})}}));d=Z.length?l.xScale():j.xScale(),n.scale(d)._ticks(a.utils.calcTicksX(V/100,v)).tickSize(-W,0),n.domain([Math.ceil(c[0]),Math.floor(c[1])]),da.select(".nv-x.nv-axis").transition().duration(L).call(n),b.transition().duration(L).call(l),h.transition().duration(L).call(j),da.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),p.scale(f)._ticks(a.utils.calcTicksY(W/36,v)).tickSize(-V,0),q.scale(g)._ticks(a.utils.calcTicksY(W/36,v)).tickSize(Z.length?0:-V,0),da.select(".nv-focus .nv-y1.nv-axis").style("opacity",Z.length?1:0),da.select(".nv-focus .nv-y2.nv-axis").style("opacity",$.length&&!$[0].disabled?1:0).attr("transform","translate("+d.range()[1]+",0)"),da.select(".nv-focus .nv-y1.nv-axis").transition().duration(L).call(p),da.select(".nv-focus .nv-y2.nv-axis").transition().duration(L).call(q)}var U=d3.select(this);a.utils.initSVG(U);var V=a.utils.availableWidth(y,U,w),W=a.utils.availableHeight(z,U,w)-(E?H:0),X=H-x.top-x.bottom;if(b.update=function(){U.transition().duration(L).call(b)},b.container=this,M.setter(R(v),b.update).getter(Q(v)).update(),M.disabled=v.map(function(a){return!!a.disabled}),!N){var Y;N={};for(Y in M)M[Y]instanceof Array?N[Y]=M[Y].slice(0):N[Y]=M[Y]}if(!(v&&v.length&&v.filter(function(a){return a.values.length}).length))return a.utils.noData(b,U),b;U.selectAll(".nv-noData").remove();var Z=v.filter(function(a){return!a.disabled&&a.bar}),$=v.filter(function(a){return!a.bar});d=l.xScale(),e=o.scale(),f=l.yScale(),g=j.yScale(),h=m.yScale(),i=k.yScale();var _=v.filter(function(a){return!a.disabled&&a.bar}).map(function(a){return a.values.map(function(a,b){return{x:A(a,b),y:B(a,b)}})}),aa=v.filter(function(a){return!a.disabled&&!a.bar}).map(function(a){return a.values.map(function(a,b){return{x:A(a,b),y:B(a,b)}})});d.range([0,V]),e.domain(d3.extent(d3.merge(_.concat(aa)),function(a){return a.x})).range([0,V]);var ba=U.selectAll("g.nv-wrap.nv-linePlusBar").data([v]),ca=ba.enter().append("g").attr("class","nvd3 nv-wrap nv-linePlusBar").append("g"),da=ba.select("g");ca.append("g").attr("class","nv-legendWrap");var ea=ca.append("g").attr("class","nv-focus");ea.append("g").attr("class","nv-x nv-axis"),ea.append("g").attr("class","nv-y1 nv-axis"),ea.append("g").attr("class","nv-y2 nv-axis"),ea.append("g").attr("class","nv-barsWrap"),ea.append("g").attr("class","nv-linesWrap");var fa=ca.append("g").attr("class","nv-context");if(fa.append("g").attr("class","nv-x nv-axis"),fa.append("g").attr("class","nv-y1 nv-axis"),fa.append("g").attr("class","nv-y2 nv-axis"),fa.append("g").attr("class","nv-barsWrap"),fa.append("g").attr("class","nv-linesWrap"),fa.append("g").attr("class","nv-brushBackground"),fa.append("g").attr("class","nv-x nv-brush"),D){var ga=t.align()?V/2:V,ha=t.align()?ga:0;t.width(ga),da.select(".nv-legendWrap").datum(v.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(a.bar?O:P),a})).call(t),w.top!=t.height()&&(w.top=t.height(),W=a.utils.availableHeight(z,U,w)-H),da.select(".nv-legendWrap").attr("transform","translate("+ha+","+-w.top+")")}ba.attr("transform","translate("+w.left+","+w.top+")"),da.select(".nv-context").style("display",E?"initial":"none"),m.width(V).height(X).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&v[b].bar})),k.width(V).height(X).color(v.map(function(a,b){return a.color||C(a,b)}).filter(function(a,b){return!v[b].disabled&&!v[b].bar}));var ia=da.select(".nv-context .nv-barsWrap").datum(Z.length?Z:[{values:[]}]),ja=da.select(".nv-context .nv-linesWrap").datum($[0].disabled?[{values:[]}]:$);da.select(".nv-context").attr("transform","translate(0,"+(W+w.bottom+x.top)+")"),ia.transition().call(m),ja.transition().call(k),G&&(o._ticks(a.utils.calcTicksX(V/100,v)).tickSize(-X,0),da.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+h.range()[0]+")"),da.select(".nv-context .nv-x.nv-axis").transition().call(o)),F&&(r.scale(h)._ticks(X/36).tickSize(-V,0),s.scale(i)._ticks(X/36).tickSize(Z.length?0:-V,0),da.select(".nv-context .nv-y3.nv-axis").style("opacity",Z.length?1:0).attr("transform","translate(0,"+e.range()[0]+")"),da.select(".nv-context .nv-y2.nv-axis").style("opacity",$.length?1:0).attr("transform","translate("+e.range()[1]+",0)"),da.select(".nv-context .nv-y1.nv-axis").transition().call(r),da.select(".nv-context .nv-y2.nv-axis").transition().call(s)),u.x(e).on("brush",T),I&&u.extent(I);var ka=da.select(".nv-brushBackground").selectAll("g").data([I||u.extent()]),la=ka.enter().append("g");la.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",X),la.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",X);var ma=da.select(".nv-x.nv-brush").call(u);ma.selectAll("rect").attr("height",X),ma.selectAll(".resize").append("path").attr("d",J),t.dispatch.on("stateChange",function(a){for(var c in a)M[c]=a[c];K.stateChange(M),b.update()}),K.on("changeState",function(a){"undefined"!=typeof a.disabled&&(v.forEach(function(b,c){b.disabled=a.disabled[c]}),M.disabled=a.disabled),b.update()}),T()}),b}var c,d,e,f,g,h,i,j=a.models.line(),k=a.models.line(),l=a.models.historicalBar(),m=a.models.historicalBar(),n=a.models.axis(),o=a.models.axis(),p=a.models.axis(),q=a.models.axis(),r=a.models.axis(),s=a.models.axis(),t=a.models.legend(),u=d3.svg.brush(),v=a.models.tooltip(),w={top:30,right:30,bottom:30,left:60},x={top:0,right:30,bottom:20,left:60},y=null,z=null,A=function(a){return a.x},B=function(a){return a.y},C=a.utils.defaultColor(),D=!0,E=!0,F=!1,G=!0,H=50,I=null,J=null,K=d3.dispatch("brush","stateChange","changeState"),L=0,M=a.utils.state(),N=null,O=" (left axis)",P=" (right axis)";j.clipEdge(!0),k.interactive(!1),n.orient("bottom").tickPadding(5),p.orient("left"),q.orient("right"),o.orient("bottom").tickPadding(5),r.orient("left"),s.orient("right"),v.headerEnabled(!0).headerFormatter(function(a,b){return n.tickFormat()(a,b)});var Q=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},R=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return j.dispatch.on("elementMouseover.tooltip",function(a){v.duration(100).valueFormatter(function(a,b){return q.tickFormat()(a,b)}).data(a).position(a.pos).hidden(!1)}),j.dispatch.on("elementMouseout.tooltip",function(a){v.hidden(!0)}),l.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={value:b.y()(a.data),color:a.color},v.duration(0).valueFormatter(function(a,b){return p.tickFormat()(a,b)}).data(a).hidden(!1)}),l.dispatch.on("elementMouseout.tooltip",function(a){v.hidden(!0)}),l.dispatch.on("elementMousemove.tooltip",function(a){v.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=K,b.legend=t,b.lines=j,b.lines2=k,b.bars=l,b.bars2=m,b.xAxis=n,b.x2Axis=o,b.y1Axis=p,b.y2Axis=q,b.y3Axis=r,b.y4Axis=s,b.tooltip=v,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return y},set:function(a){y=a}},height:{get:function(){return z},set:function(a){z=a}},showLegend:{get:function(){return D},set:function(a){D=a}},brushExtent:{get:function(){return I},set:function(a){I=a}},noData:{get:function(){return J},set:function(a){J=a}},focusEnable:{get:function(){return E},set:function(a){E=a}},focusHeight:{get:function(){return H},set:function(a){H=a}},focusShowAxisX:{get:function(){return G},set:function(a){G=a}},focusShowAxisY:{get:function(){return F},set:function(a){F=a}},legendLeftAxisHint:{get:function(){return O},set:function(a){O=a}},legendRightAxisHint:{get:function(){return P},set:function(a){P=a}},tooltips:{get:function(){return v.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),v.enabled(!!b)}},tooltipContent:{get:function(){return v.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),v.contentGenerator(b)}},margin:{get:function(){return w},set:function(a){w.top=void 0!==a.top?a.top:w.top,w.right=void 0!==a.right?a.right:w.right,w.bottom=void 0!==a.bottom?a.bottom:w.bottom,w.left=void 0!==a.left?a.left:w.left}},duration:{get:function(){return L},set:function(a){L=a}},color:{get:function(){return C},set:function(b){C=a.utils.getColor(b),t.color(C)}},x:{get:function(){return A},set:function(a){A=a,j.x(a),k.x(a),l.x(a),m.x(a)}},y:{get:function(){return B},set:function(a){B=a,j.y(a),k.y(a),l.y(a),m.y(a)}}}),a.utils.inheritOptions(b,j),a.utils.initOptions(b),b},a.models.lineWithFocusChart=function(){"use strict";function b(o){return o.each(function(o){function z(a){var b=+("e"==a),c=b?1:-1,d=M/3;return"M"+.5*c+","+d+"A6,6 0 0 "+b+" "+6.5*c+","+(d+6)+"V"+(2*d-6)+"A6,6 0 0 "+b+" "+.5*c+","+2*d+"ZM"+2.5*c+","+(d+8)+"V"+(2*d-8)+"M"+4.5*c+","+(d+8)+"V"+(2*d-8)}function G(){n.empty()||n.extent(y),U.data([n.empty()?e.domain():y]).each(function(a,b){var d=e(a[0])-c.range()[0],f=K-e(a[1]);d3.select(this).select(".left").attr("width",0>d?0:d),d3.select(this).select(".right").attr("x",e(a[1])).attr("width",0>f?0:f)})}function H(){y=n.empty()?null:n.extent();var a=n.empty()?e.domain():n.extent();if(!(Math.abs(a[0]-a[1])<=1)){A.brush({extent:a,brush:n}),G();var b=Q.select(".nv-focus .nv-linesWrap").datum(o.filter(function(a){return!a.disabled}).map(function(b,c){return{key:b.key,area:b.area,values:b.values.filter(function(b,c){return g.x()(b,c)>=a[0]&&g.x()(b,c)<=a[1]})}}));b.transition().duration(B).call(g),Q.select(".nv-focus .nv-x.nv-axis").transition().duration(B).call(i),Q.select(".nv-focus .nv-y.nv-axis").transition().duration(B).call(j)}}var I=d3.select(this),J=this;a.utils.initSVG(I);var K=a.utils.availableWidth(t,I,q),L=a.utils.availableHeight(u,I,q)-v,M=v-r.top-r.bottom;if(b.update=function(){I.transition().duration(B).call(b)},b.container=this,C.setter(F(o),b.update).getter(E(o)).update(),C.disabled=o.map(function(a){return!!a.disabled}),!D){var N;D={};for(N in C)C[N]instanceof Array?D[N]=C[N].slice(0):D[N]=C[N]}if(!(o&&o.length&&o.filter(function(a){return a.values.length}).length))return a.utils.noData(b,I),b;I.selectAll(".nv-noData").remove(),c=g.xScale(),d=g.yScale(),e=h.xScale(),f=h.yScale();var O=I.selectAll("g.nv-wrap.nv-lineWithFocusChart").data([o]),P=O.enter().append("g").attr("class","nvd3 nv-wrap nv-lineWithFocusChart").append("g"),Q=O.select("g");P.append("g").attr("class","nv-legendWrap");var R=P.append("g").attr("class","nv-focus");R.append("g").attr("class","nv-x nv-axis"),R.append("g").attr("class","nv-y nv-axis"),R.append("g").attr("class","nv-linesWrap"),R.append("g").attr("class","nv-interactive");var S=P.append("g").attr("class","nv-context");S.append("g").attr("class","nv-x nv-axis"),S.append("g").attr("class","nv-y nv-axis"),S.append("g").attr("class","nv-linesWrap"),S.append("g").attr("class","nv-brushBackground"),S.append("g").attr("class","nv-x nv-brush"),x&&(m.width(K),Q.select(".nv-legendWrap").datum(o).call(m),q.top!=m.height()&&(q.top=m.height(),L=a.utils.availableHeight(u,I,q)-v),Q.select(".nv-legendWrap").attr("transform","translate(0,"+-q.top+")")),O.attr("transform","translate("+q.left+","+q.top+")"),w&&(p.width(K).height(L).margin({left:q.left,top:q.top}).svgContainer(I).xScale(c),O.select(".nv-interactive").call(p)),g.width(K).height(L).color(o.map(function(a,b){return a.color||s(a,b)}).filter(function(a,b){return!o[b].disabled})),h.defined(g.defined()).width(K).height(M).color(o.map(function(a,b){return a.color||s(a,b)}).filter(function(a,b){return!o[b].disabled})),Q.select(".nv-context").attr("transform","translate(0,"+(L+q.bottom+r.top)+")");var T=Q.select(".nv-context .nv-linesWrap").datum(o.filter(function(a){return!a.disabled}));d3.transition(T).call(h),i.scale(c)._ticks(a.utils.calcTicksX(K/100,o)).tickSize(-L,0),j.scale(d)._ticks(a.utils.calcTicksY(L/36,o)).tickSize(-K,0),Q.select(".nv-focus .nv-x.nv-axis").attr("transform","translate(0,"+L+")"),n.x(e).on("brush",function(){H()}),y&&n.extent(y);var U=Q.select(".nv-brushBackground").selectAll("g").data([y||n.extent()]),V=U.enter().append("g");V.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",M),V.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",M);var W=Q.select(".nv-x.nv-brush").call(n);W.selectAll("rect").attr("height",M),W.selectAll(".resize").append("path").attr("d",z),H(),k.scale(e)._ticks(a.utils.calcTicksX(K/100,o)).tickSize(-M,0),Q.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),d3.transition(Q.select(".nv-context .nv-x.nv-axis")).call(k),l.scale(f)._ticks(a.utils.calcTicksY(M/36,o)).tickSize(-K,0),d3.transition(Q.select(".nv-context .nv-y.nv-axis")).call(l),Q.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+f.range()[0]+")"),m.dispatch.on("stateChange",function(a){for(var c in a)C[c]=a[c];A.stateChange(C),b.update()}),p.dispatch.on("elementMousemove",function(c){g.clearHighlights();var d,f,h,k=[];if(o.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(i,j){var l=n.empty()?e.domain():n.extent(),m=i.values.filter(function(a,b){return g.x()(a,b)>=l[0]&&g.x()(a,b)<=l[1]});f=a.interactiveBisect(m,c.pointXValue,g.x());var o=m[f],p=b.y()(o,f);null!=p&&g.highlightPoint(j,f,!0),void 0!==o&&(void 0===d&&(d=o),void 0===h&&(h=b.xScale()(b.x()(o,f))),k.push({key:i.key,value:b.y()(o,f),color:s(i,i.seriesIndex)}))}),k.length>2){var l=b.yScale().invert(c.mouseY),m=Math.abs(b.yScale().domain()[0]-b.yScale().domain()[1]),r=.03*m,t=a.nearestValueIndex(k.map(function(a){return a.value}),l,r);null!==t&&(k[t].highlight=!0)}var u=i.tickFormat()(b.x()(d,f));p.tooltip.position({left:c.mouseX+q.left,top:c.mouseY+q.top}).chartContainer(J.parentNode).valueFormatter(function(a,b){return null==a?"N/A":j.tickFormat()(a)}).data({value:u,index:f,series:k})(),p.renderGuideLine(h)}),p.dispatch.on("elementMouseout",function(a){g.clearHighlights()}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&o.forEach(function(b,c){b.disabled=a.disabled[c]}),b.update()})}),b}var c,d,e,f,g=a.models.line(),h=a.models.line(),i=a.models.axis(),j=a.models.axis(),k=a.models.axis(),l=a.models.axis(),m=a.models.legend(),n=d3.svg.brush(),o=a.models.tooltip(),p=a.interactiveGuideline(),q={top:30,right:30,bottom:30,left:60},r={top:0,right:30,bottom:20,left:60},s=a.utils.defaultColor(),t=null,u=null,v=50,w=!1,x=!0,y=null,z=null,A=d3.dispatch("brush","stateChange","changeState"),B=250,C=a.utils.state(),D=null;g.clipEdge(!0).duration(0),h.interactive(!1),i.orient("bottom").tickPadding(5),j.orient("left"),k.orient("bottom").tickPadding(5),l.orient("left"),o.valueFormatter(function(a,b){return j.tickFormat()(a,b)}).headerFormatter(function(a,b){return i.tickFormat()(a,b)});var E=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},F=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return g.dispatch.on("elementMouseover.tooltip",function(a){o.data(a).position(a.pos).hidden(!1)}),g.dispatch.on("elementMouseout.tooltip",function(a){o.hidden(!0)}),b.dispatch=A,b.legend=m,b.lines=g,b.lines2=h,b.xAxis=i,b.yAxis=j,b.x2Axis=k,b.y2Axis=l,b.interactiveLayer=p,b.tooltip=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return t},set:function(a){t=a}},height:{get:function(){return u},set:function(a){u=a}},focusHeight:{get:function(){return v},set:function(a){v=a}},showLegend:{get:function(){return x},set:function(a){x=a}},brushExtent:{get:function(){return y},set:function(a){y=a}},defaultState:{get:function(){return D},set:function(a){D=a}},noData:{get:function(){return z},set:function(a){z=a}},tooltips:{get:function(){return o.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),o.enabled(!!b)}},tooltipContent:{get:function(){return o.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),o.contentGenerator(b)}},margin:{get:function(){return q},set:function(a){q.top=void 0!==a.top?a.top:q.top,q.right=void 0!==a.right?a.right:q.right,q.bottom=void 0!==a.bottom?a.bottom:q.bottom,q.left=void 0!==a.left?a.left:q.left}},color:{get:function(){return s},set:function(b){s=a.utils.getColor(b),m.color(s)}},interpolate:{get:function(){return g.interpolate()},set:function(a){g.interpolate(a),h.interpolate(a)}},xTickFormat:{get:function(){return i.tickFormat()},set:function(a){i.tickFormat(a),k.tickFormat(a)}},yTickFormat:{get:function(){return j.tickFormat()},set:function(a){j.tickFormat(a),l.tickFormat(a)}},duration:{get:function(){return B},set:function(a){B=a,j.duration(B),l.duration(B),i.duration(B),k.duration(B)}},x:{get:function(){return g.x()},set:function(a){g.x(a),h.x(a)}},y:{get:function(){return g.y()},set:function(a){g.y(a),h.y(a)}},useInteractiveGuideline:{get:function(){return w},set:function(a){w=a,w&&(g.interactive(!1),g.useVoronoi(!1))}}}),a.utils.inheritOptions(b,g),a.utils.initOptions(b),b},a.models.multiBar=function(){"use strict";function b(G){return E.reset(),G.each(function(b){var G=k-j.left-j.right,H=l-j.top-j.bottom;p=d3.select(this),a.utils.initSVG(p);var I=0;if(z&&b.length&&(z=[{values:b[0].values.map(function(a){return{x:a.x,y:0,series:a.series,size:.01}})}]),v){var J=d3.layout.stack().offset(w).values(function(a){return a.values}).y(r)(!b.length&&z?z:b);J.forEach(function(a,c){a.nonStackable?(b[c].nonStackableSeries=I++,J[c]=b[c]):c>0&&J[c-1].nonStackable&&J[c].values.map(function(a,b){a.y0-=J[c-1].values[b].y,a.y1=a.y0+a.y})}),b=J}b.forEach(function(a,b){a.values.forEach(function(c){c.series=b,c.key=a.key})}),v&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a,f){if(!b[f].nonStackable){var g=a.values[c];g.size=Math.abs(g.y),g.y<0?(g.y1=e,e-=g.size):(g.y1=g.size+d,d+=g.size)}})});var K=d&&e?[]:b.map(function(a,b){return a.values.map(function(a,c){return{x:q(a,c),y:r(a,c),y0:a.y0,y1:a.y1,idx:b,yErr:s(a,c)}})});m.domain(d||d3.merge(K).map(function(a){return a.x})).rangeBands(f||[0,G],C),n.domain(e||d3.extent(d3.merge(d3.merge(K).map(function(a){var c=a.y;v&&!b[a.idx].nonStackable&&(c=a.y>0?a.y1:a.y1+a.y);var d=a.yErr;return d?d.length?[c+d[0],c+d[1]]:(d=Math.abs(d),[c-d,c+d]):[c]})).concat(t))).range(g||[H,0]),m.domain()[0]===m.domain()[1]&&(m.domain()[0]?m.domain([m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]):m.domain([-1,1])),n.domain()[0]===n.domain()[1]&&(n.domain()[0]?n.domain([n.domain()[0]+.01*n.domain()[0],n.domain()[1]-.01*n.domain()[1]]):n.domain([-1,1])),h=h||m,i=i||n;var L=p.selectAll("g.nv-wrap.nv-multibar").data([b]),M=L.enter().append("g").attr("class","nvd3 nv-wrap nv-multibar"),N=M.append("defs"),O=M.append("g"),P=L.select("g");O.append("g").attr("class","nv-groups"),L.attr("transform","translate("+j.left+","+j.top+")"),N.append("clipPath").attr("id","nv-edge-clip-"+o).append("rect"),L.select("#nv-edge-clip-"+o+" rect").attr("width",G).attr("height",H),P.attr("clip-path",u?"url(#nv-edge-clip-"+o+")":"");var Q=L.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});Q.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);var R=E.transition(Q.exit().selectAll("g.nv-bar"),"multibarExit",Math.min(100,B)).attr("y",function(a,c,d){var e=i(0)||0;return v&&b[a.series]&&!b[a.series].nonStackable&&(e=i(a.y0)),e}).attr("height",0).remove();R.delay&&R.delay(function(a,b){var c=b*(B/(F+1))-b;return c}),Q.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return x(a,b)}).style("stroke",function(a,b){return x(a,b)}),Q.style("stroke-opacity",1).style("fill-opacity",.75);var S=Q.selectAll("g.nv-bar").data(function(a){return z&&!b.length?z.values:a.values});S.exit().remove();var T=S.enter().append("g").attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}).attr("transform",function(a,c,d){var e=v&&!b[d].nonStackable?0:d*m.rangeBand()/b.length,f=i(v&&!b[d].nonStackable?a.y0:0)||0;return"translate("+e+","+f+")"});T.append("rect").attr("height",0).attr("width",function(a,c,d){return m.rangeBand()/(v&&!b[d].nonStackable?1:b.length)}).style("fill",function(a,b,c){return x(a,c,b)}).style("stroke",function(a,b,c){return x(a,c,b)}),S.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),D.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),D.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){D.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){D.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){D.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),s(b[0].values[0],0)&&(T.append("polyline"),S.select("polyline").attr("fill","none").attr("stroke",function(a,b,c){return y(a,c,b)}).attr("points",function(a,c){var d=s(a,c),e=.8*m.rangeBand()/(2*(v?1:b.length));d=d.length?d:[-Math.abs(d),Math.abs(d)],d=d.map(function(a){return n(a)-n(0)});var f=[[-e,d[0]],[e,d[0]],[0,d[0]],[0,d[1]],[-e,d[1]],[e,d[1]]];return f.map(function(a){return a.join(",")}).join(" ")}).attr("transform",function(a,c){var d=m.rangeBand()/(2*(v?1:b.length)),e=r(a,c)<0?n(r(a,c))-n(0):0;return"translate("+d+", "+e+")"})),S.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}),A&&(c||(c=b.map(function(){return!0})),S.select("rect").style("fill",function(a,b,d){return d3.rgb(A(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(A(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}));var U=S.watchTransition(E,"multibar",Math.min(250,B)).delay(function(a,c){return c*B/b[0].values.length});v?U.attr("transform",function(a,c,d){var e=0;e=b[d].nonStackable?r(a,c)<0?n(0):n(0)-n(r(a,c))<-1?n(0)-1:n(r(a,c))||0:n(a.y1);var f=0;b[d].nonStackable&&(f=a.series*m.rangeBand()/b.length,b.length!==I&&(f=b[d].nonStackableSeries*m.rangeBand()/(2*I)));var g=f+m(q(a,c));return"translate("+g+","+e+")"}).select("rect").attr("height",function(a,c,d){return b[d].nonStackable?Math.max(Math.abs(n(r(a,c))-n(0)),1)||0:Math.max(Math.abs(n(a.y+a.y0)-n(a.y0)),1)}).attr("width",function(a,c,d){if(b[d].nonStackable){var e=m.rangeBand()/I;return b.length!==I&&(e=m.rangeBand()/(2*I)),e}return m.rangeBand()}):U.attr("transform",function(a,c){var d=a.series*m.rangeBand()/b.length+m(q(a,c)),e=r(a,c)<0?n(0):n(0)-n(r(a,c))<1?n(0)-1:n(r(a,c))||0;return"translate("+d+","+e+")"}).select("rect").attr("width",m.rangeBand()/b.length).attr("height",function(a,b){return Math.max(Math.abs(n(r(a,b))-n(0)),1)||0}),h=m.copy(),i=n.copy(),b[0]&&b[0].values&&(F=b[0].values.length)}),E.renderEnd("multibar immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=d3.scale.ordinal(),n=d3.scale.linear(),o=Math.floor(1e4*Math.random()),p=null,q=function(a){return a.x},r=function(a){return a.y},s=function(a){return a.yErr},t=[0],u=!0,v=!1,w="zero",x=a.utils.defaultColor(),y=a.utils.defaultColor(),z=!1,A=null,B=500,C=.1,D=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),E=a.utils.renderWatch(D,B),F=0;return b.dispatch=D,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return q},set:function(a){q=a}},y:{get:function(){return r},set:function(a){r=a}},yErr:{get:function(){return s},set:function(a){s=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return t},set:function(a){t=a}},stacked:{get:function(){return v},set:function(a){v=a}},stackOffset:{get:function(){return w},set:function(a){w=a}},clipEdge:{get:function(){return u},set:function(a){u=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return o},set:function(a){o=a}},hideable:{get:function(){ -return z},set:function(a){z=a}},groupSpacing:{get:function(){return C},set:function(a){C=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return B},set:function(a){B=a,E.reset(B)}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}},barColor:{get:function(){return A},set:function(b){A=b?a.utils.getColor(b):null}},errorBarColor:{get:function(){return y},set:function(b){y=b?a.utils.getColor(b):null}}}),a.utils.initOptions(b),b},a.models.multiBarChart=function(){"use strict";function b(j){return D.reset(),D.models(e),r&&D.models(f),s&&D.models(g),j.each(function(j){var z=d3.select(this);a.utils.initSVG(z);var D=a.utils.availableWidth(l,z,k),H=a.utils.availableHeight(m,z,k);if(b.update=function(){0===C?z.call(b):z.transition().duration(C).call(b)},b.container=this,x.setter(G(j),b.update).getter(F(j)).update(),x.disabled=j.map(function(a){return!!a.disabled}),!y){var I;y={};for(I in x)x[I]instanceof Array?y[I]=x[I].slice(0):y[I]=x[I]}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,z),b;z.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var J=z.selectAll("g.nv-wrap.nv-multiBarWithLegend").data([j]),K=J.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarWithLegend").append("g"),L=J.select("g");if(K.append("g").attr("class","nv-x nv-axis"),K.append("g").attr("class","nv-y nv-axis"),K.append("g").attr("class","nv-barsWrap"),K.append("g").attr("class","nv-legendWrap"),K.append("g").attr("class","nv-controlsWrap"),q&&(h.width(D-B()),L.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),H=a.utils.availableHeight(m,z,k)),L.select(".nv-legendWrap").attr("transform","translate("+B()+","+-k.top+")")),o){var M=[{key:p.grouped||"Grouped",disabled:e.stacked()},{key:p.stacked||"Stacked",disabled:!e.stacked()}];i.width(B()).color(["#444","#444","#444"]),L.select(".nv-controlsWrap").datum(M).attr("transform","translate(0,"+-k.top+")").call(i)}J.attr("transform","translate("+k.left+","+k.top+")"),t&&L.select(".nv-y.nv-axis").attr("transform","translate("+D+",0)"),e.disabled(j.map(function(a){return a.disabled})).width(D).height(H).color(j.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!j[b].disabled}));var N=L.select(".nv-barsWrap").datum(j.filter(function(a){return!a.disabled}));if(N.call(e),r){f.scale(c)._ticks(a.utils.calcTicksX(D/100,j)).tickSize(-H,0),L.select(".nv-x.nv-axis").attr("transform","translate(0,"+d.range()[0]+")"),L.select(".nv-x.nv-axis").call(f);var O=L.select(".nv-x.nv-axis > g").selectAll("g");if(O.selectAll("line, text").style("opacity",1),v){var P=function(a,b){return"translate("+a+","+b+")"},Q=5,R=17;O.selectAll("text").attr("transform",function(a,b,c){return P(0,c%2==0?Q:R)});var S=d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;L.selectAll(".nv-x.nv-axis .nv-axisMaxMin text").attr("transform",function(a,b){return P(0,0===b||S%2!==0?R:Q)})}u&&O.filter(function(a,b){return b%Math.ceil(j[0].values.length/(D/100))!==0}).selectAll("text, line").style("opacity",0),w&&O.selectAll(".tick text").attr("transform","rotate("+w+" 0,0)").style("text-anchor",w>0?"start":"end"),L.select(".nv-x.nv-axis").selectAll("g.nv-axisMaxMin text").style("opacity",1)}s&&(g.scale(d)._ticks(a.utils.calcTicksY(H/36,j)).tickSize(-D,0),L.select(".nv-y.nv-axis").call(g)),h.dispatch.on("stateChange",function(a){for(var c in a)x[c]=a[c];A.stateChange(x),b.update()}),i.dispatch.on("legendClick",function(a,c){if(a.disabled){switch(M=M.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":case p.grouped:e.stacked(!1);break;case"Stacked":case p.stacked:e.stacked(!0)}x.stacked=e.stacked(),A.stateChange(x),b.update()}}),A.on("changeState",function(a){"undefined"!=typeof a.disabled&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),x.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),x.stacked=a.stacked,E=a.stacked),b.update()})}),D.renderEnd("multibarchart immediate"),b}var c,d,e=a.models.multiBar(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=null,m=null,n=a.utils.defaultColor(),o=!0,p={},q=!0,r=!0,s=!0,t=!1,u=!0,v=!1,w=0,x=a.utils.state(),y=null,z=null,A=d3.dispatch("stateChange","changeState","renderEnd"),B=function(){return o?180:0},C=250;x.stacked=!1,e.stacked(!1),f.orient("bottom").tickPadding(7).showMaxMin(!1).tickFormat(function(a){return a}),g.orient(t?"right":"left").tickFormat(d3.format(",.1f")),j.duration(0).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)}),i.updateState(!1);var D=a.utils.renderWatch(A),E=!1,F=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:E}}},G=function(a){return function(b){void 0!==b.stacked&&(E=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return e.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={key:a.data.key,value:b.y()(a.data),color:a.color},j.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){j.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(a){j.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=A,b.multibar=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.state=x,b.tooltip=j,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showControls:{get:function(){return o},set:function(a){o=a}},controlLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return y},set:function(a){y=a}},noData:{get:function(){return z},set:function(a){z=a}},reduceXTicks:{get:function(){return u},set:function(a){u=a}},rotateLabels:{get:function(){return w},set:function(a){w=a}},staggerLabels:{get:function(){return v},set:function(a){v=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return C},set:function(a){C=a,e.duration(C),f.duration(C),g.duration(C),D.reset(C)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n)}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,g.orient(t?"right":"left")}},barColor:{get:function(){return e.barColor},set:function(a){e.barColor(a),h.color(function(a,b){return d3.rgb("#ccc").darker(1.5*b).toString()})}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiBarHorizontal=function(){"use strict";function b(m){return F.reset(),m.each(function(b){var m=k-j.left-j.right,D=l-j.top-j.bottom;n=d3.select(this),a.utils.initSVG(n),x&&(b=d3.layout.stack().offset("zero").values(function(a){return a.values}).y(r)(b)),b.forEach(function(a,b){a.values.forEach(function(c){c.series=b,c.key=a.key})}),x&&b[0].values.map(function(a,c){var d=0,e=0;b.map(function(a){var b=a.values[c];b.size=Math.abs(b.y),b.y<0?(b.y1=e-b.size,e-=b.size):(b.y1=d,d+=b.size)})});var G=d&&e?[]:b.map(function(a){return a.values.map(function(a,b){return{x:q(a,b),y:r(a,b),y0:a.y0,y1:a.y1,yErr:s(a,b)}})});o.domain(d||d3.merge(G).map(function(a){return a.x})).rangeBands(f||[0,D],B),p.domain(e||d3.extent(d3.merge(d3.merge(G).map(function(a){var b=a.y;x&&(b=a.y>0?a.y1+a.y:a.y1);var c=a.yErr;return c?c.length?[b+c[0],b+c[1]]:(c=Math.abs(c),[b-c,b+c]):[b]})).concat(t))),y&&!x?p.range(g||[p.domain()[0]<0?A:0,m-(p.domain()[1]>0?A:0)]):p.range(g||[0,m]),h=h||o,i=i||d3.scale.linear().domain(p.domain()).range([p(0),p(0)]);var H=d3.select(this).selectAll("g.nv-wrap.nv-multibarHorizontal").data([b]),I=H.enter().append("g").attr("class","nvd3 nv-wrap nv-multibarHorizontal"),J=(I.append("defs"),I.append("g"));H.select("g");J.append("g").attr("class","nv-groups"),H.attr("transform","translate("+j.left+","+j.top+")");var K=H.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a,b){return b});K.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),K.exit().watchTransition(F,"multibarhorizontal: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),K.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}).style("fill",function(a,b){return u(a,b)}).style("stroke",function(a,b){return u(a,b)}),K.watchTransition(F,"multibarhorizontal: groups").style("stroke-opacity",1).style("fill-opacity",.75);var L=K.selectAll("g.nv-bar").data(function(a){return a.values});L.exit().remove();var M=L.enter().append("g").attr("transform",function(a,c,d){return"translate("+i(x?a.y0:0)+","+(x?0:d*o.rangeBand()/b.length+o(q(a,c)))+")"});M.append("rect").attr("width",0).attr("height",o.rangeBand()/(x?1:b.length)),L.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),E.elementMouseover({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1),E.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){E.elementMouseout({data:a,index:b,color:d3.select(this).style("fill")})}).on("mousemove",function(a,b){E.elementMousemove({data:a,index:b,color:d3.select(this).style("fill")})}).on("click",function(a,b){E.elementClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}).on("dblclick",function(a,b){E.elementDblClick({data:a,index:b,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),s(b[0].values[0],0)&&(M.append("polyline"),L.select("polyline").attr("fill","none").attr("stroke",function(a,b,c){return w(a,c,b)}).attr("points",function(a,c){var d=s(a,c),e=.8*o.rangeBand()/(2*(x?1:b.length));d=d.length?d:[-Math.abs(d),Math.abs(d)],d=d.map(function(a){return p(a)-p(0)});var f=[[d[0],-e],[d[0],e],[d[0],0],[d[1],0],[d[1],-e],[d[1],e]];return f.map(function(a){return a.join(",")}).join(" ")}).attr("transform",function(a,c){var d=o.rangeBand()/(2*(x?1:b.length));return"translate("+(r(a,c)<0?0:p(r(a,c))-p(0))+", "+d+")"})),M.append("text"),y&&!x?(L.select("text").attr("text-anchor",function(a,b){return r(a,b)<0?"end":"start"}).attr("y",o.rangeBand()/(2*b.length)).attr("dy",".32em").text(function(a,b){var c=C(r(a,b)),d=s(a,b);return void 0===d?c:d.length?c+"+"+C(Math.abs(d[1]))+"-"+C(Math.abs(d[0])):c+"±"+C(Math.abs(d))}),L.watchTransition(F,"multibarhorizontal: bars").select("text").attr("x",function(a,b){return r(a,b)<0?-4:p(r(a,b))-p(0)+4})):L.selectAll("text").text(""),z&&!x?(M.append("text").classed("nv-bar-label",!0),L.select("text.nv-bar-label").attr("text-anchor",function(a,b){return r(a,b)<0?"start":"end"}).attr("y",o.rangeBand()/(2*b.length)).attr("dy",".32em").text(function(a,b){return q(a,b)}),L.watchTransition(F,"multibarhorizontal: bars").select("text.nv-bar-label").attr("x",function(a,b){return r(a,b)<0?p(0)-p(r(a,b))+4:-4})):L.selectAll("text.nv-bar-label").text(""),L.attr("class",function(a,b){return r(a,b)<0?"nv-bar negative":"nv-bar positive"}),v&&(c||(c=b.map(function(){return!0})),L.style("fill",function(a,b,d){return d3.rgb(v(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()}).style("stroke",function(a,b,d){return d3.rgb(v(a,b)).darker(c.map(function(a,b){return b}).filter(function(a,b){return!c[b]})[d]).toString()})),x?L.watchTransition(F,"multibarhorizontal: bars").attr("transform",function(a,b){return"translate("+p(a.y1)+","+o(q(a,b))+")"}).select("rect").attr("width",function(a,b){return Math.abs(p(r(a,b)+a.y0)-p(a.y0))}).attr("height",o.rangeBand()):L.watchTransition(F,"multibarhorizontal: bars").attr("transform",function(a,c){return"translate("+p(r(a,c)<0?r(a,c):0)+","+(a.series*o.rangeBand()/b.length+o(q(a,c)))+")"}).select("rect").attr("height",o.rangeBand()/b.length).attr("width",function(a,b){return Math.max(Math.abs(p(r(a,b))-p(0)),1)}),h=o.copy(),i=p.copy()}),F.renderEnd("multibarHorizontal immediate"),b}var c,d,e,f,g,h,i,j={top:0,right:0,bottom:0,left:0},k=960,l=500,m=Math.floor(1e4*Math.random()),n=null,o=d3.scale.ordinal(),p=d3.scale.linear(),q=function(a){return a.x},r=function(a){return a.y},s=function(a){return a.yErr},t=[0],u=a.utils.defaultColor(),v=null,w=a.utils.defaultColor(),x=!1,y=!1,z=!1,A=60,B=.1,C=d3.format(",.2f"),D=250,E=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),F=a.utils.renderWatch(E,D);return b.dispatch=E,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},x:{get:function(){return q},set:function(a){q=a}},y:{get:function(){return r},set:function(a){r=a}},yErr:{get:function(){return s},set:function(a){s=a}},xScale:{get:function(){return o},set:function(a){o=a}},yScale:{get:function(){return p},set:function(a){p=a}},xDomain:{get:function(){return d},set:function(a){d=a}},yDomain:{get:function(){return e},set:function(a){e=a}},xRange:{get:function(){return f},set:function(a){f=a}},yRange:{get:function(){return g},set:function(a){g=a}},forceY:{get:function(){return t},set:function(a){t=a}},stacked:{get:function(){return x},set:function(a){x=a}},showValues:{get:function(){return y},set:function(a){y=a}},disabled:{get:function(){return c},set:function(a){c=a}},id:{get:function(){return m},set:function(a){m=a}},valueFormat:{get:function(){return C},set:function(a){C=a}},valuePadding:{get:function(){return A},set:function(a){A=a}},groupSpacing:{get:function(){return B},set:function(a){B=a}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},duration:{get:function(){return D},set:function(a){D=a,F.reset(D)}},color:{get:function(){return u},set:function(b){u=a.utils.getColor(b)}},barColor:{get:function(){return v},set:function(b){v=b?a.utils.getColor(b):null}},errorBarColor:{get:function(){return w},set:function(b){w=b?a.utils.getColor(b):null}}}),a.utils.initOptions(b),b},a.models.multiBarHorizontalChart=function(){"use strict";function b(j){return C.reset(),C.models(e),r&&C.models(f),s&&C.models(g),j.each(function(j){var w=d3.select(this);a.utils.initSVG(w);var C=a.utils.availableWidth(l,w,k),D=a.utils.availableHeight(m,w,k);if(b.update=function(){w.transition().duration(z).call(b)},b.container=this,t=e.stacked(),u.setter(B(j),b.update).getter(A(j)).update(),u.disabled=j.map(function(a){return!!a.disabled}),!v){var E;v={};for(E in u)u[E]instanceof Array?v[E]=u[E].slice(0):v[E]=u[E]}if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,w),b;w.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var F=w.selectAll("g.nv-wrap.nv-multiBarHorizontalChart").data([j]),G=F.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarHorizontalChart").append("g"),H=F.select("g");if(G.append("g").attr("class","nv-x nv-axis"),G.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),G.append("g").attr("class","nv-barsWrap"),G.append("g").attr("class","nv-legendWrap"),G.append("g").attr("class","nv-controlsWrap"),q&&(h.width(C-y()),H.select(".nv-legendWrap").datum(j).call(h),k.top!=h.height()&&(k.top=h.height(),D=a.utils.availableHeight(m,w,k)),H.select(".nv-legendWrap").attr("transform","translate("+y()+","+-k.top+")")),o){var I=[{key:p.grouped||"Grouped",disabled:e.stacked()},{key:p.stacked||"Stacked",disabled:!e.stacked()}];i.width(y()).color(["#444","#444","#444"]),H.select(".nv-controlsWrap").datum(I).attr("transform","translate(0,"+-k.top+")").call(i)}F.attr("transform","translate("+k.left+","+k.top+")"),e.disabled(j.map(function(a){return a.disabled})).width(C).height(D).color(j.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!j[b].disabled}));var J=H.select(".nv-barsWrap").datum(j.filter(function(a){return!a.disabled}));if(J.transition().call(e),r){f.scale(c)._ticks(a.utils.calcTicksY(D/24,j)).tickSize(-C,0),H.select(".nv-x.nv-axis").call(f);var K=H.select(".nv-x.nv-axis").selectAll("g");K.selectAll("line, text")}s&&(g.scale(d)._ticks(a.utils.calcTicksX(C/100,j)).tickSize(-D,0),H.select(".nv-y.nv-axis").attr("transform","translate(0,"+D+")"),H.select(".nv-y.nv-axis").call(g)),H.select(".nv-zeroLine line").attr("x1",d(0)).attr("x2",d(0)).attr("y1",0).attr("y2",-D),h.dispatch.on("stateChange",function(a){for(var c in a)u[c]=a[c];x.stateChange(u),b.update()}),i.dispatch.on("legendClick",function(a,c){if(a.disabled){switch(I=I.map(function(a){return a.disabled=!0,a}),a.disabled=!1,a.key){case"Grouped":e.stacked(!1);break;case"Stacked":e.stacked(!0)}u.stacked=e.stacked(),x.stateChange(u),t=e.stacked(),b.update()}}),x.on("changeState",function(a){"undefined"!=typeof a.disabled&&(j.forEach(function(b,c){b.disabled=a.disabled[c]}),u.disabled=a.disabled),"undefined"!=typeof a.stacked&&(e.stacked(a.stacked),u.stacked=a.stacked,t=a.stacked),b.update()})}),C.renderEnd("multibar horizontal chart immediate"),b}var c,d,e=a.models.multiBarHorizontal(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend().height(30),i=a.models.legend().height(30),j=a.models.tooltip(),k={top:30,right:20,bottom:50,left:60},l=null,m=null,n=a.utils.defaultColor(),o=!0,p={},q=!0,r=!0,s=!0,t=!1,u=a.utils.state(),v=null,w=null,x=d3.dispatch("stateChange","changeState","renderEnd"),y=function(){return o?180:0},z=250;u.stacked=!1,e.stacked(t),f.orient("left").tickPadding(5).showMaxMin(!1).tickFormat(function(a){return a}),g.orient("bottom").tickFormat(d3.format(",.1f")),j.duration(0).valueFormatter(function(a,b){return g.tickFormat()(a,b)}).headerFormatter(function(a,b){return f.tickFormat()(a,b)}),i.updateState(!1);var A=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),stacked:t}}},B=function(a){return function(b){void 0!==b.stacked&&(t=b.stacked),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}},C=a.utils.renderWatch(x,z);return e.dispatch.on("elementMouseover.tooltip",function(a){a.value=b.x()(a.data),a.series={key:a.data.key,value:b.y()(a.data),color:a.color},j.data(a).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){j.hidden(!0)}),e.dispatch.on("elementMousemove.tooltip",function(a){j.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=x,b.multibar=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.state=u,b.tooltip=j,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return l},set:function(a){l=a}},height:{get:function(){return m},set:function(a){m=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showControls:{get:function(){return o},set:function(a){o=a}},controlLabels:{get:function(){return p},set:function(a){p=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return v},set:function(a){v=a}},noData:{get:function(){return w},set:function(a){w=a}},tooltips:{get:function(){return j.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),j.enabled(!!b)}},tooltipContent:{get:function(){return j.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),j.contentGenerator(b)}},margin:{get:function(){return k},set:function(a){k.top=void 0!==a.top?a.top:k.top,k.right=void 0!==a.right?a.right:k.right,k.bottom=void 0!==a.bottom?a.bottom:k.bottom,k.left=void 0!==a.left?a.left:k.left}},duration:{get:function(){return z},set:function(a){z=a,C.reset(z),e.duration(z),f.duration(z),g.duration(z)}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),h.color(n)}},barColor:{get:function(){return e.barColor},set:function(a){e.barColor(a),h.color(function(a,b){return d3.rgb("#ccc").darker(1.5*b).toString()})}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.multiChart=function(){"use strict";function b(j){return j.each(function(j){function k(a){var b=2===j[a.seriesIndex].yAxis?z:y;a.value=a.point.x,a.series={value:a.point.y,color:a.point.color},B.duration(100).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).position(a.pos).hidden(!1)}function l(a){var b=2===j[a.seriesIndex].yAxis?z:y;a.point.x=v.x()(a.point),a.point.y=v.y()(a.point),B.duration(100).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).position(a.pos).hidden(!1)}function n(a){var b=2===j[a.data.series].yAxis?z:y;a.value=t.x()(a.data),a.series={value:t.y()(a.data),color:a.color},B.duration(0).valueFormatter(function(a,c){return b.tickFormat()(a,c)}).data(a).hidden(!1)}var C=d3.select(this);a.utils.initSVG(C),b.update=function(){C.transition().call(b)},b.container=this;var D=a.utils.availableWidth(g,C,e),E=a.utils.availableHeight(h,C,e),F=j.filter(function(a){return"line"==a.type&&1==a.yAxis}),G=j.filter(function(a){return"line"==a.type&&2==a.yAxis}),H=j.filter(function(a){return"bar"==a.type&&1==a.yAxis}),I=j.filter(function(a){return"bar"==a.type&&2==a.yAxis}),J=j.filter(function(a){return"area"==a.type&&1==a.yAxis}),K=j.filter(function(a){return"area"==a.type&&2==a.yAxis});if(!(j&&j.length&&j.filter(function(a){return a.values.length}).length))return a.utils.noData(b,C),b;C.selectAll(".nv-noData").remove();var L=j.filter(function(a){return!a.disabled&&1==a.yAxis}).map(function(a){return a.values.map(function(a,b){return{x:a.x,y:a.y}})}),M=j.filter(function(a){return!a.disabled&&2==a.yAxis}).map(function(a){return a.values.map(function(a,b){return{x:a.x,y:a.y}})});o.domain(d3.extent(d3.merge(L.concat(M)),function(a){return a.x})).range([0,D]);var N=C.selectAll("g.wrap.multiChart").data([j]),O=N.enter().append("g").attr("class","wrap nvd3 multiChart").append("g");O.append("g").attr("class","nv-x nv-axis"),O.append("g").attr("class","nv-y1 nv-axis"),O.append("g").attr("class","nv-y2 nv-axis"),O.append("g").attr("class","lines1Wrap"),O.append("g").attr("class","lines2Wrap"),O.append("g").attr("class","bars1Wrap"),O.append("g").attr("class","bars2Wrap"),O.append("g").attr("class","stack1Wrap"),O.append("g").attr("class","stack2Wrap"),O.append("g").attr("class","legendWrap");var P=N.select("g"),Q=j.map(function(a,b){return j[b].color||f(a,b)});if(i){var R=A.align()?D/2:D,S=A.align()?R:0;A.width(R),A.color(Q),P.select(".legendWrap").datum(j.map(function(a){return a.originalKey=void 0===a.originalKey?a.key:a.originalKey,a.key=a.originalKey+(1==a.yAxis?"":" (right axis)"),a})).call(A),e.top!=A.height()&&(e.top=A.height(),E=a.utils.availableHeight(h,C,e)),P.select(".legendWrap").attr("transform","translate("+S+","+-e.top+")")}r.width(D).height(E).interpolate(m).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"line"==j[b].type})),s.width(D).height(E).interpolate(m).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"line"==j[b].type})),t.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"bar"==j[b].type})),u.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"bar"==j[b].type})),v.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&1==j[b].yAxis&&"area"==j[b].type})),w.width(D).height(E).color(Q.filter(function(a,b){return!j[b].disabled&&2==j[b].yAxis&&"area"==j[b].type})),P.attr("transform","translate("+e.left+","+e.top+")");var T=P.select(".lines1Wrap").datum(F.filter(function(a){return!a.disabled})),U=P.select(".bars1Wrap").datum(H.filter(function(a){return!a.disabled})),V=P.select(".stack1Wrap").datum(J.filter(function(a){return!a.disabled})),W=P.select(".lines2Wrap").datum(G.filter(function(a){return!a.disabled})),X=P.select(".bars2Wrap").datum(I.filter(function(a){return!a.disabled})),Y=P.select(".stack2Wrap").datum(K.filter(function(a){return!a.disabled})),Z=J.length?J.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[],$=K.length?K.map(function(a){return a.values}).reduce(function(a,b){return a.map(function(a,c){return{x:a.x,y:a.y+b[c].y}})}).concat([{x:0,y:0}]):[];p.domain(c||d3.extent(d3.merge(L).concat(Z),function(a){return a.y})).range([0,E]),q.domain(d||d3.extent(d3.merge(M).concat($),function(a){return a.y})).range([0,E]),r.yDomain(p.domain()),t.yDomain(p.domain()),v.yDomain(p.domain()),s.yDomain(q.domain()),u.yDomain(q.domain()),w.yDomain(q.domain()),J.length&&d3.transition(V).call(v),K.length&&d3.transition(Y).call(w),H.length&&d3.transition(U).call(t),I.length&&d3.transition(X).call(u),F.length&&d3.transition(T).call(r),G.length&&d3.transition(W).call(s),x._ticks(a.utils.calcTicksX(D/100,j)).tickSize(-E,0),P.select(".nv-x.nv-axis").attr("transform","translate(0,"+E+")"),d3.transition(P.select(".nv-x.nv-axis")).call(x),y._ticks(a.utils.calcTicksY(E/36,j)).tickSize(-D,0),d3.transition(P.select(".nv-y1.nv-axis")).call(y),z._ticks(a.utils.calcTicksY(E/36,j)).tickSize(-D,0),d3.transition(P.select(".nv-y2.nv-axis")).call(z),P.select(".nv-y1.nv-axis").classed("nv-disabled",L.length?!1:!0).attr("transform","translate("+o.range()[0]+",0)"),P.select(".nv-y2.nv-axis").classed("nv-disabled",M.length?!1:!0).attr("transform","translate("+o.range()[1]+",0)"),A.dispatch.on("stateChange",function(a){b.update()}),r.dispatch.on("elementMouseover.tooltip",k),s.dispatch.on("elementMouseover.tooltip",k),r.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),s.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),v.dispatch.on("elementMouseover.tooltip",l),w.dispatch.on("elementMouseover.tooltip",l),v.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),w.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),t.dispatch.on("elementMouseover.tooltip",n),u.dispatch.on("elementMouseover.tooltip",n),t.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),u.dispatch.on("elementMouseout.tooltip",function(a){B.hidden(!0)}),t.dispatch.on("elementMousemove.tooltip",function(a){B.position({top:d3.event.pageY,left:d3.event.pageX})()}),u.dispatch.on("elementMousemove.tooltip",function(a){B.position({top:d3.event.pageY,left:d3.event.pageX})()})}),b}var c,d,e={top:30,right:20,bottom:50,left:60},f=a.utils.defaultColor(),g=null,h=null,i=!0,j=null,k=function(a){return a.x},l=function(a){return a.y},m="monotone",n=!0,o=d3.scale.linear(),p=d3.scale.linear(),q=d3.scale.linear(),r=a.models.line().yScale(p),s=a.models.line().yScale(q),t=a.models.multiBar().stacked(!1).yScale(p),u=a.models.multiBar().stacked(!1).yScale(q),v=a.models.stackedArea().yScale(p),w=a.models.stackedArea().yScale(q),x=a.models.axis().scale(o).orient("bottom").tickPadding(5),y=a.models.axis().scale(p).orient("left"),z=a.models.axis().scale(q).orient("right"),A=a.models.legend().height(30),B=a.models.tooltip(),C=d3.dispatch();return b.dispatch=C,b.lines1=r,b.lines2=s,b.bars1=t,b.bars2=u,b.stack1=v,b.stack2=w,b.xAxis=x,b.yAxis1=y,b.yAxis2=z,b.tooltip=B,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},showLegend:{get:function(){return i},set:function(a){i=a}},yDomain1:{get:function(){return c},set:function(a){c=a}},yDomain2:{get:function(){return d},set:function(a){d=a}},noData:{get:function(){return j},set:function(a){j=a}},interpolate:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return B.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),B.enabled(!!b)}},tooltipContent:{get:function(){return B.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),B.contentGenerator(b)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},color:{get:function(){return f},set:function(b){f=a.utils.getColor(b)}},x:{get:function(){return k},set:function(a){k=a,r.x(a),s.x(a),t.x(a),u.x(a),v.x(a),w.x(a)}},y:{get:function(){return l},set:function(a){l=a,r.y(a),s.y(a),v.y(a),w.y(a),t.y(a),u.y(a)}},useVoronoi:{get:function(){return n},set:function(a){n=a,r.useVoronoi(a),s.useVoronoi(a),v.useVoronoi(a),w.useVoronoi(a)}}}),a.utils.initOptions(b),b},a.models.ohlcBar=function(){"use strict";function b(y){return y.each(function(b){k=d3.select(this);var y=a.utils.availableWidth(h,k,g),A=a.utils.availableHeight(i,k,g);a.utils.initSVG(k);var B=y/b[0].values.length*.9;l.domain(c||d3.extent(b[0].values.map(n).concat(t))),v?l.range(e||[.5*y/b[0].values.length,y*(b[0].values.length-.5)/b[0].values.length]):l.range(e||[5+B/2,y-B/2-5]),m.domain(d||[d3.min(b[0].values.map(s).concat(u)),d3.max(b[0].values.map(r).concat(u))]).range(f||[A,0]),l.domain()[0]===l.domain()[1]&&(l.domain()[0]?l.domain([l.domain()[0]-.01*l.domain()[0],l.domain()[1]+.01*l.domain()[1]]):l.domain([-1,1])),m.domain()[0]===m.domain()[1]&&(m.domain()[0]?m.domain([m.domain()[0]+.01*m.domain()[0],m.domain()[1]-.01*m.domain()[1]]):m.domain([-1,1]));var C=d3.select(this).selectAll("g.nv-wrap.nv-ohlcBar").data([b[0].values]),D=C.enter().append("g").attr("class","nvd3 nv-wrap nv-ohlcBar"),E=D.append("defs"),F=D.append("g"),G=C.select("g");F.append("g").attr("class","nv-ticks"),C.attr("transform","translate("+g.left+","+g.top+")"),k.on("click",function(a,b){z.chartClick({data:a,index:b,pos:d3.event,id:j})}),E.append("clipPath").attr("id","nv-chart-clip-path-"+j).append("rect"),C.select("#nv-chart-clip-path-"+j+" rect").attr("width",y).attr("height",A),G.attr("clip-path",w?"url(#nv-chart-clip-path-"+j+")":"");var H=C.select(".nv-ticks").selectAll(".nv-tick").data(function(a){return a});H.exit().remove(),H.enter().append("path").attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}).attr("d",function(a,b){return"m0,0l0,"+(m(p(a,b))-m(r(a,b)))+"l"+-B/2+",0l"+B/2+",0l0,"+(m(s(a,b))-m(p(a,b)))+"l0,"+(m(q(a,b))-m(s(a,b)))+"l"+B/2+",0l"+-B/2+",0z"}).attr("transform",function(a,b){return"translate("+l(n(a,b))+","+m(r(a,b))+")"}).attr("fill",function(a,b){return x[0]}).attr("stroke",function(a,b){return x[0]}).attr("x",0).attr("y",function(a,b){return m(Math.max(0,o(a,b)))}).attr("height",function(a,b){return Math.abs(m(o(a,b))-m(0))}),H.attr("class",function(a,b,c){return(p(a,b)>q(a,b)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+c+"-"+b}),d3.transition(H).attr("transform",function(a,b){return"translate("+l(n(a,b))+","+m(r(a,b))+")"}).attr("d",function(a,c){var d=y/b[0].values.length*.9;return"m0,0l0,"+(m(p(a,c))-m(r(a,c)))+"l"+-d/2+",0l"+d/2+",0l0,"+(m(s(a,c))-m(p(a,c)))+"l0,"+(m(q(a,c))-m(s(a,c)))+"l"+d/2+",0l"+-d/2+",0z"})}),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=Math.floor(1e4*Math.random()),k=null,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=function(a){return a.open},q=function(a){return a.close},r=function(a){return a.high},s=function(a){return a.low; -},t=[],u=[],v=!1,w=!0,x=a.utils.defaultColor(),y=!1,z=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove");return b.highlightPoint=function(a,c){b.clearHighlights(),k.select(".nv-ohlcBar .nv-tick-0-"+a).classed("hover",c)},b.clearHighlights=function(){k.select(".nv-ohlcBar .nv-tick.hover").classed("hover",!1)},b.dispatch=z,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},padData:{get:function(){return v},set:function(a){v=a}},clipEdge:{get:function(){return w},set:function(a){w=a}},id:{get:function(){return j},set:function(a){j=a}},interactive:{get:function(){return y},set:function(a){y=a}},x:{get:function(){return n},set:function(a){n=a}},y:{get:function(){return o},set:function(a){o=a}},open:{get:function(){return p()},set:function(a){p=a}},close:{get:function(){return q()},set:function(a){q=a}},high:{get:function(){return r},set:function(a){r=a}},low:{get:function(){return s},set:function(a){s=a}},margin:{get:function(){return g},set:function(a){g.top=void 0!=a.top?a.top:g.top,g.right=void 0!=a.right?a.right:g.right,g.bottom=void 0!=a.bottom?a.bottom:g.bottom,g.left=void 0!=a.left?a.left:g.left}},color:{get:function(){return x},set:function(b){x=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.parallelCoordinates=function(){"use strict";function b(p){return p.each(function(b){function p(a){return F(h.map(function(b){if(isNaN(a[b])||isNaN(parseFloat(a[b]))){var c=g[b].domain(),d=g[b].range(),e=c[0]-(c[1]-c[0])/9;if(J.indexOf(b)<0){var h=d3.scale.linear().domain([e,c[1]]).range([x-12,d[1]]);g[b].brush.y(h),J.push(b)}return[f(b),g[b](e)]}return J.length>0?(D.style("display","inline"),E.style("display","inline")):(D.style("display","none"),E.style("display","none")),[f(b),g[b](a[b])]}))}function q(){var a=h.filter(function(a){return!g[a].brush.empty()}),b=a.map(function(a){return g[a].brush.extent()});k=[],a.forEach(function(a,c){k[c]={dimension:a,extent:b[c]}}),l=[],M.style("display",function(c){var d=a.every(function(a,d){return isNaN(c[a])&&b[d][0]==g[a].brush.y().domain()[0]?!0:b[d][0]<=c[a]&&c[a]<=b[d][1]});return d&&l.push(c),d?null:"none"}),o.brush({filters:k,active:l})}function r(a,b){m[a]=this.parentNode.__origin__=f(a),L.attr("visibility","hidden")}function s(a,b){m[a]=Math.min(w,Math.max(0,this.parentNode.__origin__+=d3.event.x)),M.attr("d",p),h.sort(function(a,b){return u(a)-u(b)}),f.domain(h),N.attr("transform",function(a){return"translate("+u(a)+")"})}function t(a,b){delete this.parentNode.__origin__,delete m[a],d3.select(this.parentNode).attr("transform","translate("+f(a)+")"),M.attr("d",p),L.attr("d",p).attr("visibility",null)}function u(a){var b=m[a];return null==b?f(a):b}var v=d3.select(this),w=a.utils.availableWidth(d,v,c),x=a.utils.availableHeight(e,v,c);a.utils.initSVG(v),l=b,f.rangePoints([0,w],1).domain(h);var y={};h.forEach(function(a){var c=d3.extent(b,function(b){return+b[a]});return y[a]=!1,void 0===c[0]&&(y[a]=!0,c[0]=0,c[1]=0),c[0]===c[1]&&(c[0]=c[0]-1,c[1]=c[1]+1),g[a]=d3.scale.linear().domain(c).range([.9*(x-12),0]),g[a].brush=d3.svg.brush().y(g[a]).on("brush",q),"name"!=a});var z=v.selectAll("g.nv-wrap.nv-parallelCoordinates").data([b]),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-parallelCoordinates"),B=A.append("g"),C=z.select("g");B.append("g").attr("class","nv-parallelCoordinates background"),B.append("g").attr("class","nv-parallelCoordinates foreground"),B.append("g").attr("class","nv-parallelCoordinates missingValuesline"),z.attr("transform","translate("+c.left+","+c.top+")");var D,E,F=d3.svg.line().interpolate("cardinal").tension(n),G=d3.svg.axis().orient("left"),H=d3.behavior.drag().on("dragstart",r).on("drag",s).on("dragend",t),I=f.range()[1]-f.range()[0],J=[],K=[0+I/2,x-12,w-I/2,x-12];D=z.select(".missingValuesline").selectAll("line").data([K]),D.enter().append("line"),D.exit().remove(),D.attr("x1",function(a){return a[0]}).attr("y1",function(a){return a[1]}).attr("x2",function(a){return a[2]}).attr("y2",function(a){return a[3]}),E=z.select(".missingValuesline").selectAll("text").data(["undefined values"]),E.append("text").data(["undefined values"]),E.enter().append("text"),E.exit().remove(),E.attr("y",x).attr("x",w-92-I/2).text(function(a){return a});var L=z.select(".background").selectAll("path").data(b);L.enter().append("path"),L.exit().remove(),L.attr("d",p);var M=z.select(".foreground").selectAll("path").data(b);M.enter().append("path"),M.exit().remove(),M.attr("d",p).attr("stroke",j),M.on("mouseover",function(a,b){d3.select(this).classed("hover",!0),o.elementMouseover({label:a.name,data:a.data,index:b,pos:[d3.mouse(this.parentNode)[0],d3.mouse(this.parentNode)[1]]})}),M.on("mouseout",function(a,b){d3.select(this).classed("hover",!1),o.elementMouseout({label:a.name,data:a.data,index:b})});var N=C.selectAll(".dimension").data(h),O=N.enter().append("g").attr("class","nv-parallelCoordinates dimension");O.append("g").attr("class","nv-parallelCoordinates nv-axis"),O.append("g").attr("class","nv-parallelCoordinates-brush"),O.append("text").attr("class","nv-parallelCoordinates nv-label"),N.attr("transform",function(a){return"translate("+f(a)+",0)"}),N.exit().remove(),N.select(".nv-label").style("cursor","move").attr("dy","-1em").attr("text-anchor","middle").text(String).on("mouseover",function(a,b){o.elementMouseover({dim:a,pos:[d3.mouse(this.parentNode.parentNode)[0],d3.mouse(this.parentNode.parentNode)[1]]})}).on("mouseout",function(a,b){o.elementMouseout({dim:a})}).call(H),N.select(".nv-axis").each(function(a,b){d3.select(this).call(G.scale(g[a]).tickFormat(d3.format(i[b])))}),N.select(".nv-parallelCoordinates-brush").each(function(a){d3.select(this).call(g[a].brush)}).selectAll("rect").attr("x",-8).attr("width",16)}),b}var c={top:30,right:0,bottom:10,left:0},d=null,e=null,f=d3.scale.ordinal(),g={},h=[],i=[],j=a.utils.defaultColor(),k=[],l=[],m=[],n=1,o=d3.dispatch("brush","elementMouseover","elementMouseout");return b.dispatch=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},dimensionNames:{get:function(){return h},set:function(a){h=a}},dimensionFormats:{get:function(){return i},set:function(a){i=a}},lineTension:{get:function(){return n},set:function(a){n=a}},dimensions:{get:function(){return h},set:function(b){a.deprecated("dimensions","use dimensionNames instead"),h=b}},margin:{get:function(){return c},set:function(a){c.top=void 0!==a.top?a.top:c.top,c.right=void 0!==a.right?a.right:c.right,c.bottom=void 0!==a.bottom?a.bottom:c.bottom,c.left=void 0!==a.left?a.left:c.left}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.pie=function(){"use strict";function b(E){return D.reset(),E.each(function(b){function E(a,b){a.endAngle=isNaN(a.endAngle)?0:a.endAngle,a.startAngle=isNaN(a.startAngle)?0:a.startAngle,p||(a.innerRadius=0);var c=d3.interpolate(this._current,a);return this._current=c(0),function(a){return B[b](c(a))}}var F=d-c.left-c.right,G=e-c.top-c.bottom,H=Math.min(F,G)/2,I=[],J=[];if(i=d3.select(this),0===z.length)for(var K=H-H/5,L=y*H,M=0;Mc)return"";if("function"==typeof n)d=n(a,b,{key:f(a.data),value:g(a.data),percent:k(c)});else switch(n){case"key":d=f(a.data);break;case"value":d=k(g(a.data));break;case"percent":d=d3.format("%")(c)}return d})}}),D.renderEnd("pie immediate"),b}var c={top:0,right:0,bottom:0,left:0},d=500,e=500,f=function(a){return a.x},g=function(a){return a.y},h=Math.floor(1e4*Math.random()),i=null,j=a.utils.defaultColor(),k=d3.format(",.2f"),l=!0,m=!1,n="key",o=.02,p=!1,q=!1,r=!0,s=0,t=!1,u=!1,v=!1,w=!1,x=0,y=.5,z=[],A=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),B=[],C=[],D=a.utils.renderWatch(A);return b.dispatch=A,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{arcsRadius:{get:function(){return z},set:function(a){z=a}},width:{get:function(){return d},set:function(a){d=a}},height:{get:function(){return e},set:function(a){e=a}},showLabels:{get:function(){return l},set:function(a){l=a}},title:{get:function(){return q},set:function(a){q=a}},titleOffset:{get:function(){return s},set:function(a){s=a}},labelThreshold:{get:function(){return o},set:function(a){o=a}},valueFormat:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return f},set:function(a){f=a}},id:{get:function(){return h},set:function(a){h=a}},endAngle:{get:function(){return w},set:function(a){w=a}},startAngle:{get:function(){return u},set:function(a){u=a}},padAngle:{get:function(){return v},set:function(a){v=a}},cornerRadius:{get:function(){return x},set:function(a){x=a}},donutRatio:{get:function(){return y},set:function(a){y=a}},labelsOutside:{get:function(){return m},set:function(a){m=a}},labelSunbeamLayout:{get:function(){return t},set:function(a){t=a}},donut:{get:function(){return p},set:function(a){p=a}},growOnHover:{get:function(){return r},set:function(a){r=a}},pieLabelsOutside:{get:function(){return m},set:function(b){m=b,a.deprecated("pieLabelsOutside","use labelsOutside instead")}},donutLabelsOutside:{get:function(){return m},set:function(b){m=b,a.deprecated("donutLabelsOutside","use labelsOutside instead")}},labelFormat:{get:function(){return k},set:function(b){k=b,a.deprecated("labelFormat","use valueFormat instead")}},margin:{get:function(){return c},set:function(a){c.top="undefined"!=typeof a.top?a.top:c.top,c.right="undefined"!=typeof a.right?a.right:c.right,c.bottom="undefined"!=typeof a.bottom?a.bottom:c.bottom,c.left="undefined"!=typeof a.left?a.left:c.left}},y:{get:function(){return g},set:function(a){g=d3.functor(a)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},labelType:{get:function(){return n},set:function(a){n=a||"key"}}}),a.utils.initOptions(b),b},a.models.pieChart=function(){"use strict";function b(e){return q.reset(),q.models(c),e.each(function(e){var k=d3.select(this);a.utils.initSVG(k);var n=a.utils.availableWidth(g,k,f),o=a.utils.availableHeight(h,k,f);if(b.update=function(){k.transition().call(b)},b.container=this,l.setter(s(e),b.update).getter(r(e)).update(),l.disabled=e.map(function(a){return!!a.disabled}),!m){var q;m={};for(q in l)l[q]instanceof Array?m[q]=l[q].slice(0):m[q]=l[q]}if(!e||!e.length)return a.utils.noData(b,k),b;k.selectAll(".nv-noData").remove();var t=k.selectAll("g.nv-wrap.nv-pieChart").data([e]),u=t.enter().append("g").attr("class","nvd3 nv-wrap nv-pieChart").append("g"),v=t.select("g");if(u.append("g").attr("class","nv-pieWrap"),u.append("g").attr("class","nv-legendWrap"),i)if("top"===j)d.width(n).key(c.x()),t.select(".nv-legendWrap").datum(e).call(d),f.top!=d.height()&&(f.top=d.height(),o=a.utils.availableHeight(h,k,f)),t.select(".nv-legendWrap").attr("transform","translate(0,"+-f.top+")");else if("right"===j){var w=a.models.legend().width();w>n/2&&(w=n/2),d.height(o).key(c.x()),d.width(w),n-=d.width(),t.select(".nv-legendWrap").datum(e).call(d).attr("transform","translate("+n+",0)")}t.attr("transform","translate("+f.left+","+f.top+")"),c.width(n).height(o);var x=v.select(".nv-pieWrap").datum([e]);d3.transition(x).call(c),d.dispatch.on("stateChange",function(a){for(var c in a)l[c]=a[c];p.stateChange(l),b.update()}),p.on("changeState",function(a){"undefined"!=typeof a.disabled&&(e.forEach(function(b,c){b.disabled=a.disabled[c]}),l.disabled=a.disabled),b.update()})}),q.renderEnd("pieChart immediate"),b}var c=a.models.pie(),d=a.models.legend(),e=a.models.tooltip(),f={top:30,right:20,bottom:20,left:20},g=null,h=null,i=!0,j="top",k=a.utils.defaultColor(),l=a.utils.state(),m=null,n=null,o=250,p=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd");e.headerEnabled(!1).duration(0).valueFormatter(function(a,b){return c.valueFormat()(a,b)});var q=a.utils.renderWatch(p),r=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},s=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:b.x()(a.data),value:b.y()(a.data),color:a.color},e.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(a){e.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(a){e.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.legend=d,b.dispatch=p,b.pie=c,b.tooltip=e,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{noData:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return i},set:function(a){i=a}},legendPosition:{get:function(){return j},set:function(a){j=a}},defaultState:{get:function(){return m},set:function(a){m=a}},tooltips:{get:function(){return e.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),e.enabled(!!b)}},tooltipContent:{get:function(){return e.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),e.contentGenerator(b)}},color:{get:function(){return k},set:function(a){k=a,d.color(k),c.color(k)}},duration:{get:function(){return o},set:function(a){o=a,q.reset(o)}},margin:{get:function(){return f},set:function(a){f.top=void 0!==a.top?a.top:f.top,f.right=void 0!==a.right?a.right:f.right,f.bottom=void 0!==a.bottom?a.bottom:f.bottom,f.left=void 0!==a.left?a.left:f.left}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.scatter=function(){"use strict";function b(N){return P.reset(),N.each(function(b){function N(){if(O=!1,!w)return!1;if(M===!0){var a=d3.merge(b.map(function(a,b){return a.values.map(function(a,c){var d=p(a,c),e=q(a,c);return[m(d)+1e-4*Math.random(),n(e)+1e-4*Math.random(),b,c,a]}).filter(function(a,b){return x(a[4],b)})}));if(0==a.length)return!1;a.length<3&&(a.push([m.range()[0]-20,n.range()[0]-20,null,null]),a.push([m.range()[1]+20,n.range()[1]+20,null,null]),a.push([m.range()[0]-20,n.range()[0]+20,null,null]),a.push([m.range()[1]+20,n.range()[1]-20,null,null]));var c=d3.geom.polygon([[-10,-10],[-10,i+10],[h+10,i+10],[h+10,-10]]),d=d3.geom.voronoi(a).map(function(b,d){return{data:c.clip(b),series:a[d][2],point:a[d][3]}});U.select(".nv-point-paths").selectAll("path").remove();var e=U.select(".nv-point-paths").selectAll("path").data(d),f=e.enter().append("svg:path").attr("d",function(a){return a&&a.data&&0!==a.data.length?"M"+a.data.join(",")+"Z":"M 0 0"}).attr("id",function(a,b){return"nv-path-"+b}).attr("clip-path",function(a,b){return"url(#nv-clip-"+b+")"});C&&f.style("fill",d3.rgb(230,230,230)).style("fill-opacity",.4).style("stroke-opacity",1).style("stroke",d3.rgb(200,200,200)),B&&(U.select(".nv-point-clips").selectAll("clipPath").remove(),U.select(".nv-point-clips").selectAll("clipPath").data(a).enter().append("svg:clipPath").attr("id",function(a,b){return"nv-clip-"+b}).append("svg:circle").attr("cx",function(a){return a[0]}).attr("cy",function(a){return a[1]}).attr("r",D));var k=function(a,c){if(O)return 0;var d=b[a.series];if(void 0!==d){var e=d.values[a.point];e.color=j(d,a.series),e.x=p(e),e.y=q(e);var f=l.node().getBoundingClientRect(),h=window.pageYOffset||document.documentElement.scrollTop,i=window.pageXOffset||document.documentElement.scrollLeft,k={left:m(p(e,a.point))+f.left+i+g.left+10,top:n(q(e,a.point))+f.top+h+g.top+10};c({point:e,series:d,pos:k,seriesIndex:a.series,pointIndex:a.point})}};e.on("click",function(a){k(a,L.elementClick)}).on("dblclick",function(a){k(a,L.elementDblClick)}).on("mouseover",function(a){k(a,L.elementMouseover)}).on("mouseout",function(a,b){k(a,L.elementMouseout)})}else U.select(".nv-groups").selectAll(".nv-group").selectAll(".nv-point").on("click",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementClick({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("dblclick",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementDblClick({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c})}).on("mouseover",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementMouseover({point:e,series:d,pos:[m(p(e,c))+g.left,n(q(e,c))+g.top],seriesIndex:a.series,pointIndex:c,color:j(a,c)})}).on("mouseout",function(a,c){if(O||!b[a.series])return 0;var d=b[a.series],e=d.values[c];L.elementMouseout({point:e,series:d,seriesIndex:a.series,pointIndex:c,color:j(a,c)})})}l=d3.select(this);var R=a.utils.availableWidth(h,l,g),S=a.utils.availableHeight(i,l,g);a.utils.initSVG(l),b.forEach(function(a,b){a.values.forEach(function(a){a.series=b})});var T=E&&F&&I?[]:d3.merge(b.map(function(a){return a.values.map(function(a,b){return{x:p(a,b),y:q(a,b),size:r(a,b)}})}));m.domain(E||d3.extent(T.map(function(a){return a.x}).concat(t))),y&&b[0]?m.range(G||[(R*z+R)/(2*b[0].values.length),R-R*(1+z)/(2*b[0].values.length)]):m.range(G||[0,R]),n.domain(F||d3.extent(T.map(function(a){return a.y}).concat(u))).range(H||[S,0]),o.domain(I||d3.extent(T.map(function(a){return a.size}).concat(v))).range(J||Q),K=m.domain()[0]===m.domain()[1]||n.domain()[0]===n.domain()[1],m.domain()[0]===m.domain()[1]&&(m.domain()[0]?m.domain([m.domain()[0]-.01*m.domain()[0],m.domain()[1]+.01*m.domain()[1]]):m.domain([-1,1])),n.domain()[0]===n.domain()[1]&&(n.domain()[0]?n.domain([n.domain()[0]-.01*n.domain()[0],n.domain()[1]+.01*n.domain()[1]]):n.domain([-1,1])),isNaN(m.domain()[0])&&m.domain([-1,1]),isNaN(n.domain()[0])&&n.domain([-1,1]),c=c||m,d=d||n,e=e||o;var U=l.selectAll("g.nv-wrap.nv-scatter").data([b]),V=U.enter().append("g").attr("class","nvd3 nv-wrap nv-scatter nv-chart-"+k),W=V.append("defs"),X=V.append("g"),Y=U.select("g");U.classed("nv-single-point",K),X.append("g").attr("class","nv-groups"),X.append("g").attr("class","nv-point-paths"),V.append("g").attr("class","nv-point-clips"),U.attr("transform","translate("+g.left+","+g.top+")"),W.append("clipPath").attr("id","nv-edge-clip-"+k).append("rect"),U.select("#nv-edge-clip-"+k+" rect").attr("width",R).attr("height",S>0?S:0),Y.attr("clip-path",A?"url(#nv-edge-clip-"+k+")":""),O=!0;var Z=U.select(".nv-groups").selectAll(".nv-group").data(function(a){return a},function(a){return a.key});Z.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6),Z.exit().remove(),Z.attr("class",function(a,b){return"nv-group nv-series-"+b}).classed("hover",function(a){return a.hover}),Z.watchTransition(P,"scatter: groups").style("fill",function(a,b){return j(a,b)}).style("stroke",function(a,b){return j(a,b)}).style("stroke-opacity",1).style("fill-opacity",.5);var $=Z.selectAll("path.nv-point").data(function(a){return a.values.map(function(a,b){return[a,b]}).filter(function(a,b){return x(a[0],b)})});$.enter().append("path").style("fill",function(a){return a.color}).style("stroke",function(a){return a.color}).attr("transform",function(a){return"translate("+c(p(a[0],a[1]))+","+d(q(a[0],a[1]))+")"}).attr("d",a.utils.symbol().type(function(a){return s(a[0])}).size(function(a){return o(r(a[0],a[1]))})),$.exit().remove(),Z.exit().selectAll("path.nv-point").watchTransition(P,"scatter exit").attr("transform",function(a){return"translate("+m(p(a[0],a[1]))+","+n(q(a[0],a[1]))+")"}).remove(),$.each(function(a){d3.select(this).classed("nv-point",!0).classed("nv-point-"+a[1],!0).classed("nv-noninteractive",!w).classed("hover",!1)}),$.watchTransition(P,"scatter points").attr("transform",function(a){return"translate("+m(p(a[0],a[1]))+","+n(q(a[0],a[1]))+")"}).attr("d",a.utils.symbol().type(function(a){return s(a[0])}).size(function(a){return o(r(a[0],a[1]))})),clearTimeout(f),f=setTimeout(N,300),c=m.copy(),d=n.copy(),e=o.copy()}),P.renderEnd("scatter immediate"),b}var c,d,e,f,g={top:0,right:0,bottom:0,left:0},h=null,i=null,j=a.utils.defaultColor(),k=Math.floor(1e5*Math.random()),l=null,m=d3.scale.linear(),n=d3.scale.linear(),o=d3.scale.linear(),p=function(a){return a.x},q=function(a){return a.y},r=function(a){return a.size||1},s=function(a){return a.shape||"circle"},t=[],u=[],v=[],w=!0,x=function(a){return!a.notActive},y=!1,z=.1,A=!1,B=!0,C=!1,D=function(){return 25},E=null,F=null,G=null,H=null,I=null,J=null,K=!1,L=d3.dispatch("elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),M=!0,N=250,O=!1,P=a.utils.renderWatch(L,N),Q=[16,256];return b.dispatch=L,b.options=a.utils.optionsFunc.bind(b),b._calls=new function(){this.clearHighlights=function(){return a.dom.write(function(){l.selectAll(".nv-point.hover").classed("hover",!1)}),null},this.highlightPoint=function(b,c,d){a.dom.write(function(){l.select(" .nv-series-"+b+" .nv-point-"+c).classed("hover",d)})}},L.on("elementMouseover.point",function(a){w&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!0)}),L.on("elementMouseout.point",function(a){w&&b._calls.highlightPoint(a.seriesIndex,a.pointIndex,!1)}),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xScale:{get:function(){return m},set:function(a){m=a}},yScale:{get:function(){return n},set:function(a){n=a}},pointScale:{get:function(){return o},set:function(a){o=a}},xDomain:{get:function(){return E},set:function(a){E=a}},yDomain:{get:function(){return F},set:function(a){F=a}},pointDomain:{get:function(){return I},set:function(a){I=a}},xRange:{get:function(){return G},set:function(a){G=a}},yRange:{get:function(){return H},set:function(a){H=a}},pointRange:{get:function(){return J},set:function(a){J=a}},forceX:{get:function(){return t},set:function(a){t=a}},forceY:{get:function(){return u},set:function(a){u=a}},forcePoint:{get:function(){return v},set:function(a){v=a}},interactive:{get:function(){return w},set:function(a){w=a}},pointActive:{get:function(){return x},set:function(a){x=a}},padDataOuter:{get:function(){return z},set:function(a){z=a}},padData:{get:function(){return y},set:function(a){y=a}},clipEdge:{get:function(){return A},set:function(a){A=a}},clipVoronoi:{get:function(){return B},set:function(a){B=a}},clipRadius:{get:function(){return D},set:function(a){D=a}},showVoronoi:{get:function(){return C},set:function(a){C=a}},id:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return p},set:function(a){p=d3.functor(a)}},y:{get:function(){return q},set:function(a){q=d3.functor(a)}},pointSize:{get:function(){return r},set:function(a){r=d3.functor(a)}},pointShape:{get:function(){return s},set:function(a){s=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},duration:{get:function(){return N},set:function(a){N=a,P.reset(N)}},color:{get:function(){return j},set:function(b){j=a.utils.getColor(b)}},useVoronoi:{get:function(){return M},set:function(a){M=a,M===!1&&(B=!1)}}}),a.utils.initOptions(b),b},a.models.scatterChart=function(){"use strict";function b(z){return D.reset(),D.models(c),t&&D.models(d),u&&D.models(e),q&&D.models(g),r&&D.models(h),z.each(function(z){m=d3.select(this),a.utils.initSVG(m);var G=a.utils.availableWidth(k,m,j),H=a.utils.availableHeight(l,m,j);if(b.update=function(){0===A?m.call(b):m.transition().duration(A).call(b)},b.container=this,w.setter(F(z),b.update).getter(E(z)).update(),w.disabled=z.map(function(a){return!!a.disabled}),!x){var I;x={};for(I in w)w[I]instanceof Array?x[I]=w[I].slice(0):x[I]=w[I]}if(!(z&&z.length&&z.filter(function(a){return a.values.length}).length))return a.utils.noData(b,m),D.renderEnd("scatter immediate"),b;m.selectAll(".nv-noData").remove(),o=c.xScale(),p=c.yScale();var J=m.selectAll("g.nv-wrap.nv-scatterChart").data([z]),K=J.enter().append("g").attr("class","nvd3 nv-wrap nv-scatterChart nv-chart-"+c.id()),L=K.append("g"),M=J.select("g");if(L.append("rect").attr("class","nvd3 nv-background").style("pointer-events","none"),L.append("g").attr("class","nv-x nv-axis"),L.append("g").attr("class","nv-y nv-axis"),L.append("g").attr("class","nv-scatterWrap"),L.append("g").attr("class","nv-regressionLinesWrap"),L.append("g").attr("class","nv-distWrap"),L.append("g").attr("class","nv-legendWrap"),v&&M.select(".nv-y.nv-axis").attr("transform","translate("+G+",0)"),s){var N=G;f.width(N),J.select(".nv-legendWrap").datum(z).call(f),j.top!=f.height()&&(j.top=f.height(),H=a.utils.availableHeight(l,m,j)),J.select(".nv-legendWrap").attr("transform","translate(0,"+-j.top+")")}J.attr("transform","translate("+j.left+","+j.top+")"),c.width(G).height(H).color(z.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!z[b].disabled})),J.select(".nv-scatterWrap").datum(z.filter(function(a){return!a.disabled})).call(c),J.select(".nv-regressionLinesWrap").attr("clip-path","url(#nv-edge-clip-"+c.id()+")");var O=J.select(".nv-regressionLinesWrap").selectAll(".nv-regLines").data(function(a){return a});O.enter().append("g").attr("class","nv-regLines");var P=O.selectAll(".nv-regLine").data(function(a){return[a]});P.enter().append("line").attr("class","nv-regLine").style("stroke-opacity",0),P.filter(function(a){return a.intercept&&a.slope}).watchTransition(D,"scatterPlusLineChart: regline").attr("x1",o.range()[0]).attr("x2",o.range()[1]).attr("y1",function(a,b){return p(o.domain()[0]*a.slope+a.intercept)}).attr("y2",function(a,b){return p(o.domain()[1]*a.slope+a.intercept)}).style("stroke",function(a,b,c){return n(a,c)}).style("stroke-opacity",function(a,b){return a.disabled||"undefined"==typeof a.slope||"undefined"==typeof a.intercept?0:1}),t&&(d.scale(o)._ticks(a.utils.calcTicksX(G/100,z)).tickSize(-H,0),M.select(".nv-x.nv-axis").attr("transform","translate(0,"+p.range()[0]+")").call(d)),u&&(e.scale(p)._ticks(a.utils.calcTicksY(H/36,z)).tickSize(-G,0),M.select(".nv-y.nv-axis").call(e)),q&&(g.getData(c.x()).scale(o).width(G).color(z.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!z[b].disabled})),L.select(".nv-distWrap").append("g").attr("class","nv-distributionX"),M.select(".nv-distributionX").attr("transform","translate(0,"+p.range()[0]+")").datum(z.filter(function(a){return!a.disabled})).call(g)),r&&(h.getData(c.y()).scale(p).width(H).color(z.map(function(a,b){return a.color||n(a,b)}).filter(function(a,b){return!z[b].disabled})),L.select(".nv-distWrap").append("g").attr("class","nv-distributionY"),M.select(".nv-distributionY").attr("transform","translate("+(v?G:-h.size())+",0)").datum(z.filter(function(a){return!a.disabled})).call(h)),f.dispatch.on("stateChange",function(a){for(var c in a)w[c]=a[c];y.stateChange(w),b.update()}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&(z.forEach(function(b,c){b.disabled=a.disabled[c]}),w.disabled=a.disabled),b.update()}),c.dispatch.on("elementMouseout.tooltip",function(a){i.hidden(!0),m.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",0),m.select(".nv-chart-"+c.id()+" .nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",h.size())}),c.dispatch.on("elementMouseover.tooltip",function(a){m.select(".nv-series-"+a.seriesIndex+" .nv-distx-"+a.pointIndex).attr("y1",a.pos.top-H-j.top),m.select(".nv-series-"+a.seriesIndex+" .nv-disty-"+a.pointIndex).attr("x2",a.pos.left+g.size()-j.left),i.position(a.pos).data(a).hidden(!1); -}),B=o.copy(),C=p.copy()}),D.renderEnd("scatter with line immediate"),b}var c=a.models.scatter(),d=a.models.axis(),e=a.models.axis(),f=a.models.legend(),g=a.models.distribution(),h=a.models.distribution(),i=a.models.tooltip(),j={top:30,right:20,bottom:50,left:75},k=null,l=null,m=null,n=a.utils.defaultColor(),o=c.xScale(),p=c.yScale(),q=!1,r=!1,s=!0,t=!0,u=!0,v=!1,w=a.utils.state(),x=null,y=d3.dispatch("stateChange","changeState","renderEnd"),z=null,A=250;c.xScale(o).yScale(p),d.orient("bottom").tickPadding(10),e.orient(v?"right":"left").tickPadding(10),g.axis("x"),h.axis("y"),i.headerFormatter(function(a,b){return d.tickFormat()(a,b)}).valueFormatter(function(a,b){return e.tickFormat()(a,b)});var B,C,D=a.utils.renderWatch(y,A),E=function(a){return function(){return{active:a.map(function(a){return!a.disabled})}}},F=function(a){return function(b){void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}};return b.dispatch=y,b.scatter=c,b.legend=f,b.xAxis=d,b.yAxis=e,b.distX=g,b.distY=h,b.tooltip=i,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return k},set:function(a){k=a}},height:{get:function(){return l},set:function(a){l=a}},container:{get:function(){return m},set:function(a){m=a}},showDistX:{get:function(){return q},set:function(a){q=a}},showDistY:{get:function(){return r},set:function(a){r=a}},showLegend:{get:function(){return s},set:function(a){s=a}},showXAxis:{get:function(){return t},set:function(a){t=a}},showYAxis:{get:function(){return u},set:function(a){u=a}},defaultState:{get:function(){return x},set:function(a){x=a}},noData:{get:function(){return z},set:function(a){z=a}},duration:{get:function(){return A},set:function(a){A=a}},tooltips:{get:function(){return i.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),i.enabled(!!b)}},tooltipContent:{get:function(){return i.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),i.contentGenerator(b)}},tooltipXContent:{get:function(){return i.contentGenerator()},set:function(b){a.deprecated("tooltipContent","This option is removed, put values into main tooltip.")}},tooltipYContent:{get:function(){return i.contentGenerator()},set:function(b){a.deprecated("tooltipContent","This option is removed, put values into main tooltip.")}},margin:{get:function(){return j},set:function(a){j.top=void 0!==a.top?a.top:j.top,j.right=void 0!==a.right?a.right:j.right,j.bottom=void 0!==a.bottom?a.bottom:j.bottom,j.left=void 0!==a.left?a.left:j.left}},rightAlignYAxis:{get:function(){return v},set:function(a){v=a,e.orient(a?"right":"left")}},color:{get:function(){return n},set:function(b){n=a.utils.getColor(b),f.color(n),g.color(n),h.color(n)}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.models.sparkline=function(){"use strict";function b(k){return k.each(function(b){var k=h-g.left-g.right,q=i-g.top-g.bottom;j=d3.select(this),a.utils.initSVG(j),l.domain(c||d3.extent(b,n)).range(e||[0,k]),m.domain(d||d3.extent(b,o)).range(f||[q,0]);var r=j.selectAll("g.nv-wrap.nv-sparkline").data([b]),s=r.enter().append("g").attr("class","nvd3 nv-wrap nv-sparkline");s.append("g"),r.select("g");r.attr("transform","translate("+g.left+","+g.top+")");var t=r.selectAll("path").data(function(a){return[a]});t.enter().append("path"),t.exit().remove(),t.style("stroke",function(a,b){return a.color||p(a,b)}).attr("d",d3.svg.line().x(function(a,b){return l(n(a,b))}).y(function(a,b){return m(o(a,b))}));var u=r.selectAll("circle.nv-point").data(function(a){function b(b){if(-1!=b){var c=a[b];return c.pointIndex=b,c}return null}var c=a.map(function(a,b){return o(a,b)}),d=b(c.lastIndexOf(m.domain()[1])),e=b(c.indexOf(m.domain()[0])),f=b(c.length-1);return[e,d,f].filter(function(a){return null!=a})});u.enter().append("circle"),u.exit().remove(),u.attr("cx",function(a,b){return l(n(a,a.pointIndex))}).attr("cy",function(a,b){return m(o(a,a.pointIndex))}).attr("r",2).attr("class",function(a,b){return n(a,a.pointIndex)==l.domain()[1]?"nv-point nv-currentValue":o(a,a.pointIndex)==m.domain()[0]?"nv-point nv-minValue":"nv-point nv-maxValue"})}),b}var c,d,e,f,g={top:2,right:0,bottom:2,left:0},h=400,i=32,j=null,k=!0,l=d3.scale.linear(),m=d3.scale.linear(),n=function(a){return a.x},o=function(a){return a.y},p=a.utils.getColor(["#000"]);return b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return h},set:function(a){h=a}},height:{get:function(){return i},set:function(a){i=a}},xDomain:{get:function(){return c},set:function(a){c=a}},yDomain:{get:function(){return d},set:function(a){d=a}},xRange:{get:function(){return e},set:function(a){e=a}},yRange:{get:function(){return f},set:function(a){f=a}},xScale:{get:function(){return l},set:function(a){l=a}},yScale:{get:function(){return m},set:function(a){m=a}},animate:{get:function(){return k},set:function(a){k=a}},x:{get:function(){return n},set:function(a){n=d3.functor(a)}},y:{get:function(){return o},set:function(a){o=d3.functor(a)}},margin:{get:function(){return g},set:function(a){g.top=void 0!==a.top?a.top:g.top,g.right=void 0!==a.right?a.right:g.right,g.bottom=void 0!==a.bottom?a.bottom:g.bottom,g.left=void 0!==a.left?a.left:g.left}},color:{get:function(){return p},set:function(b){p=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.sparklinePlus=function(){"use strict";function b(p){return p.each(function(q){function r(){if(!j){var a=A.selectAll(".nv-hoverValue").data(i),b=a.enter().append("g").attr("class","nv-hoverValue").style("stroke-opacity",0).style("fill-opacity",0);a.exit().transition().duration(250).style("stroke-opacity",0).style("fill-opacity",0).remove(),a.attr("transform",function(a){return"translate("+c(e.x()(q[a],a))+",0)"}).transition().duration(250).style("stroke-opacity",1).style("fill-opacity",1),i.length&&(b.append("line").attr("x1",0).attr("y1",-f.top).attr("x2",0).attr("y2",v),b.append("text").attr("class","nv-xValue").attr("x",-6).attr("y",-f.top).attr("text-anchor","end").attr("dy",".9em"),A.select(".nv-hoverValue .nv-xValue").text(k(e.x()(q[i[0]],i[0]))),b.append("text").attr("class","nv-yValue").attr("x",6).attr("y",-f.top).attr("text-anchor","start").attr("dy",".9em"),A.select(".nv-hoverValue .nv-yValue").text(l(e.y()(q[i[0]],i[0]))))}}function s(){function a(a,b){for(var c=Math.abs(e.x()(a[0],0)-b),d=0,f=0;fc;++c){for(b=0,d=0;bb;b++)a[b][c][1]/=d;else for(b=0;e>b;b++)a[b][c][1]=0}for(c=0;f>c;++c)g[c]=0;return g}}),u.renderEnd("stackedArea immediate"),b}var c,d,e={top:0,right:0,bottom:0,left:0},f=960,g=500,h=a.utils.defaultColor(),i=Math.floor(1e5*Math.random()),j=null,k=function(a){return a.x},l=function(a){return a.y},m="stack",n="zero",o="default",p="linear",q=!1,r=a.models.scatter(),s=250,t=d3.dispatch("areaClick","areaMouseover","areaMouseout","renderEnd","elementClick","elementMouseover","elementMouseout");r.pointSize(2.2).pointDomain([2.2,2.2]);var u=a.utils.renderWatch(t,s);return b.dispatch=t,b.scatter=r,r.dispatch.on("elementClick",function(){t.elementClick.apply(this,arguments)}),r.dispatch.on("elementMouseover",function(){t.elementMouseover.apply(this,arguments)}),r.dispatch.on("elementMouseout",function(){t.elementMouseout.apply(this,arguments)}),b.interpolate=function(a){return arguments.length?(p=a,b):p},b.duration=function(a){return arguments.length?(s=a,u.reset(s),r.duration(s),b):s},b.dispatch=t,b.scatter=r,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return f},set:function(a){f=a}},height:{get:function(){return g},set:function(a){g=a}},clipEdge:{get:function(){return q},set:function(a){q=a}},offset:{get:function(){return n},set:function(a){n=a}},order:{get:function(){return o},set:function(a){o=a}},interpolate:{get:function(){return p},set:function(a){p=a}},x:{get:function(){return k},set:function(a){k=d3.functor(a)}},y:{get:function(){return l},set:function(a){l=d3.functor(a)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}},color:{get:function(){return h},set:function(b){h=a.utils.getColor(b)}},style:{get:function(){return m},set:function(a){switch(m=a){case"stack":b.offset("zero"),b.order("default");break;case"stream":b.offset("wiggle"),b.order("inside-out");break;case"stream-center":b.offset("silhouette"),b.order("inside-out");break;case"expand":b.offset("expand"),b.order("default");break;case"stack_percent":b.offset(b.d3_stackedOffset_stackPercent),b.order("default")}}},duration:{get:function(){return s},set:function(a){s=a,u.reset(s),r.duration(s)}}}),a.utils.inheritOptions(b,r),a.utils.initOptions(b),b},a.models.stackedAreaChart=function(){"use strict";function b(k){return F.reset(),F.models(e),r&&F.models(f),s&&F.models(g),k.each(function(k){var x=d3.select(this),F=this;a.utils.initSVG(x);var K=a.utils.availableWidth(m,x,l),L=a.utils.availableHeight(n,x,l);if(b.update=function(){x.transition().duration(C).call(b)},b.container=this,v.setter(I(k),b.update).getter(H(k)).update(),v.disabled=k.map(function(a){return!!a.disabled}),!w){var M;w={};for(M in v)v[M]instanceof Array?w[M]=v[M].slice(0):w[M]=v[M]}if(!(k&&k.length&&k.filter(function(a){return a.values.length}).length))return a.utils.noData(b,x),b;x.selectAll(".nv-noData").remove(),c=e.xScale(),d=e.yScale();var N=x.selectAll("g.nv-wrap.nv-stackedAreaChart").data([k]),O=N.enter().append("g").attr("class","nvd3 nv-wrap nv-stackedAreaChart").append("g"),P=N.select("g");if(O.append("rect").style("opacity",0),O.append("g").attr("class","nv-x nv-axis"),O.append("g").attr("class","nv-y nv-axis"),O.append("g").attr("class","nv-stackedWrap"),O.append("g").attr("class","nv-legendWrap"),O.append("g").attr("class","nv-controlsWrap"),O.append("g").attr("class","nv-interactive"),P.select("rect").attr("width",K).attr("height",L),q){var Q=p?K-z:K;h.width(Q),P.select(".nv-legendWrap").datum(k).call(h),l.top!=h.height()&&(l.top=h.height(),L=a.utils.availableHeight(n,x,l)),P.select(".nv-legendWrap").attr("transform","translate("+(K-Q)+","+-l.top+")")}if(p){var R=[{key:B.stacked||"Stacked",metaKey:"Stacked",disabled:"stack"!=e.style(),style:"stack"},{key:B.stream||"Stream",metaKey:"Stream",disabled:"stream"!=e.style(),style:"stream"},{key:B.expanded||"Expanded",metaKey:"Expanded",disabled:"expand"!=e.style(),style:"expand"},{key:B.stack_percent||"Stack %",metaKey:"Stack_Percent",disabled:"stack_percent"!=e.style(),style:"stack_percent"}];z=A.length/3*260,R=R.filter(function(a){return-1!==A.indexOf(a.metaKey)}),i.width(z).color(["#444","#444","#444"]),P.select(".nv-controlsWrap").datum(R).call(i),l.top!=Math.max(i.height(),h.height())&&(l.top=Math.max(i.height(),h.height()),L=a.utils.availableHeight(n,x,l)),P.select(".nv-controlsWrap").attr("transform","translate(0,"+-l.top+")")}N.attr("transform","translate("+l.left+","+l.top+")"),t&&P.select(".nv-y.nv-axis").attr("transform","translate("+K+",0)"),u&&(j.width(K).height(L).margin({left:l.left,top:l.top}).svgContainer(x).xScale(c),N.select(".nv-interactive").call(j)),e.width(K).height(L);var S=P.select(".nv-stackedWrap").datum(k);if(S.transition().call(e),r&&(f.scale(c)._ticks(a.utils.calcTicksX(K/100,k)).tickSize(-L,0),P.select(".nv-x.nv-axis").attr("transform","translate(0,"+L+")"),P.select(".nv-x.nv-axis").transition().duration(0).call(f)),s){var T;if(T="wiggle"===e.offset()?0:a.utils.calcTicksY(L/36,k),g.scale(d)._ticks(T).tickSize(-K,0),"expand"===e.style()||"stack_percent"===e.style()){var U=g.tickFormat();D&&U===J||(D=U),g.tickFormat(J)}else D&&(g.tickFormat(D),D=null);P.select(".nv-y.nv-axis").transition().duration(0).call(g)}e.dispatch.on("areaClick.toggle",function(a){1===k.filter(function(a){return!a.disabled}).length?k.forEach(function(a){a.disabled=!1}):k.forEach(function(b,c){b.disabled=c!=a.seriesIndex}),v.disabled=k.map(function(a){return!!a.disabled}),y.stateChange(v),b.update()}),h.dispatch.on("stateChange",function(a){for(var c in a)v[c]=a[c];y.stateChange(v),b.update()}),i.dispatch.on("legendClick",function(a,c){a.disabled&&(R=R.map(function(a){return a.disabled=!0,a}),a.disabled=!1,e.style(a.style),v.style=e.style(),y.stateChange(v),b.update())}),j.dispatch.on("elementMousemove",function(c){e.clearHighlights();var d,g,h,i=[];if(k.filter(function(a,b){return a.seriesIndex=b,!a.disabled}).forEach(function(f,j){g=a.interactiveBisect(f.values,c.pointXValue,b.x());var k=f.values[g],l=b.y()(k,g);if(null!=l&&e.highlightPoint(j,g,!0),"undefined"!=typeof k){"undefined"==typeof d&&(d=k),"undefined"==typeof h&&(h=b.xScale()(b.x()(k,g)));var m="expand"==e.style()?k.display.y:b.y()(k,g);i.push({key:f.key,value:m,color:o(f,f.seriesIndex),stackedValue:k.display})}}),i.reverse(),i.length>2){var m=b.yScale().invert(c.mouseY),n=null;i.forEach(function(a,b){m=Math.abs(m);var c=Math.abs(a.stackedValue.y0),d=Math.abs(a.stackedValue.y);return m>=c&&d+c>=m?void(n=b):void 0}),null!=n&&(i[n].highlight=!0)}var p=f.tickFormat()(b.x()(d,g)),q=j.tooltip.valueFormatter();"expand"===e.style()||"stack_percent"===e.style()?(E||(E=q),q=d3.format(".1%")):E&&(q=E,E=null),j.tooltip.position({left:h+l.left,top:c.mouseY+l.top}).chartContainer(F.parentNode).valueFormatter(q).data({value:p,series:i})(),j.renderGuideLine(h)}),j.dispatch.on("elementMouseout",function(a){e.clearHighlights()}),y.on("changeState",function(a){"undefined"!=typeof a.disabled&&k.length===a.disabled.length&&(k.forEach(function(b,c){b.disabled=a.disabled[c]}),v.disabled=a.disabled),"undefined"!=typeof a.style&&(e.style(a.style),G=a.style),b.update()})}),F.renderEnd("stacked Area chart immediate"),b}var c,d,e=a.models.stackedArea(),f=a.models.axis(),g=a.models.axis(),h=a.models.legend(),i=a.models.legend(),j=a.interactiveGuideline(),k=a.models.tooltip(),l={top:30,right:25,bottom:50,left:60},m=null,n=null,o=a.utils.defaultColor(),p=!0,q=!0,r=!0,s=!0,t=!1,u=!1,v=a.utils.state(),w=null,x=null,y=d3.dispatch("stateChange","changeState","renderEnd"),z=250,A=["Stacked","Stream","Expanded"],B={},C=250;v.style=e.style(),f.orient("bottom").tickPadding(7),g.orient(t?"right":"left"),k.headerFormatter(function(a,b){return f.tickFormat()(a,b)}).valueFormatter(function(a,b){return g.tickFormat()(a,b)}),j.tooltip.headerFormatter(function(a,b){return f.tickFormat()(a,b)}).valueFormatter(function(a,b){return g.tickFormat()(a,b)});var D=null,E=null;i.updateState(!1);var F=a.utils.renderWatch(y),G=e.style(),H=function(a){return function(){return{active:a.map(function(a){return!a.disabled}),style:e.style()}}},I=function(a){return function(b){void 0!==b.style&&(G=b.style),void 0!==b.active&&a.forEach(function(a,c){a.disabled=!b.active[c]})}},J=d3.format("%");return e.dispatch.on("elementMouseover.tooltip",function(a){a.point.x=e.x()(a.point),a.point.y=e.y()(a.point),k.data(a).position(a.pos).hidden(!1)}),e.dispatch.on("elementMouseout.tooltip",function(a){k.hidden(!0)}),b.dispatch=y,b.stacked=e,b.legend=h,b.controls=i,b.xAxis=f,b.yAxis=g,b.interactiveLayer=j,b.tooltip=k,b.dispatch=y,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return m},set:function(a){m=a}},height:{get:function(){return n},set:function(a){n=a}},showLegend:{get:function(){return q},set:function(a){q=a}},showXAxis:{get:function(){return r},set:function(a){r=a}},showYAxis:{get:function(){return s},set:function(a){s=a}},defaultState:{get:function(){return w},set:function(a){w=a}},noData:{get:function(){return x},set:function(a){x=a}},showControls:{get:function(){return p},set:function(a){p=a}},controlLabels:{get:function(){return B},set:function(a){B=a}},controlOptions:{get:function(){return A},set:function(a){A=a}},tooltips:{get:function(){return k.enabled()},set:function(b){a.deprecated("tooltips","use chart.tooltip.enabled() instead"),k.enabled(!!b)}},tooltipContent:{get:function(){return k.contentGenerator()},set:function(b){a.deprecated("tooltipContent","use chart.tooltip.contentGenerator() instead"),k.contentGenerator(b)}},margin:{get:function(){return l},set:function(a){l.top=void 0!==a.top?a.top:l.top,l.right=void 0!==a.right?a.right:l.right,l.bottom=void 0!==a.bottom?a.bottom:l.bottom,l.left=void 0!==a.left?a.left:l.left}},duration:{get:function(){return C},set:function(a){C=a,F.reset(C),e.duration(C),f.duration(C),g.duration(C)}},color:{get:function(){return o},set:function(b){o=a.utils.getColor(b),h.color(o),e.color(o)}},rightAlignYAxis:{get:function(){return t},set:function(a){t=a,g.orient(t?"right":"left")}},useInteractiveGuideline:{get:function(){return u},set:function(a){u=!!a,b.interactive(!a),b.useVoronoi(!a),e.scatter.interactive(!a)}}}),a.utils.inheritOptions(b,e),a.utils.initOptions(b),b},a.models.sunburst=function(){"use strict";function b(u){return t.reset(),u.each(function(b){function t(a){a.x0=a.x,a.dx0=a.dx}function u(a){var b=d3.interpolate(p.domain(),[a.x,a.x+a.dx]),c=d3.interpolate(q.domain(),[a.y,1]),d=d3.interpolate(q.range(),[a.y?20:0,y]);return function(a,e){return e?function(b){return s(a)}:function(e){return p.domain(b(e)),q.domain(c(e)).range(d(e)),s(a)}}}l=d3.select(this);var v,w=a.utils.availableWidth(g,l,f),x=a.utils.availableHeight(h,l,f),y=Math.min(w,x)/2;a.utils.initSVG(l);var z=l.selectAll(".nv-wrap.nv-sunburst").data(b),A=z.enter().append("g").attr("class","nvd3 nv-wrap nv-sunburst nv-chart-"+k),B=A.selectAll("nv-sunburst");z.attr("transform","translate("+w/2+","+x/2+")"),l.on("click",function(a,b){o.chartClick({data:a,index:b,pos:d3.event,id:k})}),q.range([0,y]),c=c||b,e=b[0],r.value(j[i]||j.count),v=B.data(r.nodes).enter().append("path").attr("d",s).style("fill",function(a){return m((a.children?a:a.parent).name)}).style("stroke","#FFF").on("click",function(a){d!==c&&c!==a&&(d=c),c=a,v.transition().duration(n).attrTween("d",u(a))}).each(t).on("dblclick",function(a){d.parent==a&&v.transition().duration(n).attrTween("d",u(e))}).each(t).on("mouseover",function(a,b){d3.select(this).classed("hover",!0).style("opacity",.8),o.elementMouseover({data:a,color:d3.select(this).style("fill")})}).on("mouseout",function(a,b){d3.select(this).classed("hover",!1).style("opacity",1),o.elementMouseout({data:a})}).on("mousemove",function(a,b){o.elementMousemove({data:a})})}),t.renderEnd("sunburst immediate"),b}var c,d,e,f={top:0,right:0,bottom:0,left:0},g=null,h=null,i="count",j={count:function(a){return 1},size:function(a){return a.size}},k=Math.floor(1e4*Math.random()),l=null,m=a.utils.defaultColor(),n=500,o=d3.dispatch("chartClick","elementClick","elementDblClick","elementMousemove","elementMouseover","elementMouseout","renderEnd"),p=d3.scale.linear().range([0,2*Math.PI]),q=d3.scale.sqrt(),r=d3.layout.partition().sort(null).value(function(a){return 1}),s=d3.svg.arc().startAngle(function(a){return Math.max(0,Math.min(2*Math.PI,p(a.x)))}).endAngle(function(a){return Math.max(0,Math.min(2*Math.PI,p(a.x+a.dx)))}).innerRadius(function(a){return Math.max(0,q(a.y))}).outerRadius(function(a){return Math.max(0,q(a.y+a.dy))}),t=a.utils.renderWatch(o);return b.dispatch=o,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{width:{get:function(){return g},set:function(a){g=a}},height:{get:function(){return h},set:function(a){h=a}},mode:{get:function(){return i},set:function(a){i=a}},id:{get:function(){return k},set:function(a){k=a}},duration:{get:function(){return n},set:function(a){n=a}},margin:{get:function(){return f},set:function(a){f.top=void 0!=a.top?a.top:f.top,f.right=void 0!=a.right?a.right:f.right,f.bottom=void 0!=a.bottom?a.bottom:f.bottom,f.left=void 0!=a.left?a.left:f.left}},color:{get:function(){return m},set:function(b){m=a.utils.getColor(b)}}}),a.utils.initOptions(b),b},a.models.sunburstChart=function(){"use strict";function b(d){return m.reset(),m.models(c),d.each(function(d){var h=d3.select(this);a.utils.initSVG(h);var i=a.utils.availableWidth(f,h,e),j=a.utils.availableHeight(g,h,e);if(b.update=function(){0===k?h.call(b):h.transition().duration(k).call(b)},b.container=this,!d||!d.length)return a.utils.noData(b,h),b;h.selectAll(".nv-noData").remove();var l=h.selectAll("g.nv-wrap.nv-sunburstChart").data(d),m=l.enter().append("g").attr("class","nvd3 nv-wrap nv-sunburstChart").append("g"),n=l.select("g");m.append("g").attr("class","nv-sunburstWrap"),l.attr("transform","translate("+e.left+","+e.top+")"),c.width(i).height(j);var o=n.select(".nv-sunburstWrap").datum(d);d3.transition(o).call(c)}),m.renderEnd("sunburstChart immediate"),b}var c=a.models.sunburst(),d=a.models.tooltip(),e={top:30,right:20,bottom:20,left:20},f=null,g=null,h=a.utils.defaultColor(),i=(Math.round(1e5*Math.random()),null),j=null,k=250,l=d3.dispatch("tooltipShow","tooltipHide","stateChange","changeState","renderEnd"),m=a.utils.renderWatch(l);return d.headerEnabled(!1).duration(0).valueFormatter(function(a,b){return a}),c.dispatch.on("elementMouseover.tooltip",function(a){a.series={key:a.data.name,value:a.data.size,color:a.color},d.data(a).hidden(!1)}),c.dispatch.on("elementMouseout.tooltip",function(a){d.hidden(!0)}),c.dispatch.on("elementMousemove.tooltip",function(a){d.position({top:d3.event.pageY,left:d3.event.pageX})()}),b.dispatch=l,b.sunburst=c,b.tooltip=d,b.options=a.utils.optionsFunc.bind(b),b._options=Object.create({},{noData:{get:function(){return j},set:function(a){j=a}},defaultState:{get:function(){return i},set:function(a){i=a}},color:{get:function(){return h},set:function(a){h=a,c.color(h)}},duration:{get:function(){return k},set:function(a){k=a,m.reset(k),c.duration(k)}},margin:{get:function(){return e},set:function(a){e.top=void 0!==a.top?a.top:e.top,e.right=void 0!==a.right?a.right:e.right,e.bottom=void 0!==a.bottom?a.bottom:e.bottom,e.left=void 0!==a.left?a.left:e.left}}}),a.utils.inheritOptions(b,c),a.utils.initOptions(b),b},a.version="1.8.1"}(); \ No newline at end of file diff --git a/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.css b/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.css deleted file mode 100644 index 9adaabb1..00000000 --- a/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.css +++ /dev/null @@ -1,179 +0,0 @@ - -div.dataTables_length label { - float: left; - text-align: left; -} - -div.dataTables_length select { - width: 75px; -} - -div.dataTables_filter label { - float: right; -} - -div.dataTables_info { - padding-top: 8px; -} - -div.dataTables_paginate { - float: right; - margin: 0; -} - -table.table { - clear: both; - margin-bottom: 6px !important; - max-width: none !important; -} - -table.table thead .sorting, -table.table thead .sorting_asc, -table.table thead .sorting_desc, -table.table thead .sorting_asc_disabled, -table.table thead .sorting_desc_disabled { - cursor: pointer; - *cursor: hand; -} - -table.table thead .sorting { background: url('images/sort_both.png') no-repeat center right; } -table.table thead .sorting_asc { background: url('images/sort_asc.png') no-repeat center right; } -table.table thead .sorting_desc { background: url('images/sort_desc.png') no-repeat center right; } - -table.table thead .sorting_asc_disabled { background: url('images/sort_asc_disabled.png') no-repeat center right; } -table.table thead .sorting_desc_disabled { background: url('images/sort_desc_disabled.png') no-repeat center right; } - -table.dataTable th:active { - outline: none; -} - -/* Scrolling */ -div.dataTables_scrollHead table { - margin-bottom: 0 !important; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -div.dataTables_scrollHead table thead tr:last-child th:first-child, -div.dataTables_scrollHead table thead tr:last-child td:first-child { - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} - -div.dataTables_scrollBody table { - border-top: none; - margin-bottom: 0 !important; -} - -div.dataTables_scrollBody tbody tr:first-child th, -div.dataTables_scrollBody tbody tr:first-child td { - border-top: none; -} - -div.dataTables_scrollFoot table { - border-top: none; -} - - - - -/* - * TableTools styles - */ -.table tbody tr.active td, -.table tbody tr.active th { - background-color: #08C; - color: white; -} - -.table tbody tr.active:hover td, -.table tbody tr.active:hover th { - background-color: #0075b0 !important; -} - -.table-striped tbody tr.active:nth-child(odd) td, -.table-striped tbody tr.active:nth-child(odd) th { - background-color: #017ebc; -} - -table.DTTT_selectable tbody tr { - cursor: pointer; - *cursor: hand; -} - -div.DTTT .btn { - color: #333 !important; - font-size: 12px; -} - -div.DTTT .btn:hover { - text-decoration: none !important; -} - - -ul.DTTT_dropdown.dropdown-menu a { - color: #333 !important; /* needed only when demo_page.css is included */ -} - -ul.DTTT_dropdown.dropdown-menu li:hover a { - background-color: #0088cc; - color: white !important; -} - -/* TableTools information display */ -div.DTTT_print_info.modal { - height: 150px; - margin-top: -75px; - text-align: center; -} - -div.DTTT_print_info h6 { - font-weight: normal; - font-size: 28px; - line-height: 28px; - margin: 1em; -} - -div.DTTT_print_info p { - font-size: 14px; - line-height: 20px; -} - - - -/* - * FixedColumns styles - */ -div.DTFC_LeftHeadWrapper table, -div.DTFC_LeftFootWrapper table, -table.DTFC_Cloned tr.even { - background-color: white; -} - -div.DTFC_LeftHeadWrapper table { - margin-bottom: 0 !important; - border-top-right-radius: 0 !important; - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} - -div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child, -div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child { - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; -} - -div.DTFC_LeftBodyWrapper table { - border-top: none; - margin-bottom: 0 !important; -} - -div.DTFC_LeftBodyWrapper tbody tr:first-child th, -div.DTFC_LeftBodyWrapper tbody tr:first-child td { - border-top: none; -} - -div.DTFC_LeftFootWrapper table { - border-top: none; -} - diff --git a/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.js b/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.js deleted file mode 100644 index cfe3e9d2..00000000 --- a/wqflask/wqflask/static/packages/DT_bootstrap/DT_bootstrap.js +++ /dev/null @@ -1,159 +0,0 @@ -/* Set the defaults for DataTables initialisation */ -$.extend( true, $.fn.dataTable.defaults, { - "sDom": "<'row-fluid'<'span6'l><'span6'f>r>t<'row-fluid'<'span6'i><'span6'p>>", - "sPaginationType": "bootstrap", - "oLanguage": { - "sLengthMenu": "_MENU_ records per page" - } -} ); - - -/* Default class modification */ -$.extend( $.fn.dataTableExt.oStdClasses, { - "sWrapper": "dataTables_wrapper form-inline" -} ); - - -/* API method to get paging information */ -$.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings ) -{ - return { - "iStart": oSettings._iDisplayStart, - "iEnd": oSettings.fnDisplayEnd(), - "iLength": oSettings._iDisplayLength, - "iTotal": oSettings.fnRecordsTotal(), - "iFilteredTotal": oSettings.fnRecordsDisplay(), - "iPage": oSettings._iDisplayLength === -1 ? - 0 : Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ), - "iTotalPages": oSettings._iDisplayLength === -1 ? - 0 : Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength ) - }; -}; - - -/* Bootstrap style pagination control */ -$.extend( $.fn.dataTableExt.oPagination, { - "bootstrap": { - "fnInit": function( oSettings, nPaging, fnDraw ) { - var oLang = oSettings.oLanguage.oPaginate; - var fnClickHandler = function ( e ) { - e.preventDefault(); - if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) { - fnDraw( oSettings ); - } - }; - - $(nPaging).addClass('pagination').append( - '' - ); - var els = $('a', nPaging); - $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler ); - $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler ); - }, - - "fnUpdate": function ( oSettings, fnDraw ) { - var iListLength = 5; - var oPaging = oSettings.oInstance.fnPagingInfo(); - var an = oSettings.aanFeatures.p; - var i, ien, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2); - - if ( oPaging.iTotalPages < iListLength) { - iStart = 1; - iEnd = oPaging.iTotalPages; - } - else if ( oPaging.iPage <= iHalf ) { - iStart = 1; - iEnd = iListLength; - } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) { - iStart = oPaging.iTotalPages - iListLength + 1; - iEnd = oPaging.iTotalPages; - } else { - iStart = oPaging.iPage - iHalf + 1; - iEnd = iStart + iListLength - 1; - } - - for ( i=0, ien=an.length ; i'+j+'') - .insertBefore( $('li:last', an[i])[0] ) - .bind('click', function (e) { - e.preventDefault(); - oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength; - fnDraw( oSettings ); - } ); - } - - // Add / remove disabled classes from the static elements - if ( oPaging.iPage === 0 ) { - $('li:first', an[i]).addClass('disabled'); - } else { - $('li:first', an[i]).removeClass('disabled'); - } - - if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) { - $('li:last', an[i]).addClass('disabled'); - } else { - $('li:last', an[i]).removeClass('disabled'); - } - } - } - } -} ); - - -/* - * TableTools Bootstrap compatibility - * Required TableTools 2.1+ - */ -if ( $.fn.DataTable.TableTools ) { - // Set the classes that TableTools uses to something suitable for Bootstrap - $.extend( true, $.fn.DataTable.TableTools.classes, { - "container": "DTTT btn-group", - "buttons": { - "normal": "btn", - "disabled": "disabled" - }, - "collection": { - "container": "DTTT_dropdown dropdown-menu", - "buttons": { - "normal": "", - "disabled": "disabled" - } - }, - "print": { - "info": "DTTT_print_info modal" - }, - "select": { - "row": "active" - } - } ); - - // Have the collection use a bootstrap compatible dropdown - $.extend( true, $.fn.DataTable.TableTools.DEFAULTS.oTags, { - "collection": { - "container": "ul", - "button": "li", - "liner": "a" - } - } ); -} - - -/* Table initialisation */ -//$(document).ready(function() { -// $('#example').dataTable( { -// "sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p>>", -// "sPaginationType": "bootstrap", -// "oLanguage": { -// "sLengthMenu": "_MENU_ records per page" -// } -// } ); -//} ); \ No newline at end of file diff --git a/wqflask/wqflask/static/packages/DT_bootstrap/images b/wqflask/wqflask/static/packages/DT_bootstrap/images deleted file mode 120000 index f5f1b7d0..00000000 --- a/wqflask/wqflask/static/packages/DT_bootstrap/images +++ /dev/null @@ -1 +0,0 @@ -../../new/packages/DataTables/images/ \ No newline at end of file diff --git a/wqflask/wqflask/templates/index_page_orig.html b/wqflask/wqflask/templates/index_page_orig.html index 48ed0ec5..92392b39 100755 --- a/wqflask/wqflask/templates/index_page_orig.html +++ b/wqflask/wqflask/templates/index_page_orig.html @@ -202,7 +202,9 @@ +
+