#167 Patching to make render error-free in IE7. Modernizr is used to disable libraries.
#167 Patching to make render error-free in IE7. Modernizr is used to disable libraries.

import logging import logging
import datetime import datetime
import os import os
   
from pylons import config from pylons import config
   
from ckan.lib.cli import CkanCommand from ckan.lib.cli import CkanCommand
# No other CKAN imports allowed until _load_config is run, # No other CKAN imports allowed until _load_config is run,
# or logging is disabled # or logging is disabled
   
   
class InitDB(CkanCommand): class InitDB(CkanCommand):
"""Initialise the extension's database tables """Initialise the extension's database tables
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 0 max_args = 0
min_args = 0 min_args = 0
   
def command(self): def command(self):
self._load_config() self._load_config()
   
import ckan.model as model import ckan.model as model
model.Session.remove() model.Session.remove()
model.Session.configure(bind=model.meta.engine) model.Session.configure(bind=model.meta.engine)
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga_report')
   
import ga_model import ga_model
ga_model.init_tables() ga_model.init_tables()
log.info("DB tables are setup") log.info("DB tables are setup")
   
   
class GetAuthToken(CkanCommand): class GetAuthToken(CkanCommand):
""" Get's the Google auth token """ Get's the Google auth token
   
Usage: paster getauthtoken <credentials_file> Usage: paster getauthtoken <credentials_file>
   
Where <credentials_file> is the file name containing the details Where <credentials_file> is the file name containing the details
for the service (obtained from https://code.google.com/apis/console). for the service (obtained from https://code.google.com/apis/console).
By default this is set to credentials.json By default this is set to credentials.json
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 0 max_args = 0
min_args = 0 min_args = 0
   
def command(self): def command(self):
""" """
In this case we don't want a valid service, but rather just to In this case we don't want a valid service, but rather just to
force the user through the auth flow. We allow this to complete to force the user through the auth flow. We allow this to complete to
act as a form of verification instead of just getting the token and act as a form of verification instead of just getting the token and
assuming it is correct. assuming it is correct.
""" """
from ga_auth import init_service from ga_auth import init_service
init_service('token.dat', init_service('token.dat',
self.args[0] if self.args self.args[0] if self.args
else 'credentials.json') else 'credentials.json')
   
class FixTimePeriods(CkanCommand): class FixTimePeriods(CkanCommand):
""" """
Fixes the 'All' records for GA_Urls Fixes the 'All' records for GA_Urls
   
It is possible that older urls that haven't recently been visited It is possible that older urls that haven't recently been visited
do not have All records. This command will traverse through those do not have All records. This command will traverse through those
records and generate valid All records for them. records and generate valid All records for them.
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 0 max_args = 0
min_args = 0 min_args = 0
   
def __init__(self, name): def __init__(self, name):
super(FixTimePeriods, self).__init__(name) super(FixTimePeriods, self).__init__(name)
   
def command(self): def command(self):
import ckan.model as model import ckan.model as model
from ga_model import post_update_url_stats from ga_model import post_update_url_stats
self._load_config() self._load_config()
model.Session.remove() model.Session.remove()
model.Session.configure(bind=model.meta.engine) model.Session.configure(bind=model.meta.engine)
   
log = logging.getLogger('ckanext.ga_report') log = logging.getLogger('ckanext.ga_report')
   
log.info("Updating 'All' records for old URLs") log.info("Updating 'All' records for old URLs")
post_update_url_stats() post_update_url_stats()
log.info("Processing complete") log.info("Processing complete")
   
   
   
class LoadAnalytics(CkanCommand): class LoadAnalytics(CkanCommand):
"""Get data from Google Analytics API and save it """Get data from Google Analytics API and save it
in the ga_model in the ga_model
   
Usage: paster loadanalytics <time-period> Usage: paster loadanalytics <time-period>
   
Where <time-period> is: Where <time-period> is:
all - data for all time all - data for all time
latest - (default) just the 'latest' data latest - (default) just the 'latest' data
YYYY-MM - just data for the specific month YYYY-MM - just data for the specific month
""" """
summary = __doc__.split('\n')[0] summary = __doc__.split('\n')[0]
usage = __doc__ usage = __doc__
max_args = 1 max_args = 1
min_args = 0 min_args = 0
   
def __init__(self, name): def __init__(self, name):
super(LoadAnalytics, self).__init__(name) super(LoadAnalytics, self).__init__(name)
self.parser.add_option('-d', '--delete-first', self.parser.add_option('-d', '--delete-first',
action='store_true', action='store_true',
default=False, default=False,
dest='delete_first', dest='delete_first',
help='Delete data for the period first') help='Delete data for the period first')
self.parser.add_option('-s', '--skip_url_stats', self.parser.add_option('-s', '--skip_url_stats',
action='store_true', action='store_true',
default=False, default=False,
dest='skip_url_stats', dest='skip_url_stats',
help='Skip the download of URL data - just do site-wide stats') help='Skip the download of URL data - just do site-wide stats')
   
def command(self): def command(self):
self._load_config() self._load_config()
   
from download_analytics import DownloadAnalytics from download_analytics import DownloadAnalytics
from ga_auth import (init_service, get_profile_id) from ga_auth import (init_service, get_profile_id)
   
ga_token_filepath = os.path.expanduser(config.get('googleanalytics.token.filepath', '')) ga_token_filepath = os.path.expanduser(config.get('googleanalytics.token.filepath', ''))
if not ga_token_filepath: if not ga_token_filepath:
print 'ERROR: In the CKAN config you need to specify the filepath of the ' \ print 'ERROR: In the CKAN config you need to specify the filepath of the ' \
'Google Analytics token file under key: googleanalytics.token.filepath' 'Google Analytics token file under key: googleanalytics.token.filepath'
return return
   
try: try:
svc = init_service(ga_token_filepath, None) svc = init_service(ga_token_filepath, None)
except TypeError: except TypeError:
print ('Have you correctly run the getauthtoken task and ' print ('Have you correctly run the getauthtoken task and '
'specified the correct token file in the CKAN config under ' 'specified the correct token file in the CKAN config under '
'"googleanalytics.token.filepath"?') '"googleanalytics.token.filepath"?')
return return
   
downloader = DownloadAnalytics(svc, profile_id=get_profile_id(svc), downloader = DownloadAnalytics(svc, profile_id=get_profile_id(svc),
delete_first=self.options.delete_first, delete_first=self.options.delete_first,
skip_url_stats=self.options.skip_url_stats) skip_url_stats=self.options.skip_url_stats)
   
time_period = self.args[0] if self.args else 'latest' time_period = self.args[0] if self.args else 'latest'
if time_period == 'all': if time_period == 'all':
downloader.all_() downloader.all_()
elif time_period == 'latest': elif time_period == 'latest':
downloader.latest() downloader.latest()
else: else:
# The month to use # The month to use
for_date = datetime.datetime.strptime(time_period, '%Y-%m') for_date = datetime.datetime.strptime(time_period, '%Y-%m')
downloader.specific_month(for_date) downloader.specific_month(for_date)
   
import re import re
import csv import csv
import sys import sys
import json import json
import logging import logging
import operator import operator
import collections import collections
from ckan.lib.base import (BaseController, c, g, render, request, response, abort) from ckan.lib.base import (BaseController, c, g, render, request, response, abort)
   
import sqlalchemy import sqlalchemy
from sqlalchemy import func, cast, Integer from sqlalchemy import func, cast, Integer
import ckan.model as model import ckan.model as model
from ga_model import GA_Url, GA_Stat, GA_ReferralStat, GA_Publisher from ga_model import GA_Url, GA_Stat, GA_ReferralStat, GA_Publisher
   
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
DOWNLOADS_AVAILABLE_FROM = '2012-12' DOWNLOADS_AVAILABLE_FROM = '2012-12'
   
def _get_month_name(strdate): def _get_month_name(strdate):
import calendar import calendar
from time import strptime from time import strptime
d = strptime(strdate, '%Y-%m') d = strptime(strdate, '%Y-%m')
return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year) return '%s %s' % (calendar.month_name[d.tm_mon], d.tm_year)
   
def _get_unix_epoch(strdate): def _get_unix_epoch(strdate):
from time import strptime,mktime from time import strptime,mktime
d = strptime(strdate, '%Y-%m') d = strptime(strdate, '%Y-%m')
return int(mktime(d)) return int(mktime(d))
   
def _month_details(cls, stat_key=None): def _month_details(cls, stat_key=None):
''' '''
Returns a list of all the periods for which we have data, unfortunately Returns a list of all the periods for which we have data, unfortunately
knows too much about the type of the cls being passed as GA_Url has a knows too much about the type of the cls being passed as GA_Url has a
more complex query more complex query
   
This may need extending if we add a period_name to the stats This may need extending if we add a period_name to the stats
''' '''
months = [] months = []
day = None day = None
   
q = model.Session.query(cls.period_name,cls.period_complete_day)\ q = model.Session.query(cls.period_name,cls.period_complete_day)\
.filter(cls.period_name!='All').distinct(cls.period_name) .filter(cls.period_name!='All').distinct(cls.period_name)
if stat_key: if stat_key:
q= q.filter(cls.stat_name==stat_key) q= q.filter(cls.stat_name==stat_key)
   
vals = q.order_by("period_name desc").all() vals = q.order_by("period_name desc").all()
   
if vals and vals[0][1]: if vals and vals[0][1]:
day = int(vals[0][1]) day = int(vals[0][1])
ordinal = 'th' if 11 <= day <= 13 \ ordinal = 'th' if 11 <= day <= 13 \
else {1:'st',2:'nd',3:'rd'}.get(day % 10, 'th') else {1:'st',2:'nd',3:'rd'}.get(day % 10, 'th')
day = "{day}{ordinal}".format(day=day, ordinal=ordinal) day = "{day}{ordinal}".format(day=day, ordinal=ordinal)
   
for m in vals: for m in vals:
months.append( (m[0], _get_month_name(m[0]))) months.append( (m[0], _get_month_name(m[0])))
   
return months, day return months, day
   
   
class GaReport(BaseController): class GaReport(BaseController):
   
def csv(self, month): def csv(self, month):
import csv import csv
   
q = model.Session.query(GA_Stat).filter(GA_Stat.stat_name!='Downloads') q = model.Session.query(GA_Stat).filter(GA_Stat.stat_name!='Downloads')
if month != 'all': if month != 'all':
q = q.filter(GA_Stat.period_name==month) q = q.filter(GA_Stat.period_name==month)
entries = q.order_by('GA_Stat.period_name, GA_Stat.stat_name, GA_Stat.key').all() entries = q.order_by('GA_Stat.period_name, GA_Stat.stat_name, GA_Stat.key').all()
   
response.headers['Content-Type'] = "text/csv; charset=utf-8" response.headers['Content-Type'] = "text/csv; charset=utf-8"
response.headers['Content-Disposition'] = str('attachment; filename=stats_%s.csv' % (month,)) response.headers['Content-Disposition'] = str('attachment; filename=stats_%s.csv' % (month,))
   
writer = csv.writer(response) writer = csv.writer(response)
writer.writerow(["Period", "Statistic", "Key", "Value"]) writer.writerow(["Period", "Statistic", "Key", "Value"])
   
for entry in entries: for entry in entries:
writer.writerow([entry.period_name.encode('utf-8'), writer.writerow([entry.period_name.encode('utf-8'),
entry.stat_name.encode('utf-8'), entry.stat_name.encode('utf-8'),
entry.key.encode('utf-8'), entry.key.encode('utf-8'),
entry.value.encode('utf-8')]) entry.value.encode('utf-8')])
   
   
def index(self): def index(self):
   
# Get the month details by fetching distinct values and determining the # Get the month details by fetching distinct values and determining the
# month names from the values. # month names from the values.
c.months, c.day = _month_details(GA_Stat) c.months, c.day = _month_details(GA_Stat)
   
# Work out which month to show, based on query params of the first item # Work out which month to show, based on query params of the first item
c.month_desc = 'all months' c.month_desc = 'all months'
c.month = request.params.get('month', '') c.month = request.params.get('month', '')
if c.month: if c.month:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
q = model.Session.query(GA_Stat).\ q = model.Session.query(GA_Stat).\
filter(GA_Stat.stat_name=='Totals') filter(GA_Stat.stat_name=='Totals')
if c.month: if c.month:
q = q.filter(GA_Stat.period_name==c.month) q = q.filter(GA_Stat.period_name==c.month)
entries = q.order_by('ga_stat.key').all() entries = q.order_by('ga_stat.key').all()
   
def clean_key(key, val): def clean_key(key, val):
if key in ['Average time on site', 'Pages per visit', 'New visits', 'Bounce rate (home page)']: if key in ['Average time on site', 'Pages per visit', 'New visits', 'Bounce rate (home page)']:
val = "%.2f" % round(float(val), 2) val = "%.2f" % round(float(val), 2)
if key == 'Average time on site': if key == 'Average time on site':
mins, secs = divmod(float(val), 60) mins, secs = divmod(float(val), 60)
hours, mins = divmod(mins, 60) hours, mins = divmod(mins, 60)
val = '%02d:%02d:%02d (%s seconds) ' % (hours, mins, secs, val) val = '%02d:%02d:%02d (%s seconds) ' % (hours, mins, secs, val)
if key in ['New visits','Bounce rate (home page)']: if key in ['New visits','Bounce rate (home page)']:
val = "%s%%" % val val = "%s%%" % val
if key in ['Total page views', 'Total visits']: if key in ['Total page views', 'Total visits']:
val = int(val) val = int(val)
   
return key, val return key, val
   
# Query historic values for sparkline rendering # Query historic values for sparkline rendering
sparkline_query = model.Session.query(GA_Stat)\ sparkline_query = model.Session.query(GA_Stat)\
.filter(GA_Stat.stat_name=='Totals')\ .filter(GA_Stat.stat_name=='Totals')\
.order_by(GA_Stat.period_name) .order_by(GA_Stat.period_name)
sparkline_data = {} sparkline_data = {}
for x in sparkline_query: for x in sparkline_query:
sparkline_data[x.key] = sparkline_data.get(x.key,[]) sparkline_data[x.key] = sparkline_data.get(x.key,[])
key, val = clean_key(x.key,float(x.value)) key, val = clean_key(x.key,float(x.value))
tooltip = '%s: %s' % (_get_month_name(x.period_name), val) tooltip = '%s: %s' % (_get_month_name(x.period_name), val)
sparkline_data[x.key].append( (tooltip,x.value) ) sparkline_data[x.key].append( (tooltip,x.value) )
# Trim the latest month, as it looks like a huge dropoff # Trim the latest month, as it looks like a huge dropoff
for key in sparkline_data: for key in sparkline_data:
sparkline_data[key] = sparkline_data[key][:-1] sparkline_data[key] = sparkline_data[key][:-1]
   
c.global_totals = [] c.global_totals = []
if c.month: if c.month:
for e in entries: for e in entries:
key, val = clean_key(e.key, e.value) key, val = clean_key(e.key, e.value)
sparkline = sparkline_data[e.key] sparkline = sparkline_data[e.key]
c.global_totals.append((key, val, sparkline)) c.global_totals.append((key, val, sparkline))
else: else:
d = collections.defaultdict(list) d = collections.defaultdict(list)
for e in entries: for e in entries:
d[e.key].append(float(e.value)) d[e.key].append(float(e.value))
for k, v in d.iteritems(): for k, v in d.iteritems():
if k in ['Total page views', 'Total visits']: if k in ['Total page views', 'Total visits']:
v = sum(v) v = sum(v)
else: else:
v = float(sum(v))/float(len(v)) v = float(sum(v))/float(len(v))
sparkline = sparkline_data[k] sparkline = sparkline_data[k]
key, val = clean_key(k,v) key, val = clean_key(k,v)
   
c.global_totals.append((key, val, sparkline)) c.global_totals.append((key, val, sparkline))
# Sort the global totals into a more pleasant order # Sort the global totals into a more pleasant order
def sort_func(x): def sort_func(x):
key = x[0] key = x[0]
total_order = ['Total page views','Total visits','Pages per visit'] total_order = ['Total page views','Total visits','Pages per visit']
if key in total_order: if key in total_order:
return total_order.index(key) return total_order.index(key)
return 999 return 999
c.global_totals = sorted(c.global_totals, key=sort_func) c.global_totals = sorted(c.global_totals, key=sort_func)
   
keys = { keys = {
'Browser versions': 'browser_versions', 'Browser versions': 'browser_versions',
'Browsers': 'browsers', 'Browsers': 'browsers',
'Operating Systems versions': 'os_versions', 'Operating Systems versions': 'os_versions',
'Operating Systems': 'os', 'Operating Systems': 'os',
'Social sources': 'social_networks', 'Social sources': 'social_networks',
'Languages': 'languages', 'Languages': 'languages',
'Country': 'country' 'Country': 'country'
} }
   
def shorten_name(name, length=60): def shorten_name(name, length=60):
return (name[:length] + '..') if len(name) > 60 else name return (name[:length] + '..') if len(name) > 60 else name
   
def fill_out_url(url): def fill_out_url(url):
import urlparse import urlparse
return urlparse.urljoin(g.site_url, url) return urlparse.urljoin(g.site_url, url)
   
c.social_referrer_totals, c.social_referrers = [], [] c.social_referrer_totals, c.social_referrers = [], []
q = model.Session.query(GA_ReferralStat) q = model.Session.query(GA_ReferralStat)
q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q
q = q.order_by('ga_referrer.count::int desc') q = q.order_by('ga_referrer.count::int desc')
for entry in q.all(): for entry in q.all():
c.social_referrers.append((shorten_name(entry.url), fill_out_url(entry.url), c.social_referrers.append((shorten_name(entry.url), fill_out_url(entry.url),
entry.source,entry.count)) entry.source,entry.count))
   
q = model.Session.query(GA_ReferralStat.url, q = model.Session.query(GA_ReferralStat.url,
func.sum(GA_ReferralStat.count).label('count')) func.sum(GA_ReferralStat.count).label('count'))
q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q q = q.filter(GA_ReferralStat.period_name==c.month) if c.month else q
q = q.order_by('count desc').group_by(GA_ReferralStat.url) q = q.order_by('count desc').group_by(GA_ReferralStat.url)
for entry in q.all(): for entry in q.all():
c.social_referrer_totals.append((shorten_name(entry[0]), fill_out_url(entry[0]),'', c.social_referrer_totals.append((shorten_name(entry[0]), fill_out_url(entry[0]),'',
entry[1])) entry[1]))
   
for k, v in keys.iteritems(): for k, v in keys.iteritems():
q = model.Session.query(GA_Stat).\ q = model.Session.query(GA_Stat).\
filter(GA_Stat.stat_name==k).\ filter(GA_Stat.stat_name==k).\
order_by(GA_Stat.period_name) order_by(GA_Stat.period_name)
# Run the query on all months to gather graph data # Run the query on all months to gather graph data
graph = {} graph = {}
for stat in q: for stat in q:
graph[ stat.key ] = graph.get(stat.key,{ graph[ stat.key ] = graph.get(stat.key,{
'name':stat.key, 'name':stat.key,
'data': [] 'data': []
}) })
graph[ stat.key ]['data'].append({ graph[ stat.key ]['data'].append({
'x':_get_unix_epoch(stat.period_name), 'x':_get_unix_epoch(stat.period_name),
'y':float(stat.value) 'y':float(stat.value)
}) })
setattr(c, v+'_graph', json.dumps( _to_rickshaw(graph.values(),percentageMode=True) )) setattr(c, v+'_graph', json.dumps( _to_rickshaw(graph.values(),percentageMode=True) ))
   
# Buffer the tabular data # Buffer the tabular data
if c.month: if c.month:
entries = [] entries = []
q = q.filter(GA_Stat.period_name==c.month).\ q = q.filter(GA_Stat.period_name==c.month).\
order_by('ga_stat.value::int desc') order_by('ga_stat.value::int desc')
   
d = collections.defaultdict(int) d = collections.defaultdict(int)
for e in q.all(): for e in q.all():
d[e.key] += int(e.value) d[e.key] += int(e.value)
entries = [] entries = []
for key, val in d.iteritems(): for key, val in d.iteritems():
entries.append((key,val,)) entries.append((key,val,))
entries = sorted(entries, key=operator.itemgetter(1), reverse=True) entries = sorted(entries, key=operator.itemgetter(1), reverse=True)
   
# Get the total for each set of values and then set the value as # Get the total for each set of values and then set the value as
# a percentage of the total # a percentage of the total
if k == 'Social sources': if k == 'Social sources':
total = sum([x for n,x,graph in c.global_totals if n == 'Total visits']) total = sum([x for n,x,graph in c.global_totals if n == 'Total visits'])
else: else:
total = sum([num for _,num in entries]) total = sum([num for _,num in entries])
setattr(c, v, [(k,_percent(v,total)) for k,v in entries ]) setattr(c, v, [(k,_percent(v,total)) for k,v in entries ])
   
return render('ga_report/site/index.html') return render('ga_report/site/index.html')
   
   
class GaDatasetReport(BaseController): class GaDatasetReport(BaseController):
""" """
Displays the pageview and visit count for datasets Displays the pageview and visit count for datasets
with options to filter by publisher and time period. with options to filter by publisher and time period.
""" """
def publisher_csv(self, month): def publisher_csv(self, month):
''' '''
Returns a CSV of each publisher with the total number of dataset Returns a CSV of each publisher with the total number of dataset
views & visits. views & visits.
''' '''
c.month = month if not month == 'all' else '' c.month = month if not month == 'all' else ''
response.headers['Content-Type'] = "text/csv; charset=utf-8" response.headers['Content-Type'] = "text/csv; charset=utf-8"
response.headers['Content-Disposition'] = str('attachment; filename=publishers_%s.csv' % (month,)) response.headers['Content-Disposition'] = str('attachment; filename=publishers_%s.csv' % (month,))
   
writer = csv.writer(response) writer = csv.writer(response)
writer.writerow(["Publisher Title", "Publisher Name", "Views", "Visits", "Period Name"]) writer.writerow(["Publisher Title", "Publisher Name", "Views", "Visits", "Period Name"])
   
top_publishers, top_publishers_graph = _get_top_publishers(None) top_publishers, top_publishers_graph = _get_top_publishers(None)
   
for publisher,view,visit in top_publishers: for publisher,view,visit in top_publishers:
writer.writerow([publisher.title.encode('utf-8'), writer.writerow([publisher.title.encode('utf-8'),
publisher.name.encode('utf-8'), publisher.name.encode('utf-8'),
view, view,
visit, visit,
month]) month])
   
def dataset_csv(self, id='all', month='all'): def dataset_csv(self, id='all', month='all'):
''' '''
Returns a CSV with the number of views & visits for each dataset. Returns a CSV with the number of views & visits for each dataset.
   
:param id: A Publisher ID or None if you want for all :param id: A Publisher ID or None if you want for all
:param month: The time period, or 'all' :param month: The time period, or 'all'
''' '''
c.month = month if not month == 'all' else '' c.month = month if not month == 'all' else ''
if id != 'all': if id != 'all':
c.publisher = model.Group.get(id) c.publisher = model.Group.get(id)
if not c.publisher: if not c.publisher:
abort(404, 'A publisher with that name could not be found') abort(404, 'A publisher with that name could not be found')
   
packages = self._get_packages(c.publisher) packages = self._get_packages(c.publisher)
response.headers['Content-Type'] = "text/csv; charset=utf-8" response.headers['Content-Type'] = "text/csv; charset=utf-8"
response.headers['Content-Disposition'] = \ response.headers['Content-Disposition'] = \
str('attachment; filename=datasets_%s_%s.csv' % (c.publisher_name, month,)) str('attachment; filename=datasets_%s_%s.csv' % (c.publisher_name, month,))
   
writer = csv.writer(response) writer = csv.writer(response)
writer.writerow(["Dataset Title", "Dataset Name", "Views", "Visits", "Resource downloads", "Period Name"]) writer.writerow(["Dataset Title", "Dataset Name", "Views", "Visits", "Resource downloads", "Period Name"])
   
for package,view,visit,downloads in packages: for package,view,visit,downloads in packages:
writer.writerow([package.title.encode('utf-8'), writer.writerow([package.title.encode('utf-8'),
package.name.encode('utf-8'), package.name.encode('utf-8'),
view, view,
visit, visit,
downloads, downloads,
month]) month])
   
def publishers(self): def publishers(self):
'''A list of publishers and the number of views/visits for each''' '''A list of publishers and the number of views/visits for each'''
   
# Get the month details by fetching distinct values and determining the # Get the month details by fetching distinct values and determining the
# month names from the values. # month names from the values.
c.months, c.day = _month_details(GA_Url) c.months, c.day = _month_details(GA_Url)
   
# Work out which month to show, based on query params of the first item # Work out which month to show, based on query params of the first item
c.month = request.params.get('month', '') c.month = request.params.get('month', '')
c.month_desc = 'all months' c.month_desc = 'all months'
if c.month: if c.month:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
c.top_publishers, graph_data = _get_top_publishers() c.top_publishers, graph_data = _get_top_publishers()
c.top_publishers_graph = json.dumps( _to_rickshaw(graph_data.values()) ) c.top_publishers_graph = json.dumps( _to_rickshaw(graph_data.values()) )
   
return render('ga_report/publisher/index.html') return render('ga_report/publisher/index.html')
   
def _get_packages(self, publisher=None, count=-1): def _get_packages(self, publisher=None, count=-1):
'''Returns the datasets in order of views''' '''Returns the datasets in order of views'''
have_download_data = True have_download_data = True
month = c.month or 'All' month = c.month or 'All'
if month != 'All': if month != 'All':
have_download_data = month >= DOWNLOADS_AVAILABLE_FROM have_download_data = month >= DOWNLOADS_AVAILABLE_FROM
   
q = model.Session.query(GA_Url,model.Package)\ q = model.Session.query(GA_Url,model.Package)\
.filter(model.Package.name==GA_Url.package_id)\ .filter(model.Package.name==GA_Url.package_id)\
.filter(GA_Url.url.like('/dataset/%')) .filter(GA_Url.url.like('/dataset/%'))
if publisher: if publisher:
q = q.filter(GA_Url.department_id==publisher.name) q = q.filter(GA_Url.department_id==publisher.name)
q = q.filter(GA_Url.period_name==month) q = q.filter(GA_Url.period_name==month)
q = q.order_by('ga_url.pageviews::int desc') q = q.order_by('ga_url.pageviews::int desc')
top_packages = [] top_packages = []
if count == -1: if count == -1:
entries = q.all() entries = q.all()
else: else:
entries = q.limit(count) entries = q.limit(count)
   
for entry,package in entries: for entry,package in entries:
if package: if package:
# Downloads .... # Downloads ....
if have_download_data: if have_download_data:
dls = model.Session.query(GA_Stat).\ dls = model.Session.query(GA_Stat).\
filter(GA_Stat.stat_name=='Downloads').\ filter(GA_Stat.stat_name=='Downloads').\
filter(GA_Stat.key==package.name) filter(GA_Stat.key==package.name)
if month != 'All': # Fetch everything unless the month is specific if month != 'All': # Fetch everything unless the month is specific
dls = dls.filter(GA_Stat.period_name==month) dls = dls.filter(GA_Stat.period_name==month)
downloads = 0 downloads = 0
for x in dls: for x in dls:
downloads += int(x.value) downloads += int(x.value)
else: else:
downloads = 'No data' downloads = 'No data'
top_packages.append((package, entry.pageviews, entry.visits, downloads)) top_packages.append((package, entry.pageviews, entry.visits, downloads))
else: else:
log.warning('Could not find package associated package') log.warning('Could not find package associated package')
   
return top_packages return top_packages
   
def read(self): def read(self):
''' '''
Lists the most popular datasets across all publishers Lists the most popular datasets across all publishers
''' '''
return self.read_publisher(None) return self.read_publisher(None)
   
def read_publisher(self, id): def read_publisher(self, id):
''' '''
Lists the most popular datasets for a publisher (or across all publishers) Lists the most popular datasets for a publisher (or across all publishers)
''' '''
count = 20 count = 20
   
c.publishers = _get_publishers() c.publishers = _get_publishers()
   
id = request.params.get('publisher', id) id = request.params.get('publisher', id)
if id and id != 'all': if id and id != 'all':
c.publisher = model.Group.get(id) c.publisher = model.Group.get(id)
if not c.publisher: if not c.publisher:
abort(404, 'A publisher with that name could not be found') abort(404, 'A publisher with that name could not be found')
c.publisher_name = c.publisher.name c.publisher_name = c.publisher.name
c.top_packages = [] # package, dataset_views in c.top_packages c.top_packages = [] # package, dataset_views in c.top_packages
   
# Get the month details by fetching distinct values and determining the # Get the month details by fetching distinct values and determining the
# month names from the values. # month names from the values.
c.months, c.day = _month_details(GA_Url) c.months, c.day = _month_details(GA_Url)
   
# Work out which month to show, based on query params of the first item # Work out which month to show, based on query params of the first item
c.month = request.params.get('month', '') c.month = request.params.get('month', '')
if not c.month: if not c.month:
c.month_desc = 'all months' c.month_desc = 'all months'
else: else:
c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month]) c.month_desc = ''.join([m[1] for m in c.months if m[0]==c.month])
   
month = c.month or 'All' month = c.month or 'All'
c.publisher_page_views = 0 c.publisher_page_views = 0
q = model.Session.query(GA_Url).\ q = model.Session.query(GA_Url).\
filter(GA_Url.url=='/publisher/%s' % c.publisher_name) filter(GA_Url.url=='/publisher/%s' % c.publisher_name)
entry = q.filter(GA_Url.period_name==c.month).first() entry = q.filter(GA_Url.period_name==c.month).first()
c.publisher_page_views = entry.pageviews if entry else 0 c.publisher_page_views = entry.pageviews if entry else 0
   
c.top_packages = self._get_packages(c.publisher, 20) c.top_packages = self._get_packages(c.publisher, 20)
   
# Graph query # Graph query
top_package_names = [ x[0].name for x in c.top_packages ] top_package_names = [ x[0].name for x in c.top_packages ]
graph_query = model.Session.query(GA_Url,model.Package)\ graph_query = model.Session.query(GA_Url,model.Package)\
.filter(model.Package.name==GA_Url.package_id)\ .filter(model.Package.name==GA_Url.package_id)\
.filter(GA_Url.url.like('/dataset/%'))\ .filter(GA_Url.url.like('/dataset/%'))\
.filter(GA_Url.package_id.in_(top_package_names)) .filter(GA_Url.package_id.in_(top_package_names))
graph_data = {} graph_data = {}
for entry,package in graph_query: for entry,package in graph_query:
if not package: continue if not package: continue
if entry.period_name=='All': continue if entry.period_name=='All': continue
graph_data[package.id] = graph_data.get(package.id,{ graph_data[package.id] = graph_data.get(package.id,{
'name':package.title, 'name':package.title,
'data':[] 'data':[]
}) })
graph_data[package.id]['data'].append({ graph_data[package.id]['data'].append({
'x':_get_unix_epoch(entry.period_name), 'x':_get_unix_epoch(entry.period_name),
'y':int(entry.pageviews), 'y':int(entry.pageviews),
}) })
c.graph_data = json.dumps( _to_rickshaw(graph_data.values()) ) c.graph_data = json.dumps( _to_rickshaw(graph_data.values()) )
   
return render('ga_report/publisher/read.html') return render('ga_report/publisher/read.html')
   
def _to_rickshaw(data, percentageMode=False): def _to_rickshaw(data, percentageMode=False):
if data==[]: if data==[]:
return data return data
# Create a consistent x-axis # Create a consistent x-axis
num_points = [ len(package['data']) for package in data ] num_points = [ len(package['data']) for package in data ]
ideal_index = num_points.index( max(num_points) ) ideal_index = num_points.index( max(num_points) )
x_axis = [ point['x'] for point in data[ideal_index]['data'] ] x_axis = [ point['x'] for point in data[ideal_index]['data'] ]
for package in data: for package in data:
xs = [ point['x'] for point in package['data'] ] xs = [ point['x'] for point in package['data'] ]
assert set(xs).issubset( set(x_axis) ), (xs, x_axis) assert set(xs).issubset( set(x_axis) ), (xs, x_axis)
# Zero pad any missing values # Zero pad any missing values
for x in set(x_axis).difference(set(xs)): for x in set(x_axis).difference(set(xs)):
package['data'].append( {'x':x, 'y':0} ) package['data'].append( {'x':x, 'y':0} )
assert len(package['data'])==len(x_axis), (len(package['data']),len(x_axis),package['data'],x_axis,set(x_axis).difference(set(xs))) assert len(package['data'])==len(x_axis), (len(package['data']),len(x_axis),package['data'],x_axis,set(x_axis).difference(set(xs)))
if percentageMode: if percentageMode:
# Transform data into percentage stacks # Transform data into percentage stacks
totals = {} totals = {}
for x in x_axis: for x in x_axis:
for package in data: for package in data:
for point in package['data']: for point in package['data']:
totals[ point['x'] ] = totals.get(point['x'],0) + point['y'] totals[ point['x'] ] = totals.get(point['x'],0) + point['y']
# Roll insignificant series into a catch-all # Roll insignificant series into a catch-all
THRESHOLD = 0.01 THRESHOLD = 0.01
significant_series = [] significant_series = []
for package in data: for package in data:
for point in package['data']: for point in package['data']:
fraction = float(point['y']) / totals[point['x']] fraction = float(point['y']) / totals[point['x']]
if fraction>THRESHOLD and not (package in significant_series): if fraction>THRESHOLD and not (package in significant_series):
significant_series.append(package) significant_series.append(package)
temp = {} temp = {}
for package in data: for package in data:
if package in significant_series: continue if package in significant_series: continue
for point in package['data']: for point in package['data']:
temp[point['x']] = temp.get(point['x'],0) + point['y'] temp[point['x']] = temp.get(point['x'],0) + point['y']
catch_all = { 'name':'Other','data': [ {'x':x,'y':y} for x,y in temp.items() ] } catch_all = { 'name':'Other','data': [ {'x':x,'y':y} for x,y in temp.items() ] }
# Roll insignificant series into one # Roll insignificant series into one
data = significant_series data = significant_series
data.append(catch_all) data.append(catch_all)
  # Turn each point into a percentage
  for package in data:
  for point in package['data']:
  point['y'] = (point['y']*100) / totals[point['x']]
# Sort the points # Sort the points
for package in data: for package in data:
package['data'] = sorted( package['data'], key=lambda x:x['x'] ) package['data'] = sorted( package['data'], key=lambda x:x['x'] )
# Strip the latest month's incomplete analytics # Strip the latest month's incomplete analytics
package['data'] = package['data'][:-1] package['data'] = package['data'][:-1]
return data return data
   
   
def _get_top_publishers(limit=20): def _get_top_publishers(limit=20):
''' '''
Returns a list of the top 20 publishers by dataset visits. Returns a list of the top 20 publishers by dataset visits.
(The number to show can be varied with 'limit') (The number to show can be varied with 'limit')
''' '''
month = c.month or 'All' month = c.month or 'All'
connection = model.Session.connection() connection = model.Session.connection()
q = """ q = """
select department_id, sum(pageviews::int) views, sum(visits::int) visits select department_id, sum(pageviews::int) views, sum(visits::int) visits
from ga_url from ga_url
where department_id <> '' where department_id <> ''
and package_id <> '' and package_id <> ''
and url like '/dataset/%%' and url like '/dataset/%%'
and period_name=%s and period_name=%s
group by department_id order by views desc group by department_id order by views desc
""" """
if limit: if limit:
q = q + " limit %s;" % (limit) q = q + " limit %s;" % (limit)
   
top_publishers = [] top_publishers = []
res = connection.execute(q, month) res = connection.execute(q, month)
department_ids = [] department_ids = []
for row in res: for row in res:
g = model.Group.get(row[0]) g = model.Group.get(row[0])
if g: if g:
department_ids.append(row[0]) department_ids.append(row[0])
top_publishers.append((g, row[1], row[2])) top_publishers.append((g, row[1], row[2]))
   
graph = {} graph = {}
if limit is not None: if limit is not None:
# Query for a history graph of these publishers # Query for a history graph of these publishers
q = model.Session.query( q = model.Session.query(
GA_Url.department_id, GA_Url.department_id,
GA_Url.period_name, GA_Url.period_name,
func.sum(cast(GA_Url.pageviews,sqlalchemy.types.INT)))\ func.sum(cast(GA_Url.pageviews,sqlalchemy.types.INT)))\
.filter( GA_Url.department_id.in_(department_ids) )\ .filter( GA_Url.department_id.in_(department_ids) )\
.filter( GA_Url.period_name!='All' )\ .filter( GA_Url.period_name!='All' )\
.filter( GA_Url.url.like('/dataset/%') )\ .filter( GA_Url.url.like('/dataset/%') )\
.filter( GA_Url.package_id!='' )\ .filter( GA_Url.package_id!='' )\
.group_by( GA_Url.department_id, GA_Url.period_name ) .group_by( GA_Url.department_id, GA_Url.period_name )
for dept_id,period_name,views in q: for dept_id,period_name,views in q:
graph[dept_id] = graph.get( dept_id, { graph[dept_id] = graph.get( dept_id, {
'name' : model.Group.get(dept_id).title, 'name' : model.Group.get(dept_id).title,
'data' : [] 'data' : []
}) })
graph[dept_id]['data'].append({ graph[dept_id]['data'].append({
'x': _get_unix_epoch(period_name), 'x': _get_unix_epoch(period_name),
'y': views 'y': views
}) })
return top_publishers, graph return top_publishers, graph
   
   
def _get_publishers(): def _get_publishers():
''' '''
Returns a list of all publishers. Each item is a tuple: Returns a list of all publishers. Each item is a tuple:
(name, title) (name, title)
''' '''
publishers = [] publishers = []
for pub in model.Session.query(model.Group).\ for pub in model.Session.query(model.Group).\
filter(model.Group.type=='publisher').\ filter(model.Group.type=='publisher').\
filter(model.Group.state=='active').\ filter(model.Group.state=='active').\
order_by(model.Group.name): order_by(model.Group.name):
publishers.append((pub.name, pub.title)) publishers.append((pub.name, pub.title))
return publishers return publishers
   
def _percent(num, total): def _percent(num, total):
p = 100 * float(num)/float(total) p = 100 * float(num)/float(total)
return "%.2f%%" % round(p, 2) return "%.2f%%" % round(p, 2)
   
import os import os
import logging import logging
import datetime import datetime
import collections import collections
from pylons import config from pylons import config
from ga_model import _normalize_url from ga_model import _normalize_url
import ga_model import ga_model
   
#from ga_client import GA #from ga_client import GA
   
log = logging.getLogger('ckanext.ga-report') log = logging.getLogger('ckanext.ga-report')
   
FORMAT_MONTH = '%Y-%m' FORMAT_MONTH = '%Y-%m'
MIN_VIEWS = 50 MIN_VIEWS = 50
MIN_VISITS = 20 MIN_VISITS = 20
MIN_DOWNLOADS = 10 MIN_DOWNLOADS = 10
   
class DownloadAnalytics(object): class DownloadAnalytics(object):
'''Downloads and stores analytics info''' '''Downloads and stores analytics info'''
   
def __init__(self, service=None, profile_id=None, delete_first=False, def __init__(self, service=None, profile_id=None, delete_first=False,
skip_url_stats=False): skip_url_stats=False):
self.period = config['ga-report.period'] self.period = config['ga-report.period']
self.service = service self.service = service
self.profile_id = profile_id self.profile_id = profile_id
self.delete_first = delete_first self.delete_first = delete_first
self.skip_url_stats = skip_url_stats self.skip_url_stats = skip_url_stats
   
def specific_month(self, date): def specific_month(self, date):
import calendar import calendar
   
first_of_this_month = datetime.datetime(date.year, date.month, 1) first_of_this_month = datetime.datetime(date.year, date.month, 1)
_, last_day_of_month = calendar.monthrange(int(date.year), int(date.month)) _, last_day_of_month = calendar.monthrange(int(date.year), int(date.month))
last_of_this_month = datetime.datetime(date.year, date.month, last_day_of_month) last_of_this_month = datetime.datetime(date.year, date.month, last_day_of_month)
  # if this is the latest month, note that it is only up until today
  now = datetime.datetime.now()
  if now.year == date.year and now.month == date.month:
  last_day_of_month = now.day
  last_of_this_month = now
periods = ((date.strftime(FORMAT_MONTH), periods = ((date.strftime(FORMAT_MONTH),
last_day_of_month, last_day_of_month,
first_of_this_month, last_of_this_month),) first_of_this_month, last_of_this_month),)
self.download_and_store(periods) self.download_and_store(periods)
   
   
def latest(self): def latest(self):
if self.period == 'monthly': if self.period == 'monthly':
# from first of this month to today # from first of this month to today
now = datetime.datetime.now() now = datetime.datetime.now()
first_of_this_month = datetime.datetime(now.year, now.month, 1) first_of_this_month = datetime.datetime(now.year, now.month, 1)
periods = ((now.strftime(FORMAT_MONTH), periods = ((now.strftime(FORMAT_MONTH),
now.day, now.day,
first_of_this_month, now),) first_of_this_month, now),)
else: else:
raise NotImplementedError raise NotImplementedError
self.download_and_store(periods) self.download_and_store(periods)
   
   
def for_date(self, for_date): def for_date(self, for_date):
assert isinstance(since_date, datetime.datetime) assert isinstance(since_date, datetime.datetime)
periods = [] # (period_name, period_complete_day, start_date, end_date) periods = [] # (period_name, period_complete_day, start_date, end_date)
if self.period == 'monthly': if self.period == 'monthly':
first_of_the_months_until_now = [] first_of_the_months_until_now = []
year = for_date.year year = for_date.year
month = for_date.month month = for_date.month
now = datetime.datetime.now() now = datetime.datetime.now()
first_of_this_month = datetime.datetime(now.year, now.month, 1) first_of_this_month = datetime.datetime(now.year, now.month, 1)
while True: while True:
first_of_the_month = datetime.datetime(year, month, 1) first_of_the_month = datetime.datetime(year, month, 1)
if first_of_the_month == first_of_this_month: if first_of_the_month == first_of_this_month:
periods.append((now.strftime(FORMAT_MONTH), periods.append((now.strftime(FORMAT_MONTH),
now.day, now.day,
first_of_this_month, now)) first_of_this_month, now))
break break
elif first_of_the_month < first_of_this_month: elif first_of_the_month < first_of_this_month:
in_the_next_month = first_of_the_month + datetime.timedelta(40) in_the_next_month = first_of_the_month + datetime.timedelta(40)
last_of_the_month = datetime.datetime(in_the_next_month.year, last_of_the_month = datetime.datetime(in_the_next_month.year,
in_the_next_month.month, 1)\ in_the_next_month.month, 1)\
- datetime.timedelta(1) - datetime.timedelta(1)
periods.append((now.strftime(FORMAT_MONTH), 0, periods.append((now.strftime(FORMAT_MONTH), 0,
first_of_the_month, last_of_the_month)) first_of_the_month, last_of_the_month))
else: else:
# first_of_the_month has got to the future somehow # first_of_the_month has got to the future somehow
break break
month += 1 month += 1
if month > 12: if month > 12:
year += 1 year += 1
month = 1 month = 1
else: else:
raise NotImplementedError raise NotImplementedError
self.download_and_store(periods) self.download_and_store(periods)
   
@staticmethod @staticmethod
def get_full_period_name(period_name, period_complete_day): def get_full_period_name(period_name, period_complete_day):
if period_complete_day: if period_complete_day:
return period_name + ' (up to %ith)' % period_complete_day return period_name + ' (up to %ith)' % period_complete_day
else: else:
return period_name return period_name
   
   
def download_and_store(self, periods): def download_and_store(self, periods):
for period_name, period_complete_day, start_date, end_date in periods: for period_name, period_complete_day, start_date, end_date in periods:
log.info('Period "%s" (%s - %s)', log.info('Period "%s" (%s - %s)',
self.get_full_period_name(period_name, period_complete_day), self.get_full_period_name(period_name, period_complete_day),
start_date.strftime('%Y-%m-%d'), start_date.strftime('%Y-%m-%d'),
end_date.strftime('%Y-%m-%d')) end_date.strftime('%Y-%m-%d'))
   
if self.delete_first: if self.delete_first:
log.info('Deleting existing Analytics for this period "%s"', log.info('Deleting existing Analytics for this period "%s"',
period_name) period_name)
ga_model.delete(period_name) ga_model.delete(period_name)
   
if not self.skip_url_stats: if not self.skip_url_stats:
# Clean out old url data before storing the new # Clean out old url data before storing the new
ga_model.pre_update_url_stats(period_name) ga_model.pre_update_url_stats(period_name)
   
accountName = config.get('googleanalytics.account') accountName = config.get('googleanalytics.account')
   
log.info('Downloading analytics for dataset views') log.info('Downloading analytics for dataset views')
data = self.download(start_date, end_date, '~/%s/dataset/[a-z0-9-_]+' % accountName) data = self.download(start_date, end_date, '~/%s/dataset/[a-z0-9-_]+' % accountName)
   
log.info('Storing dataset views (%i rows)', len(data.get('url'))) log.info('Storing dataset views (%i rows)', len(data.get('url')))
self.store(period_name, period_complete_day, data, ) self.store(period_name, period_complete_day, data, )
   
log.info('Downloading analytics for publisher views') log.info('Downloading analytics for publisher views')
data = self.download(start_date, end_date, '~/%s/publisher/[a-z0-9-_]+' % accountName) data = self.download(start_date, end_date, '~/%s/publisher/[a-z0-9-_]+' % accountName)
   
log.info('Storing publisher views (%i rows)', len(data.get('url'))) log.info('Storing publisher views (%i rows)', len(data.get('url')))
self.store(period_name, period_complete_day, data,) self.store(period_name, period_complete_day, data,)
   
# Make sure the All records are correct. # Make sure the All records are correct.
ga_model.post_update_url_stats() ga_model.post_update_url_stats()
   
log.info('Aggregating datasets by publisher') log.info('Associating datasets with their publisher')
ga_model.update_publisher_stats(period_name) # about 30 seconds. ga_model.update_publisher_stats(period_name) # about 30 seconds.
   
   
log.info('Downloading and storing analytics for site-wide stats') log.info('Downloading and storing analytics for site-wide stats')
self.sitewide_stats( period_name, period_complete_day ) self.sitewide_stats( period_name, period_complete_day )
   
log.info('Downloading and storing analytics for social networks') log.info('Downloading and storing analytics for social networks')
self.update_social_info(period_name, start_date, end_date) self.update_social_info(period_name, start_date, end_date)
   
   
def update_social_info(self, period_name, start_date, end_date): def update_social_info(self, period_name, start_date, end_date):
start_date = start_date.strftime('%Y-%m-%d') start_date = start_date.strftime('%Y-%m-%d')
end_date = end_date.strftime('%Y-%m-%d') end_date = end_date.strftime('%Y-%m-%d')
query = 'ga:hasSocialSourceReferral=~Yes$' query = 'ga:hasSocialSourceReferral=~Yes$'
metrics = 'ga:entrances' metrics = 'ga:entrances'
sort = '-ga:entrances' sort = '-ga:entrances'
   
# Supported query params at # Supported query params at
# https://developers.google.com/analytics/devguides/reporting/core/v3/reference # https://developers.google.com/analytics/devguides/reporting/core/v3/reference
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
filters=query, filters=query,
start_date=start_date, start_date=start_date,
metrics=metrics, metrics=metrics,
sort=sort, sort=sort,
dimensions="ga:landingPagePath,ga:socialNetwork", dimensions="ga:landingPagePath,ga:socialNetwork",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
data = collections.defaultdict(list) data = collections.defaultdict(list)
rows = results.get('rows',[]) rows = results.get('rows',[])
for row in rows: for row in rows:
url = _normalize_url('http:/' + row[0]) url = _normalize_url('http:/' + row[0])
data[url].append( (row[1], int(row[2]),) ) data[url].append( (row[1], int(row[2]),) )
ga_model.update_social(period_name, data) ga_model.update_social(period_name, data)
   
   
def download(self, start_date, end_date, path=None): def download(self, start_date, end_date, path=None):
'''Get data from GA for a given time period''' '''Get data from GA for a given time period'''
start_date = start_date.strftime('%Y-%m-%d') start_date = start_date.strftime('%Y-%m-%d')
end_date = end_date.strftime('%Y-%m-%d') end_date = end_date.strftime('%Y-%m-%d')
query = 'ga:pagePath=%s$' % path query = 'ga:pagePath=%s$' % path
metrics = 'ga:pageviews, ga:visits' metrics = 'ga:pageviews, ga:visits'
sort = '-ga:pageviews' sort = '-ga:pageviews'
   
# Supported query params at # Supported query params at
# https://developers.google.com/analytics/devguides/reporting/core/v3/reference # https://developers.google.com/analytics/devguides/reporting/core/v3/reference
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
filters=query, filters=query,
start_date=start_date, start_date=start_date,
metrics=metrics, metrics=metrics,
sort=sort, sort=sort,
dimensions="ga:pagePath", dimensions="ga:pagePath",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
   
packages = [] packages = []
log.info("There are %d results" % results['totalResults']) log.info("There are %d results" % results['totalResults'])
for entry in results.get('rows'): for entry in results.get('rows'):
(loc,pageviews,visits) = entry (loc,pageviews,visits) = entry
url = _normalize_url('http:/' + loc) # strips off domain e.g. www.data.gov.uk or data.gov.uk url = _normalize_url('http:/' + loc) # strips off domain e.g. www.data.gov.uk or data.gov.uk
   
if not url.startswith('/dataset/') and not url.startswith('/publisher/'): if not url.startswith('/dataset/') and not url.startswith('/publisher/'):
# filter out strays like: # filter out strays like:
# /data/user/login?came_from=http://data.gov.uk/dataset/os-code-point-open # /data/user/login?came_from=http://data.gov.uk/dataset/os-code-point-open
# /403.html?page=/about&from=http://data.gov.uk/publisher/planning-inspectorate # /403.html?page=/about&from=http://data.gov.uk/publisher/planning-inspectorate
continue continue
packages.append( (url, pageviews, visits,) ) # Temporary hack packages.append( (url, pageviews, visits,) ) # Temporary hack
return dict(url=packages) return dict(url=packages)
   
def store(self, period_name, period_complete_day, data): def store(self, period_name, period_complete_day, data):
if 'url' in data: if 'url' in data:
ga_model.update_url_stats(period_name, period_complete_day, data['url']) ga_model.update_url_stats(period_name, period_complete_day, data['url'])
   
def sitewide_stats(self, period_name, period_complete_day): def sitewide_stats(self, period_name, period_complete_day):
import calendar import calendar
year, month = period_name.split('-') year, month = period_name.split('-')
_, last_day_of_month = calendar.monthrange(int(year), int(month)) _, last_day_of_month = calendar.monthrange(int(year), int(month))
   
start_date = '%s-01' % period_name start_date = '%s-01' % period_name
end_date = '%s-%s' % (period_name, last_day_of_month) end_date = '%s-%s' % (period_name, last_day_of_month)
funcs = ['_totals_stats', '_social_stats', '_os_stats', funcs = ['_totals_stats', '_social_stats', '_os_stats',
'_locale_stats', '_browser_stats', '_mobile_stats', '_download_stats'] '_locale_stats', '_browser_stats', '_mobile_stats', '_download_stats']
for f in funcs: for f in funcs:
log.info('Downloading analytics for %s' % f.split('_')[1]) log.info('Downloading analytics for %s' % f.split('_')[1])
getattr(self, f)(start_date, end_date, period_name, period_complete_day) getattr(self, f)(start_date, end_date, period_name, period_complete_day)
   
def _get_results(result_data, f): def _get_results(result_data, f):
data = {} data = {}
for result in result_data: for result in result_data:
key = f(result) key = f(result)
data[key] = data.get(key,0) + result[1] data[key] = data.get(key,0) + result[1]
return data return data
   
def _totals_stats(self, start_date, end_date, period_name, period_complete_day): def _totals_stats(self, start_date, end_date, period_name, period_complete_day):
""" Fetches distinct totals, total pageviews etc """ """ Fetches distinct totals, total pageviews etc """
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
ga_model.update_sitewide_stats(period_name, "Totals", {'Total page views': result_data[0][0]}, ga_model.update_sitewide_stats(period_name, "Totals", {'Total page views': result_data[0][0]},
period_complete_day) period_complete_day)
   
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviewsPerVisit,ga:avgTimeOnSite,ga:percentNewVisits,ga:visits', metrics='ga:pageviewsPerVisit,ga:avgTimeOnSite,ga:percentNewVisits,ga:visits',
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
data = { data = {
'Pages per visit': result_data[0][0], 'Pages per visit': result_data[0][0],
'Average time on site': result_data[0][1], 'Average time on site': result_data[0][1],
'New visits': result_data[0][2], 'New visits': result_data[0][2],
'Total visits': result_data[0][3], 'Total visits': result_data[0][3],
} }
ga_model.update_sitewide_stats(period_name, "Totals", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Totals", data, period_complete_day)
   
# Bounces from / or another configurable page. # Bounces from / or another configurable page.
path = '/%s%s' % (config.get('googleanalytics.account'), path = '/%s%s' % (config.get('googleanalytics.account'),
config.get('ga-report.bounce_url', '/')) config.get('ga-report.bounce_url', '/'))
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
filters='ga:pagePath==%s' % (path,), filters='ga:pagePath==%s' % (path,),
start_date=start_date, start_date=start_date,
metrics='ga:visitBounceRate', metrics='ga:visitBounceRate',
dimensions='ga:pagePath', dimensions='ga:pagePath',
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
if not result_data or len(result_data) != 1: if not result_data or len(result_data) != 1:
log.error('Could not pinpoint the bounces for path: %s. Got results: %r', log.error('Could not pinpoint the bounces for path: %s. Got results: %r',
path, result_data) path, result_data)
return return
results = result_data[0] results = result_data[0]
bounces = float(results[1]) bounces = float(results[1])
# visitBounceRate is already a % # visitBounceRate is already a %
log.info('Google reports visitBounceRate as %s', bounces) log.info('Google reports visitBounceRate as %s', bounces)
ga_model.update_sitewide_stats(period_name, "Totals", {'Bounce rate (home page)': float(bounces)}, ga_model.update_sitewide_stats(period_name, "Totals", {'Bounce rate (home page)': float(bounces)},
period_complete_day) period_complete_day)
   
   
def _locale_stats(self, start_date, end_date, period_name, period_complete_day): def _locale_stats(self, start_date, end_date, period_name, period_complete_day):
""" Fetches stats about language and country """ """ Fetches stats about language and country """
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
dimensions="ga:language,ga:country", dimensions="ga:language,ga:country",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
data = {} data = {}
for result in result_data: for result in result_data:
data[result[0]] = data.get(result[0], 0) + int(result[2]) data[result[0]] = data.get(result[0], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Languages", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Languages", data, period_complete_day)
   
data = {} data = {}
for result in result_data: for result in result_data:
data[result[1]] = data.get(result[1], 0) + int(result[2]) data[result[1]] = data.get(result[1], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Country", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Country", data, period_complete_day)
   
   
def _download_stats(self, start_date, end_date, period_name, period_complete_day): def _download_stats(self, start_date, end_date, period_name, period_complete_day):
""" Fetches stats about language and country """ """ Fetches stats about data downloads """
import ckan.model as model import ckan.model as model
   
data = {} data = {}
   
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
filters='ga:eventAction==download', filters='ga:eventAction==download',
metrics='ga:totalEvents', metrics='ga:totalEvents',
sort='-ga:totalEvents', sort='-ga:totalEvents',
dimensions="ga:eventLabel", dimensions="ga:eventLabel",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
if not result_data: if not result_data:
# We may not have data for this time period, so we need to bail # We may not have data for this time period, so we need to bail
# early. # early.
log.info("There is no download data for this time period") log.info("There is no download data for this time period")
return return
   
def process_result_data(result_data, cached=False): def process_result_data(result_data, cached=False):
  progress_total = len(result_data)
  progress_count = 0
  resources_not_matched = []
for result in result_data: for result in result_data:
  progress_count += 1
  if progress_count % 100 == 0:
  log.debug('.. %d/%d done so far', progress_count, progress_total)
   
url = result[0].strip() url = result[0].strip()
   
# Get package id associated with the resource that has this URL. # Get package id associated with the resource that has this URL.
q = model.Session.query(model.Resource) q = model.Session.query(model.Resource)
if cached: if cached:
r = q.filter(model.Resource.cache_url.like("%s%%" % url)).first() r = q.filter(model.Resource.cache_url.like("%s%%" % url)).first()
else: else:
r = q.filter(model.Resource.url.like("%s%%" % url)).first() r = q.filter(model.Resource.url.like("%s%%" % url)).first()
   
package_name = r.resource_group.package.name if r else "" package_name = r.resource_group.package.name if r else ""
if package_name: if package_name:
data[package_name] = data.get(package_name, 0) + int(result[1]) data[package_name] = data.get(package_name, 0) + int(result[1])
else: else:
log.warning(u"Could not find resource for URL: {url}".format(url=url)) resources_not_matched.append(url)
continue continue
  if resources_not_matched:
  log.debug('Could not match %i or %i resource URLs to datasets. e.g. %r',
  len(resources_not_matched), progress_total, resources_not_matched[:3])
   
  log.info('Associating downloads of resource URLs with their respective datasets')
process_result_data(results.get('rows')) process_result_data(results.get('rows'))
   
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
filters='ga:eventAction==download-cache', filters='ga:eventAction==download-cache',
metrics='ga:totalEvents', metrics='ga:totalEvents',
sort='-ga:totalEvents', sort='-ga:totalEvents',
dimensions="ga:eventLabel", dimensions="ga:eventLabel",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
  log.info('Associating downloads of cache resource URLs with their respective datasets')
process_result_data(results.get('rows'), cached=False) process_result_data(results.get('rows'), cached=False)
   
self._filter_out_long_tail(data, MIN_DOWNLOADS) self._filter_out_long_tail(data, MIN_DOWNLOADS)
ga_model.update_sitewide_stats(period_name, "Downloads", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Downloads", data, period_complete_day)
   
def _social_stats(self, start_date, end_date, period_name, period_complete_day): def _social_stats(self, start_date, end_date, period_name, period_complete_day):
""" Finds out which social sites people are referred from """ """ Finds out which social sites people are referred from """
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
dimensions="ga:socialNetwork,ga:referralPath", dimensions="ga:socialNetwork,ga:referralPath",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
data = {} data = {}
for result in result_data: for result in result_data:
if not result[0] == '(not set)': if not result[0] == '(not set)':
data[result[0]] = data.get(result[0], 0) + int(result[2]) data[result[0]] = data.get(result[0], 0) + int(result[2])
self._filter_out_long_tail(data, 3) self._filter_out_long_tail(data, 3)
ga_model.update_sitewide_stats(period_name, "Social sources", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Social sources", data, period_complete_day)
   
   
def _os_stats(self, start_date, end_date, period_name, period_complete_day): def _os_stats(self, start_date, end_date, period_name, period_complete_day):
""" Operating system stats """ """ Operating system stats """
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
dimensions="ga:operatingSystem,ga:operatingSystemVersion", dimensions="ga:operatingSystem,ga:operatingSystemVersion",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
data = {} data = {}
for result in result_data: for result in result_data:
data[result[0]] = data.get(result[0], 0) + int(result[2]) data[result[0]] = data.get(result[0], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Operating Systems", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Operating Systems", data, period_complete_day)
   
data = {} data = {}
for result in result_data: for result in result_data:
if int(result[2]) >= MIN_VIEWS: if int(result[2]) >= MIN_VIEWS:
key = "%s %s" % (result[0],result[1]) key = "%s %s" % (result[0],result[1])
data[key] = result[2] data[key] = result[2]
ga_model.update_sitewide_stats(period_name, "Operating Systems versions", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Operating Systems versions", data, period_complete_day)
   
   
def _browser_stats(self, start_date, end_date, period_name, period_complete_day): def _browser_stats(self, start_date, end_date, period_name, period_complete_day):
""" Information about browsers and browser versions """ """ Information about browsers and browser versions """
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
dimensions="ga:browser,ga:browserVersion", dimensions="ga:browser,ga:browserVersion",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
result_data = results.get('rows') result_data = results.get('rows')
# e.g. [u'Firefox', u'19.0', u'20'] # e.g. [u'Firefox', u'19.0', u'20']
   
data = {} data = {}
for result in result_data: for result in result_data:
data[result[0]] = data.get(result[0], 0) + int(result[2]) data[result[0]] = data.get(result[0], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Browsers", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Browsers", data, period_complete_day)
   
data = {} data = {}
for result in result_data: for result in result_data:
key = "%s %s" % (result[0], self._filter_browser_version(result[0], result[1])) key = "%s %s" % (result[0], self._filter_browser_version(result[0], result[1]))
data[key] = data.get(key, 0) + int(result[2]) data[key] = data.get(key, 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Browser versions", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Browser versions", data, period_complete_day)
   
@classmethod @classmethod
def _filter_browser_version(cls, browser, version_str): def _filter_browser_version(cls, browser, version_str):
''' '''
Simplifies a browser version string if it is detailed. Simplifies a browser version string if it is detailed.
i.e. groups together Firefox 3.5.1 and 3.5.2 to be just 3. i.e. groups together Firefox 3.5.1 and 3.5.2 to be just 3.
This is helpful when viewing stats and good to protect privacy. This is helpful when viewing stats and good to protect privacy.
''' '''
ver = version_str ver = version_str
parts = ver.split('.') parts = ver.split('.')
if len(parts) > 1: if len(parts) > 1:
if parts[1][0] == '0': if parts[1][0] == '0':
ver = parts[0] ver = parts[0]
else: else:
ver = "%s" % (parts[0]) ver = "%s" % (parts[0])
# Special case complex version nums # Special case complex version nums
if browser in ['Safari', 'Android Browser']: if browser in ['Safari', 'Android Browser']:
ver = parts[0] ver = parts[0]
if len(ver) > 2: if len(ver) > 2:
num_hidden_digits = len(ver) - 2 num_hidden_digits = len(ver) - 2
ver = ver[0] + ver[1] + 'X' * num_hidden_digits ver = ver[0] + ver[1] + 'X' * num_hidden_digits
return ver return ver
   
def _mobile_stats(self, start_date, end_date, period_name, period_complete_day): def _mobile_stats(self, start_date, end_date, period_name, period_complete_day):
""" Info about mobile devices """ """ Info about mobile devices """
   
results = self.service.data().ga().get( results = self.service.data().ga().get(
ids='ga:' + self.profile_id, ids='ga:' + self.profile_id,
start_date=start_date, start_date=start_date,
metrics='ga:pageviews', metrics='ga:pageviews',
sort='-ga:pageviews', sort='-ga:pageviews',
dimensions="ga:mobileDeviceBranding, ga:mobileDeviceInfo", dimensions="ga:mobileDeviceBranding, ga:mobileDeviceInfo",
max_results=10000, max_results=10000,
end_date=end_date).execute() end_date=end_date).execute()
   
result_data = results.get('rows') result_data = results.get('rows')
data = {} data = {}
for result in result_data: for result in result_data:
data[result[0]] = data.get(result[0], 0) + int(result[2]) data[result[0]] = data.get(result[0], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Mobile brands", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Mobile brands", data, period_complete_day)
   
data = {} data = {}
for result in result_data: for result in result_data:
data[result[1]] = data.get(result[1], 0) + int(result[2]) data[result[1]] = data.get(result[1], 0) + int(result[2])
self._filter_out_long_tail(data, MIN_VIEWS) self._filter_out_long_tail(data, MIN_VIEWS)
ga_model.update_sitewide_stats(period_name, "Mobile devices", data, period_complete_day) ga_model.update_sitewide_stats(period_name, "Mobile devices", data, period_complete_day)
   
@classmethod @classmethod
def _filter_out_long_tail(cls, data, threshold=10): def _filter_out_long_tail(cls, data, threshold=10):
''' '''
Given data which is a frequency distribution, filter out Given data which is a frequency distribution, filter out
results which are below a threshold count. This is good to protect results which are below a threshold count. This is good to protect
privacy. privacy.
''' '''
for key, value in data.items(): for key, value in data.items():
if value < threshold: if value < threshold:
del data[key] del data[key]
   
import re import re
import uuid import uuid
   
from sqlalchemy import Table, Column, MetaData, ForeignKey from sqlalchemy import Table, Column, MetaData, ForeignKey
from sqlalchemy import types from sqlalchemy import types
from sqlalchemy.sql import select from sqlalchemy.sql import select
from sqlalchemy.orm import mapper, relation from sqlalchemy.orm import mapper, relation
from sqlalchemy import func from sqlalchemy import func
   
import ckan.model as model import ckan.model as model
from ckan.lib.base import * from ckan.lib.base import *
   
log = __import__('logging').getLogger(__name__) log = __import__('logging').getLogger(__name__)
   
def make_uuid(): def make_uuid():
return unicode(uuid.uuid4()) return unicode(uuid.uuid4())
   
metadata = MetaData() metadata = MetaData()
   
class GA_Url(object): class GA_Url(object):
   
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k,v in kwargs.items(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
   
url_table = Table('ga_url', metadata, url_table = Table('ga_url', metadata,
Column('id', types.UnicodeText, primary_key=True, Column('id', types.UnicodeText, primary_key=True,
default=make_uuid), default=make_uuid),
Column('period_name', types.UnicodeText), Column('period_name', types.UnicodeText),
Column('period_complete_day', types.Integer), Column('period_complete_day', types.Integer),
Column('pageviews', types.UnicodeText), Column('pageviews', types.UnicodeText),
Column('visits', types.UnicodeText), Column('visits', types.UnicodeText),
Column('url', types.UnicodeText), Column('url', types.UnicodeText),
Column('department_id', types.UnicodeText), Column('department_id', types.UnicodeText),
Column('package_id', types.UnicodeText), Column('package_id', types.UnicodeText),
) )
mapper(GA_Url, url_table) mapper(GA_Url, url_table)
   
   
class GA_Stat(object): class GA_Stat(object):
   
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k,v in kwargs.items(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
   
stat_table = Table('ga_stat', metadata, stat_table = Table('ga_stat', metadata,
Column('id', types.UnicodeText, primary_key=True, Column('id', types.UnicodeText, primary_key=True,
default=make_uuid), default=make_uuid),
Column('period_name', types.UnicodeText), Column('period_name', types.UnicodeText),
Column('period_complete_day', types.UnicodeText), Column('period_complete_day', types.UnicodeText),
Column('stat_name', types.UnicodeText), Column('stat_name', types.UnicodeText),
Column('key', types.UnicodeText), Column('key', types.UnicodeText),
Column('value', types.UnicodeText), ) Column('value', types.UnicodeText), )
mapper(GA_Stat, stat_table) mapper(GA_Stat, stat_table)
   
   
class GA_Publisher(object): class GA_Publisher(object):
   
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k,v in kwargs.items(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
   
pub_table = Table('ga_publisher', metadata, pub_table = Table('ga_publisher', metadata,
Column('id', types.UnicodeText, primary_key=True, Column('id', types.UnicodeText, primary_key=True,
default=make_uuid), default=make_uuid),
Column('period_name', types.UnicodeText), Column('period_name', types.UnicodeText),
Column('publisher_name', types.UnicodeText), Column('publisher_name', types.UnicodeText),
Column('views', types.UnicodeText), Column('views', types.UnicodeText),
Column('visits', types.UnicodeText), Column('visits', types.UnicodeText),
Column('toplevel', types.Boolean, default=False), Column('toplevel', types.Boolean, default=False),
Column('subpublishercount', types.Integer, default=0), Column('subpublishercount', types.Integer, default=0),
Column('parent', types.UnicodeText), Column('parent', types.UnicodeText),
) )
mapper(GA_Publisher, pub_table) mapper(GA_Publisher, pub_table)
   
   
class GA_ReferralStat(object): class GA_ReferralStat(object):
   
def __init__(self, **kwargs): def __init__(self, **kwargs):
for k,v in kwargs.items(): for k,v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
   
referrer_table = Table('ga_referrer', metadata, referrer_table = Table('ga_referrer', metadata,
Column('id', types.UnicodeText, primary_key=True, Column('id', types.UnicodeText, primary_key=True,
default=make_uuid), default=make_uuid),
Column('period_name', types.UnicodeText), Column('period_name', types.UnicodeText),
Column('source', types.UnicodeText), Column('source', types.UnicodeText),
Column('url', types.UnicodeText), Column('url', types.UnicodeText),
Column('count', types.Integer), Column('count', types.Integer),
) )
mapper(GA_ReferralStat, referrer_table) mapper(GA_ReferralStat, referrer_table)
   
   
   
def init_tables(): def init_tables():
metadata.create_all(model.meta.engine) metadata.create_all(model.meta.engine)
   
   
cached_tables = {} cached_tables = {}
   
   
def get_table(name): def get_table(name):
if name not in cached_tables: if name not in cached_tables:
meta = MetaData() meta = MetaData()
meta.reflect(bind=model.meta.engine) meta.reflect(bind=model.meta.engine)
table = meta.tables[name] table = meta.tables[name]
cached_tables[name] = table cached_tables[name] = table
return cached_tables[name] return cached_tables[name]
   
   
def _normalize_url(url): def _normalize_url(url):
'''Strip off the hostname etc. Do this before storing it. '''Strip off the hostname etc. Do this before storing it.
   
>>> normalize_url('http://data.gov.uk/dataset/weekly_fuel_prices') >>> normalize_url('http://data.gov.uk/dataset/weekly_fuel_prices')
'/dataset/weekly_fuel_prices' '/dataset/weekly_fuel_prices'
''' '''
return '/' + '/'.join(url.split('/')[3:]) return '/' + '/'.join(url.split('/')[3:])
   
   
def _get_package_and_publisher(url): def _get_package_and_publisher(url):
# e.g. /dataset/fuel_prices # e.g. /dataset/fuel_prices
# e.g. /dataset/fuel_prices/resource/e63380d4 # e.g. /dataset/fuel_prices/resource/e63380d4
dataset_match = re.match('/dataset/([^/]+)(/.*)?', url) dataset_match = re.match('/dataset/([^/]+)(/.*)?', url)
if dataset_match: if dataset_match:
dataset_ref = dataset_match.groups()[0] dataset_ref = dataset_match.groups()[0]
dataset = model.Package.get(dataset_ref) dataset = model.Package.get(dataset_ref)
if dataset: if dataset:
publisher_groups = dataset.get_groups('publisher') publisher_groups = dataset.get_groups('publisher')
if publisher_groups: if publisher_groups:
return dataset_ref,publisher_groups[0].name return dataset_ref,publisher_groups[0].name
return dataset_ref, None return dataset_ref, None
else: else:
publisher_match = re.match('/publisher/([^/]+)(/.*)?', url) publisher_match = re.match('/publisher/([^/]+)(/.*)?', url)
if publisher_match: if publisher_match:
return None, publisher_match.groups()[0] return None, publisher_match.groups()[0]
return None, None return None, None
   
def update_sitewide_stats(period_name, stat_name, data, period_complete_day): def update_sitewide_stats(period_name, stat_name, data, period_complete_day):
for k,v in data.iteritems(): for k,v in data.iteritems():
item = model.Session.query(GA_Stat).\ item = model.Session.query(GA_Stat).\
filter(GA_Stat.period_name==period_name).\ filter(GA_Stat.period_name==period_name).\
filter(GA_Stat.key==k).\ filter(GA_Stat.key==k).\
filter(GA_Stat.stat_name==stat_name).first() filter(GA_Stat.stat_name==stat_name).first()
if item: if item:
item.period_name = period_name item.period_name = period_name
item.key = k item.key = k
item.value = v item.value = v
item.period_complete_day = period_complete_day item.period_complete_day = period_complete_day
model.Session.add(item) model.Session.add(item)
else: else:
# create the row # create the row
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': period_name, 'period_name': period_name,
'period_complete_day': period_complete_day, 'period_complete_day': period_complete_day,
'key': k, 'key': k,
'value': v, 'value': v,
'stat_name': stat_name 'stat_name': stat_name
} }
model.Session.add(GA_Stat(**values)) model.Session.add(GA_Stat(**values))
model.Session.commit() model.Session.commit()
   
   
def pre_update_url_stats(period_name): def pre_update_url_stats(period_name):
log.debug("Deleting '%s' records" % period_name) q = model.Session.query(GA_Url).\
model.Session.query(GA_Url).\ filter(GA_Url.period_name==period_name)
filter(GA_Url.period_name==period_name).delete() log.debug("Deleting %d '%s' records" % (q.count(), period_name))
  q.delete()
count = model.Session.query(GA_Url).\  
filter(GA_Url.period_name == 'All').count() q = model.Session.query(GA_Url).\
log.debug("Deleting %d 'All' records" % count) filter(GA_Url.period_name == 'All')
count = model.Session.query(GA_Url).\ log.debug("Deleting %d 'All' records..." % q.count())
filter(GA_Url.period_name == 'All').delete() q.delete()
log.debug("Deleted %d 'All' records" % count)  
   
model.Session.flush() model.Session.flush()
model.Session.commit() model.Session.commit()
model.repo.commit_and_remove() model.repo.commit_and_remove()
  log.debug('...done')
   
def post_update_url_stats(): def post_update_url_stats():
   
""" Check the distinct url field in ga_url and make sure """ Check the distinct url field in ga_url and make sure
it has an All record. If not then create one. it has an All record. If not then create one.
   
After running this then every URL should have an All After running this then every URL should have an All
record regardless of whether the URL has an entry for record regardless of whether the URL has an entry for
the month being currently processed. the month being currently processed.
""" """
  log.debug('Post-processing "All" records...')
query = """select url, pageviews::int, visits::int query = """select url, pageviews::int, visits::int
from ga_url from ga_url
where url not in (select url from ga_url where period_name ='All')""" where url not in (select url from ga_url where period_name ='All')"""
connection = model.Session.connection() connection = model.Session.connection()
res = connection.execute(query) res = connection.execute(query)
   
views, visits = {}, {} views, visits = {}, {}
# url, views, visits # url, views, visits
for row in res: for row in res:
views[row[0]] = views.get(row[0], 0) + row[1] views[row[0]] = views.get(row[0], 0) + row[1]
visits[row[0]] = visits.get(row[0], 0) + row[2] visits[row[0]] = visits.get(row[0], 0) + row[2]
   
  progress_total = len(views.keys())
  progress_count = 0
for key in views.keys(): for key in views.keys():
  progress_count += 1
  if progress_count % 100 == 0:
  log.debug('.. %d/%d done so far', progress_count, progress_total)
   
package, publisher = _get_package_and_publisher(key) package, publisher = _get_package_and_publisher(key)
   
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': "All", 'period_name': "All",
'period_complete_day': 0, 'period_complete_day': 0,
'url': key, 'url': key,
'pageviews': views[key], 'pageviews': views[key],
'visits': visits[key], 'visits': visits[key],
'department_id': publisher, 'department_id': publisher,
'package_id': publisher 'package_id': package
} }
model.Session.add(GA_Url(**values)) model.Session.add(GA_Url(**values))
model.Session.commit() model.Session.commit()
  log.debug('..done')
   
   
def update_url_stats(period_name, period_complete_day, url_data): def update_url_stats(period_name, period_complete_day, url_data):
''' '''
Given a list of urls and number of hits for each during a given period, Given a list of urls and number of hits for each during a given period,
stores them in GA_Url under the period and recalculates the totals for stores them in GA_Url under the period and recalculates the totals for
the 'All' period. the 'All' period.
''' '''
  progress_total = len(url_data)
  progress_count = 0
for url, views, visits in url_data: for url, views, visits in url_data:
  progress_count += 1
  if progress_count % 100 == 0:
  log.debug('.. %d/%d done so far', progress_count, progress_total)
   
package, publisher = _get_package_and_publisher(url) package, publisher = _get_package_and_publisher(url)
   
   
item = model.Session.query(GA_Url).\ item = model.Session.query(GA_Url).\
filter(GA_Url.period_name==period_name).\ filter(GA_Url.period_name==period_name).\
filter(GA_Url.url==url).first() filter(GA_Url.url==url).first()
if item: if item:
item.pageviews = item.pageviews + views item.pageviews = item.pageviews + views
item.visits = item.visits + visits item.visits = item.visits + visits
if not item.package_id: if not item.package_id:
item.package_id = package item.package_id = package
if not item.department_id: if not item.department_id:
item.department_id = publisher item.department_id = publisher
model.Session.add(item) model.Session.add(item)
else: else:
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': period_name, 'period_name': period_name,
'period_complete_day': period_complete_day, 'period_complete_day': period_complete_day,
'url': url, 'url': url,
'pageviews': views, 'pageviews': views,
'visits': visits, 'visits': visits,
'department_id': publisher, 'department_id': publisher,
'package_id': package 'package_id': package
} }
model.Session.add(GA_Url(**values)) model.Session.add(GA_Url(**values))
model.Session.commit() model.Session.commit()
   
if package: if package:
old_pageviews, old_visits = 0, 0 old_pageviews, old_visits = 0, 0
old = model.Session.query(GA_Url).\ old = model.Session.query(GA_Url).\
filter(GA_Url.period_name=='All').\ filter(GA_Url.period_name=='All').\
filter(GA_Url.url==url).all() filter(GA_Url.url==url).all()
old_pageviews = sum([int(o.pageviews) for o in old]) old_pageviews = sum([int(o.pageviews) for o in old])
old_visits = sum([int(o.visits) for o in old]) old_visits = sum([int(o.visits) for o in old])
   
entries = model.Session.query(GA_Url).\ entries = model.Session.query(GA_Url).\
filter(GA_Url.period_name!='All').\ filter(GA_Url.period_name!='All').\
filter(GA_Url.url==url).all() filter(GA_Url.url==url).all()
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': 'All', 'period_name': 'All',
'period_complete_day': 0, 'period_complete_day': 0,
'url': url, 'url': url,
'pageviews': sum([int(e.pageviews) for e in entries]) + int(old_pageviews), 'pageviews': sum([int(e.pageviews) for e in entries]) + int(old_pageviews),
'visits': sum([int(e.visits or 0) for e in entries]) + int(old_visits), 'visits': sum([int(e.visits or 0) for e in entries]) + int(old_visits),
'department_id': publisher, 'department_id': publisher,
'package_id': package 'package_id': package
} }
   
model.Session.add(GA_Url(**values)) model.Session.add(GA_Url(**values))
model.Session.commit() model.Session.commit()
   
   
   
   
def update_social(period_name, data): def update_social(period_name, data):
# Clean up first. # Clean up first.
model.Session.query(GA_ReferralStat).\ model.Session.query(GA_ReferralStat).\
filter(GA_ReferralStat.period_name==period_name).delete() filter(GA_ReferralStat.period_name==period_name).delete()
   
for url,data in data.iteritems(): for url,data in data.iteritems():
for entry in data: for entry in data:
source = entry[0] source = entry[0]
count = entry[1] count = entry[1]
   
item = model.Session.query(GA_ReferralStat).\ item = model.Session.query(GA_ReferralStat).\
filter(GA_ReferralStat.period_name==period_name).\ filter(GA_ReferralStat.period_name==period_name).\
filter(GA_ReferralStat.source==source).\ filter(GA_ReferralStat.source==source).\
filter(GA_ReferralStat.url==url).first() filter(GA_ReferralStat.url==url).first()
if item: if item:
item.count = item.count + count item.count = item.count + count
model.Session.add(item) model.Session.add(item)
else: else:
# create the row # create the row
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': period_name, 'period_name': period_name,
'source': source, 'source': source,
'url': url, 'url': url,
'count': count, 'count': count,
} }
model.Session.add(GA_ReferralStat(**values)) model.Session.add(GA_ReferralStat(**values))
model.Session.commit() model.Session.commit()
   
def update_publisher_stats(period_name): def update_publisher_stats(period_name):
""" """
Updates the publisher stats from the data retrieved for /dataset/* Updates the publisher stats from the data retrieved for /dataset/*
and /publisher/*. Will run against each dataset and generates the and /publisher/*. Will run against each dataset and generates the
totals for the entire tree beneath each publisher. totals for the entire tree beneath each publisher.
""" """
toplevel = get_top_level() toplevel = get_top_level()
publishers = model.Session.query(model.Group).\ publishers = model.Session.query(model.Group).\
filter(model.Group.type=='publisher').\ filter(model.Group.type=='publisher').\
filter(model.Group.state=='active').all() filter(model.Group.state=='active').all()
for publisher in publishers: for publisher in publishers:
views, visits, subpub = update_publisher(period_name, publisher, publisher.name) views, visits, subpub = update_publisher(period_name, publisher, publisher.name)
parent, parents = '', publisher.get_groups('publisher') parent, parents = '', publisher.get_groups('publisher')
if parents: if parents:
parent = parents[0].name parent = parents[0].name
item = model.Session.query(GA_Publisher).\ item = model.Session.query(GA_Publisher).\
filter(GA_Publisher.period_name==period_name).\ filter(GA_Publisher.period_name==period_name).\
filter(GA_Publisher.publisher_name==publisher.name).first() filter(GA_Publisher.publisher_name==publisher.name).first()
if item: if item:
item.views = views item.views = views
item.visits = visits item.visits = visits
item.publisher_name = publisher.name item.publisher_name = publisher.name
item.toplevel = publisher in toplevel item.toplevel = publisher in toplevel
item.subpublishercount = subpub item.subpublishercount = subpub
item.parent = parent item.parent = parent
model.Session.add(item) model.Session.add(item)
else: else:
# create the row # create the row
values = {'id': make_uuid(), values = {'id': make_uuid(),
'period_name': period_name, 'period_name': period_name,
'publisher_name': publisher.name, 'publisher_name': publisher.name,
'views': views, 'views': views,
'visits': visits, 'visits': visits,
'toplevel': publisher in toplevel, 'toplevel': publisher in toplevel,
'subpublishercount': subpub, 'subpublishercount': subpub,
'parent': parent 'parent': parent
} }
model.Session.add(GA_Publisher(**values)) model.Session.add(GA_Publisher(**values))
model.Session.commit() model.Session.commit()
   
   
def update_publisher(period_name, pub, part=''): def update_publisher(period_name, pub, part=''):
views,visits,subpub = 0, 0, 0 views,visits,subpub = 0, 0, 0
for publisher in go_down_tree(pub): for publisher in go_down_tree(pub):
subpub = subpub + 1 subpub = subpub + 1
items = model.Session.query(GA_Url).\ items = model.Session.query(GA_Url).\
filter(GA_Url.period_name==period_name).\ filter(GA_Url.period_name==period_name).\
filter(GA_Url.department_id==publisher.name).all() filter(GA_Url.department_id==publisher.name).all()
for item in items: for item in items:
views = views + int(item.pageviews) views = views + int(item.pageviews)
visits = visits + int(item.visits) visits = visits + int(item.visits)
   
return views, visits, (subpub-1) return views, visits, (subpub-1)
   
   
def get_top_level(): def get_top_level():
'''Returns the top level publishers.''' '''Returns the top level publishers.'''
return model.Session.query(model.Group).\ return model.Session.query(model.Group).\
outerjoin(model.Member, model.Member.table_id == model.Group.id and \ outerjoin(model.Member, model.Member.table_id == model.Group.id and \
model.Member.table_name == 'group' and \ model.Member.table_name == 'group' and \
model.Member.state == 'active').\ model.Member.state == 'active').\
filter(model.Member.id==None).\ filter(model.Member.id==None).\
filter(model.Group.type=='publisher').\ filter(model.Group.type=='publisher').\
order_by(model.Group.name).all() order_by(model.Group.name).all()
   
def get_children(publisher): def get_children(publisher):
'''Finds child publishers for the given publisher (object). (Not recursive)''' '''Finds child publishers for the given publisher (object). (Not recursive)'''
from ckan.model.group import HIERARCHY_CTE from ckan.model.group import HIERARCHY_CTE
return model.Session.query(model.Group).\ return model.Session.query(model.Group).\
from_statement(HIERARCHY_CTE).params(id=publisher.id, type='publisher').\ from_statement(HIERARCHY_CTE).params(id=publisher.id, type='publisher').\
all() all()
   
def go_down_tree(publisher): def go_down_tree(publisher):
'''Provided with a publisher object, it walks down the hierarchy and yields each publisher, '''Provided with a publisher object, it walks down the hierarchy and yields each publisher,
including the one you supply.''' including the one you supply.'''
yield publisher yield publisher
for child in get_children(publisher): for child in get_children(publisher):
for grandchild in go_down_tree(child): for grandchild in go_down_tree(child):
yield grandchild yield grandchild
   
def delete(period_name): def delete(period_name):
''' '''
Deletes table data for the specified period, or specify 'all' Deletes table data for the specified period, or specify 'all'
for all periods. for all periods.
''' '''
for object_type in (GA_Url, GA_Stat, GA_Publisher, GA_ReferralStat): for object_type in (GA_Url, GA_Stat, GA_Publisher, GA_ReferralStat):
q = model.Session.query(object_type) q = model.Session.query(object_type)
if period_name != 'All': if period_name != 'All':
q = q.filter_by(period_name=period_name) q = q.filter_by(period_name=period_name)
q.delete() q.delete()
model.repo.commit_and_remove() model.repo.commit_and_remove()
   
def get_score_for_dataset(dataset_name): def get_score_for_dataset(dataset_name):
''' '''
Returns a "current popularity" score for a dataset, Returns a "current popularity" score for a dataset,
based on how many views it has had recently. based on how many views it has had recently.
''' '''
import datetime import datetime
now = datetime.datetime.now() now = datetime.datetime.now()
last_month = now - datetime.timedelta(days=30) last_month = now - datetime.timedelta(days=30)
period_names = ['%s-%02d' % (last_month.year, last_month.month), period_names = ['%s-%02d' % (last_month.year, last_month.month),
'%s-%02d' % (now.year, now.month), '%s-%02d' % (now.year, now.month),
] ]
   
score = 0 score = 0
for period_name in period_names: for period_name in period_names:
score /= 2 # previous periods are discounted by 50% score /= 2 # previous periods are discounted by 50%
entry = model.Session.query(GA_Url)\ entry = model.Session.query(GA_Url)\
.filter(GA_Url.period_name==period_name)\ .filter(GA_Url.period_name==period_name)\
.filter(GA_Url.package_id==dataset_name).first() .filter(GA_Url.package_id==dataset_name).first()
# score # score
if entry: if entry:
views = float(entry.pageviews) views = float(entry.pageviews)
if entry.period_complete_day: if entry.period_complete_day:
views_per_day = views / entry.period_complete_day views_per_day = views / entry.period_complete_day
else: else:
views_per_day = views / 15 # guess views_per_day = views / 15 # guess
score += views_per_day score += views_per_day
   
score = int(score * 100) score = int(score * 100)
log.debug('Popularity %s: %s', score, dataset_name) log.debug('Popularity %s: %s', score, dataset_name)
return score return score
   
import logging import logging
import operator import operator
   
import ckan.lib.base as base import ckan.lib.base as base
import ckan.model as model import ckan.model as model
from ckan.logic import get_action from ckan.logic import get_action
   
from ckanext.ga_report.ga_model import GA_Url, GA_Publisher from ckanext.ga_report.ga_model import GA_Url, GA_Publisher
from ckanext.ga_report.controller import _get_publishers from ckanext.ga_report.controller import _get_publishers
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
   
def popular_datasets(count=10): def popular_datasets(count=10):
import random import random
   
publisher = None publisher = None
publishers = _get_publishers(30) publishers = _get_publishers(30)
total = len(publishers) total = len(publishers)
while not publisher or not datasets: while not publisher or not datasets:
rand = random.randrange(0, total) rand = random.randrange(0, total)
publisher = publishers[rand][0] publisher = publishers[rand][0]
if not publisher.state == 'active': if not publisher.state == 'active':
publisher = None publisher = None
continue continue
datasets = _datasets_for_publisher(publisher, 10)[:count] datasets = _datasets_for_publisher(publisher, 10)[:count]
   
ctx = { ctx = {
'datasets': datasets, 'datasets': datasets,
'publisher': publisher 'publisher': publisher
} }
return base.render_snippet('ga_report/ga_popular_datasets.html', **ctx) return base.render_snippet('ga_report/ga_popular_datasets.html', **ctx)
   
def single_popular_dataset(top=20): def single_popular_dataset(top=20):
'''Returns a random dataset from the most popular ones. '''Returns a random dataset from the most popular ones.
   
:param top: the number of top datasets to select from :param top: the number of top datasets to select from
''' '''
import random import random
   
top_datasets = model.Session.query(GA_Url).\ top_datasets = model.Session.query(GA_Url).\
filter(GA_Url.url.like('/dataset/%')).\ filter(GA_Url.url.like('/dataset/%')).\
order_by('ga_url.pageviews::int desc') order_by('ga_url.pageviews::int desc')
num_top_datasets = top_datasets.count() num_top_datasets = top_datasets.count()
   
dataset = None dataset = None
if num_top_datasets: if num_top_datasets:
count = 0 count = 0
while not dataset: while not dataset:
rand = random.randrange(0, min(top, num_top_datasets)) rand = random.randrange(0, min(top, num_top_datasets))
ga_url = top_datasets[rand] ga_url = top_datasets[rand]
dataset = model.Package.get(ga_url.url[len('/dataset/'):]) dataset = model.Package.get(ga_url.url[len('/dataset/'):])
if dataset and not dataset.state == 'active': if dataset and not dataset.state == 'active':
dataset = None dataset = None
# When testing, it is possible that top datasets are not available # When testing, it is possible that top datasets are not available
# so only go round this loop a few times before falling back on # so only go round this loop a few times before falling back on
# a random dataset. # a random dataset.
count += 1 count += 1
if count > 10: if count > 10:
break break
if not dataset: if not dataset:
# fallback # fallback
dataset = model.Session.query(model.Package)\ dataset = model.Session.query(model.Package)\
.filter_by(state='active').first() .filter_by(state='active').first()
if not dataset: if not dataset:
return None return None
dataset_dict = get_action('package_show')({'model': model, dataset_dict = get_action('package_show')({'model': model,
'session': model.Session, 'session': model.Session,
'validate': False}, 'validate': False},
{'id':dataset.id}) {'id':dataset.id})
return dataset_dict return dataset_dict
   
def single_popular_dataset_html(top=20): def single_popular_dataset_html(top=20):
dataset_dict = single_popular_dataset(top) dataset_dict = single_popular_dataset(top)
groups = package.get('groups', []) groups = package.get('groups', [])
publishers = [ g for g in groups if g.get('type') == 'publisher' ] publishers = [ g for g in groups if g.get('type') == 'publisher' ]
publisher = publishers[0] if publishers else {'name':'', 'title': ''} publisher = publishers[0] if publishers else {'name':'', 'title': ''}
context = { context = {
'dataset': dataset_dict, 'dataset': dataset_dict,
'publisher': publisher_dict 'publisher': publisher_dict
} }
return base.render_snippet('ga_report/ga_popular_single.html', **context) return base.render_snippet('ga_report/ga_popular_single.html', **context)
   
   
def most_popular_datasets(publisher, count=20): def most_popular_datasets(publisher, count=20):
   
if not publisher: if not publisher:
_log.error("No valid publisher passed to 'most_popular_datasets'") _log.error("No valid publisher passed to 'most_popular_datasets'")
return "" return ""
   
results = _datasets_for_publisher(publisher, count) results = _datasets_for_publisher(publisher, count)
   
ctx = { ctx = {
'dataset_count': len(results), 'dataset_count': len(results),
'datasets': results, 'datasets': results,
   
'publisher': publisher 'publisher': publisher
} }
   
return base.render_snippet('ga_report/publisher/popular.html', **ctx) return base.render_snippet('ga_report/publisher/popular.html', **ctx)
   
def _datasets_for_publisher(publisher, count): def _datasets_for_publisher(publisher, count):
datasets = {} datasets = {}
entries = model.Session.query(GA_Url).\ entries = model.Session.query(GA_Url).\
filter(GA_Url.department_id==publisher.name).\ filter(GA_Url.department_id==publisher.name).\
filter(GA_Url.url.like('/dataset/%')).\ filter(GA_Url.url.like('/dataset/%')).\
order_by('ga_url.pageviews::int desc').all() order_by('ga_url.pageviews::int desc').all()
for entry in entries: for entry in entries:
if len(datasets) < count: if len(datasets) < count:
p = model.Package.get(entry.url[len('/dataset/'):]) p = model.Package.get(entry.url[len('/dataset/'):])
  if not p:
  _log.warning("Could not find Package for {url}".format(url=entry.url))
  continue
   
if not p in datasets: if not p in datasets:
datasets[p] = {'views':0, 'visits': 0} datasets[p] = {'views':0, 'visits': 0}
datasets[p]['views'] = datasets[p]['views'] + int(entry.pageviews) datasets[p]['views'] = datasets[p]['views'] + int(entry.pageviews)
datasets[p]['visits'] = datasets[p]['visits'] + int(entry.visits) datasets[p]['visits'] = datasets[p]['visits'] + int(entry.visits)
   
results = [] results = []
for k, v in datasets.iteritems(): for k, v in datasets.iteritems():
results.append((k,v['views'],v['visits'])) results.append((k,v['views'],v['visits']))
   
return sorted(results, key=operator.itemgetter(1), reverse=True) return sorted(results, key=operator.itemgetter(1), reverse=True)
   
.table-condensed td.sparkline-cell { .table-condensed td.sparkline-cell {
padding: 1px 0 0 0; padding: 1px 0 0 0;
width: 108px; width: 108px;
text-align: center; text-align: center;
} }
.rickshaw_chart_container { .rickshaw_chart_container {
position: relative; position: relative;
height: 350px; height: 350px;
margin: 0 auto 20px auto; margin: 0 auto 20px auto;
} }
.rickshaw_chart { .rickshaw_chart {
position: absolute; position: absolute;
left: 40px; left: 40px;
width: 500px; width: 500px;
top: 0; top: 0;
bottom: 0; bottom: 0;
} }
.rickshaw_legend { .rickshaw_legend {
position: absolute;  
right: 0;  
top: 0;  
margin-left: 15px;  
padding: 0 5px;  
background: transparent; background: transparent;
max-width: 150px; width: 100%;
overflow: hidden;  
background: rgba(0,0,0,0.05);  
border-radius:5px;  
} }
.rickshaw_y_axis { .rickshaw_y_axis {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 40px; width: 40px;
} }
.rickshaw_legend .label { .rickshaw_legend .label {
background: transparent !important; background: transparent !important;
color: #000000 !important; color: #000000 !important;
font-weight: normal !important; font-weight: normal !important;
} }
   
  var CKAN = CKAN || {};
  CKAN.GA_Reports = {};
 
  CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) {
  if (!Modernizr.svg) {
  $("#chart_"+css_name)
  .html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>')
  .css('height','auto');
  return;
  }
  var graphLegends = $('#graph-legend-container');
  var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends);
 
  var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } );
  $.each(data, function(i, object) {
  object['color'] = palette.color();
  });
 
  var graphElement = document.querySelector("#chart_"+css_name);
 
  var graph = new Rickshaw.Graph( {
  element: document.querySelector("#chart_"+css_name),
  renderer: mode,
  series: data ,
  height: 328
  });
  var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
  var y_axis = new Rickshaw.Graph.Axis.Y( {
  graph: graph,
  orientation: 'left',
  tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
  element: document.getElementById('y_axis_'+css_name)
  } );
  var legend = new Rickshaw.Graph.Legend( {
  element: document.querySelector('#legend_'+css_name),
  graph: graph
  } );
  var hoverDetail = new Rickshaw.Graph.HoverDetail( {
  graph: graph,
  formatter: function(series, x, y) {
  var date = '<span class="date">' + new Date(x * 1000).toUTCString() + '</span>';
  var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
  var content = swatch + series.name + ": " + parseInt(y) + '<br>' + date;
  return content;
  }
  } );
  graph.render();
  };
 
  CKAN.GA_Reports.bind_sparklines = function() {
  /*
  * Bind to the 'totals' tab being on screen, when the
  * Sparkline graphs should be drawn.
  * Note that they cannot be drawn sooner.
  */
  $('a[href="#totals"]').on(
  'shown',
  function() {
  var sparkOptions = {
  enableTagOptions: true,
  type: 'line',
  width: 100,
  height: 26,
  chartRangeMin: 0,
  spotColor: '',
  maxSpotColor: '',
  minSpotColor: '',
  highlightSpotColor: '000000',
  lineColor: '3F8E6D',
  fillColor: 'B7E66B'
  };
  $('.sparkline').sparkline('html',sparkOptions);
  }
  );
  };
 
  CKAN.GA_Reports.bind_sidebar = function() {
  /*
  * Bind to changes in the tab behaviour:
  * Show the correct rickshaw graph in the sidebar.
  * Not to be called before all graphs load.
  */
  $('a[data-toggle="hashchange"]').on(
  'shown',
  function(e) {
  var href = $(e.target).attr('href');
  var pane = $(href);
  if (!pane.length) { console.err('bad href',href); return; }
  var legend_name = "none";
  var graph = pane.find('.rickshaw_chart');
  if (graph.length) {
  legend_name = graph.attr('id').replace('chart_','');
  }
  legend_name = '#legend_'+legend_name;
  $('#graph-legend-container > *').hide();
  $(legend_name).show();
  }
  );
  };
 
  /*
  * Custom bootstrap plugin for handling data-toggle="hashchange".
  * Behaves like data-toggle="tab" but I respond to the hashchange.
  * Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this?
  */
  $(function() {
  var mapping = {};
  $('a[data-toggle="hashchange"]').each(
  function(i,link) {
  link = $(link);
  mapping[link.attr('href')] = link;
  }
  );
  $(window).hashchange(function() {
  var link = mapping[window.location.hash];
  if (link) { link.tab('show'); }
  });
  });
 
(function(){function a(a){var b=a.source,d=a.target,e=c(b,d),f=[b];while(b!==e)b=b.parent,f.push(b);var g=f.length;while(d!==e)f.splice(g,0,d),d=d.parent;return f}function b(a){var b=[],c=a.parent;while(c!=null)b.push(a),a=c,c=c.parent;return b.push(a),b}function c(a,c){if(a===c)return a;var d=b(a),e=b(c),f=d.pop(),g=e.pop(),h=null;while(f===g)h=f,f=d.pop(),g=e.pop();return h}function g(a){a.fixed|=2}function h(a){a!==f&&(a.fixed&=1)}function i(){j(),f.fixed&=1,e=f=null}function j(){f.px+=d3.event.dx,f.py+=d3.event.dy,e.resume()}function k(a,b,c){var d=0,e=0;a.charge=0;if(!a.leaf){var f=a.nodes,g=f.length,h=-1,i;while(++h<g){i=f[h];if(i==null)continue;k(i,b,c),a.charge+=i.charge,d+=i.charge*i.cx,e+=i.charge*i.cy}}if(a.point){a.leaf||(a.point.x+=Math.random()-.5,a.point.y+=Math.random()-.5);var j=b*c[a.point.index];a.charge+=a.pointCharge=j,d+=j*a.point.x,e+=j*a.point.y}a.cx=d/a.charge,a.cy=e/a.charge}function l(a){return 20}function m(a){return 1}function o(a){return a.x}function p(a){return a.y}function q(a,b,c){a.y0=b,a.y=c}function t(a){var b=1,c=0,d=a[0][1],e,f=a.length;for(;b<f;++b)(e=a[b][1])>d&&(c=b,d=e);return c}function u(a){return a.reduce(v,0)}function v(a,b){return a+b[1]}function w(a,b){return x(a,Math.ceil(Math.log(b.length)/Math.LN2+1))}function x(a,b){var c=-1,d=+a[0],e=(a[1]-d)/b,f=[];while(++c<=b)f[c]=e*c+d;return f}function y(a){return[d3.min(a),d3.max(a)]}function z(a,b){return a.sort=d3.rebind(a,b.sort),a.children=d3.rebind(a,b.children),a.links=D,a.value=d3.rebind(a,b.value),a.nodes=function(b){return E=!0,(a.nodes=a)(b)},a}function A(a){return a.children}function B(a){return a.value}function C(a,b){return b.value-a.value}function D(a){return d3.merge(a.map(function(a){return(a.children||[]).map(function(b){return{source:a,target:b}})}))}function F(a,b){return a.value-b.value}function G(a,b){var c=a._pack_next;a._pack_next=b,b._pack_prev=a,b._pack_next=c,c._pack_prev=b}function H(a,b){a._pack_next=b,b._pack_prev=a}function I(a,b){var c=b.x-a.x,d=b.y-a.y,e=a.r+b.r;return e*e-c*c-d*d>.001}function J(a){function l(a){b=Math.min(a.x-a.r,b),c=Math.max(a.x+a.r,c),d=Math.min(a.y-a.r,d),e=Math.max(a.y+a.r,e)}var b=Infinity,c=-Infinity,d=Infinity,e=-Infinity,f=a.length,g,h,i,j,k;a.forEach(K),g=a[0],g.x=-g.r,g.y=0,l(g);if(f>1){h=a[1],h.x=h.r,h.y=0,l(h);if(f>2){i=a[2],O(g,h,i),l(i),G(g,i),g._pack_prev=i,G(i,h),h=g._pack_next;for(var m=3;m<f;m++){O(g,h,i=a[m]);var n=0,o=1,p=1;for(j=h._pack_next;j!==h;j=j._pack_next,o++)if(I(j,i)){n=1;break}if(n==1)for(k=g._pack_prev;k!==j._pack_prev;k=k._pack_prev,p++)if(I(k,i)){p<o&&(n=-1,j=k);break}n==0?(G(g,i),h=i,l(i)):n>0?(H(g,j),h=j,m--):(H(j,h),g=j,m--)}}}var q=(b+c)/2,r=(d+e)/2,s=0;for(var m=0;m<f;m++){var t=a[m];t.x-=q,t.y-=r,s=Math.max(s,t.r+Math.sqrt(t.x*t.x+t.y*t.y))}return a.forEach(L),s}function K(a){a._pack_next=a._pack_prev=a}function L(a){delete a._pack_next,delete a._pack_prev}function M(a){var b=a.children;b&&b.length?(b.forEach(M),a.r=J(b)):a.r=Math.sqrt(a.value)}function N(a,b,c,d){var e=a.children;a.x=b+=d*a.x,a.y=c+=d*a.y,a.r*=d;if(e){var f=-1,g=e.length;while(++f<g)N(e[f],b,c,d)}}function O(a,b,c){var d=a.r+c.r,e=b.x-a.x,f=b.y-a.y;if(d&&(e||f)){var g=b.r+c.r,h=Math.sqrt(e*e+f*f),i=Math.max(-1,Math.min(1,(d*d+h*h-g*g)/(2*d*h))),j=Math.acos(i),k=i*(d/=h),l=Math.sin(j)*d;c.x=a.x+k*e+l*f,c.y=a.y+k*f-l*e}else c.x=a.x+d,c.y=a.y}function P(a){return 1+d3.max(a,function(a){return a.y})}function Q(a){return a.reduce(function(a,b){return a+b.x},0)/a.length}function R(a){var b=a.children;return b&&b.length?R(b[0]):a}function S(a){var b=a.children,c;return b&&(c=b.length)?S(b[c-1]):a}function T(a,b){return a.parent==b.parent?1:2}function U(a){var b=a.children;return b&&b.length?b[0]:a._tree.thread}function V(a){var b=a.children,c;return b&&(c=b.length)?b[c-1]:a._tree.thread}function W(a,b){var c=a.children;if(c&&(e=c.length)){var d,e,f=-1;while(++f<e)b(d=W(c[f],b),a)>0&&(a=d)}return a}function X(a,b){return a.x-b.x}function Y(a,b){return b.x-a.x}function Z(a,b){return a.depth-b.depth}function $(a,b){function c(a,d){var e=a.children;if(e&&(i=e.length)){var f,g=null,h=-1,i;while(++h<i)f=e[h],c(f,g),g=f}b(a,d)}c(a,null)}function _(a){var b=0,c=0,d=a.children,e=d.length,f;while(--e>=0)f=d[e]._tree,f.prelim+=b,f.mod+=b,b+=f.shift+(c+=f.change)}function ba(a,b,c){a=a._tree,b=b._tree;var d=c/(b.number-a.number);a.change+=d,b.change-=d,b.shift+=c,b.prelim+=c,b.mod+=c}function bb(a,b,c){return a._tree.ancestor.parent==b.parent?a._tree.ancestor:c}function bc(a){return{x:a.x,y:a.y,dx:a.dx,dy:a.dy}}function bd(a,b){var c=a.x+b[3],d=a.y+b[0],e=a.dx-b[1]-b[3],f=a.dy-b[0]-b[2];return e<0&&(c+=e/2,e=0),f<0&&(d+=f/2,f=0),{x:c,y:d,dx:e,dy:f}}d3.layout={},d3.layout.bundle=function(){return function(b){var c=[],d=-1,e=b.length;while(++d<e)c.push(a(b[d]));return c}},d3.layout.chord=function(){function j(){var a={},j=[],l=d3.range(e),m=[],n,o,p,q,r;b=[],c=[],n=0,q=-1;while(++q<e){o=0,r=-1;while(++r<e)o+=d[q][r];j.push(o),m.push(d3.range(e)),n+=o}g&&l.sort(function(a,b){return g(j[a],j[b])}),h&&m.forEach(function(a,b){a.sort(function(a,c){return h(d[b][a],d[b][c])})}),n=(2*Math.PI-f*e)/n,o=0,q=-1;while(++q<e){p=o,r=-1;while(++r<e){var s=l[q],t=m[s][r],u=d[s][t],v=o,w=o+=u*n;a[s+"-"+t]={index:s,subindex:t,startAngle:v,endAngle:w,value:u}}c.push({index:s,startAngle:p,endAngle:o,value:(o-p)/n}),o+=f}q=-1;while(++q<e){r=q-1;while(++r<e){var x=a[q+"-"+r],y=a[r+"-"+q];(x.value||y.value)&&b.push(x.value<y.value?{source:y,target:x}:{source:x,target:y})}}i&&k()}function k(){b.sort(function(a,b){return i((a.source.value+a.target.value)/2,(b.source.value+b.target.value)/2)})}var a={},b,c,d,e,f=0,g,h,i;return a.matrix=function(f){return arguments.length?(e=(d=f)&&d.length,b=c=null,a):d},a.padding=function(d){return arguments.length?(f=d,b=c=null,a):f},a.sortGroups=function(d){return arguments.length?(g=d,b=c=null,a):g},a.sortSubgroups=function(c){return arguments.length?(h=c,b=null,a):h},a.sortChords=function(c){return arguments.length?(i=c,b&&k(),a):i},a.chords=function(){return b||j(),b},a.groups=function(){return c||j(),c},a},d3.layout.force=function(){function A(a){return function(b,c,d,e,f){if(b.point!==a){var g=b.cx-a.x,h=b.cy-a.y,i=1/Math.sqrt(g*g+h*h);if((e-c)*i<t){var j=b.charge*i*i;return a.px-=g*j,a.py-=h*j,!0}if(b.point&&isFinite(i)){var j=b.pointCharge*i*i;a.px-=g*j,a.py-=h*j}}return!b.charge}}function B(){var a=v.length,d=w.length,e,f,g,h,i,j,l,m,p;for(f=0;f<d;++f){g=w[f],h=g.source,i=g.target,m=i.x-h.x,p=i.y-h.y;if(j=m*m+p*p)j=n*y[f]*((j=Math.sqrt(j))-x[f])/j,m*=j,p*=j,i.x-=m*(l=h.weight/(i.weight+h.weight)),i.y-=p*l,h.x+=m*(l=1-l),h.y+=p*l}if(l=n*s){m=c[0]/2,p=c[1]/2,f=-1;if(l)while(++f<a)g=v[f],g.x+=(m-g.x)*l,g.y+=(p-g.y)*l}if(r){k(e=d3.geom.quadtree(v),n,z),f=-1;while(++f<a)(g=v[f]).fixed||e.visit(A(g))}f=-1;while(++f<a)g=v[f],g.fixed?(g.x=g.px,g.y=g.py):(g.x-=(g.px-(g.px=g.x))*o,g.y-=(g.py-(g.py=g.y))*o);return b.tick({type:"tick",alpha:n}),(n*=.99)<.005}function C(b){g(f=b),e=a}var a={},b=d3.dispatch("tick"),c=[1,1],d,n,o=.9,p=l,q=m,r=-30,s=.1,t=.8,u,v=[],w=[],x,y,z;return a.on=function(c,d){return b.on(c,d),a},a.nodes=function(b){return arguments.length?(v=b,a):v},a.links=function(b){return arguments.length?(w=b,a):w},a.size=function(b){return arguments.length?(c=b,a):c},a.linkDistance=function(b){return arguments.length?(p=d3.functor(b),a):p},a.distance=a.linkDistance,a.linkStrength=function(b){return arguments.length?(q=d3.functor(b),a):q},a.friction=function(b){return arguments.length?(o=b,a):o},a.charge=function(b){return arguments.length?(r=typeof b=="function"?b:+b,a):r},a.gravity=function(b){return arguments.length?(s=b,a):s},a.theta=function(b){return arguments.length?(t=b,a):t},a.start=function(){function k(a,c){var d=l(b),e=-1,f=d.length,g;while(++e<f)if(!isNaN(g=d[e][a]))return g;return Math.random()*c}function l(){if(!i){i=[];for(d=0;d<e;++d)i[d]=[];for(d=0;d<f;++d){var a=w[d];i[a.source.index].push(a.target),i[a.target.index].push(a.source)}}return i[b]}var b,d,e=v.length,f=w.length,g=c[0],h=c[1],i,j;for(b=0;b<e;++b)(j=v[b]).index=b,j.weight=0;x=[],y=[];for(b=0;b<f;++b)j=w[b],typeof j.source=="number"&&(j.source=v[j.source]),typeof j.target=="number"&&(j.target=v[j.target]),x[b]=p.call(this,j,b),y[b]=q.call(this,j,b),++j.source.weight,++j.target.weight;for(b=0;b<e;++b)j=v[b],isNaN(j.x)&&(j.x=k("x",g)),isNaN(j.y)&&(j.y=k("y",h)),isNaN(j.px)&&(j.px=j.x),isNaN(j.py)&&(j.py=j.y);z=[];if(typeof r=="function")for(b=0;b<e;++b)z[b]=+r.call(this,v[b],b);else for(b=0;b<e;++b)z[b]=r;return a.resume()},a.resume=function(){return n=.1,d3.timer(B),a},a.stop=function(){return n=0,a},a.drag=function(){d||(d=d3.behavior.drag().on("dragstart",C).on("drag",j).on("dragend",i)),this.on("mouseover.force",g).on("mouseout.force",h).call(d)},a};var e,f;d3.layout.partition=function(){function c(a,b,d,e){var f=a.children;a.x=b,a.y=a.depth*e,a.dx=d,a.dy=e;if(f&&(h=f.length)){var g=-1,h,i,j;d=a.value?d/a.value:0;while(++g<h)c(i=f[g],b,j=i.value*d,e),b+=j}}function d(a){var b=a.children,c=0;if(b&&(f=b.length)){var e=-1,f;while(++e<f)c=Math.max(c,d(b[e]))}return 1+c}function e(e,f){var g=a.call(this,e,f);return c(g[0],0,b[0],b[1]/d(g[0])),g}var a=d3.layout.hierarchy(),b=[1,1];return e.size=function(a){return arguments.length?(b=a,e):b},z(e,a)},d3.layout.pie=function(){function f(g,h){var i=g.map(function(b,c){return+a.call(f,b,c)}),j=+(typeof c=="function"?c.apply(this,arguments):c),k=((typeof e=="function"?e.apply(this,arguments):e)-c)/d3.sum(i),l=d3.range(g.length);b!=null&&l.sort(b===n?function(a,b){return i[b]-i[a]}:function(a,c){return b(g[a],g[c])});var m=l.map(function(a){return{data:g[a],value:d=i[a],startAngle:j,endAngle:j+=d*k}});return g.map(function(a,b){return m[l[b]]})}var a=Number,b=n,c=0,e=2*Math.PI;return f.value=function(b){return arguments.length?(a=b,f):a},f.sort=function(a){return arguments.length?(b=a,f):b},f.startAngle=function(a){return arguments.length?(c=a,f):c},f.endAngle=function(a){return arguments.length?(e=a,f):e},f};var n={};d3.layout.stack=function(){function g(h,i){var j=h.map(function(b,c){return a.call(g,b,c)}),k=j.map(function(a,b){return a.map(function(a,b){return[e.call(g,a,b),f.call(g,a,b)]})}),l=b.call(g,k,i);j=d3.permute(j,l),k=d3.permute(k,l);var m=c.call(g,k,i),n=j.length,o=j[0].length,p,q,r;for(q=0;q<o;++q){d.call(g,j[0][q],r=m[q],k[0][q][1]);for(p=1;p<n;++p)d.call(g,j[p][q],r+=k[p-1][q][1],k[p][q][1])}return h}var a=Object,b=r["default"],c=s.zero,d=q,e=o,f=p;return g.values=function(b){return arguments.length?(a=b,g):a},g.order=function(a){return arguments.length?(b=typeof a=="function"?a:r[a],g):b},g.offset=function(a){return arguments.length?(c=typeof a=="function"?a:s[a],g):c},g.x=function(a){return arguments.length?(e=a,g):e},g.y=function(a){return arguments.length?(f=a,g):f},g.out=function(a){return arguments.length?(d=a,g):d},g};var r={"inside-out":function(a){var b=a.length,c,d,e=a.map(t),f=a.map(u),g=d3.range(b).sort(function(a,b){return e[a]-e[b]}),h=0,i=0,j=[],k=[];for(c=0;c<b;++c)d=g[c],h<i?(h+=f[d],j.push(d)):(i+=f[d],k.push(d));return k.reverse().concat(j)},reverse:function(a){return d3.range(a.length).reverse()},"default":function(a){return d3.range(a.length)}},s={silhouette:function(a){var b=a.length,c=a[0].length,d=[],e=0,f,g,h,i=[];for(g=0;g<c;++g){for(f=0,h=0;f<b;f++)h+=a[f][g][1];h>e&&(e=h),d.push(h)}for(g=0;g<c;++g)i[g]=(e-d[g])/2;return i},wiggle:function(a){var b=a.length,c=a[0],d=c.length,e=0,f,g,h,i,j,k,l,m,n,o=[];o[0]=m=n=0;for(g=1;g<d;++g){for(f=0,i=0;f<b;++f)i+=a[f][g][1];for(f=0,j=0,l=c[g][0]-c[g-1][0];f<b;++f){for(h=0,k=(a[f][g][1]-a[f][g-1][1])/(2*l);h<f;++h)k+=(a[h][g][1]-a[h][g-1][1])/l;j+=k*a[f][g][1]}o[g]=m-=i?j/i*l:0,m<n&&(n=m)}for(g=0;g<d;++g)o[g]-=n;return o},expand:function(a){var b=a.length,c=a[0].length,d=1/b,e,f,g,h=[];for(f=0;f<c;++f){for(e=0,g=0;e<b;e++)g+=a[e][f][1];if(g)for(e=0;e<b;e++)a[e][f][1]/=g;else for(e=0;e<b;e++)a[e][f][1]=d}for(f=0;f<c;++f)h[f]=0;return h},zero:function(a){var b=-1,c=a[0].length,d=[];while(++b<c)d[b]=0;return d}};d3.layout.histogram=function(){function e(e,f){var g=[],h=e.map(b,this),i=c.call(this,h,f),j=d.call(this,i,h,f),k,f=-1,l=h.length,m=j.length-1,n=a?1:1/l,o;while(++f<m)k=g[f]=[],k.dx=j[f+1]-(k.x=j[f]),k.y=0;f=-1;while(++f<l)o=h[f],o>=i[0]&&o<=i[1]&&(k=g[d3.bisect(j,o,1,m)-1],k.y+=n,k.push(e[f]));return g}var a=!0,b=Number,c=y,d=w;return e.value=function(a){return arguments.length?(b=a,e):b},e.range=function(a){return arguments.length?(c=d3.functor(a),e):c},e.bins=function(a){return arguments.length?(d=typeof a=="number"?function(b){return x(b,a)}:d3.functor(a),e):d},e.frequency=function(b){return arguments.length?(a=!!b,e):a},e},d3.layout.hierarchy=function(){function e(f,h,i){var j=b.call(g,f,h),k=E?f:{data:f};k.depth=h,i.push(k);if(j&&(m=j.length)){var l=-1,m,n=k.children=[],o=0,p=h+1;while(++l<m)d=e(j[l],p,i),d.parent=k,n.push(d),o+=d.value;a&&n.sort(a),c&&(k.value=o)}else c&&(k.value=+c.call(g,f,h)||0);return k}function f(a,b){var d=a.children,e=0;if(d&&(i=d.length)){var h=-1,i,j=b+1;while(++h<i)e+=f(d[h],j)}else c&&(e=+c.call(g,E?a:a.data,b)||0);return c&&(a.value=e),e}function g(a){var b=[];return e(a,0,b),b}var a=C,b=A,c=B;return g.sort=function(b){return arguments.length?(a=b,g):a},g.children=function(a){return arguments.length?(b=a,g):b},g.value=function(a){return arguments.length?(c=a,g):c},g.revalue=function(a){return f(a,0),a},g};var E=!1;d3.layout.pack=function(){function c(c,d){var e=a.call(this,c,d),f=e[0];f.x=0,f.y=0,M(f);var g=b[0],h=b[1],i=1/Math.max(2*f.r/g,2*f.r/h);return N(f,g/2,h/2,i),e}var a=d3.layout.hierarchy().sort(F),b=[1,1];return c.size=function(a){return arguments.length?(b=a,c):b},z(c,a)},d3.layout.cluster=function(){function d(d,e){var f=a.call(this,d,e),g=f[0],h,i=0,j,k;$(g,function(a){var c=a.children;c&&c.length?(a.x=Q(c),a.y=P(c)):(a.x=h?i+=b(a,h):0,a.y=0,h=a)});var l=R(g),m=S(g),n=l.x-b(l,m)/2,o=m.x+b(m,l)/2;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=(1-a.y/g.y)*c[1]}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.tree=function(){function d(d,e){function h(a,c){var d=a.children,e=a._tree;if(d&&(f=d.length)){var f,g=d[0],i,k=g,l,m=-1;while(++m<f)l=d[m],h(l,i),k=j(l,i,k),i=l;_(a);var n=.5*(g._tree.prelim+l._tree.prelim);c?(e.prelim=c._tree.prelim+b(a,c),e.mod=e.prelim-n):e.prelim=n}else c&&(e.prelim=c._tree.prelim+b(a,c))}function i(a,b){a.x=a._tree.prelim+b;var c=a.children;if(c&&(e=c.length)){var d=-1,e;b+=a._tree.mod;while(++d<e)i(c[d],b)}}function j(a,c,d){if(c){var e=a,f=a,g=c,h=a.parent.children[0],i=e._tree.mod,j=f._tree.mod,k=g._tree.mod,l=h._tree.mod,m;while(g=V(g),e=U(e),g&&e)h=U(h),f=V(f),f._tree.ancestor=a,m=g._tree.prelim+k-e._tree.prelim-i+b(g,e),m>0&&(ba(bb(g,a,d),a,m),i+=m,j+=m),k+=g._tree.mod,i+=e._tree.mod,l+=h._tree.mod,j+=f._tree.mod;g&&!V(f)&&(f._tree.thread=g,f._tree.mod+=k-j),e&&!U(h)&&(h._tree.thread=e,h._tree.mod+=i-l,d=a)}return d}var f=a.call(this,d,e),g=f[0];$(g,function(a,b){a._tree={ancestor:a,prelim:0,mod:0,change:0,shift:0,number:b?b._tree.number+1:0}}),h(g),i(g,-g._tree.prelim);var k=W(g,Y),l=W(g,X),m=W(g,Z),n=k.x-b(k,l)/2,o=l.x+b(l,k)/2,p=m.depth||1;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=a.depth/p*c[1],delete a._tree}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.treemap=function(){function i(a,b){var c=-1,d=a.length,e,f;while(++c<d)f=(e=a[c]).value*(b<0?0:b),e.area=isNaN(f)||f<=0?0:f}function j(a){var b=a.children;if(b&&b.length){var c=e(a),d=[],f=b.slice(),g,h=Infinity,k,n=Math.min(c.dx,c.dy),o;i(f,c.dx*c.dy/a.value),d.area=0;while((o=f.length)>0)d.push(g=f[o-1]),d.area+=g.area,(k=l(d,n))<=h?(f.pop(),h=k):(d.area-=d.pop().area,m(d,n,c,!1),n=Math.min(c.dx,c.dy),d.length=d.area=0,h=Infinity);d.length&&(m(d,n,c,!0),d.length=d.area=0),b.forEach(j)}}function k(a){var b=a.children;if(b&&b.length){var c=e(a),d=b.slice(),f,g=[];i(d,c.dx*c.dy/a.value),g.area=0;while(f=d.pop())g.push(f),g.area+=f.area,f.z!=null&&(m(g,f.z?c.dx:c.dy,c,!d.length),g.length=g.area=0);b.forEach(k)}}function l(a,b){var c=a.area,d,e=0,f=Infinity,g=-1,i=a.length;while(++g<i){if(!(d=a[g].area))continue;d<f&&(f=d),d>e&&(e=d)}return c*=c,b*=b,c?Math.max(b*e*h/c,c/(b*f*h)):Infinity}function m(a,c,d,e){var f=-1,g=a.length,h=d.x,i=d.y,j=c?b(a.area/c):0,k;if(c==d.dx){if(e||j>d.dy)j=j?d.dy:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dy=j,h+=k.dx=j?b(k.area/j):0;k.z=!0,k.dx+=d.x+d.dx-h,d.y+=j,d.dy-=j}else{if(e||j>d.dx)j=j?d.dx:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dx=j,i+=k.dy=j?b(k.area/j):0;k.z=!1,k.dy+=d.y+d.dy-i,d.x+=j,d.dx-=j}}function n(b){var d=g||a(b),e=d[0];return e.x=0,e.y=0,e.dx=c[0],e.dy=c[1],g&&a.revalue(e),i([e],e.dx*e.dy/e.value),(g?k:j)(e),f&&(g=d),d}var a=d3.layout.hierarchy(),b=Math.round,c=[1,1],d=null,e=bc,f=!1,g,h=.5*(1+Math.sqrt(5));return n.size=function(a){return arguments.length?(c=a,n):c},n.padding=function(a){function b(b){var c=a.call(n,b,b.depth);return c==null?bc(b):bd(b,typeof c=="number"?[c,c,c,c]:c)}function c(b){return bd(b,a)}if(!arguments.length)return d;var f;return e=(d=a)==null?bc:(f=typeof a)==="function"?b:f==="number"?(a=[a,a,a,a],c):c,n},n.round=function(a){return arguments.length?(b=a?Math.round:Number,n):b!=Number},n.sticky=function(a){return arguments.length?(f=a,g=null,n):f},n.ratio=function(a){return arguments.length?(h=a,n):h},z(n,a)}})(); if(Modernizr.svg){(function(){function a(a){var b=a.source,d=a.target,e=c(b,d),f=[b];while(b!==e)b=b.parent,f.push(b);var g=f.length;while(d!==e)f.splice(g,0,d),d=d.parent;return f}function b(a){var b=[],c=a.parent;while(c!=null)b.push(a),a=c,c=c.parent;return b.push(a),b}function c(a,c){if(a===c)return a;var d=b(a),e=b(c),f=d.pop(),g=e.pop(),h=null;while(f===g)h=f,f=d.pop(),g=e.pop();return h}function g(a){a.fixed|=2}function h(a){a!==f&&(a.fixed&=1)}function i(){j(),f.fixed&=1,e=f=null}function j(){f.px+=d3.event.dx,f.py+=d3.event.dy,e.resume()}function k(a,b,c){var d=0,e=0;a.charge=0;if(!a.leaf){var f=a.nodes,g=f.length,h=-1,i;while(++h<g){i=f[h];if(i==null)continue;k(i,b,c),a.charge+=i.charge,d+=i.charge*i.cx,e+=i.charge*i.cy}}if(a.point){a.leaf||(a.point.x+=Math.random()-.5,a.point.y+=Math.random()-.5);var j=b*c[a.point.index];a.charge+=a.pointCharge=j,d+=j*a.point.x,e+=j*a.point.y}a.cx=d/a.charge,a.cy=e/a.charge}function l(a){return 20}function m(a){return 1}function o(a){return a.x}function p(a){return a.y}function q(a,b,c){a.y0=b,a.y=c}function t(a){var b=1,c=0,d=a[0][1],e,f=a.length;for(;b<f;++b)(e=a[b][1])>d&&(c=b,d=e);return c}function u(a){return a.reduce(v,0)}function v(a,b){return a+b[1]}function w(a,b){return x(a,Math.ceil(Math.log(b.length)/Math.LN2+1))}function x(a,b){var c=-1,d=+a[0],e=(a[1]-d)/b,f=[];while(++c<=b)f[c]=e*c+d;return f}function y(a){return[d3.min(a),d3.max(a)]}function z(a,b){return a.sort=d3.rebind(a,b.sort),a.children=d3.rebind(a,b.children),a.links=D,a.value=d3.rebind(a,b.value),a.nodes=function(b){return E=!0,(a.nodes=a)(b)},a}function A(a){return a.children}function B(a){return a.value}function C(a,b){return b.value-a.value}function D(a){return d3.merge(a.map(function(a){return(a.children||[]).map(function(b){return{source:a,target:b}})}))}function F(a,b){return a.value-b.value}function G(a,b){var c=a._pack_next;a._pack_next=b,b._pack_prev=a,b._pack_next=c,c._pack_prev=b}function H(a,b){a._pack_next=b,b._pack_prev=a}function I(a,b){var c=b.x-a.x,d=b.y-a.y,e=a.r+b.r;return e*e-c*c-d*d>.001}function J(a){function l(a){b=Math.min(a.x-a.r,b),c=Math.max(a.x+a.r,c),d=Math.min(a.y-a.r,d),e=Math.max(a.y+a.r,e)}var b=Infinity,c=-Infinity,d=Infinity,e=-Infinity,f=a.length,g,h,i,j,k;a.forEach(K),g=a[0],g.x=-g.r,g.y=0,l(g);if(f>1){h=a[1],h.x=h.r,h.y=0,l(h);if(f>2){i=a[2],O(g,h,i),l(i),G(g,i),g._pack_prev=i,G(i,h),h=g._pack_next;for(var m=3;m<f;m++){O(g,h,i=a[m]);var n=0,o=1,p=1;for(j=h._pack_next;j!==h;j=j._pack_next,o++)if(I(j,i)){n=1;break}if(n==1)for(k=g._pack_prev;k!==j._pack_prev;k=k._pack_prev,p++)if(I(k,i)){p<o&&(n=-1,j=k);break}n==0?(G(g,i),h=i,l(i)):n>0?(H(g,j),h=j,m--):(H(j,h),g=j,m--)}}}var q=(b+c)/2,r=(d+e)/2,s=0;for(var m=0;m<f;m++){var t=a[m];t.x-=q,t.y-=r,s=Math.max(s,t.r+Math.sqrt(t.x*t.x+t.y*t.y))}return a.forEach(L),s}function K(a){a._pack_next=a._pack_prev=a}function L(a){delete a._pack_next,delete a._pack_prev}function M(a){var b=a.children;b&&b.length?(b.forEach(M),a.r=J(b)):a.r=Math.sqrt(a.value)}function N(a,b,c,d){var e=a.children;a.x=b+=d*a.x,a.y=c+=d*a.y,a.r*=d;if(e){var f=-1,g=e.length;while(++f<g)N(e[f],b,c,d)}}function O(a,b,c){var d=a.r+c.r,e=b.x-a.x,f=b.y-a.y;if(d&&(e||f)){var g=b.r+c.r,h=Math.sqrt(e*e+f*f),i=Math.max(-1,Math.min(1,(d*d+h*h-g*g)/(2*d*h))),j=Math.acos(i),k=i*(d/=h),l=Math.sin(j)*d;c.x=a.x+k*e+l*f,c.y=a.y+k*f-l*e}else c.x=a.x+d,c.y=a.y}function P(a){return 1+d3.max(a,function(a){return a.y})}function Q(a){return a.reduce(function(a,b){return a+b.x},0)/a.length}function R(a){var b=a.children;return b&&b.length?R(b[0]):a}function S(a){var b=a.children,c;return b&&(c=b.length)?S(b[c-1]):a}function T(a,b){return a.parent==b.parent?1:2}function U(a){var b=a.children;return b&&b.length?b[0]:a._tree.thread}function V(a){var b=a.children,c;return b&&(c=b.length)?b[c-1]:a._tree.thread}function W(a,b){var c=a.children;if(c&&(e=c.length)){var d,e,f=-1;while(++f<e)b(d=W(c[f],b),a)>0&&(a=d)}return a}function X(a,b){return a.x-b.x}function Y(a,b){return b.x-a.x}function Z(a,b){return a.depth-b.depth}function $(a,b){function c(a,d){var e=a.children;if(e&&(i=e.length)){var f,g=null,h=-1,i;while(++h<i)f=e[h],c(f,g),g=f}b(a,d)}c(a,null)}function _(a){var b=0,c=0,d=a.children,e=d.length,f;while(--e>=0)f=d[e]._tree,f.prelim+=b,f.mod+=b,b+=f.shift+(c+=f.change)}function ba(a,b,c){a=a._tree,b=b._tree;var d=c/(b.number-a.number);a.change+=d,b.change-=d,b.shift+=c,b.prelim+=c,b.mod+=c}function bb(a,b,c){return a._tree.ancestor.parent==b.parent?a._tree.ancestor:c}function bc(a){return{x:a.x,y:a.y,dx:a.dx,dy:a.dy}}function bd(a,b){var c=a.x+b[3],d=a.y+b[0],e=a.dx-b[1]-b[3],f=a.dy-b[0]-b[2];return e<0&&(c+=e/2,e=0),f<0&&(d+=f/2,f=0),{x:c,y:d,dx:e,dy:f}}d3.layout={},d3.layout.bundle=function(){return function(b){var c=[],d=-1,e=b.length;while(++d<e)c.push(a(b[d]));return c}},d3.layout.chord=function(){function j(){var a={},j=[],l=d3.range(e),m=[],n,o,p,q,r;b=[],c=[],n=0,q=-1;while(++q<e){o=0,r=-1;while(++r<e)o+=d[q][r];j.push(o),m.push(d3.range(e)),n+=o}g&&l.sort(function(a,b){return g(j[a],j[b])}),h&&m.forEach(function(a,b){a.sort(function(a,c){return h(d[b][a],d[b][c])})}),n=(2*Math.PI-f*e)/n,o=0,q=-1;while(++q<e){p=o,r=-1;while(++r<e){var s=l[q],t=m[s][r],u=d[s][t],v=o,w=o+=u*n;a[s+"-"+t]={index:s,subindex:t,startAngle:v,endAngle:w,value:u}}c.push({index:s,startAngle:p,endAngle:o,value:(o-p)/n}),o+=f}q=-1;while(++q<e){r=q-1;while(++r<e){var x=a[q+"-"+r],y=a[r+"-"+q];(x.value||y.value)&&b.push(x.value<y.value?{source:y,target:x}:{source:x,target:y})}}i&&k()}function k(){b.sort(function(a,b){return i((a.source.value+a.target.value)/2,(b.source.value+b.target.value)/2)})}var a={},b,c,d,e,f=0,g,h,i;return a.matrix=function(f){return arguments.length?(e=(d=f)&&d.length,b=c=null,a):d},a.padding=function(d){return arguments.length?(f=d,b=c=null,a):f},a.sortGroups=function(d){return arguments.length?(g=d,b=c=null,a):g},a.sortSubgroups=function(c){return arguments.length?(h=c,b=null,a):h},a.sortChords=function(c){return arguments.length?(i=c,b&&k(),a):i},a.chords=function(){return b||j(),b},a.groups=function(){return c||j(),c},a},d3.layout.force=function(){function A(a){return function(b,c,d,e,f){if(b.point!==a){var g=b.cx-a.x,h=b.cy-a.y,i=1/Math.sqrt(g*g+h*h);if((e-c)*i<t){var j=b.charge*i*i;return a.px-=g*j,a.py-=h*j,!0}if(b.point&&isFinite(i)){var j=b.pointCharge*i*i;a.px-=g*j,a.py-=h*j}}return!b.charge}}function B(){var a=v.length,d=w.length,e,f,g,h,i,j,l,m,p;for(f=0;f<d;++f){g=w[f],h=g.source,i=g.target,m=i.x-h.x,p=i.y-h.y;if(j=m*m+p*p)j=n*y[f]*((j=Math.sqrt(j))-x[f])/j,m*=j,p*=j,i.x-=m*(l=h.weight/(i.weight+h.weight)),i.y-=p*l,h.x+=m*(l=1-l),h.y+=p*l}if(l=n*s){m=c[0]/2,p=c[1]/2,f=-1;if(l)while(++f<a)g=v[f],g.x+=(m-g.x)*l,g.y+=(p-g.y)*l}if(r){k(e=d3.geom.quadtree(v),n,z),f=-1;while(++f<a)(g=v[f]).fixed||e.visit(A(g))}f=-1;while(++f<a)g=v[f],g.fixed?(g.x=g.px,g.y=g.py):(g.x-=(g.px-(g.px=g.x))*o,g.y-=(g.py-(g.py=g.y))*o);return b.tick({type:"tick",alpha:n}),(n*=.99)<.005}function C(b){g(f=b),e=a}var a={},b=d3.dispatch("tick"),c=[1,1],d,n,o=.9,p=l,q=m,r=-30,s=.1,t=.8,u,v=[],w=[],x,y,z;return a.on=function(c,d){return b.on(c,d),a},a.nodes=function(b){return arguments.length?(v=b,a):v},a.links=function(b){return arguments.length?(w=b,a):w},a.size=function(b){return arguments.length?(c=b,a):c},a.linkDistance=function(b){return arguments.length?(p=d3.functor(b),a):p},a.distance=a.linkDistance,a.linkStrength=function(b){return arguments.length?(q=d3.functor(b),a):q},a.friction=function(b){return arguments.length?(o=b,a):o},a.charge=function(b){return arguments.length?(r=typeof b=="function"?b:+b,a):r},a.gravity=function(b){return arguments.length?(s=b,a):s},a.theta=function(b){return arguments.length?(t=b,a):t},a.start=function(){function k(a,c){var d=l(b),e=-1,f=d.length,g;while(++e<f)if(!isNaN(g=d[e][a]))return g;return Math.random()*c}function l(){if(!i){i=[];for(d=0;d<e;++d)i[d]=[];for(d=0;d<f;++d){var a=w[d];i[a.source.index].push(a.target),i[a.target.index].push(a.source)}}return i[b]}var b,d,e=v.length,f=w.length,g=c[0],h=c[1],i,j;for(b=0;b<e;++b)(j=v[b]).index=b,j.weight=0;x=[],y=[];for(b=0;b<f;++b)j=w[b],typeof j.source=="number"&&(j.source=v[j.source]),typeof j.target=="number"&&(j.target=v[j.target]),x[b]=p.call(this,j,b),y[b]=q.call(this,j,b),++j.source.weight,++j.target.weight;for(b=0;b<e;++b)j=v[b],isNaN(j.x)&&(j.x=k("x",g)),isNaN(j.y)&&(j.y=k("y",h)),isNaN(j.px)&&(j.px=j.x),isNaN(j.py)&&(j.py=j.y);z=[];if(typeof r=="function")for(b=0;b<e;++b)z[b]=+r.call(this,v[b],b);else for(b=0;b<e;++b)z[b]=r;return a.resume()},a.resume=function(){return n=.1,d3.timer(B),a},a.stop=function(){return n=0,a},a.drag=function(){d||(d=d3.behavior.drag().on("dragstart",C).on("drag",j).on("dragend",i)),this.on("mouseover.force",g).on("mouseout.force",h).call(d)},a};var e,f;d3.layout.partition=function(){function c(a,b,d,e){var f=a.children;a.x=b,a.y=a.depth*e,a.dx=d,a.dy=e;if(f&&(h=f.length)){var g=-1,h,i,j;d=a.value?d/a.value:0;while(++g<h)c(i=f[g],b,j=i.value*d,e),b+=j}}function d(a){var b=a.children,c=0;if(b&&(f=b.length)){var e=-1,f;while(++e<f)c=Math.max(c,d(b[e]))}return 1+c}function e(e,f){var g=a.call(this,e,f);return c(g[0],0,b[0],b[1]/d(g[0])),g}var a=d3.layout.hierarchy(),b=[1,1];return e.size=function(a){return arguments.length?(b=a,e):b},z(e,a)},d3.layout.pie=function(){function f(g,h){var i=g.map(function(b,c){return+a.call(f,b,c)}),j=+(typeof c=="function"?c.apply(this,arguments):c),k=((typeof e=="function"?e.apply(this,arguments):e)-c)/d3.sum(i),l=d3.range(g.length);b!=null&&l.sort(b===n?function(a,b){return i[b]-i[a]}:function(a,c){return b(g[a],g[c])});var m=l.map(function(a){return{data:g[a],value:d=i[a],startAngle:j,endAngle:j+=d*k}});return g.map(function(a,b){return m[l[b]]})}var a=Number,b=n,c=0,e=2*Math.PI;return f.value=function(b){return arguments.length?(a=b,f):a},f.sort=function(a){return arguments.length?(b=a,f):b},f.startAngle=function(a){return arguments.length?(c=a,f):c},f.endAngle=function(a){return arguments.length?(e=a,f):e},f};var n={};d3.layout.stack=function(){function g(h,i){var j=h.map(function(b,c){return a.call(g,b,c)}),k=j.map(function(a,b){return a.map(function(a,b){return[e.call(g,a,b),f.call(g,a,b)]})}),l=b.call(g,k,i);j=d3.permute(j,l),k=d3.permute(k,l);var m=c.call(g,k,i),n=j.length,o=j[0].length,p,q,r;for(q=0;q<o;++q){d.call(g,j[0][q],r=m[q],k[0][q][1]);for(p=1;p<n;++p)d.call(g,j[p][q],r+=k[p-1][q][1],k[p][q][1])}return h}var a=Object,b=r["default"],c=s.zero,d=q,e=o,f=p;return g.values=function(b){return arguments.length?(a=b,g):a},g.order=function(a){return arguments.length?(b=typeof a=="function"?a:r[a],g):b},g.offset=function(a){return arguments.length?(c=typeof a=="function"?a:s[a],g):c},g.x=function(a){return arguments.length?(e=a,g):e},g.y=function(a){return arguments.length?(f=a,g):f},g.out=function(a){return arguments.length?(d=a,g):d},g};var r={"inside-out":function(a){var b=a.length,c,d,e=a.map(t),f=a.map(u),g=d3.range(b).sort(function(a,b){return e[a]-e[b]}),h=0,i=0,j=[],k=[];for(c=0;c<b;++c)d=g[c],h<i?(h+=f[d],j.push(d)):(i+=f[d],k.push(d));return k.reverse().concat(j)},reverse:function(a){return d3.range(a.length).reverse()},"default":function(a){return d3.range(a.length)}},s={silhouette:function(a){var b=a.length,c=a[0].length,d=[],e=0,f,g,h,i=[];for(g=0;g<c;++g){for(f=0,h=0;f<b;f++)h+=a[f][g][1];h>e&&(e=h),d.push(h)}for(g=0;g<c;++g)i[g]=(e-d[g])/2;return i},wiggle:function(a){var b=a.length,c=a[0],d=c.length,e=0,f,g,h,i,j,k,l,m,n,o=[];o[0]=m=n=0;for(g=1;g<d;++g){for(f=0,i=0;f<b;++f)i+=a[f][g][1];for(f=0,j=0,l=c[g][0]-c[g-1][0];f<b;++f){for(h=0,k=(a[f][g][1]-a[f][g-1][1])/(2*l);h<f;++h)k+=(a[h][g][1]-a[h][g-1][1])/l;j+=k*a[f][g][1]}o[g]=m-=i?j/i*l:0,m<n&&(n=m)}for(g=0;g<d;++g)o[g]-=n;return o},expand:function(a){var b=a.length,c=a[0].length,d=1/b,e,f,g,h=[];for(f=0;f<c;++f){for(e=0,g=0;e<b;e++)g+=a[e][f][1];if(g)for(e=0;e<b;e++)a[e][f][1]/=g;else for(e=0;e<b;e++)a[e][f][1]=d}for(f=0;f<c;++f)h[f]=0;return h},zero:function(a){var b=-1,c=a[0].length,d=[];while(++b<c)d[b]=0;return d}};d3.layout.histogram=function(){function e(e,f){var g=[],h=e.map(b,this),i=c.call(this,h,f),j=d.call(this,i,h,f),k,f=-1,l=h.length,m=j.length-1,n=a?1:1/l,o;while(++f<m)k=g[f]=[],k.dx=j[f+1]-(k.x=j[f]),k.y=0;f=-1;while(++f<l)o=h[f],o>=i[0]&&o<=i[1]&&(k=g[d3.bisect(j,o,1,m)-1],k.y+=n,k.push(e[f]));return g}var a=!0,b=Number,c=y,d=w;return e.value=function(a){return arguments.length?(b=a,e):b},e.range=function(a){return arguments.length?(c=d3.functor(a),e):c},e.bins=function(a){return arguments.length?(d=typeof a=="number"?function(b){return x(b,a)}:d3.functor(a),e):d},e.frequency=function(b){return arguments.length?(a=!!b,e):a},e},d3.layout.hierarchy=function(){function e(f,h,i){var j=b.call(g,f,h),k=E?f:{data:f};k.depth=h,i.push(k);if(j&&(m=j.length)){var l=-1,m,n=k.children=[],o=0,p=h+1;while(++l<m)d=e(j[l],p,i),d.parent=k,n.push(d),o+=d.value;a&&n.sort(a),c&&(k.value=o)}else c&&(k.value=+c.call(g,f,h)||0);return k}function f(a,b){var d=a.children,e=0;if(d&&(i=d.length)){var h=-1,i,j=b+1;while(++h<i)e+=f(d[h],j)}else c&&(e=+c.call(g,E?a:a.data,b)||0);return c&&(a.value=e),e}function g(a){var b=[];return e(a,0,b),b}var a=C,b=A,c=B;return g.sort=function(b){return arguments.length?(a=b,g):a},g.children=function(a){return arguments.length?(b=a,g):b},g.value=function(a){return arguments.length?(c=a,g):c},g.revalue=function(a){return f(a,0),a},g};var E=!1;d3.layout.pack=function(){function c(c,d){var e=a.call(this,c,d),f=e[0];f.x=0,f.y=0,M(f);var g=b[0],h=b[1],i=1/Math.max(2*f.r/g,2*f.r/h);return N(f,g/2,h/2,i),e}var a=d3.layout.hierarchy().sort(F),b=[1,1];return c.size=function(a){return arguments.length?(b=a,c):b},z(c,a)},d3.layout.cluster=function(){function d(d,e){var f=a.call(this,d,e),g=f[0],h,i=0,j,k;$(g,function(a){var c=a.children;c&&c.length?(a.x=Q(c),a.y=P(c)):(a.x=h?i+=b(a,h):0,a.y=0,h=a)});var l=R(g),m=S(g),n=l.x-b(l,m)/2,o=m.x+b(m,l)/2;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=(1-a.y/g.y)*c[1]}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.tree=function(){function d(d,e){function h(a,c){var d=a.children,e=a._tree;if(d&&(f=d.length)){var f,g=d[0],i,k=g,l,m=-1;while(++m<f)l=d[m],h(l,i),k=j(l,i,k),i=l;_(a);var n=.5*(g._tree.prelim+l._tree.prelim);c?(e.prelim=c._tree.prelim+b(a,c),e.mod=e.prelim-n):e.prelim=n}else c&&(e.prelim=c._tree.prelim+b(a,c))}function i(a,b){a.x=a._tree.prelim+b;var c=a.children;if(c&&(e=c.length)){var d=-1,e;b+=a._tree.mod;while(++d<e)i(c[d],b)}}function j(a,c,d){if(c){var e=a,f=a,g=c,h=a.parent.children[0],i=e._tree.mod,j=f._tree.mod,k=g._tree.mod,l=h._tree.mod,m;while(g=V(g),e=U(e),g&&e)h=U(h),f=V(f),f._tree.ancestor=a,m=g._tree.prelim+k-e._tree.prelim-i+b(g,e),m>0&&(ba(bb(g,a,d),a,m),i+=m,j+=m),k+=g._tree.mod,i+=e._tree.mod,l+=h._tree.mod,j+=f._tree.mod;g&&!V(f)&&(f._tree.thread=g,f._tree.mod+=k-j),e&&!U(h)&&(h._tree.thread=e,h._tree.mod+=i-l,d=a)}return d}var f=a.call(this,d,e),g=f[0];$(g,function(a,b){a._tree={ancestor:a,prelim:0,mod:0,change:0,shift:0,number:b?b._tree.number+1:0}}),h(g),i(g,-g._tree.prelim);var k=W(g,Y),l=W(g,X),m=W(g,Z),n=k.x-b(k,l)/2,o=l.x+b(l,k)/2,p=m.depth||1;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=a.depth/p*c[1],delete a._tree}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.treemap=function(){function i(a,b){var c=-1,d=a.length,e,f;while(++c<d)f=(e=a[c]).value*(b<0?0:b),e.area=isNaN(f)||f<=0?0:f}function j(a){var b=a.children;if(b&&b.length){var c=e(a),d=[],f=b.slice(),g,h=Infinity,k,n=Math.min(c.dx,c.dy),o;i(f,c.dx*c.dy/a.value),d.area=0;while((o=f.length)>0)d.push(g=f[o-1]),d.area+=g.area,(k=l(d,n))<=h?(f.pop(),h=k):(d.area-=d.pop().area,m(d,n,c,!1),n=Math.min(c.dx,c.dy),d.length=d.area=0,h=Infinity);d.length&&(m(d,n,c,!0),d.length=d.area=0),b.forEach(j)}}function k(a){var b=a.children;if(b&&b.length){var c=e(a),d=b.slice(),f,g=[];i(d,c.dx*c.dy/a.value),g.area=0;while(f=d.pop())g.push(f),g.area+=f.area,f.z!=null&&(m(g,f.z?c.dx:c.dy,c,!d.length),g.length=g.area=0);b.forEach(k)}}function l(a,b){var c=a.area,d,e=0,f=Infinity,g=-1,i=a.length;while(++g<i){if(!(d=a[g].area))continue;d<f&&(f=d),d>e&&(e=d)}return c*=c,b*=b,c?Math.max(b*e*h/c,c/(b*f*h)):Infinity}function m(a,c,d,e){var f=-1,g=a.length,h=d.x,i=d.y,j=c?b(a.area/c):0,k;if(c==d.dx){if(e||j>d.dy)j=j?d.dy:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dy=j,h+=k.dx=j?b(k.area/j):0;k.z=!0,k.dx+=d.x+d.dx-h,d.y+=j,d.dy-=j}else{if(e||j>d.dx)j=j?d.dx:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dx=j,i+=k.dy=j?b(k.area/j):0;k.z=!1,k.dy+=d.y+d.dy-i,d.x+=j,d.dx-=j}}function n(b){var d=g||a(b),e=d[0];return e.x=0,e.y=0,e.dx=c[0],e.dy=c[1],g&&a.revalue(e),i([e],e.dx*e.dy/e.value),(g?k:j)(e),f&&(g=d),d}var a=d3.layout.hierarchy(),b=Math.round,c=[1,1],d=null,e=bc,f=!1,g,h=.5*(1+Math.sqrt(5));return n.size=function(a){return arguments.length?(c=a,n):c},n.padding=function(a){function b(b){var c=a.call(n,b,b.depth);return c==null?bc(b):bd(b,typeof c=="number"?[c,c,c,c]:c)}function c(b){return bd(b,a)}if(!arguments.length)return d;var f;return e=(d=a)==null?bc:(f=typeof a)==="function"?b:f==="number"?(a=[a,a,a,a],c):c,n},n.round=function(a){return arguments.length?(b=a?Math.round:Number,n):b!=Number},n.sticky=function(a){return arguments.length?(f=a,g=null,n):f},n.ratio=function(a){return arguments.length?(h=a,n):h},z(n,a)}})();}
   
(function() { if (Modernizr.svg){(function() {
function d3_class(ctor, properties) { function d3_class(ctor, properties) {
try { try {
for (var key in properties) { for (var key in properties) {
Object.defineProperty(ctor.prototype, key, { Object.defineProperty(ctor.prototype, key, {
value: properties[key], value: properties[key],
enumerable: false enumerable: false
}); });
} }
} catch (e) { } catch (e) {
ctor.prototype = properties; ctor.prototype = properties;
} }
} }
function d3_arrayCopy(pseudoarray) { function d3_arrayCopy(pseudoarray) {
var i = -1, n = pseudoarray.length, array = []; var i = -1, n = pseudoarray.length, array = [];
while (++i < n) array.push(pseudoarray[i]); while (++i < n) array.push(pseudoarray[i]);
return array; return array;
} }
function d3_arraySlice(pseudoarray) { function d3_arraySlice(pseudoarray) {
return Array.prototype.slice.call(pseudoarray); return Array.prototype.slice.call(pseudoarray);
} }
function d3_Map() {} function d3_Map() {}
function d3_identity(d) { function d3_identity(d) {
return d; return d;
} }
function d3_this() { function d3_this() {
return this; return this;
} }
function d3_true() { function d3_true() {
return true; return true;
} }
function d3_functor(v) { function d3_functor(v) {
return typeof v === "function" ? v : function() { return typeof v === "function" ? v : function() {
return v; return v;
}; };
} }
function d3_rebind(target, source, method) { function d3_rebind(target, source, method) {
return function() { return function() {
var value = method.apply(source, arguments); var value = method.apply(source, arguments);
return arguments.length ? target : value; return arguments.length ? target : value;
}; };
} }
function d3_number(x) { function d3_number(x) {
return x != null && !isNaN(x); return x != null && !isNaN(x);
} }
function d3_zipLength(d) { function d3_zipLength(d) {
return d.length; return d.length;
} }
function d3_splitter(d) { function d3_splitter(d) {
return d == null; return d == null;
} }
function d3_collapse(s) { function d3_collapse(s) {
return s.trim().replace(/\s+/g, " "); return s.trim().replace(/\s+/g, " ");
} }
function d3_range_integerScale(x) { function d3_range_integerScale(x) {
var k = 1; var k = 1;
while (x * k % 1) k *= 10; while (x * k % 1) k *= 10;
return k; return k;
} }
function d3_dispatch() {} function d3_dispatch() {}
function d3_dispatch_event(dispatch) { function d3_dispatch_event(dispatch) {
function event() { function event() {
var z = listeners, i = -1, n = z.length, l; var z = listeners, i = -1, n = z.length, l;
while (++i < n) if (l = z[i].on) l.apply(this, arguments); while (++i < n) if (l = z[i].on) l.apply(this, arguments);
return dispatch; return dispatch;
} }
var listeners = [], listenerByName = new d3_Map; var listeners = [], listenerByName = new d3_Map;
event.on = function(name, listener) { event.on = function(name, listener) {
var l = listenerByName.get(name), i; var l = listenerByName.get(name), i;
if (arguments.length < 2) return l && l.on; if (arguments.length < 2) return l && l.on;
if (l) { if (l) {
l.on = null; l.on = null;
listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
listenerByName.remove(name); listenerByName.remove(name);
} }
if (listener) listeners.push(listenerByName.set(name, { if (listener) listeners.push(listenerByName.set(name, {
on: listener on: listener
})); }));
return dispatch; return dispatch;
}; };
return event; return event;
} }
function d3_format_precision(x, p) { function d3_format_precision(x, p) {
return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1); return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
} }
function d3_format_typeDefault(x) { function d3_format_typeDefault(x) {
return x + ""; return x + "";
} }
function d3_format_group(value) { function d3_format_group(value) {
var i = value.lastIndexOf("."), f = i >= 0 ? value.substring(i) : (i = value.length, ""), t = []; var i = value.lastIndexOf("."), f = i >= 0 ? value.substring(i) : (i = value.length, ""), t = [];
while (i > 0) t.push(value.substring(i -= 3, i + 3)); while (i > 0) t.push(value.substring(i -= 3, i + 3));
return t.reverse().join(",") + f; return t.reverse().join(",") + f;
} }
function d3_formatPrefix(d, i) { function d3_formatPrefix(d, i) {
var k = Math.pow(10, Math.abs(8 - i) * 3); var k = Math.pow(10, Math.abs(8 - i) * 3);
return { return {
scale: i > 8 ? function(d) { scale: i > 8 ? function(d) {
return d / k; return d / k;
} : function(d) { } : function(d) {
return d * k; return d * k;
}, },
symbol: d symbol: d
}; };
} }
function d3_ease_clamp(f) { function d3_ease_clamp(f) {
return function(t) { return function(t) {
return t <= 0 ? 0 : t >= 1 ? 1 : f(t); return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
}; };
} }
function d3_ease_reverse(f) { function d3_ease_reverse(f) {
return function(t) { return function(t) {
return 1 - f(1 - t); return 1 - f(1 - t);
}; };
} }
function d3_ease_reflect(f) { function d3_ease_reflect(f) {
return function(t) { return function(t) {
return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t)); return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
}; };
} }
function d3_ease_identity(t) { function d3_ease_identity(t) {
return t; return t;
} }
function d3_ease_poly(e) { function d3_ease_poly(e) {
return function(t) { return function(t) {
return Math.pow(t, e); return Math.pow(t, e);
}; };
} }
function d3_ease_sin(t) { function d3_ease_sin(t) {
return 1 - Math.cos(t * Math.PI / 2); return 1 - Math.cos(t * Math.PI / 2);
} }
function d3_ease_exp(t) { function d3_ease_exp(t) {
return Math.pow(2, 10 * (t - 1)); return Math.pow(2, 10 * (t - 1));
} }
function d3_ease_circle(t) { function d3_ease_circle(t) {
return 1 - Math.sqrt(1 - t * t); return 1 - Math.sqrt(1 - t * t);
} }
function d3_ease_elastic(a, p) { function d3_ease_elastic(a, p) {
var s; var s;
if (arguments.length < 2) p = .45; if (arguments.length < 2) p = .45;
if (arguments.length < 1) { if (arguments.length < 1) {
a = 1; a = 1;
s = p / 4; s = p / 4;
} else s = p / (2 * Math.PI) * Math.asin(1 / a); } else s = p / (2 * Math.PI) * Math.asin(1 / a);
return function(t) { return function(t) {
return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p); return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p);
}; };
} }
function d3_ease_back(s) { function d3_ease_back(s) {
if (!s) s = 1.70158; if (!s) s = 1.70158;
return function(t) { return function(t) {
return t * t * ((s + 1) * t - s); return t * t * ((s + 1) * t - s);
}; };
} }
function d3_ease_bounce(t) { function d3_ease_bounce(t) {
return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; return t < 1 / 2.75 ? 7.5625 * t * t : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
} }
function d3_eventCancel() { function d3_eventCancel() {
d3.event.stopPropagation(); d3.event.stopPropagation();
d3.event.preventDefault(); d3.event.preventDefault();
} }
function d3_eventSource() { function d3_eventSource() {
var e = d3.event, s; var e = d3.event, s;
while (s = e.sourceEvent) e = s; while (s = e.sourceEvent) e = s;
return e; return e;
} }
function d3_eventDispatch(target) { function d3_eventDispatch(target) {
var dispatch = new d3_dispatch, i = 0, n = arguments.length; var dispatch = new d3_dispatch, i = 0, n = arguments.length;
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
dispatch.of = function(thiz, argumentz) { dispatch.of = function(thiz, argumentz) {
return function(e1) { return function(e1) {
try { try {
var e0 = e1.sourceEvent = d3.event; var e0 = e1.sourceEvent = d3.event;
e1.target = target; e1.target = target;
d3.event = e1; d3.event = e1;
dispatch[e1.type].apply(thiz, argumentz); dispatch[e1.type].apply(thiz, argumentz);
} finally { } finally {
d3.event = e0; d3.event = e0;
} }
}; };
}; };
return dispatch; return dispatch;
} }
function d3_transform(m) { function d3_transform(m) {
var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; var r0 = [ m.a, m.b ], r1 = [ m.c, m.d ], kx = d3_transformNormalize(r0), kz = d3_transformDot(r0, r1), ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
if (r0[0] * r1[1] < r1[0] * r0[1]) { if (r0[0] * r1[1] < r1[0] * r0[1]) {
r0[0] *= -1; r0[0] *= -1;
r0[1] *= -1; r0[1] *= -1;
kx *= -1; kx *= -1;
kz *= -1; kz *= -1;
} }
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees; this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_transformDegrees;
this.translate = [ m.e, m.f ]; this.translate = [ m.e, m.f ];
this.scale = [ kx, ky ]; this.scale = [ kx, ky ];
this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0; this.skew = ky ? Math.atan2(kz, ky) * d3_transformDegrees : 0;
} }
function d3_transformDot(a, b) { function d3_transformDot(a, b) {
return a[0] * b[0] + a[1] * b[1]; return a[0] * b[0] + a[1] * b[1];
} }
function d3_transformNormalize(a) { function d3_transformNormalize(a) {
var k = Math.sqrt(d3_transformDot(a, a)); var k = Math.sqrt(d3_transformDot(a, a));
if (k) { if (k) {
a[0] /= k; a[0] /= k;
a[1] /= k; a[1] /= k;
} }
return k; return k;
} }
function d3_transformCombine(a, b, k) { function d3_transformCombine(a, b, k) {
a[0] += k * b[0]; a[0] += k * b[0];
a[1] += k * b[1]; a[1] += k * b[1];
return a; return a;
} }
function d3_interpolateByName(name) { function d3_interpolateByName(name) {
return name == "transform" ? d3.interpolateTransform : d3.interpolate; return name == "transform" ? d3.interpolateTransform : d3.interpolate;
} }
function d3_uninterpolateNumber(a, b) { function d3_uninterpolateNumber(a, b) {
b = b - (a = +a) ? 1 / (b - a) : 0; b = b - (a = +a) ? 1 / (b - a) : 0;
return function(x) { return function(x) {
return (x - a) * b; return (x - a) * b;
}; };
} }
function d3_uninterpolateClamp(a, b) { function d3_uninterpolateClamp(a, b) {
b = b - (a = +a) ? 1 / (b - a) : 0; b = b - (a = +a) ? 1 / (b - a) : 0;
return function(x) { return function(x) {
return Math.max(0, Math.min(1, (x - a) * b)); return Math.max(0, Math.min(1, (x - a) * b));
}; };
} }
function d3_Color() {} function d3_Color() {}
function d3_rgb(r, g, b) { function d3_rgb(r, g, b) {
return new d3_Rgb(r, g, b); return new d3_Rgb(r, g, b);
} }
function d3_Rgb(r, g, b) { function d3_Rgb(r, g, b) {
this.r = r; this.r = r;
this.g = g; this.g = g;
this.b = b; this.b = b;
} }
function d3_rgb_hex(v) { function d3_rgb_hex(v) {
return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16); return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
} }
function d3_rgb_parse(format, rgb, hsl) { function d3_rgb_parse(format, rgb, hsl) {
var r = 0, g = 0, b = 0, m1, m2, name; var r = 0, g = 0, b = 0, m1, m2, name;
m1 = /([a-z]+)\((.*)\)/i.exec(format); m1 = /([a-z]+)\((.*)\)/i.exec(format);
if (m1) { if (m1) {
m2 = m1[2].split(","); m2 = m1[2].split(",");
switch (m1[1]) { switch (m1[1]) {
case "hsl": case "hsl":
{ {
return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100); return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
} }
case "rgb": case "rgb":
{ {
return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2])); return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
} }
} }
} }
if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b);
if (format != null && format.charAt(0) === "#") { if (format != null && format.charAt(0) === "#") {
if (format.length === 4) { if (format.length === 4) {
r = format.charAt(1); r = format.charAt(1);
r += r; r += r;
g = format.charAt(2); g = format.charAt(2);
g += g; g += g;
b = format.charAt(3); b = format.charAt(3);
b += b; b += b;
} else if (format.length === 7) { } else if (format.length === 7) {
r = format.substring(1, 3); r = format.substring(1, 3);
g = format.substring(3, 5); g = format.substring(3, 5);
b = format.substring(5, 7); b = format.substring(5, 7);
} }
r = parseInt(r, 16); r = parseInt(r, 16);
g = parseInt(g, 16); g = parseInt(g, 16);
b = parseInt(b, 16); b = parseInt(b, 16);
} }
return rgb(r, g, b); return rgb(r, g, b);
} }
function d3_rgb_hsl(r, g, b) { function d3_rgb_hsl(r, g, b) {
var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2; var min = Math.min(r /= 255, g /= 255, b /= 255), max = Math.max(r, g, b), d = max - min, h, s, l = (max + min) / 2;
if (d) { if (d) {
s = l < .5 ? d / (max + min) : d / (2 - max - min); s = l < .5 ? d / (max + min) : d / (2 - max - min);
if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4; if (r == max) h = (g - b) / d + (g < b ? 6 : 0); else if (g == max) h = (b - r) / d + 2; else h = (r - g) / d + 4;
h *= 60; h *= 60;
} else { } else {
s = h = 0; s = h = 0;
} }
return d3_hsl(h, s, l); return d3_hsl(h, s, l);
} }
function d3_rgb_lab(r, g, b) { function d3_rgb_lab(r, g, b) {
r = d3_rgb_xyz(r); r = d3_rgb_xyz(r);
g = d3_rgb_xyz(g); g = d3_rgb_xyz(g);
b = d3_rgb_xyz(b); b = d3_rgb_xyz(b);
var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z); var x = d3_xyz_lab((.4124564 * r + .3575761 * g + .1804375 * b) / d3_lab_X), y = d3_xyz_lab((.2126729 * r + .7151522 * g + .072175 * b) / d3_lab_Y), z = d3_xyz_lab((.0193339 * r + .119192 * g + .9503041 * b) / d3_lab_Z);
return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
} }
function d3_rgb_xyz(r) { function d3_rgb_xyz(r) {
return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4); return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
} }
function d3_rgb_parseNumber(c) { function d3_rgb_parseNumber(c) {
var f = parseFloat(c); var f = parseFloat(c);
return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
} }
function d3_hsl(h, s, l) { function d3_hsl(h, s, l) {
return new d3_Hsl(h, s, l); return new d3_Hsl(h, s, l);
} }
function d3_Hsl(h, s, l) { function d3_Hsl(h, s, l) {
this.h = h; this.h = h;
this.s = s; this.s = s;
this.l = l; this.l = l;
} }
function d3_hsl_rgb(h, s, l) { function d3_hsl_rgb(h, s, l) {
function v(h) { function v(h) {
if (h > 360) h -= 360; else if (h < 0) h += 360; if (h > 360) h -= 360; else if (h < 0) h += 360;
if (h < 60) return m1 + (m2 - m1) * h / 60; if (h < 60) return m1 + (m2 - m1) * h / 60;
if (h < 180) return m2; if (h < 180) return m2;
if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
return m1; return m1;
} }
function vv(h) { function vv(h) {
return Math.round(v(h) * 255); return Math.round(v(h) * 255);
} }
var m1, m2; var m1, m2;
h = h % 360; h = h % 360;
if (h < 0) h += 360; if (h < 0) h += 360;
s = s < 0 ? 0 : s > 1 ? 1 : s; s = s < 0 ? 0 : s > 1 ? 1 : s;
l = l < 0 ? 0 : l > 1 ? 1 : l; l = l < 0 ? 0 : l > 1 ? 1 : l;
m2 = l <= .5 ? l * (1 + s) : l + s - l * s; m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
m1 = 2 * l - m2; m1 = 2 * l - m2;
return d3_rgb(vv(h + 120), vv(h), vv(h - 120)); return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
} }
function d3_hcl(h, c, l) { function d3_hcl(h, c, l) {
return new d3_Hcl(h, c, l); return new d3_Hcl(h, c, l);
} }
function d3_Hcl(h, c, l) { function d3_Hcl(h, c, l) {
this.h = h; this.h = h;
this.c = c; this.c = c;
this.l = l; this.l = l;
} }
function d3_hcl_lab(h, c, l) { function d3_hcl_lab(h, c, l) {
return d3_lab(l, Math.cos(h *= Math.PI / 180) * c, Math.sin(h) * c); return d3_lab(l, Math.cos(h *= Math.PI / 180) * c, Math.sin(h) * c);
} }
function d3_lab(l, a, b) { function d3_lab(l, a, b) {
return new d3_Lab(l, a, b); return new d3_Lab(l, a, b);
} }
function d3_Lab(l, a, b) { function d3_Lab(l, a, b) {
this.l = l; this.l = l;
this.a = a; this.a = a;
this.b = b; this.b = b;
} }
function d3_lab_rgb(l, a, b) { function d3_lab_rgb(l, a, b) {
var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200; var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
x = d3_lab_xyz(x) * d3_lab_X; x = d3_lab_xyz(x) * d3_lab_X;
y = d3_lab_xyz(y) * d3_lab_Y; y = d3_lab_xyz(y) * d3_lab_Y;
z = d3_lab_xyz(z) * d3_lab_Z; z = d3_lab_xyz(z) * d3_lab_Z;
return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z)); return d3_rgb(d3_xyz_rgb(3.2404542 * x - 1.5371385 * y - .4985314 * z), d3_xyz_rgb(-.969266 * x + 1.8760108 * y + .041556 * z), d3_xyz_rgb(.0556434 * x - .2040259 * y + 1.0572252 * z));
} }
function d3_lab_hcl(l, a, b) { function d3_lab_hcl(l, a, b) {
return d3_hcl(Math.atan2(b, a) / Math.PI * 180, Math.sqrt(a * a + b * b), l); return d3_hcl(Math.atan2(b, a) / Math.PI * 180, Math.sqrt(a * a + b * b), l);
} }
function d3_lab_xyz(x) { function d3_lab_xyz(x) {
return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037; return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
} }
function d3_xyz_lab(x) { function d3_xyz_lab(x) {
return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
} }
function d3_xyz_rgb(r) { function d3_xyz_rgb(r) {
return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055)); return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
} }
function d3_selection(groups) { function d3_selection(groups) {
d3_arraySubclass(groups, d3_selectionPrototype); d3_arraySubclass(groups, d3_selectionPrototype);
return groups; return groups;
} }
function d3_selection_selector(selector) { function d3_selection_selector(selector) {
return function() { return function() {
return d3_select(selector, this); return d3_select(selector, this);
}; };
} }
function d3_selection_selectorAll(selector) { function d3_selection_selectorAll(selector) {
return function() { return function() {
return d3_selectAll(selector, this); return d3_selectAll(selector, this);
}; };
} }
function d3_selection_attr(name, value) { function d3_selection_attr(name, value) {
function attrNull() { function attrNull() {
this.removeAttribute(name); this.removeAttribute(name);
} }
function attrNullNS() { function attrNullNS() {
this.removeAttributeNS(name.space, name.local); this.removeAttributeNS(name.space, name.local);
} }
function attrConstant() { function attrConstant() {
this.setAttribute(name, value); this.setAttribute(name, value);
} }
function attrConstantNS() { function attrConstantNS() {
this.setAttributeNS(name.space, name.local, value); this.setAttributeNS(name.space, name.local, value);
} }
function attrFunction() { function attrFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.removeAttribute(name); else this.setAttribute(name, x); if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
} }
function attrFunctionNS() { function attrFunctionNS() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
} }
name = d3.ns.qualify(name); name = d3.ns.qualify(name);
return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant; return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
} }
function d3_selection_classedRe(name) { function d3_selection_classedRe(name) {
return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
} }
function d3_selection_classed(name, value) { function d3_selection_classed(name, value) {
function classedConstant() { function classedConstant() {
var i = -1; var i = -1;
while (++i < n) name[i](this, value); while (++i < n) name[i](this, value);
} }
function classedFunction() { function classedFunction() {
var i = -1, x = value.apply(this, arguments); var i = -1, x = value.apply(this, arguments);
while (++i < n) name[i](this, x); while (++i < n) name[i](this, x);
} }
name = name.trim().split(/\s+/).map(d3_selection_classedName); name = name.trim().split(/\s+/).map(d3_selection_classedName);
var n = name.length; var n = name.length;
return typeof value === "function" ? classedFunction : classedConstant; return typeof value === "function" ? classedFunction : classedConstant;
} }
function d3_selection_classedName(name) { function d3_selection_classedName(name) {
var re = d3_selection_classedRe(name); var re = d3_selection_classedRe(name);
return function(node, value) { return function(node, value) {
if (c = node.classList) return value ? c.add(name) : c.remove(name); if (c = node.classList) return value ? c.add(name) : c.remove(name);
var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c; var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
if (value) { if (value) {
re.lastIndex = 0; re.lastIndex = 0;
if (!re.test(cv)) { if (!re.test(cv)) {
cv = d3_collapse(cv + " " + name); cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv; else node.className = cv; if (cb) c.baseVal = cv; else node.className = cv;
} }
} else if (cv) { } else if (cv) {
cv = d3_collapse(cv.replace(re, " ")); cv = d3_collapse(cv.replace(re, " "));
if (cb) c.baseVal = cv; else node.className = cv; if (cb) c.baseVal = cv; else node.className = cv;
} }
}; };
} }
function d3_selection_style(name, value, priority) { function d3_selection_style(name, value, priority) {
function styleNull() { function styleNull() {
this.style.removeProperty(name); this.style.removeProperty(name);
} }
function styleConstant() { function styleConstant() {
this.style.setProperty(name, value, priority); this.style.setProperty(name, value, priority);
} }
function styleFunction() { function styleFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
} }
return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant; return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
} }
function d3_selection_property(name, value) { function d3_selection_property(name, value) {
function propertyNull() { function propertyNull() {
delete this[name]; delete this[name];
} }
function propertyConstant() { function propertyConstant() {
this[name] = value; this[name] = value;
} }
function propertyFunction() { function propertyFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) delete this[name]; else this[name] = x; if (x == null) delete this[name]; else this[name] = x;
} }
return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant; return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
} }
function d3_selection_dataNode(data) { function d3_selection_dataNode(data) {
return { return {
__data__: data __data__: data
}; };
} }
function d3_selection_filter(selector) { function d3_selection_filter(selector) {
return function() { return function() {
return d3_selectMatches(this, selector); return d3_selectMatches(this, selector);
}; };
} }
function d3_selection_sortComparator(comparator) { function d3_selection_sortComparator(comparator) {
if (!arguments.length) comparator = d3.ascending; if (!arguments.length) comparator = d3.ascending;
return function(a, b) { return function(a, b) {
return comparator(a && a.__data__, b && b.__data__); return comparator(a && a.__data__, b && b.__data__);
}; };
} }
function d3_selection_on(type, listener, capture) { function d3_selection_on(type, listener, capture) {
function onRemove() { function onRemove() {
var wrapper = this[name]; var wrapper = this[name];
if (wrapper) { if (wrapper) {
this.removeEventListener(type, wrapper, wrapper.$); this.removeEventListener(type, wrapper, wrapper.$);
delete this[name]; delete this[name];
} }
} }
function onAdd() { function onAdd() {
function wrapper(e) { function wrapper(e) {
var o = d3.event; var o = d3.event;
d3.event = e; d3.event = e;
args[0] = node.__data__; args[0] = node.__data__;
try { try {
listener.apply(node, args); listener.apply(node, args);
} finally { } finally {
d3.event = o; d3.event = o;
} }
} }
var node = this, args = arguments; var node = this, args = arguments;
onRemove.call(this); onRemove.call(this);
this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture); this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
wrapper._ = listener; wrapper._ = listener;
} }
var name = "__on" + type, i = type.indexOf("."); var name = "__on" + type, i = type.indexOf(".");
if (i > 0) type = type.substring(0, i); if (i > 0) type = type.substring(0, i);
return listener ? onAdd : onRemove; return listener ? onAdd : onRemove;
} }
function d3_selection_each(groups, callback) { function d3_selection_each(groups, callback) {
for (var j = 0, m = groups.length; j < m; j++) { for (var j = 0, m = groups.length; j < m; j++) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
if (node = group[i]) callback(node, i, j); if (node = group[i]) callback(node, i, j);
} }
} }
return groups; return groups;
} }
function d3_selection_enter(selection) { function d3_selection_enter(selection) {
d3_arraySubclass(selection, d3_selection_enterPrototype); d3_arraySubclass(selection, d3_selection_enterPrototype);
return selection; return selection;
} }
function d3_transition(groups, id, time) { function d3_transition(groups, id, time) {
d3_arraySubclass(groups, d3_transitionPrototype); d3_arraySubclass(groups, d3_transitionPrototype);
var tweens = new d3_Map, event = d3.dispatch("start", "end"), ease = d3_transitionEase; var tweens = new d3_Map, event = d3.dispatch("start", "end"), ease = d3_transitionEase;
groups.id = id; groups.id = id;
groups.time = time; groups.time = time;
groups.tween = function(name, tween) { groups.tween = function(name, tween) {
if (arguments.length < 2) return tweens.get(name); if (arguments.length < 2) return tweens.get(name);
if (tween == null) tweens.remove(name); else tweens.set(name, tween); if (tween == null) tweens.remove(name); else tweens.set(name, tween);
return groups; return groups;
}; };
groups.ease = function(value) { groups.ease = function(value) {
if (!arguments.length) return ease; if (!arguments.length) return ease;
ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments); ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments);
return groups; return groups;
}; };
groups.each = function(type, listener) { groups.each = function(type, listener) {
if (arguments.length < 2) return d3_transition_each.call(groups, type); if (arguments.length < 2) return d3_transition_each.call(groups, type);
event.on(type, listener); event.on(type, listener);
return groups; return groups;
}; };
d3.timer(function(elapsed) { d3.timer(function(elapsed) {
return d3_selection_each(groups, function(node, i, j) { return d3_selection_each(groups, function(node, i, j) {
function start(elapsed) { function start(elapsed) {
if (lock.active > id) return stop(); if (lock.active > id) return stop();
lock.active = id; lock.active = id;
tweens.forEach(function(key, value) { tweens.forEach(function(key, value) {
if (value = value.call(node, d, i)) { if (value = value.call(node, d, i)) {
tweened.push(value); tweened.push(value);
} }
}); });
event.start.call(node, d, i); event.start.call(node, d, i);
if (!tick(elapsed)) d3.timer(tick, 0, time); if (!tick(elapsed)) d3.timer(tick, 0, time);
return 1; return 1;
} }
function tick(elapsed) { function tick(elapsed) {
if (lock.active !== id) return stop(); if (lock.active !== id) return stop();
var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length; var t = (elapsed - delay) / duration, e = ease(t), n = tweened.length;
while (n > 0) { while (n > 0) {
tweened[--n].call(node, e); tweened[--n].call(node, e);
} }
if (t >= 1) { if (t >= 1) {
stop(); stop();
d3_transitionId = id; d3_transitionId = id;
event.end.call(node, d, i); event.end.call(node, d, i);
d3_transitionId = 0; d3_transitionId = 0;
return 1; return 1;
} }
} }
function stop() { function stop() {
if (!--lock.count) delete node.__transition__; if (!--lock.count) delete node.__transition__;
return 1; return 1;
} }
var tweened = [], delay = node.delay, duration = node.duration, lock = (node = node.node).__transition__ || (node.__transition__ = { var tweened = [], delay = node.delay, duration = node.duration, lock = (node = node.node).__transition__ || (node.__transition__ = {
active: 0, active: 0,
count: 0 count: 0
}), d = node.__data__; }), d = node.__data__;
++lock.count; ++lock.count;
delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time); delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time);
}); });
}, 0, time); }, 0, time);
return groups; return groups;
} }
function d3_transition_each(callback) { function d3_transition_each(callback) {
var id = d3_transitionId, ease = d3_transitionEase, delay = d3_transitionDelay, duration = d3_transitionDuration; var id = d3_transitionId, ease = d3_transitionEase, delay = d3_transitionDelay, duration = d3_transitionDuration;
d3_transitionId = this.id; d3_transitionId = this.id;
d3_transitionEase = this.ease(); d3_transitionEase = this.ease();
d3_selection_each(this, function(node, i, j) { d3_selection_each(this, function(node, i, j) {
d3_transitionDelay = node.delay; d3_transitionDelay = node.delay;
d3_transitionDuration = node.duration; d3_transitionDuration = node.duration;
callback.call(node = node.node, node.__data__, i, j); callback.call(node = node.node, node.__data__, i, j);
}); });
d3_transitionId = id; d3_transitionId = id;
d3_transitionEase = ease; d3_transitionEase = ease;
d3_transitionDelay = delay; d3_transitionDelay = delay;
d3_transitionDuration = duration; d3_transitionDuration = duration;
return this; return this;
} }
function d3_tweenNull(d, i, a) { function d3_tweenNull(d, i, a) {
return a != "" && d3_tweenRemove; return a != "" && d3_tweenRemove;
} }
function d3_tweenByName(b, name) { function d3_tweenByName(b, name) {
return d3.tween(b, d3_interpolateByName(name)); return d3.tween(b, d3_interpolateByName(name));
} }
function d3_timer_step() { function d3_timer_step() {
var elapsed, now = Date.now(), t1 = d3_timer_queue; var elapsed, now = Date.now(), t1 = d3_timer_queue;
while (t1) { while (t1) {
elapsed = now - t1.then; elapsed = now - t1.then;
if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed); if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
t1 = t1.next; t1 = t1.next;
} }
var delay = d3_timer_flush() - now; var delay = d3_timer_flush() - now;
if (delay > 24) { if (delay > 24) {
if (isFinite(delay)) { if (isFinite(delay)) {
clearTimeout(d3_timer_timeout); clearTimeout(d3_timer_timeout);
d3_timer_timeout = setTimeout(d3_timer_step, delay); d3_timer_timeout = setTimeout(d3_timer_step, delay);
} }
d3_timer_interval = 0; d3_timer_interval = 0;
} else { } else {
d3_timer_interval = 1; d3_timer_interval = 1;
d3_timer_frame(d3_timer_step); d3_timer_frame(d3_timer_step);
} }
} }
function d3_timer_flush() { function d3_timer_flush() {
var t0 = null, t1 = d3_timer_queue, then = Infinity; var t0 = null, t1 = d3_timer_queue, then = Infinity;
while (t1) { while (t1) {
if (t1.flush) { if (t1.flush) {
delete d3_timer_byId[t1.callback.id]; delete d3_timer_byId[t1.callback.id];
t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next; t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
} else { } else {
then = Math.min(then, t1.then + t1.delay); then = Math.min(then, t1.then + t1.delay);
t1 = (t0 = t1).next; t1 = (t0 = t1).next;
} }
} }
return then; return then;
} }
function d3_mousePoint(container, e) { function d3_mousePoint(container, e) {
var svg = container.ownerSVGElement || container; var svg = container.ownerSVGElement || container;
if (svg.createSVGPoint) { if (svg.createSVGPoint) {
var point = svg.createSVGPoint(); var point = svg.createSVGPoint();
if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) { if (d3_mouse_bug44083 < 0 && (window.scrollX || window.scrollY)) {
svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0); svg = d3.select(document.body).append("svg").style("position", "absolute").style("top", 0).style("left", 0);
var ctm = svg[0][0].getScreenCTM(); var ctm = svg[0][0].getScreenCTM();
d3_mouse_bug44083 = !(ctm.f || ctm.e); d3_mouse_bug44083 = !(ctm.f || ctm.e);
svg.remove(); svg.remove();
} }
if (d3_mouse_bug44083) { if (d3_mouse_bug44083) {
point.x = e.pageX; point.x = e.pageX;
point.y = e.pageY; point.y = e.pageY;
} else { } else {
point.x = e.clientX; point.x = e.clientX;
point.y = e.clientY; point.y = e.clientY;
} }
point = point.matrixTransform(container.getScreenCTM().inverse()); point = point.matrixTransform(container.getScreenCTM().inverse());
return [ point.x, point.y ]; return [ point.x, point.y ];
} }
var rect = container.getBoundingClientRect(); var rect = container.getBoundingClientRect();
return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ]; return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
} }
function d3_noop() {} function d3_noop() {}
function d3_scaleExtent(domain) { function d3_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1]; var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [ start, stop ] : [ stop, start ]; return start < stop ? [ start, stop ] : [ stop, start ];
} }
function d3_scaleRange(scale) { function d3_scaleRange(scale) {
return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range()); return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
} }
function d3_scale_nice(domain, nice) { function d3_scale_nice(domain, nice) {
var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx; var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
if (x1 < x0) { if (x1 < x0) {
dx = i0, i0 = i1, i1 = dx; dx = i0, i0 = i1, i1 = dx;
dx = x0, x0 = x1, x1 = dx; dx = x0, x0 = x1, x1 = dx;
} }
if (nice = nice(x1 - x0)) { if (nice = nice(x1 - x0)) {
domain[i0] = nice.floor(x0); domain[i0] = nice.floor(x0);
domain[i1] = nice.ceil(x1); domain[i1] = nice.ceil(x1);
} }
return domain; return domain;
} }
function d3_scale_niceDefault() { function d3_scale_niceDefault() {
return Math; return Math;
} }
function d3_scale_linear(domain, range, interpolate, clamp) { function d3_scale_linear(domain, range, interpolate, clamp) {
function rescale() { function rescale() {
var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber; var linear = Math.min(domain.length, range.length) > 2 ? d3_scale_polylinear : d3_scale_bilinear, uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
output = linear(domain, range, uninterpolate, interpolate); output = linear(domain, range, uninterpolate, interpolate);
input = linear(range, domain, uninterpolate, d3.interpolate); input = linear(range, domain, uninterpolate, d3.interpolate);
return scale; return scale;
} }
function scale(x) { function scale(x) {
return output(x); return output(x);
} }
var output, input; var output, input;
scale.invert = function(y) { scale.invert = function(y) {
return input(y); return input(y);
}; };
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return domain; if (!arguments.length) return domain;
domain = x.map(Number); domain = x.map(Number);
return rescale(); return rescale();
}; };
scale.range = function(x) { scale.range = function(x) {
if (!arguments.length) return range; if (!arguments.length) return range;
range = x; range = x;
return rescale(); return rescale();
}; };
scale.rangeRound = function(x) { scale.rangeRound = function(x) {
return scale.range(x).interpolate(d3.interpolateRound); return scale.range(x).interpolate(d3.interpolateRound);
}; };
scale.clamp = function(x) { scale.clamp = function(x) {
if (!arguments.length) return clamp; if (!arguments.length) return clamp;
clamp = x; clamp = x;
return rescale(); return rescale();
}; };
scale.interpolate = function(x) { scale.interpolate = function(x) {
if (!arguments.length) return interpolate; if (!arguments.length) return interpolate;
interpolate = x; interpolate = x;
return rescale(); return rescale();
}; };
scale.ticks = function(m) { scale.ticks = function(m) {
return d3_scale_linearTicks(domain, m); return d3_scale_linearTicks(domain, m);
}; };
scale.tickFormat = function(m) { scale.tickFormat = function(m) {
return d3_scale_linearTickFormat(domain, m); return d3_scale_linearTickFormat(domain, m);
}; };
scale.nice = function() { scale.nice = function() {
d3_scale_nice(domain, d3_scale_linearNice); d3_scale_nice(domain, d3_scale_linearNice);
return rescale(); return rescale();
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_linear(domain, range, interpolate, clamp); return d3_scale_linear(domain, range, interpolate, clamp);
}; };
return rescale(); return rescale();
} }
function d3_scale_linearRebind(scale, linear) { function d3_scale_linearRebind(scale, linear) {
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
} }
function d3_scale_linearNice(dx) { function d3_scale_linearNice(dx) {
dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1); dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
return dx && { return dx && {
floor: function(x) { floor: function(x) {
return Math.floor(x / dx) * dx; return Math.floor(x / dx) * dx;
}, },
ceil: function(x) { ceil: function(x) {
return Math.ceil(x / dx) * dx; return Math.ceil(x / dx) * dx;
} }
}; };
} }
function d3_scale_linearTickRange(domain, m) { function d3_scale_linearTickRange(domain, m) {
var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step; var extent = d3_scaleExtent(domain), span = extent[1] - extent[0], step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)), err = m / span * step;
if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2; if (err <= .15) step *= 10; else if (err <= .35) step *= 5; else if (err <= .75) step *= 2;
extent[0] = Math.ceil(extent[0] / step) * step; extent[0] = Math.ceil(extent[0] / step) * step;
extent[1] = Math.floor(extent[1] / step) * step + step * .5; extent[1] = Math.floor(extent[1] / step) * step + step * .5;
extent[2] = step; extent[2] = step;
return extent; return extent;
} }
function d3_scale_linearTicks(domain, m) { function d3_scale_linearTicks(domain, m) {
return d3.range.apply(d3, d3_scale_linearTickRange(domain, m)); return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
} }
function d3_scale_linearTickFormat(domain, m) { function d3_scale_linearTickFormat(domain, m) {
return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f"); return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
} }
function d3_scale_bilinear(domain, range, uninterpolate, interpolate) { function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]); var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
return function(x) { return function(x) {
return i(u(x)); return i(u(x));
}; };
} }
function d3_scale_polylinear(domain, range, uninterpolate, interpolate) { function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1; var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
if (domain[k] < domain[0]) { if (domain[k] < domain[0]) {
domain = domain.slice().reverse(); domain = domain.slice().reverse();
range = range.slice().reverse(); range = range.slice().reverse();
} }
while (++j <= k) { while (++j <= k) {
u.push(uninterpolate(domain[j - 1], domain[j])); u.push(uninterpolate(domain[j - 1], domain[j]));
i.push(interpolate(range[j - 1], range[j])); i.push(interpolate(range[j - 1], range[j]));
} }
return function(x) { return function(x) {
var j = d3.bisect(domain, x, 1, k) - 1; var j = d3.bisect(domain, x, 1, k) - 1;
return i[j](u[j](x)); return i[j](u[j](x));
}; };
} }
function d3_scale_log(linear, log) { function d3_scale_log(linear, log) {
function scale(x) { function scale(x) {
return linear(log(x)); return linear(log(x));
} }
var pow = log.pow; var pow = log.pow;
scale.invert = function(x) { scale.invert = function(x) {
return pow(linear.invert(x)); return pow(linear.invert(x));
}; };
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(pow); if (!arguments.length) return linear.domain().map(pow);
log = x[0] < 0 ? d3_scale_logn : d3_scale_logp; log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
pow = log.pow; pow = log.pow;
linear.domain(x.map(log)); linear.domain(x.map(log));
return scale; return scale;
}; };
scale.nice = function() { scale.nice = function() {
linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault)); linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
return scale; return scale;
}; };
scale.ticks = function() { scale.ticks = function() {
var extent = d3_scaleExtent(linear.domain()), ticks = []; var extent = d3_scaleExtent(linear.domain()), ticks = [];
if (extent.every(isFinite)) { if (extent.every(isFinite)) {
var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]); var i = Math.floor(extent[0]), j = Math.ceil(extent[1]), u = pow(extent[0]), v = pow(extent[1]);
if (log === d3_scale_logn) { if (log === d3_scale_logn) {
ticks.push(pow(i)); ticks.push(pow(i));
for (; i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k); for (; i++ < j; ) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
} else { } else {
for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k); for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
ticks.push(pow(i)); ticks.push(pow(i));
} }
for (i = 0; ticks[i] < u; i++) {} for (i = 0; ticks[i] < u; i++) {}
for (j = ticks.length; ticks[j - 1] > v; j--) {} for (j = ticks.length; ticks[j - 1] > v; j--) {}
ticks = ticks.slice(i, j); ticks = ticks.slice(i, j);
} }
return ticks; return ticks;
}; };
scale.tickFormat = function(n, format) { scale.tickFormat = function(n, format) {
if (arguments.length < 2) format = d3_scale_logFormat; if (arguments.length < 2) format = d3_scale_logFormat;
if (arguments.length < 1) return format; if (arguments.length < 1) return format;
var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil), e; var k = Math.max(.1, n / scale.ticks().length), f = log === d3_scale_logn ? (e = -1e-12, Math.floor) : (e = 1e-12, Math.ceil), e;
return function(d) { return function(d) {
return d / pow(f(log(d) + e)) <= k ? format(d) : ""; return d / pow(f(log(d) + e)) <= k ? format(d) : "";
}; };
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_log(linear.copy(), log); return d3_scale_log(linear.copy(), log);
}; };
return d3_scale_linearRebind(scale, linear); return d3_scale_linearRebind(scale, linear);
} }
function d3_scale_logp(x) { function d3_scale_logp(x) {
return Math.log(x < 0 ? 0 : x) / Math.LN10; return Math.log(x < 0 ? 0 : x) / Math.LN10;
} }
function d3_scale_logn(x) { function d3_scale_logn(x) {
return -Math.log(x > 0 ? 0 : -x) / Math.LN10; return -Math.log(x > 0 ? 0 : -x) / Math.LN10;
} }
function d3_scale_pow(linear, exponent) { function d3_scale_pow(linear, exponent) {
function scale(x) { function scale(x) {
return linear(powp(x)); return linear(powp(x));
} }
var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent); var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
scale.invert = function(x) { scale.invert = function(x) {
return powb(linear.invert(x)); return powb(linear.invert(x));
}; };
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(powb); if (!arguments.length) return linear.domain().map(powb);
linear.domain(x.map(powp)); linear.domain(x.map(powp));
return scale; return scale;
}; };
scale.ticks = function(m) { scale.ticks = function(m) {
return d3_scale_linearTicks(scale.domain(), m); return d3_scale_linearTicks(scale.domain(), m);
}; };
scale.tickFormat = function(m) { scale.tickFormat = function(m) {
return d3_scale_linearTickFormat(scale.domain(), m); return d3_scale_linearTickFormat(scale.domain(), m);
}; };
scale.nice = function() { scale.nice = function() {
return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice)); return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
}; };
scale.exponent = function(x) { scale.exponent = function(x) {
if (!arguments.length) return exponent; if (!arguments.length) return exponent;
var domain = scale.domain(); var domain = scale.domain();
powp = d3_scale_powPow(exponent = x); powp = d3_scale_powPow(exponent = x);
powb = d3_scale_powPow(1 / exponent); powb = d3_scale_powPow(1 / exponent);
return scale.domain(domain); return scale.domain(domain);
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_pow(linear.copy(), exponent); return d3_scale_pow(linear.copy(), exponent);
}; };
return d3_scale_linearRebind(scale, linear); return d3_scale_linearRebind(scale, linear);
} }
function d3_scale_powPow(e) { function d3_scale_powPow(e) {
return function(x) { return function(x) {
return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e); return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
}; };
} }
function d3_scale_ordinal(domain, ranger) { function d3_scale_ordinal(domain, ranger) {
function scale(x) { function scale(x) {
return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length]; return range[((index.get(x) || index.set(x, domain.push(x))) - 1) % range.length];
} }
function steps(start, step) { function steps(start, step) {
return d3.range(domain.length).map(function(i) { return d3.range(domain.length).map(function(i) {
return start + step * i; return start + step * i;
}); });
} }
var index, range, rangeBand; var index, range, rangeBand;
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return domain; if (!arguments.length) return domain;
domain = []; domain = [];
index = new d3_Map; index = new d3_Map;
var i = -1, n = x.length, xi; var i = -1, n = x.length, xi;
while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi)); while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
return scale[ranger.t].apply(scale, ranger.a); return scale[ranger.t].apply(scale, ranger.a);
}; };
scale.range = function(x) { scale.range = function(x) {
if (!arguments.length) return range; if (!arguments.length) return range;
range = x; range = x;
rangeBand = 0; rangeBand = 0;
ranger = { ranger = {
t: "range", t: "range",
a: arguments a: arguments
}; };
return scale; return scale;
}; };
scale.rangePoints = function(x, padding) { scale.rangePoints = function(x, padding) {
if (arguments.length < 2) padding = 0; if (arguments.length < 2) padding = 0;
var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding); var start = x[0], stop = x[1], step = (stop - start) / (Math.max(1, domain.length - 1) + padding);
range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step); range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
rangeBand = 0; rangeBand = 0;
ranger = { ranger = {
t: "rangePoints", t: "rangePoints",
a: arguments a: arguments
}; };
return scale; return scale;
}; };
scale.rangeBands = function(x, padding, outerPadding) { scale.rangeBands = function(x, padding, outerPadding) {
if (arguments.length < 2) padding = 0; if (arguments.length < 2) padding = 0;
if (arguments.length < 3) outerPadding = padding; if (arguments.length < 3) outerPadding = padding;
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding); var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = (stop - start) / (domain.length - padding + 2 * outerPadding);
range = steps(start + step * outerPadding, step); range = steps(start + step * outerPadding, step);
if (reverse) range.reverse(); if (reverse) range.reverse();
rangeBand = step * (1 - padding); rangeBand = step * (1 - padding);
ranger = { ranger = {
t: "rangeBands", t: "rangeBands",
a: arguments a: arguments
}; };
return scale; return scale;
}; };
scale.rangeRoundBands = function(x, padding, outerPadding) { scale.rangeRoundBands = function(x, padding, outerPadding) {
if (arguments.length < 2) padding = 0; if (arguments.length < 2) padding = 0;
if (arguments.length < 3) outerPadding = padding; if (arguments.length < 3) outerPadding = padding;
var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step; var reverse = x[1] < x[0], start = x[reverse - 0], stop = x[1 - reverse], step = Math.floor((stop - start) / (domain.length - padding + 2 * outerPadding)), error = stop - start - (domain.length - padding) * step;
range = steps(start + Math.round(error / 2), step); range = steps(start + Math.round(error / 2), step);
if (reverse) range.reverse(); if (reverse) range.reverse();
rangeBand = Math.round(step * (1 - padding)); rangeBand = Math.round(step * (1 - padding));
ranger = { ranger = {
t: "rangeRoundBands", t: "rangeRoundBands",
a: arguments a: arguments
}; };
return scale; return scale;
}; };
scale.rangeBand = function() { scale.rangeBand = function() {
return rangeBand; return rangeBand;
}; };
scale.rangeExtent = function() { scale.rangeExtent = function() {
return d3_scaleExtent(ranger.a[0]); return d3_scaleExtent(ranger.a[0]);
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_ordinal(domain, ranger); return d3_scale_ordinal(domain, ranger);
}; };
return scale.domain(domain); return scale.domain(domain);
} }
function d3_scale_quantile(domain, range) { function d3_scale_quantile(domain, range) {
function rescale() { function rescale() {
var k = 0, n = domain.length, q = range.length; var k = 0, n = domain.length, q = range.length;
thresholds = []; thresholds = [];
while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q); while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
return scale; return scale;
} }
function scale(x) { function scale(x) {
if (isNaN(x = +x)) return NaN; if (isNaN(x = +x)) return NaN;
return range[d3.bisect(thresholds, x)]; return range[d3.bisect(thresholds, x)];
} }
var thresholds; var thresholds;
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return domain; if (!arguments.length) return domain;
domain = x.filter(function(d) { domain = x.filter(function(d) {
return !isNaN(d); return !isNaN(d);
}).sort(d3.ascending); }).sort(d3.ascending);
return rescale(); return rescale();
}; };
scale.range = function(x) { scale.range = function(x) {
if (!arguments.length) return range; if (!arguments.length) return range;
range = x; range = x;
return rescale(); return rescale();
}; };
scale.quantiles = function() { scale.quantiles = function() {
return thresholds; return thresholds;
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_quantile(domain, range); return d3_scale_quantile(domain, range);
}; };
return rescale(); return rescale();
} }
function d3_scale_quantize(x0, x1, range) { function d3_scale_quantize(x0, x1, range) {
function scale(x) { function scale(x) {
return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))]; return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
} }
function rescale() { function rescale() {
kx = range.length / (x1 - x0); kx = range.length / (x1 - x0);
i = range.length - 1; i = range.length - 1;
return scale; return scale;
} }
var kx, i; var kx, i;
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return [ x0, x1 ]; if (!arguments.length) return [ x0, x1 ];
x0 = +x[0]; x0 = +x[0];
x1 = +x[x.length - 1]; x1 = +x[x.length - 1];
return rescale(); return rescale();
}; };
scale.range = function(x) { scale.range = function(x) {
if (!arguments.length) return range; if (!arguments.length) return range;
range = x; range = x;
return rescale(); return rescale();
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_quantize(x0, x1, range); return d3_scale_quantize(x0, x1, range);
}; };
return rescale(); return rescale();
} }
function d3_scale_threshold(domain, range) { function d3_scale_threshold(domain, range) {
function scale(x) { function scale(x) {
return range[d3.bisect(domain, x)]; return range[d3.bisect(domain, x)];
} }
scale.domain = function(_) { scale.domain = function(_) {
if (!arguments.length) return domain; if (!arguments.length) return domain;
domain = _; domain = _;
return scale; return scale;
}; };
scale.range = function(_) { scale.range = function(_) {
if (!arguments.length) return range; if (!arguments.length) return range;
range = _; range = _;
return scale; return scale;
}; };
scale.copy = function() { scale.copy = function() {
return d3_scale_threshold(domain, range); return d3_scale_threshold(domain, range);
}; };
return scale; return scale;
} }
function d3_scale_identity(domain) { function d3_scale_identity(domain) {
function identity(x) { function identity(x) {
return +x; return +x;
} }
identity.invert = identity; identity.invert = identity;
identity.domain = identity.range = function(x) { identity.domain = identity.range = function(x) {
if (!arguments.length) return domain; if (!arguments.length) return domain;
domain = x.map(identity); domain = x.map(identity);
return identity; return identity;
}; };
identity.ticks = function(m) { identity.ticks = function(m) {
return d3_scale_linearTicks(domain, m); return d3_scale_linearTicks(domain, m);
}; };
identity.tickFormat = function(m) { identity.tickFormat = function(m) {
return d3_scale_linearTickFormat(domain, m); return d3_scale_linearTickFormat(domain, m);
}; };
identity.copy = function() { identity.copy = function() {
return d3_scale_identity(domain); return d3_scale_identity(domain);
}; };
return identity; return identity;
} }
function d3_svg_arcInnerRadius(d) { function d3_svg_arcInnerRadius(d) {
return d.innerRadius; return d.innerRadius;
} }
function d3_svg_arcOuterRadius(d) { function d3_svg_arcOuterRadius(d) {
return d.outerRadius; return d.outerRadius;
} }
function d3_svg_arcStartAngle(d) { function d3_svg_arcStartAngle(d) {
return d.startAngle; return d.startAngle;
} }
function d3_svg_arcEndAngle(d) { function d3_svg_arcEndAngle(d) {
return d.endAngle; return d.endAngle;
} }
function d3_svg_line(projection) { function d3_svg_line(projection) {
function line(data) { function line(data) {
function segment() { function segment() {
segments.push("M", interpolate(projection(points), tension)); segments.push("M", interpolate(projection(points), tension));
} }
var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y); var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
while (++i < n) { while (++i < n) {
if (defined.call(this, d = data[i], i)) { if (defined.call(this, d = data[i], i)) {
points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]); points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
} else if (points.length) { } else if (points.length) {
segment(); segment();
points = []; points = [];
} }
} }
if (points.length) segment(); if (points.length) segment();
return segments.length ? segments.join("") : null; return segments.length ? segments.join("") : null;
} }
var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7; var x = d3_svg_lineX, y = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
line.x = function(_) { line.x = function(_) {
if (!arguments.length) return x; if (!arguments.length) return x;
x = _; x = _;
return line; return line;
}; };
line.y = function(_) { line.y = function(_) {
if (!arguments.length) return y; if (!arguments.length) return y;
y = _; y = _;
return line; return line;
}; };
line.defined = function(_) { line.defined = function(_) {
if (!arguments.length) return defined; if (!arguments.length) return defined;
defined = _; defined = _;
return line; return line;
}; };
line.interpolate = function(_) { line.interpolate = function(_) {
if (!arguments.length) return interpolateKey; if (!arguments.length) return interpolateKey;
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
return line; return line;
}; };
line.tension = function(_) { line.tension = function(_) {
if (!arguments.length) return tension; if (!arguments.length) return tension;
tension = _; tension = _;
return line; return line;
}; };
return line; return line;
} }
function d3_svg_lineX(d) { function d3_svg_lineX(d) {
return d[0]; return d[0];
} }
function d3_svg_lineY(d) { function d3_svg_lineY(d) {
return d[1]; return d[1];
} }
function d3_svg_lineLinear(points) { function d3_svg_lineLinear(points) {
return points.join("L"); return points.join("L");
} }
function d3_svg_lineLinearClosed(points) { function d3_svg_lineLinearClosed(points) {
return d3_svg_lineLinear(points) + "Z"; return d3_svg_lineLinear(points) + "Z";
} }
function d3_svg_lineStepBefore(points) { function d3_svg_lineStepBefore(points) {
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]); while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
return path.join(""); return path.join("");
} }
function d3_svg_lineStepAfter(points) { function d3_svg_lineStepAfter(points) {
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ]; var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]); while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
return path.join(""); return path.join("");
} }
function d3_svg_lineCardinalOpen(points, tension) { function d3_svg_lineCardinalOpen(points, tension) {
return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension)); return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1), d3_svg_lineCardinalTangents(points, tension));
} }
function d3_svg_lineCardinalClosed(points, tension) { function d3_svg_lineCardinalClosed(points, tension) {
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension)); return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite((points.push(points[0]), points), d3_svg_lineCardinalTangents([ points[points.length - 2] ].concat(points, [ points[1] ]), tension));
} }
function d3_svg_lineCardinal(points, tension, closed) { function d3_svg_lineCardinal(points, tension, closed) {
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension)); return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineCardinalTangents(points, tension));
} }
function d3_svg_lineHermite(points, tangents) { function d3_svg_lineHermite(points, tangents) {
if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) { if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
return d3_svg_lineLinear(points); return d3_svg_lineLinear(points);
} }
var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1; var quad = points.length != tangents.length, path = "", p0 = points[0], p = points[1], t0 = tangents[0], t = t0, pi = 1;
if (quad) { if (quad) {
path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1]; path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
p0 = points[1]; p0 = points[1];
pi = 2; pi = 2;
} }
if (tangents.length > 1) { if (tangents.length > 1) {
t = tangents[1]; t = tangents[1];
p = points[pi]; p = points[pi];
pi++; pi++;
path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1]) + "," + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
for (var i = 2; i < tangents.length; i++, pi++) { for (var i = 2; i < tangents.length; i++, pi++) {
p = points[pi]; p = points[pi];
t = tangents[i]; t = tangents[i];
path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1]; path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
} }
} }
if (quad) { if (quad) {
var lp = points[pi]; var lp = points[pi];
path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1]; path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
} }
return path; return path;
} }
function d3_svg_lineCardinalTangents(points, tension) { function d3_svg_lineCardinalTangents(points, tension) {
var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length; var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
while (++i < n) { while (++i < n) {
p0 = p1; p0 = p1;
p1 = p2; p1 = p2;
p2 = points[i]; p2 = points[i];
tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]); tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
} }
return tangents; return tangents;
} }
function d3_svg_lineBasis(points) { function d3_svg_lineBasis(points) {
if (points.length < 3) return d3_svg_lineLinear(points); if (points.length < 3) return d3_svg_lineLinear(points);
var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ]; var i = 1, n = points.length, pi = points[0], x0 = pi[0], y0 = pi[1], px = [ x0, x0, x0, (pi = points[1])[0] ], py = [ y0, y0, y0, pi[1] ], path = [ x0, ",", y0 ];
d3_svg_lineBasisBezier(path, px, py); d3_svg_lineBasisBezier(path, px, py);
while (++i < n) { while (++i < n) {
pi = points[i]; pi = points[i];
px.shift(); px.shift();
px.push(pi[0]); px.push(pi[0]);
py.shift(); py.shift();
py.push(pi[1]); py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py); d3_svg_lineBasisBezier(path, px, py);
} }
i = -1; i = -1;
while (++i < 2) { while (++i < 2) {
px.shift(); px.shift();
px.push(pi[0]); px.push(pi[0]);
py.shift(); py.shift();
py.push(pi[1]); py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py); d3_svg_lineBasisBezier(path, px, py);
} }
return path.join(""); return path.join("");
} }
function d3_svg_lineBasisOpen(points) { function d3_svg_lineBasisOpen(points) {
if (points.length < 4) return d3_svg_lineLinear(points); if (points.length < 4) return d3_svg_lineLinear(points);
var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ]; var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
while (++i < 3) { while (++i < 3) {
pi = points[i]; pi = points[i];
px.push(pi[0]); px.push(pi[0]);
py.push(pi[1]); py.push(pi[1]);
} }
path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)); path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
--i; --i;
while (++i < n) { while (++i < n) {
pi = points[i]; pi = points[i];
px.shift(); px.shift();
px.push(pi[0]); px.push(pi[0]);
py.shift(); py.shift();
py.push(pi[1]); py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py); d3_svg_lineBasisBezier(path, px, py);
} }
return path.join(""); return path.join("");
} }
function d3_svg_lineBasisClosed(points) { function d3_svg_lineBasisClosed(points) {
var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = []; var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
while (++i < 4) { while (++i < 4) {
pi = points[i % n]; pi = points[i % n];
px.push(pi[0]); px.push(pi[0]);
py.push(pi[1]); py.push(pi[1]);
} }
path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ]; path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
--i; --i;
while (++i < m) { while (++i < m) {
pi = points[i % n]; pi = points[i % n];
px.shift(); px.shift();
px.push(pi[0]); px.push(pi[0]);
py.shift(); py.shift();
py.push(pi[1]); py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py); d3_svg_lineBasisBezier(path, px, py);
} }
return path.join(""); return path.join("");
} }
function d3_svg_lineBundle(points, tension) { function d3_svg_lineBundle(points, tension) {
var n = points.length - 1; var n = points.length - 1;
if (n) { if (n) {
var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t; var x0 = points[0][0], y0 = points[0][1], dx = points[n][0] - x0, dy = points[n][1] - y0, i = -1, p, t;
while (++i <= n) { while (++i <= n) {
p = points[i]; p = points[i];
t = i / n; t = i / n;
p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx); p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy); p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
} }
} }
return d3_svg_lineBasis(points); return d3_svg_lineBasis(points);
} }
function d3_svg_lineDot4(a, b) { function d3_svg_lineDot4(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
} }
function d3_svg_lineBasisBezier(path, x, y) { function d3_svg_lineBasisBezier(path, x, y) {
path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y)); path.push("C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
} }
function d3_svg_lineSlope(p0, p1) { function d3_svg_lineSlope(p0, p1) {
return (p1[1] - p0[1]) / (p1[0] - p0[0]); return (p1[1] - p0[1]) / (p1[0] - p0[0]);
} }
function d3_svg_lineFiniteDifferences(points) { function d3_svg_lineFiniteDifferences(points) {
var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1); var i = 0, j = points.length - 1, m = [], p0 = points[0], p1 = points[1], d = m[0] = d3_svg_lineSlope(p0, p1);
while (++i < j) { while (++i < j) {
m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2; m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
} }
m[i] = d; m[i] = d;
return m; return m;
} }
function d3_svg_lineMonotoneTangents(points) { function d3_svg_lineMonotoneTangents(points) {
var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1; var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
while (++i < j) { while (++i < j) {
d = d3_svg_lineSlope(points[i], points[i + 1]); d = d3_svg_lineSlope(points[i], points[i + 1]);
if (Math.abs(d) < 1e-6) { if (Math.abs(d) < 1e-6) {
m[i] = m[i + 1] = 0; m[i] = m[i + 1] = 0;
} else { } else {
a = m[i] / d; a = m[i] / d;
b = m[i + 1] / d; b = m[i + 1] / d;
s = a * a + b * b; s = a * a + b * b;
if (s > 9) { if (s > 9) {
s = d * 3 / Math.sqrt(s); s = d * 3 / Math.sqrt(s);
m[i] = s * a; m[i] = s * a;
m[i + 1] = s * b; m[i + 1] = s * b;
} }
} }
} }
i = -1; i = -1;
while (++i <= j) { while (++i <= j) {
s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i])); s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0]) / (6 * (1 + m[i] * m[i]));
tangents.push([ s || 0, m[i] * s || 0 ]); tangents.push([ s || 0, m[i] * s || 0 ]);
} }
return tangents; return tangents;
} }
function d3_svg_lineMonotone(points) { function d3_svg_lineMonotone(points) {
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points)); return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
} }
function d3_svg_lineRadial(points) { function d3_svg_lineRadial(points) {
var point, i = -1, n = points.length, r, a; var point, i = -1, n = points.length, r, a;
while (++i < n) { while (++i < n) {
point = points[i]; point = points[i];
r = point[0]; r = point[0];
a = point[1] + d3_svg_arcOffset; a = point[1] + d3_svg_arcOffset;
point[0] = r * Math.cos(a); point[0] = r * Math.cos(a);
point[1] = r * Math.sin(a); point[1] = r * Math.sin(a);
} }
return points; return points;
} }
function d3_svg_area(projection) { function d3_svg_area(projection) {
function area(data) { function area(data) {
function segment() { function segment() {
segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z"); segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
} }
var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() { var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
return x; return x;
} : d3_functor(x1), fy1 = y0 === y1 ? function() { } : d3_functor(x1), fy1 = y0 === y1 ? function() {
return y; return y;
} : d3_functor(y1), x, y; } : d3_functor(y1), x, y;
while (++i < n) { while (++i < n) {
if (defined.call(this, d = data[i], i)) { if (defined.call(this, d = data[i], i)) {
points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]); points0.push([ x = +fx0.call(this, d, i), y = +fy0.call(this, d, i) ]);
points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]); points1.push([ +fx1.call(this, d, i), +fy1.call(this, d, i) ]);
} else if (points0.length) { } else if (points0.length) {
segment(); segment();
points0 = []; points0 = [];
points1 = []; points1 = [];
} }
} }
if (points0.length) segment(); if (points0.length) segment();
return segments.length ? segments.join("") : null; return segments.length ? segments.join("") : null;
} }
var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7; var x0 = d3_svg_lineX, x1 = d3_svg_lineX, y0 = 0, y1 = d3_svg_lineY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
area.x = function(_) { area.x = function(_) {
if (!arguments.length) return x1; if (!arguments.length) return x1;
x0 = x1 = _; x0 = x1 = _;
return area; return area;
}; };
area.x0 = function(_) { area.x0 = function(_) {
if (!arguments.length) return x0; if (!arguments.length) return x0;
x0 = _; x0 = _;
return area; return area;
}; };
area.x1 = function(_) { area.x1 = function(_) {
if (!arguments.length) return x1; if (!arguments.length) return x1;
x1 = _; x1 = _;
return area; return area;
}; };
area.y = function(_) { area.y = function(_) {
if (!arguments.length) return y1; if (!arguments.length) return y1;
y0 = y1 = _; y0 = y1 = _;
return area; return area;
}; };
area.y0 = function(_) { area.y0 = function(_) {
if (!arguments.length) return y0; if (!arguments.length) return y0;
y0 = _; y0 = _;
return area; return area;
}; };
area.y1 = function(_) { area.y1 = function(_) {
if (!arguments.length) return y1; if (!arguments.length) return y1;
y1 = _; y1 = _;
return area; return area;
}; };
area.defined = function(_) { area.defined = function(_) {
if (!arguments.length) return defined; if (!arguments.length) return defined;
defined = _; defined = _;
return area; return area;
}; };
area.interpolate = function(_) { area.interpolate = function(_) {
if (!arguments.length) return interpolateKey; if (!arguments.length) return interpolateKey;
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key; if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
interpolateReverse = interpolate.reverse || interpolate; interpolateReverse = interpolate.reverse || interpolate;
L = interpolate.closed ? "M" : "L"; L = interpolate.closed ? "M" : "L";
return area; return area;
}; };
area.tension = function(_) { area.tension = function(_) {
if (!arguments.length) return tension; if (!arguments.length) return tension;
tension = _; tension = _;
return area; return area;
}; };
return area; return area;
} }
function d3_svg_chordSource(d) { function d3_svg_chordSource(d) {
return d.source; return d.source;
} }
function d3_svg_chordTarget(d) { function d3_svg_chordTarget(d) {
return d.target; return d.target;
} }
function d3_svg_chordRadius(d) { function d3_svg_chordRadius(d) {
return d.radius; return d.radius;
} }
function d3_svg_chordStartAngle(d) { function d3_svg_chordStartAngle(d) {
return d.startAngle; return d.startAngle;
} }
function d3_svg_chordEndAngle(d) { function d3_svg_chordEndAngle(d) {
return d.endAngle; return d.endAngle;
} }
function d3_svg_diagonalProjection(d) { function d3_svg_diagonalProjection(d) {
return [ d.x, d.y ]; return [ d.x, d.y ];
} }
function d3_svg_diagonalRadialProjection(projection) { function d3_svg_diagonalRadialProjection(projection) {
return function() { return function() {
var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset; var d = projection.apply(this, arguments), r = d[0], a = d[1] + d3_svg_arcOffset;
return [ r * Math.cos(a), r * Math.sin(a) ]; return [ r * Math.cos(a), r * Math.sin(a) ];
}; };
} }
function d3_svg_symbolSize() { function d3_svg_symbolSize() {
return 64; return 64;
} }
function d3_svg_symbolType() { function d3_svg_symbolType() {
return "circle"; return "circle";
} }
function d3_svg_symbolCircle(size) { function d3_svg_symbolCircle(size) {
var r = Math.sqrt(size / Math.PI); var r = Math.sqrt(size / Math.PI);
return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z"; return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
} }
function d3_svg_axisX(selection, x) { function d3_svg_axisX(selection, x) {
selection.attr("transform", function(d) { selection.attr("transform", function(d) {
return "translate(" + x(d) + ",0)"; return "translate(" + x(d) + ",0)";
}); });
} }
function d3_svg_axisY(selection, y) { function d3_svg_axisY(selection, y) {
selection.attr("transform", function(d) { selection.attr("transform", function(d) {
return "translate(0," + y(d) + ")"; return "translate(0," + y(d) + ")";
}); });
} }
function d3_svg_axisSubdivide(scale, ticks, m) { function d3_svg_axisSubdivide(scale, ticks, m) {
subticks = []; subticks = [];
if (m && ticks.length > 1) { if (m && ticks.length > 1) {
var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v; var extent = d3_scaleExtent(scale.domain()), subticks, i = -1, n = ticks.length, d = (ticks[1] - ticks[0]) / ++m, j, v;
while (++i < n) { while (++i < n) {
for (j = m; --j > 0; ) { for (j = m; --j > 0; ) {
if ((v = +ticks[i] - j * d) >= extent[0]) { if ((v = +ticks[i] - j * d) >= extent[0]) {
subticks.push(v); subticks.push(v);
} }
} }
} }
for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) { for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1]; ) {
subticks.push(v); subticks.push(v);
} }
} }
return subticks; return subticks;
} }
function d3_behavior_zoomDelta() { function d3_behavior_zoomDelta() {
if (!d3_behavior_zoomDiv) { if (!d3_behavior_zoomDiv) {
d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode; d3_behavior_zoomDiv = d3.select("body").append("div").style("visibility", "hidden").style("top", 0).style("height", 0).style("width", 0).style("overflow-y", "scroll").append("div").style("height", "2000px").node().parentNode;
} }
var e = d3.event, delta; var e = d3.event, delta;
try { try {
d3_behavior_zoomDiv.scrollTop = 1e3; d3_behavior_zoomDiv.scrollTop = 1e3;
d3_behavior_zoomDiv.dispatchEvent(e); d3_behavior_zoomDiv.dispatchEvent(e);
delta = 1e3 - d3_behavior_zoomDiv.scrollTop; delta = 1e3 - d3_behavior_zoomDiv.scrollTop;
} catch (error) { } catch (error) {
delta = e.wheelDelta || -e.detail * 5; delta = e.wheelDelta || -e.detail * 5;
} }
return delta; return delta;
} }
function d3_layout_bundlePath(link) { function d3_layout_bundlePath(link) {
var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ]; var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
while (start !== lca) { while (start !== lca) {
start = start.parent; start = start.parent;
points.push(start); points.push(start);
} }
var k = points.length; var k = points.length;
while (end !== lca) { while (end !== lca) {
points.splice(k, 0, end); points.splice(k, 0, end);
end = end.parent; end = end.parent;
} }
return points; return points;
} }
function d3_layout_bundleAncestors(node) { function d3_layout_bundleAncestors(node) {
var ancestors = [], parent = node.parent; var ancestors = [], parent = node.parent;
while (parent != null) { while (parent != null) {
ancestors.push(node); ancestors.push(node);
node = parent; node = parent;
parent = parent.parent; parent = parent.parent;
} }
ancestors.push(node); ancestors.push(node);
return ancestors; return ancestors;
} }
function d3_layout_bundleLeastCommonAncestor(a, b) { function d3_layout_bundleLeastCommonAncestor(a, b) {
if (a === b) return a; if (a === b) return a;
var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null; var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
while (aNode === bNode) { while (aNode === bNode) {
sharedNode = aNode; sharedNode = aNode;
aNode = aNodes.pop(); aNode = aNodes.pop();
bNode = bNodes.pop(); bNode = bNodes.pop();
} }
return sharedNode; return sharedNode;
} }
function d3_layout_forceDragstart(d) { function d3_layout_forceDragstart(d) {
d.fixed |= 2; d.fixed |= 2;
} }
function d3_layout_forceDragend(d) { function d3_layout_forceDragend(d) {
d.fixed &= 1; d.fixed &= 1;
} }
function d3_layout_forceMouseover(d) { function d3_layout_forceMouseover(d) {
d.fixed |= 4; d.fixed |= 4;
} }
function d3_layout_forceMouseout(d) { function d3_layout_forceMouseout(d) {
d.fixed &= 3; d.fixed &= 3;
} }
function d3_layout_forceAccumulate(quad, alpha, charges) { function d3_layout_forceAccumulate(quad, alpha, charges) {
var cx = 0, cy = 0; var cx = 0, cy = 0;
quad.charge = 0; quad.charge = 0;
if (!quad.leaf) { if (!quad.leaf) {
var nodes = quad.nodes, n = nodes.length, i = -1, c; var nodes = quad.nodes, n = nodes.length, i = -1, c;
while (++i < n) { while (++i < n) {
c = nodes[i]; c = nodes[i];
if (c == null) continue; if (c == null) continue;
d3_layout_forceAccumulate(c, alpha, charges); d3_layout_forceAccumulate(c, alpha, charges);
quad.charge += c.charge; quad.charge += c.charge;
cx += c.charge * c.cx; cx += c.charge * c.cx;
cy += c.charge * c.cy; cy += c.charge * c.cy;
} }
} }
if (quad.point) { if (quad.point) {
if (!quad.leaf) { if (!quad.leaf) {
quad.point.x += Math.random() - .5; quad.point.x += Math.random() - .5;
quad.point.y += Math.random() - .5; quad.point.y += Math.random() - .5;
} }
var k = alpha * charges[quad.point.index]; var k = alpha * charges[quad.point.index];
quad.charge += quad.pointCharge = k; quad.charge += quad.pointCharge = k;
cx += k * quad.point.x; cx += k * quad.point.x;
cy += k * quad.point.y; cy += k * quad.point.y;
} }
quad.cx = cx / quad.charge; quad.cx = cx / quad.charge;
quad.cy = cy / quad.charge; quad.cy = cy / quad.charge;
} }
function d3_layout_forceLinkDistance(link) { function d3_layout_forceLinkDistance(link) {
return 20; return 20;
} }
function d3_layout_forceLinkStrength(link) { function d3_layout_forceLinkStrength(link) {
return 1; return 1;
} }
function d3_layout_stackX(d) { function d3_layout_stackX(d) {
return d.x; return d.x;
} }
function d3_layout_stackY(d) { function d3_layout_stackY(d) {
return d.y; return d.y;
} }
function d3_layout_stackOut(d, y0, y) { function d3_layout_stackOut(d, y0, y) {
d.y0 = y0; d.y0 = y0;
d.y = y; d.y = y;
} }
function d3_layout_stackOrderDefault(data) { function d3_layout_stackOrderDefault(data) {
return d3.range(data.length); return d3.range(data.length);
} }
function d3_layout_stackOffsetZero(data) { function d3_layout_stackOffsetZero(data) {
var j = -1, m = data[0].length, y0 = []; var j = -1, m = data[0].length, y0 = [];
while (++j < m) y0[j] = 0; while (++j < m) y0[j] = 0;
return y0; return y0;
} }
function d3_layout_stackMaxIndex(array) { function d3_layout_stackMaxIndex(array) {
var i = 1, j = 0, v = array[0][1], k, n = array.length; var i = 1, j = 0, v = array[0][1], k, n = array.length;
for (; i < n; ++i) { for (; i < n; ++i) {
if ((k = array[i][1]) > v) { if ((k = array[i][1]) > v) {
j = i; j = i;
v = k; v = k;
} }
} }
return j; return j;
} }
function d3_layout_stackReduceSum(d) { function d3_layout_stackReduceSum(d) {
return d.reduce(d3_layout_stackSum, 0); return d.reduce(d3_layout_stackSum, 0);
} }
function d3_layout_stackSum(p, d) { function d3_layout_stackSum(p, d) {
return p + d[1]; return p + d[1];
} }
function d3_layout_histogramBinSturges(range, values) { function d3_layout_histogramBinSturges(range, values) {
return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1)); return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
} }
function d3_layout_histogramBinFixed(range, n) { function d3_layout_histogramBinFixed(range, n) {
var x = -1, b = +range[0], m = (range[1] - b) / n, f = []; var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
while (++x <= n) f[x] = m * x + b; while (++x <= n) f[x] = m * x + b;
return f; return f;
} }
function d3_layout_histogramRange(values) { function d3_layout_histogramRange(values) {
return [ d3.min(values), d3.max(values) ]; return [ d3.min(values), d3.max(values) ];
} }
function d3_layout_hierarchyRebind(object, hierarchy) { function d3_layout_hierarchyRebind(object, hierarchy) {
d3.rebind(object, hierarchy, "sort", "children", "value"); d3.rebind(object, hierarchy, "sort", "children", "value");
object.links = d3_layout_hierarchyLinks; object.links = d3_layout_hierarchyLinks;
object.nodes = function(d) { object.nodes = function(d) {
d3_layout_hierarchyInline = true; d3_layout_hierarchyInline = true;
return (object.nodes = object)(d); return (object.nodes = object)(d);
}; };
return object; return object;
} }
function d3_layout_hierarchyChildren(d) { function d3_layout_hierarchyChildren(d) {
return d.children; return d.children;
} }
function d3_layout_hierarchyValue(d) { function d3_layout_hierarchyValue(d) {
return d.value; return d.value;
} }
function d3_layout_hierarchySort(a, b) { function d3_layout_hierarchySort(a, b) {
return b.value - a.value; return b.value - a.value;
} }
function d3_layout_hierarchyLinks(nodes) { function d3_layout_hierarchyLinks(nodes) {
return d3.merge(nodes.map(function(parent) { return d3.merge(nodes.map(function(parent) {
return (parent.children || []).map(function(child) { return (parent.children || []).map(function(child) {
return { return {
source: parent, source: parent,
target: child target: child
}; };
}); });
})); }));
} }
function d3_layout_packSort(a, b) { function d3_layout_packSort(a, b) {
return a.value - b.value; return a.value - b.value;
} }
function d3_layout_packInsert(a, b) { function d3_layout_packInsert(a, b) {
var c = a._pack_next; var c = a._pack_next;
a._pack_next = b; a._pack_next = b;
b._pack_prev = a; b._pack_prev = a;
b._pack_next = c; b._pack_next = c;
c._pack_prev = b; c._pack_prev = b;
} }
function d3_layout_packSplice(a, b) { function d3_layout_packSplice(a, b) {
a._pack_next = b; a._pack_next = b;
b._pack_prev = a; b._pack_prev = a;
} }
function d3_layout_packIntersects(a, b) { function d3_layout_packIntersects(a, b) {
var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r; var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
return dr * dr - dx * dx - dy * dy > .001; return dr * dr - dx * dx - dy * dy > .001;
} }
function d3_layout_packSiblings(node) { function d3_layout_packSiblings(node) {
function bound(node) { function bound(node) {
xMin = Math.min(node.x - node.r, xMin); xMin = Math.min(node.x - node.r, xMin);
xMax = Math.max(node.x + node.r, xMax); xMax = Math.max(node.x + node.r, xMax);
yMin = Math.min(node.y - node.r, yMin); yMin = Math.min(node.y - node.r, yMin);
yMax = Math.max(node.y + node.r, yMax); yMax = Math.max(node.y + node.r, yMax);
} }
if (!(nodes = node.children) || !(n = nodes.length)) return; if (!(nodes = node.children) || !(n = nodes.length)) return;
var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n; var nodes, xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, a, b, c, i, j, k, n;
nodes.forEach(d3_layout_packLink); nodes.forEach(d3_layout_packLink);
a = nodes[0]; a = nodes[0];
a.x = -a.r; a.x = -a.r;
a.y = 0; a.y = 0;
bound(a); bound(a);
if (n > 1) { if (n > 1) {
b = nodes[1]; b = nodes[1];
b.x = b.r; b.x = b.r;
b.y = 0; b.y = 0;
bound(b); bound(b);
if (n > 2) { if (n > 2) {
c = nodes[2]; c = nodes[2];
d3_layout_packPlace(a, b, c); d3_layout_packPlace(a, b, c);
bound(c); bound(c);
d3_layout_packInsert(a, c); d3_layout_packInsert(a, c);
a._pack_prev = c; a._pack_prev = c;
d3_layout_packInsert(c, b); d3_layout_packInsert(c, b);
b = a._pack_next; b = a._pack_next;
for (i = 3; i < n; i++) { for (i = 3; i < n; i++) {
d3_layout_packPlace(a, b, c = nodes[i]); d3_layout_packPlace(a, b, c = nodes[i]);
var isect = 0, s1 = 1, s2 = 1; var isect = 0, s1 = 1, s2 = 1;
for (j = b._pack_next; j !== b; j = j._pack_next, s1++) { for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
if (d3_layout_packIntersects(j, c)) { if (d3_layout_packIntersects(j, c)) {
isect = 1; isect = 1;
break; break;
} }
} }
if (isect == 1) { if (isect == 1) {
for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) { for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
if (d3_layout_packIntersects(k, c)) { if (d3_layout_packIntersects(k, c)) {
break; break;
} }
} }
} }
if (isect) { if (isect) {
if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b); if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
i--; i--;
} else { } else {
d3_layout_packInsert(a, c); d3_layout_packInsert(a, c);
b = c; b = c;
bound(c); bound(c);
} }
} }
} }
} }
var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0; var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
c = nodes[i]; c = nodes[i];
c.x -= cx; c.x -= cx;
c.y -= cy; c.y -= cy;
cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y)); cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
} }
node.r = cr; node.r = cr;
nodes.forEach(d3_layout_packUnlink); nodes.forEach(d3_layout_packUnlink);
} }
function d3_layout_packLink(node) { function d3_layout_packLink(node) {
node._pack_next = node._pack_prev = node; node._pack_next = node._pack_prev = node;
} }
function d3_layout_packUnlink(node) { function d3_layout_packUnlink(node) {
delete node._pack_next; delete node._pack_next;
delete node._pack_prev; delete node._pack_prev;
} }
function d3_layout_packTransform(node, x, y, k) { function d3_layout_packTransform(node, x, y, k) {
var children = node.children; var children = node.children;
node.x = x += k * node.x; node.x = x += k * node.x;
node.y = y += k * node.y; node.y = y += k * node.y;
node.r *= k; node.r *= k;
if (children) { if (children) {
var i = -1, n = children.length; var i = -1, n = children.length;
while (++i < n) d3_layout_packTransform(children[i], x, y, k); while (++i < n) d3_layout_packTransform(children[i], x, y, k);
} }
} }
function d3_layout_packPlace(a, b, c) { function d3_layout_packPlace(a, b, c) {
var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y; var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
if (db && (dx || dy)) { if (db && (dx || dy)) {
var da = b.r + c.r, dc = dx * dx + dy * dy; var da = b.r + c.r, dc = dx * dx + dy * dy;
da *= da; da *= da;
db *= db; db *= db;
var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc); var x = .5 + (db - da) / (2 * dc), y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
c.x = a.x + x * dx + y * dy; c.x = a.x + x * dx + y * dy;
c.y = a.y + x * dy - y * dx; c.y = a.y + x * dy - y * dx;
} else { } else {
c.x = a.x + db; c.x = a.x + db;
c.y = a.y; c.y = a.y;
} }
} }
function d3_layout_clusterY(children) { function d3_layout_clusterY(children) {
return 1 + d3.max(children, function(child) { return 1 + d3.max(children, function(child) {
return child.y; return child.y;
}); });
} }
function d3_layout_clusterX(children) { function d3_layout_clusterX(children) {
return children.reduce(function(x, child) { return children.reduce(function(x, child) {
return x + child.x; return x + child.x;
}, 0) / children.length; }, 0) / children.length;
} }
function d3_layout_clusterLeft(node) { function d3_layout_clusterLeft(node) {
var children = node.children; var children = node.children;
return children && children.length ? d3_layout_clusterLeft(children[0]) : node; return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
} }
function d3_layout_clusterRight(node) { function d3_layout_clusterRight(node) {
var children = node.children, n; var children = node.children, n;
return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node; return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
} }
function d3_layout_treeSeparation(a, b) { function d3_layout_treeSeparation(a, b) {
return a.parent == b.parent ? 1 : 2; return a.parent == b.parent ? 1 : 2;
} }
function d3_layout_treeLeft(node) { function d3_layout_treeLeft(node) {
var children = node.children; var children = node.children;
return children && children.length ? children[0] : node._tree.thread; return children && children.length ? children[0] : node._tree.thread;
} }
function d3_layout_treeRight(node) { function d3_layout_treeRight(node) {
var children = node.children, n; var children = node.children, n;
return children && (n = children.length) ? children[n - 1] : node._tree.thread; return children && (n = children.length) ? children[n - 1] : node._tree.thread;
} }
function d3_layout_treeSearch(node, compare) { function d3_layout_treeSearch(node, compare) {
var children = node.children; var children = node.children;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var child, n, i = -1; var child, n, i = -1;
while (++i < n) { while (++i < n) {
if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) { if (compare(child = d3_layout_treeSearch(children[i], compare), node) > 0) {
node = child; node = child;
} }
} }
} }
return node; return node;
} }
function d3_layout_treeRightmost(a, b) { function d3_layout_treeRightmost(a, b) {
return a.x - b.x; return a.x - b.x;
} }
function d3_layout_treeLeftmost(a, b) { function d3_layout_treeLeftmost(a, b) {
return b.x - a.x; return b.x - a.x;
} }
function d3_layout_treeDeepest(a, b) { function d3_layout_treeDeepest(a, b) {
return a.depth - b.depth; return a.depth - b.depth;
} }
function d3_layout_treeVisitAfter(node, callback) { function d3_layout_treeVisitAfter(node, callback) {
function visit(node, previousSibling) { function visit(node, previousSibling) {
var children = node.children; var children = node.children;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var child, previousChild = null, i = -1, n; var child, previousChild = null, i = -1, n;
while (++i < n) { while (++i < n) {
child = children[i]; child = children[i];
visit(child, previousChild); visit(child, previousChild);
previousChild = child; previousChild = child;
} }
} }
callback(node, previousSibling); callback(node, previousSibling);
} }
visit(node, null); visit(node, null);
} }
function d3_layout_treeShift(node) { function d3_layout_treeShift(node) {
var shift = 0, change = 0, children = node.children, i = children.length, child; var shift = 0, change = 0, children = node.children, i = children.length, child;
while (--i >= 0) { while (--i >= 0) {
child = children[i]._tree; child = children[i]._tree;
child.prelim += shift; child.prelim += shift;
child.mod += shift; child.mod += shift;
shift += child.shift + (change += child.change); shift += child.shift + (change += child.change);
} }
} }
function d3_layout_treeMove(ancestor, node, shift) { function d3_layout_treeMove(ancestor, node, shift) {
ancestor = ancestor._tree; ancestor = ancestor._tree;
node = node._tree; node = node._tree;
var change = shift / (node.number - ancestor.number); var change = shift / (node.number - ancestor.number);
ancestor.change += change; ancestor.change += change;
node.change -= change; node.change -= change;
node.shift += shift; node.shift += shift;
node.prelim += shift; node.prelim += shift;
node.mod += shift; node.mod += shift;
} }
function d3_layout_treeAncestor(vim, node, ancestor) { function d3_layout_treeAncestor(vim, node, ancestor) {
return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor; return vim._tree.ancestor.parent == node.parent ? vim._tree.ancestor : ancestor;
} }
function d3_layout_treemapPadNull(node) { function d3_layout_treemapPadNull(node) {
return { return {
x: node.x, x: node.x,
y: node.y, y: node.y,
dx: node.dx, dx: node.dx,
dy: node.dy dy: node.dy
}; };
} }
function d3_layout_treemapPad(node, padding) { function d3_layout_treemapPad(node, padding) {
var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2];
if (dx < 0) { if (dx < 0) {
x += dx / 2; x += dx / 2;
dx = 0; dx = 0;
} }
if (dy < 0) { if (dy < 0) {
y += dy / 2; y += dy / 2;
dy = 0; dy = 0;
} }
return { return {
x: x, x: x,
y: y, y: y,
dx: dx, dx: dx,
dy: dy dy: dy
}; };
} }
function d3_dsv(delimiter, mimeType) { function d3_dsv(delimiter, mimeType) {
function dsv(url, callback) { function dsv(url, callback) {
d3.text(url, mimeType, function(text) { d3.text(url, mimeType, function(text) {
callback(text && dsv.parse(text)); callback(text && dsv.parse(text));
}); });
} }
function formatRow(row) { function formatRow(row) {
return row.map(formatValue).join(delimiter); return row.map(formatValue).join(delimiter);
} }
function formatValue(text) { function formatValue(text) {
return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text; return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
} }
var reParse = new RegExp("\r\n|[" + delimiter + "\r\n]", "g"), reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0); var reParse = new RegExp("\r\n|[" + delimiter + "\r\n]", "g"), reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
dsv.parse = function(text) { dsv.parse = function(text) {
var header; var header;
return dsv.parseRows(text, function(row, i) { return dsv.parseRows(text, function(row, i) {
if (i) { if (i) {
var o = {}, j = -1, m = header.length; var o = {}, j = -1, m = header.length;
while (++j < m) o[header[j]] = row[j]; while (++j < m) o[header[j]] = row[j];
return o; return o;
} else { } else {
header = row; header = row;
return null; return null;
} }
}); });
}; };
dsv.parseRows = function(text, f) { dsv.parseRows = function(text, f) {
function token() { function token() {
if (reParse.lastIndex >= text.length) return EOF; if (reParse.lastIndex >= text.length) return EOF;
if (eol) { if (eol) {
eol = false; eol = false;
return EOL; return EOL;
} }
var j = reParse.lastIndex; var j = reParse.lastIndex;
if (text.charCodeAt(j) === 34) { if (text.charCodeAt(j) === 34) {
var i = j; var i = j;
while (i++ < text.length) { while (i++ < text.length) {
if (text.charCodeAt(i) === 34) { if (text.charCodeAt(i) === 34) {
if (text.charCodeAt(i + 1) !== 34) break; if (text.charCodeAt(i + 1) !== 34) break;
i++; i++;
} }
} }
reParse.lastIndex = i + 2; reParse.lastIndex = i + 2;
var c = text.charCodeAt(i + 1); var c = text.charCodeAt(i + 1);
if (c === 13) { if (c === 13) {
eol = true; eol = true;
if (text.charCodeAt(i + 2) === 10) reParse.lastIndex++; if (text.charCodeAt(i + 2) === 10) reParse.lastIndex++;
} else if (c === 10) { } else if (c === 10) {
eol = true; eol = true;
} }
return text.substring(j + 1, i).replace(/""/g, '"'); return text.substring(j + 1, i).replace(/""/g, '"');
} }
var m = reParse.exec(text); var m = reParse.exec(text);
if (m) { if (m) {
eol = m[0].charCodeAt(0) !== delimiterCode; eol = m[0].charCodeAt(0) !== delimiterCode;
return text.substring(j, m.index); return text.substring(j, m.index);
} }
reParse.lastIndex = text.length; reParse.lastIndex = text.length;
return text.substring(j); return text.substring(j);
} }
var EOL = {}, EOF = {}, rows = [], n = 0, t, eol; var EOL = {}, EOF = {}, rows = [], n = 0, t, eol;
reParse.lastIndex = 0; reParse.lastIndex = 0;
while ((t = token()) !== EOF) { while ((t = token()) !== EOF) {
var a = []; var a = [];
while (t !== EOL && t !== EOF) { while (t !== EOL && t !== EOF) {
a.push(t); a.push(t);
t = token(); t = token();
} }
if (f && !(a = f(a, n++))) continue; if (f && !(a = f(a, n++))) continue;
rows.push(a); rows.push(a);
} }
return rows; return rows;
}; };
dsv.format = function(rows) { dsv.format = function(rows) {
return rows.map(formatRow).join("\n"); return rows.map(formatRow).join("\n");
}; };
return dsv; return dsv;
} }
function d3_geo_type(types, defaultValue) { function d3_geo_type(types, defaultValue) {
return function(object) { return function(object) {
return object && types.hasOwnProperty(object.type) ? types[object.type](object) : defaultValue; return object && types.hasOwnProperty(object.type) ? types[object.type](object) : defaultValue;
}; };
} }
function d3_path_circle(radius) { function d3_path_circle(radius) {
return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z"; return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + +2 * radius + "z";
} }
function d3_geo_bounds(o, f) { function d3_geo_bounds(o, f) {
if (d3_geo_boundsTypes.hasOwnProperty(o.type)) d3_geo_boundsTypes[o.type](o, f); if (d3_geo_boundsTypes.hasOwnProperty(o.type)) d3_geo_boundsTypes[o.type](o, f);
} }
function d3_geo_boundsFeature(o, f) { function d3_geo_boundsFeature(o, f) {
d3_geo_bounds(o.geometry, f); d3_geo_bounds(o.geometry, f);
} }
function d3_geo_boundsFeatureCollection(o, f) { function d3_geo_boundsFeatureCollection(o, f) {
for (var a = o.features, i = 0, n = a.length; i < n; i++) { for (var a = o.features, i = 0, n = a.length; i < n; i++) {
d3_geo_bounds(a[i].geometry, f); d3_geo_bounds(a[i].geometry, f);
} }
} }
function d3_geo_boundsGeometryCollection(o, f) { function d3_geo_boundsGeometryCollection(o, f) {
for (var a = o.geometries, i = 0, n = a.length; i < n; i++) { for (var a = o.geometries, i = 0, n = a.length; i < n; i++) {
d3_geo_bounds(a[i], f); d3_geo_bounds(a[i], f);
} }
} }
function d3_geo_boundsLineString(o, f) { function d3_geo_boundsLineString(o, f) {
for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
f.apply(null, a[i]); f.apply(null, a[i]);
} }
} }
function d3_geo_boundsMultiLineString(o, f) { function d3_geo_boundsMultiLineString(o, f) {
for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
for (var b = a[i], j = 0, m = b.length; j < m; j++) { for (var b = a[i], j = 0, m = b.length; j < m; j++) {
f.apply(null, b[j]); f.apply(null, b[j]);
} }
} }
} }
function d3_geo_boundsMultiPolygon(o, f) { function d3_geo_boundsMultiPolygon(o, f) {
for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) { for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
for (var b = a[i][0], j = 0, m = b.length; j < m; j++) { for (var b = a[i][0], j = 0, m = b.length; j < m; j++) {
f.apply(null, b[j]); f.apply(null, b[j]);
} }
} }
} }
function d3_geo_boundsPoint(o, f) { function d3_geo_boundsPoint(o, f) {
f.apply(null, o.coordinates); f.apply(null, o.coordinates);
} }
function d3_geo_boundsPolygon(o, f) { function d3_geo_boundsPolygon(o, f) {
for (var a = o.coordinates[0], i = 0, n = a.length; i < n; i++) { for (var a = o.coordinates[0], i = 0, n = a.length; i < n; i++) {
f.apply(null, a[i]); f.apply(null, a[i]);
} }
} }
function d3_geo_greatArcSource(d) { function d3_geo_greatArcSource(d) {
return d.source; return d.source;
} }
function d3_geo_greatArcTarget(d) { function d3_geo_greatArcTarget(d) {
return d.target; return d.target;
} }
function d3_geo_greatArcInterpolator() { function d3_geo_greatArcInterpolator() {
function interpolate(t) { function interpolate(t) {
var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1; var B = Math.sin(t *= d) * k, A = Math.sin(d - t) * k, x = A * kx0 + B * kx1, y = A * ky0 + B * ky1, z = A * sy0 + B * sy1;
return [ Math.atan2(y, x) / d3_geo_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians ]; return [ Math.atan2(y, x) / d3_geo_radians, Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_geo_radians ];
} }
var x0, y0, cy0, sy0, kx0, ky0, x1, y1, cy1, sy1, kx1, ky1, d, k; var x0, y0, cy0, sy0, kx0, ky0, x1, y1, cy1, sy1, kx1, ky1, d, k;
interpolate.distance = function() { interpolate.distance = function() {
if (d == null) k = 1 / Math.sin(d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0))))); if (d == null) k = 1 / Math.sin(d = Math.acos(Math.max(-1, Math.min(1, sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)))));
return d; return d;
}; };
interpolate.source = function(_) { interpolate.source = function(_) {
var cx0 = Math.cos(x0 = _[0] * d3_geo_radians), sx0 = Math.sin(x0); var cx0 = Math.cos(x0 = _[0] * d3_geo_radians), sx0 = Math.sin(x0);
cy0 = Math.cos(y0 = _[1] * d3_geo_radians); cy0 = Math.cos(y0 = _[1] * d3_geo_radians);
sy0 = Math.sin(y0); sy0 = Math.sin(y0);
kx0 = cy0 * cx0; kx0 = cy0 * cx0;
ky0 = cy0 * sx0; ky0 = cy0 * sx0;
d = null; d = null;
return interpolate; return interpolate;
}; };
interpolate.target = function(_) { interpolate.target = function(_) {
var cx1 = Math.cos(x1 = _[0] * d3_geo_radians), sx1 = Math.sin(x1); var cx1 = Math.cos(x1 = _[0] * d3_geo_radians), sx1 = Math.sin(x1);
cy1 = Math.cos(y1 = _[1] * d3_geo_radians); cy1 = Math.cos(y1 = _[1] * d3_geo_radians);
sy1 = Math.sin(y1); sy1 = Math.sin(y1);
kx1 = cy1 * cx1; kx1 = cy1 * cx1;
ky1 = cy1 * sx1; ky1 = cy1 * sx1;
d = null; d = null;
return interpolate; return interpolate;
}; };
return interpolate; return interpolate;
} }
function d3_geo_greatArcInterpolate(a, b) { function d3_geo_greatArcInterpolate(a, b) {
var i = d3_geo_greatArcInterpolator().source(a).target(b); var i = d3_geo_greatArcInterpolator().source(a).target(b);
i.distance(); i.distance();
return i; return i;
} }
function d3_geom_contourStart(grid) { function d3_geom_contourStart(grid) {
var x = 0, y = 0; var x = 0, y = 0;
while (true) { while (true) {
if (grid(x, y)) { if (grid(x, y)) {
return [ x, y ]; return [ x, y ];
} }
if (x === 0) { if (x === 0) {
x = y + 1; x = y + 1;
y = 0; y = 0;
} else { } else {
x = x - 1; x = x - 1;
y = y + 1; y = y + 1;
} }
} }
} }
function d3_geom_hullCCW(i1, i2, i3, v) { function d3_geom_hullCCW(i1, i2, i3, v) {
var t, a, b, c, d, e, f; var t, a, b, c, d, e, f;
t = v[i1]; t = v[i1];
a = t[0]; a = t[0];
b = t[1]; b = t[1];
t = v[i2]; t = v[i2];
c = t[0]; c = t[0];
d = t[1]; d = t[1];
t = v[i3]; t = v[i3];
e = t[0]; e = t[0];
f = t[1]; f = t[1];
return (f - b) * (c - a) - (d - b) * (e - a) > 0; return (f - b) * (c - a) - (d - b) * (e - a) > 0;
} }
function d3_geom_polygonInside(p, a, b) { function d3_geom_polygonInside(p, a, b) {
return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
} }
function d3_geom_polygonIntersect(c, d, a, b) { function d3_geom_polygonIntersect(c, d, a, b) {
var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0], y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1], x13 = x1 - x3, x21 = x2 - x1, x43 = x4 - x3, y13 = y1 - y3, y21 = y2 - y1, y43 = y4 - y3, ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21); var x1 = c[0], x2 = d[0], x3 = a[0], x4 = b[0], y1 = c[1], y2 = d[1], y3 = a[1], y4 = b[1], x13 = x1 - x3, x21 = x2 - x1, x43 = x4 - x3, y13 = y1 - y3, y21 = y2 - y1, y43 = y4 - y3, ua = (x43 * y13 - y43 * x13) / (y43 * x21 - x43 * y21);
return [ x1 + ua * x21, y1 + ua * y21 ]; return [ x1 + ua * x21, y1 + ua * y21 ];
} }
function d3_voronoi_tessellate(vertices, callback) { function d3_voronoi_tessellate(vertices, callback) {
var Sites = { var Sites = {
list: vertices.map(function(v, i) { list: vertices.map(function(v, i) {
return { return {
index: i, index: i,
x: v[0], x: v[0],
y: v[1] y: v[1]
}; };
}).sort(function(a, b) { }).sort(function(a, b) {
return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0; return a.y < b.y ? -1 : a.y > b.y ? 1 : a.x < b.x ? -1 : a.x > b.x ? 1 : 0;
}), }),
bottomSite: null bottomSite: null
}; };
var EdgeList = { var EdgeList = {
list: [], list: [],
leftEnd: null, leftEnd: null,
rightEnd: null, rightEnd: null,
init: function() { init: function() {
EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l"); EdgeList.leftEnd = EdgeList.createHalfEdge(null, "l");
EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l"); EdgeList.rightEnd = EdgeList.createHalfEdge(null, "l");
EdgeList.leftEnd.r = EdgeList.rightEnd; EdgeList.leftEnd.r = EdgeList.rightEnd;
EdgeList.rightEnd.l = EdgeList.leftEnd; EdgeList.rightEnd.l = EdgeList.leftEnd;
EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd); EdgeList.list.unshift(EdgeList.leftEnd, EdgeList.rightEnd);
}, },
createHalfEdge: function(edge, side) { createHalfEdge: function(edge, side) {
return { return {
edge: edge, edge: edge,
side: side, side: side,
vertex: null, vertex: null,
l: null, l: null,
r: null r: null
}; };
}, },
insert: function(lb, he) { insert: function(lb, he) {
he.l = lb; he.l = lb;
he.r = lb.r; he.r = lb.r;
lb.r.l = he; lb.r.l = he;
lb.r = he; lb.r = he;
}, },
leftBound: function(p) { leftBound: function(p) {
var he = EdgeList.leftEnd; var he = EdgeList.leftEnd;
do { do {
he = he.r; he = he.r;
} while (he != EdgeList.rightEnd && Geom.rightOf(he, p)); } while (he != EdgeList.rightEnd && Geom.rightOf(he, p));
he = he.l; he = he.l;
return he; return he;
}, },
del: function(he) { del: function(he) {
he.l.r = he.r; he.l.r = he.r;
he.r.l = he.l; he.r.l = he.l;
he.edge = null; he.edge = null;
}, },
right: function(he) { right: function(he) {
return he.r; return he.r;
}, },
left: function(he) { left: function(he) {
return he.l; return he.l;
}, },
leftRegion: function(he) { leftRegion: function(he) {
return he.edge == null ? Sites.bottomSite : he.edge.region[he.side]; return he.edge == null ? Sites.bottomSite : he.edge.region[he.side];
}, },
rightRegion: function(he) { rightRegion: function(he) {
return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]]; return he.edge == null ? Sites.bottomSite : he.edge.region[d3_voronoi_opposite[he.side]];
} }
}; };
var Geom = { var Geom = {
bisect: function(s1, s2) { bisect: function(s1, s2) {
var newEdge = { var newEdge = {
region: { region: {
l: s1, l: s1,
r: s2 r: s2
}, },
ep: { ep: {
l: null, l: null,
r: null r: null
} }
}; };
var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy; var dx = s2.x - s1.x, dy = s2.y - s1.y, adx = dx > 0 ? dx : -dx, ady = dy > 0 ? dy : -dy;
newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5; newEdge.c = s1.x * dx + s1.y * dy + (dx * dx + dy * dy) * .5;
if (adx > ady) { if (adx > ady) {
newEdge.a = 1; newEdge.a = 1;
newEdge.b = dy / dx; newEdge.b = dy / dx;
newEdge.c /= dx; newEdge.c /= dx;
} else { } else {
newEdge.b = 1; newEdge.b = 1;
newEdge.a = dx / dy; newEdge.a = dx / dy;
newEdge.c /= dy; newEdge.c /= dy;
} }
return newEdge; return newEdge;
}, },
intersect: function(el1, el2) { intersect: function(el1, el2) {
var e1 = el1.edge, e2 = el2.edge; var e1 = el1.edge, e2 = el2.edge;
if (!e1 || !e2 || e1.region.r == e2.region.r) { if (!e1 || !e2 || e1.region.r == e2.region.r) {
return null; return null;
} }
var d = e1.a * e2.b - e1.b * e2.a; var d = e1.a * e2.b - e1.b * e2.a;
if (Math.abs(d) < 1e-10) { if (Math.abs(d) < 1e-10) {
return null; return null;
} }
var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e; var xint = (e1.c * e2.b - e2.c * e1.b) / d, yint = (e2.c * e1.a - e1.c * e2.a) / d, e1r = e1.region.r, e2r = e2.region.r, el, e;
if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) { if (e1r.y < e2r.y || e1r.y == e2r.y && e1r.x < e2r.x) {
el = el1; el = el1;
e = e1; e = e1;
} else { } else {
el = el2; el = el2;
e = e2; e = e2;
} }
var rightOfSite = xint >= e.region.r.x; var rightOfSite = xint >= e.region.r.x;
if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") { if (rightOfSite && el.side === "l" || !rightOfSite && el.side === "r") {
return null; return null;
} }
return { return {
x: xint, x: xint,
y: yint y: yint
}; };
}, },
rightOf: function(he, p) { rightOf: function(he, p) {
var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x; var e = he.edge, topsite = e.region.r, rightOfSite = p.x > topsite.x;
if (rightOfSite && he.side === "l") { if (rightOfSite && he.side === "l") {
return 1; return 1;
} }
if (!rightOfSite && he.side === "r") { if (!rightOfSite && he.side === "r") {
return 0; return 0;
} }
if (e.a === 1) { if (e.a === 1) {
var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0; var dyp = p.y - topsite.y, dxp = p.x - topsite.x, fast = 0, above = 0;
if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) { if (!rightOfSite && e.b < 0 || rightOfSite && e.b >= 0) {
above = fast = dyp >= e.b * dxp; above = fast = dyp >= e.b * dxp;
} else { } else {
above = p.x + p.y * e.b > e.c; above = p.x + p.y * e.b > e.c;
if (e.b < 0) { if (e.b < 0) {
above = !above; above = !above;
} }
if (!above) { if (!above) {
fast = 1; fast = 1;
} }
} }
if (!fast) { if (!fast) {
var dxs = topsite.x - e.region.l.x; var dxs = topsite.x - e.region.l.x;
above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b); above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp * (1 + 2 * dxp / dxs + e.b * e.b);
if (e.b < 0) { if (e.b < 0) {
above = !above; above = !above;
} }
} }
} else { } else {
var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y; var yl = e.c - e.a * p.x, t1 = p.y - yl, t2 = p.x - topsite.x, t3 = yl - topsite.y;
above = t1 * t1 > t2 * t2 + t3 * t3; above = t1 * t1 > t2 * t2 + t3 * t3;
} }
return he.side === "l" ? above : !above; return he.side === "l" ? above : !above;
}, },
endPoint: function(edge, side, site) { endPoint: function(edge, side, site) {
edge.ep[side] = site; edge.ep[side] = site;
if (!edge.ep[d3_voronoi_opposite[side]]) return; if (!edge.ep[d3_voronoi_opposite[side]]) return;
callback(edge); callback(edge);
}, },
distance: function(s, t) { distance: function(s, t) {
var dx = s.x - t.x, dy = s.y - t.y; var dx = s.x - t.x, dy = s.y - t.y;
return Math.sqrt(dx * dx + dy * dy); return Math.sqrt(dx * dx + dy * dy);
} }
}; };
var EventQueue = { var EventQueue = {
list: [], list: [],
insert: function(he, site, offset) { insert: function(he, site, offset) {
he.vertex = site; he.vertex = site;
he.ystar = site.y + offset; he.ystar = site.y + offset;
for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) { for (var i = 0, list = EventQueue.list, l = list.length; i < l; i++) {
var next = list[i]; var next = list[i];
if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) { if (he.ystar > next.ystar || he.ystar == next.ystar && site.x > next.vertex.x) {
continue; continue;
} else { } else {
break; break;
} }
} }
list.splice(i, 0, he); list.splice(i, 0, he);
}, },
del: function(he) { del: function(he) {
for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {} for (var i = 0, ls = EventQueue.list, l = ls.length; i < l && ls[i] != he; ++i) {}
ls.splice(i, 1); ls.splice(i, 1);
}, },
empty: function() { empty: function() {
return EventQueue.list.length === 0; return EventQueue.list.length === 0;
}, },
nextEvent: function(he) { nextEvent: function(he) {
for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) { for (var i = 0, ls = EventQueue.list, l = ls.length; i < l; ++i) {
if (ls[i] == he) return ls[i + 1]; if (ls[i] == he) return ls[i + 1];
} }
return null; return null;
}, },
min: function() { min: function() {
var elem = EventQueue.list[0]; var elem = EventQueue.list[0];
return { return {
x: elem.vertex.x, x: elem.vertex.x,
y: elem.ystar y: elem.ystar
}; };
}, },
extractMin: function() { extractMin: function() {
return EventQueue.list.shift(); return EventQueue.list.shift();
} }
}; };
EdgeList.init(); EdgeList.init();
Sites.bottomSite = Sites.list.shift(); Sites.bottomSite = Sites.list.shift();
var newSite = Sites.list.shift(), newIntStar; var newSite = Sites.list.shift(), newIntStar;
var lbnd, rbnd, llbnd, rrbnd, bisector; var lbnd, rbnd, llbnd, rrbnd, bisector;
var bot, top, temp, p, v; var bot, top, temp, p, v;
var e, pm; var e, pm;
while (true) { while (true) {
if (!EventQueue.empty()) { if (!EventQueue.empty()) {
newIntStar = EventQueue.min(); newIntStar = EventQueue.min();
} }
if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) { if (newSite && (EventQueue.empty() || newSite.y < newIntStar.y || newSite.y == newIntStar.y && newSite.x < newIntStar.x)) {
lbnd = EdgeList.leftBound(newSite); lbnd = EdgeList.leftBound(newSite);
rbnd = EdgeList.right(lbnd); rbnd = EdgeList.right(lbnd);
bot = EdgeList.rightRegion(lbnd); bot = EdgeList.rightRegion(lbnd);
e = Geom.bisect(bot, newSite); e = Geom.bisect(bot, newSite);
bisector = EdgeList.createHalfEdge(e, "l"); bisector = EdgeList.createHalfEdge(e, "l");
EdgeList.insert(lbnd, bisector); EdgeList.insert(lbnd, bisector);
p = Geom.intersect(lbnd, bisector); p = Geom.intersect(lbnd, bisector);
if (p) { if (p) {
EventQueue.del(lbnd); EventQueue.del(lbnd);
EventQueue.insert(lbnd, p, Geom.distance(p, newSite)); EventQueue.insert(lbnd, p, Geom.distance(p, newSite));
} }
lbnd = bisector; lbnd = bisector;
bisector = EdgeList.createHalfEdge(e, "r"); bisector = EdgeList.createHalfEdge(e, "r");
EdgeList.insert(lbnd, bisector); EdgeList.insert(lbnd, bisector);
p = Geom.intersect(bisector, rbnd); p = Geom.intersect(bisector, rbnd);
if (p) { if (p) {
EventQueue.insert(bisector, p, Geom.distance(p, newSite)); EventQueue.insert(bisector, p, Geom.distance(p, newSite));
} }
newSite = Sites.list.shift(); newSite = Sites.list.shift();
} else if (!EventQueue.empty()) { } else if (!EventQueue.empty()) {
lbnd = EventQueue.extractMin(); lbnd = EventQueue.extractMin();
llbnd = EdgeList.left(lbnd); llbnd = EdgeList.left(lbnd);
rbnd = EdgeList.right(lbnd); rbnd = EdgeList.right(lbnd);
rrbnd = EdgeList.right(rbnd); rrbnd = EdgeList.right(rbnd);
bot = EdgeList.leftRegion(lbnd); bot = EdgeList.leftRegion(lbnd);
top = EdgeList.rightRegion(rbnd); top = EdgeList.rightRegion(rbnd);
v = lbnd.vertex; v = lbnd.vertex;
Geom.endPoint(lbnd.edge, lbnd.side, v); Geom.endPoint(lbnd.edge, lbnd.side, v);
Geom.endPoint(rbnd.edge, rbnd.side, v); Geom.endPoint(rbnd.edge, rbnd.side, v);
EdgeList.del(lbnd); EdgeList.del(lbnd);
EventQueue.del(rbnd); EventQueue.del(rbnd);
EdgeList.del(rbnd); EdgeList.del(rbnd);
pm = "l"; pm = "l";
if (bot.y > top.y) { if (bot.y > top.y) {
temp = bot; temp = bot;
bot = top; bot = top;
top = temp; top = temp;
pm = "r"; pm = "r";
} }
e = Geom.bisect(bot, top); e = Geom.bisect(bot, top);
bisector = EdgeList.createHalfEdge(e, pm); bisector = EdgeList.createHalfEdge(e, pm);
EdgeList.insert(llbnd, bisector); EdgeList.insert(llbnd, bisector);
Geom.endPoint(e, d3_voronoi_opposite[pm], v); Geom.endPoint(e, d3_voronoi_opposite[pm], v);
p = Geom.intersect(llbnd, bisector); p = Geom.intersect(llbnd, bisector);
if (p) { if (p) {
EventQueue.del(llbnd); EventQueue.del(llbnd);
EventQueue.insert(llbnd, p, Geom.distance(p, bot)); EventQueue.insert(llbnd, p, Geom.distance(p, bot));
} }
p = Geom.intersect(bisector, rrbnd); p = Geom.intersect(bisector, rrbnd);
if (p) { if (p) {
EventQueue.insert(bisector, p, Geom.distance(p, bot)); EventQueue.insert(bisector, p, Geom.distance(p, bot));
} }
} else { } else {
break; break;
} }
} }
for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) { for (lbnd = EdgeList.right(EdgeList.leftEnd); lbnd != EdgeList.rightEnd; lbnd = EdgeList.right(lbnd)) {
callback(lbnd.edge); callback(lbnd.edge);
} }
} }
function d3_geom_quadtreeNode() { function d3_geom_quadtreeNode() {
return { return {
leaf: true, leaf: true,
nodes: [], nodes: [],
point: null point: null
}; };
} }
function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) { function d3_geom_quadtreeVisit(f, node, x1, y1, x2, y2) {
if (!f(node, x1, y1, x2, y2)) { if (!f(node, x1, y1, x2, y2)) {
var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes; var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, children = node.nodes;
if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy); if (children[0]) d3_geom_quadtreeVisit(f, children[0], x1, y1, sx, sy);
if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy); if (children[1]) d3_geom_quadtreeVisit(f, children[1], sx, y1, x2, sy);
if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2); if (children[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2); if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
} }
} }
function d3_geom_quadtreePoint(p) { function d3_geom_quadtreePoint(p) {
return { return {
x: p[0], x: p[0],
y: p[1] y: p[1]
}; };
} }
function d3_time_utc() { function d3_time_utc() {
this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]); this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
} }
function d3_time_formatAbbreviate(name) { function d3_time_formatAbbreviate(name) {
return name.substring(0, 3); return name.substring(0, 3);
} }
function d3_time_parse(date, template, string, j) { function d3_time_parse(date, template, string, j) {
var c, p, i = 0, n = template.length, m = string.length; var c, p, i = 0, n = template.length, m = string.length;
while (i < n) { while (i < n) {
if (j >= m) return -1; if (j >= m) return -1;
c = template.charCodeAt(i++); c = template.charCodeAt(i++);
if (c == 37) { if (c == 37) {
p = d3_time_parsers[template.charAt(i++)]; p = d3_time_parsers[template.charAt(i++)];
if (!p || (j = p(date, string, j)) < 0) return -1; if (!p || (j = p(date, string, j)) < 0) return -1;
} else if (c != string.charCodeAt(j++)) { } else if (c != string.charCodeAt(j++)) {
return -1; return -1;
} }
} }
return j; return j;
} }
function d3_time_formatRe(names) { function d3_time_formatRe(names) {
return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i"); return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
} }
function d3_time_formatLookup(names) { function d3_time_formatLookup(names) {
var map = new d3_Map, i = -1, n = names.length; var map = new d3_Map, i = -1, n = names.length;
while (++i < n) map.set(names[i].toLowerCase(), i); while (++i < n) map.set(names[i].toLowerCase(), i);
return map; return map;
} }
function d3_time_parseWeekdayAbbrev(date, string, i) { function d3_time_parseWeekdayAbbrev(date, string, i) {
d3_time_dayAbbrevRe.lastIndex = 0; d3_time_dayAbbrevRe.lastIndex = 0;
var n = d3_time_dayAbbrevRe.exec(string.substring(i)); var n = d3_time_dayAbbrevRe.exec(string.substring(i));
return n ? i += n[0].length : -1; return n ? i += n[0].length : -1;
} }
function d3_time_parseWeekday(date, string, i) { function d3_time_parseWeekday(date, string, i) {
d3_time_dayRe.lastIndex = 0; d3_time_dayRe.lastIndex = 0;
var n = d3_time_dayRe.exec(string.substring(i)); var n = d3_time_dayRe.exec(string.substring(i));
return n ? i += n[0].length : -1; return n ? i += n[0].length : -1;
} }
function d3_time_parseMonthAbbrev(date, string, i) { function d3_time_parseMonthAbbrev(date, string, i) {
d3_time_monthAbbrevRe.lastIndex = 0; d3_time_monthAbbrevRe.lastIndex = 0;
var n = d3_time_monthAbbrevRe.exec(string.substring(i)); var n = d3_time_monthAbbrevRe.exec(string.substring(i));
return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
} }
function d3_time_parseMonth(date, string, i) { function d3_time_parseMonth(date, string, i) {
d3_time_monthRe.lastIndex = 0; d3_time_monthRe.lastIndex = 0;
var n = d3_time_monthRe.exec(string.substring(i)); var n = d3_time_monthRe.exec(string.substring(i));
return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1; return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i += n[0].length) : -1;
} }
function d3_time_parseLocaleFull(date, string, i) { function d3_time_parseLocaleFull(date, string, i) {
return d3_time_parse(date, d3_time_formats.c.toString(), string, i); return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
} }
function d3_time_parseLocaleDate(date, string, i) { function d3_time_parseLocaleDate(date, string, i) {
return d3_time_parse(date, d3_time_formats.x.toString(), string, i); return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
} }
function d3_time_parseLocaleTime(date, string, i) { function d3_time_parseLocaleTime(date, string, i) {
return d3_time_parse(date, d3_time_formats.X.toString(), string, i); return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
} }
function d3_time_parseFullYear(date, string, i) { function d3_time_parseFullYear(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 4)); var n = d3_time_numberRe.exec(string.substring(i, i + 4));
return n ? (date.y = +n[0], i += n[0].length) : -1; return n ? (date.y = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseYear(date, string, i) { function d3_time_parseYear(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1; return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1;
} }
function d3_time_expandYear(d) { function d3_time_expandYear(d) {
return d + (d > 68 ? 1900 : 2e3); return d + (d > 68 ? 1900 : 2e3);
} }
function d3_time_parseMonthNumber(date, string, i) { function d3_time_parseMonthNumber(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.m = n[0] - 1, i += n[0].length) : -1; return n ? (date.m = n[0] - 1, i += n[0].length) : -1;
} }
function d3_time_parseDay(date, string, i) { function d3_time_parseDay(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.d = +n[0], i += n[0].length) : -1; return n ? (date.d = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseHour24(date, string, i) { function d3_time_parseHour24(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.H = +n[0], i += n[0].length) : -1; return n ? (date.H = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseMinutes(date, string, i) { function d3_time_parseMinutes(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.M = +n[0], i += n[0].length) : -1; return n ? (date.M = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseSeconds(date, string, i) { function d3_time_parseSeconds(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2)); var n = d3_time_numberRe.exec(string.substring(i, i + 2));
return n ? (date.S = +n[0], i += n[0].length) : -1; return n ? (date.S = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseMilliseconds(date, string, i) { function d3_time_parseMilliseconds(date, string, i) {
d3_time_numberRe.lastIndex = 0; d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 3)); var n = d3_time_numberRe.exec(string.substring(i, i + 3));
return n ? (date.L = +n[0], i += n[0].length) : -1; return n ? (date.L = +n[0], i += n[0].length) : -1;
} }
function d3_time_parseAmPm(date, string, i) { function d3_time_parseAmPm(date, string, i) {
var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase()); var n = d3_time_amPmLookup.get(string.substring(i, i += 2).toLowerCase());
return n == null ? -1 : (date.p = n, i); return n == null ? -1 : (date.p = n, i);
} }
function d3_time_zone(d) { function d3_time_zone(d) {
var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60; var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = ~~(Math.abs(z) / 60), zm = Math.abs(z) % 60;
return zs + d3_time_zfill2(zh) + d3_time_zfill2(zm); return zs + d3_time_zfill2(zh) + d3_time_zfill2(zm);
} }
function d3_time_formatIsoNative(date) { function d3_time_formatIsoNative(date) {
return date.toISOString(); return date.toISOString();
} }
function d3_time_interval(local, step, number) { function d3_time_interval(local, step, number) {
function round(date) { function round(date) {
var d0 = local(date), d1 = offset(d0, 1); var d0 = local(date), d1 = offset(d0, 1);
return date - d0 < d1 - date ? d0 : d1; return date - d0 < d1 - date ? d0 : d1;
} }
function ceil(date) { function ceil(date) {
step(date = local(new d3_time(date - 1)), 1); step(date = local(new d3_time(date - 1)), 1);
return date; return date;
} }
function offset(date, k) { function offset(date, k) {
step(date = new d3_time(+date), k); step(date = new d3_time(+date), k);
return date; return date;
} }
function range(t0, t1, dt) { function range(t0, t1, dt) {
var time = ceil(t0), times = []; var time = ceil(t0), times = [];
if (dt > 1) { if (dt > 1) {
while (time < t1) { while (time < t1) {
if (!(number(time) % dt)) times.push(new Date(+time)); if (!(number(time) % dt)) times.push(new Date(+time));
step(time, 1); step(time, 1);
} }
} else { } else {
while (time < t1) times.push(new Date(+time)), step(time, 1); while (time < t1) times.push(new Date(+time)), step(time, 1);
} }
return times; return times;
} }
function range_utc(t0, t1, dt) { function range_utc(t0, t1, dt) {
try { try {
d3_time = d3_time_utc; d3_time = d3_time_utc;
var utc = new d3_time_utc; var utc = new d3_time_utc;
utc._ = t0; utc._ = t0;
return range(utc, t1, dt); return range(utc, t1, dt);
} finally { } finally {
d3_time = Date; d3_time = Date;
} }
} }
local.floor = local; local.floor = local;
local.round = round; local.round = round;
local.ceil = ceil; local.ceil = ceil;
local.offset = offset; local.offset = offset;
local.range = range; local.range = range;
var utc = local.utc = d3_time_interval_utc(local); var utc = local.utc = d3_time_interval_utc(local);
utc.floor = utc; utc.floor = utc;
utc.round = d3_time_interval_utc(round); utc.round = d3_time_interval_utc(round);
utc.ceil = d3_time_interval_utc(ceil); utc.ceil = d3_time_interval_utc(ceil);
utc.offset = d3_time_interval_utc(offset); utc.offset = d3_time_interval_utc(offset);
utc.range = range_utc; utc.range = range_utc;
return local; return local;
} }
function d3_time_interval_utc(method) { function d3_time_interval_utc(method) {
return function(date, k) { return function(date, k) {
try { try {
d3_time = d3_time_utc; d3_time = d3_time_utc;
var utc = new d3_time_utc; var utc = new d3_time_utc;
utc._ = date; utc._ = date;
return method(utc, k)._; return method(utc, k)._;
} finally { } finally {
d3_time = Date; d3_time = Date;
} }
}; };
} }
function d3_time_scale(linear, methods, format) { function d3_time_scale(linear, methods, format) {
function scale(x) { function scale(x) {
return linear(x); return linear(x);
} }
scale.invert = function(x) { scale.invert = function(x) {
return d3_time_scaleDate(linear.invert(x)); return d3_time_scaleDate(linear.invert(x));
}; };
scale.domain = function(x) { scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(d3_time_scaleDate); if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
linear.domain(x); linear.domain(x);
return scale; return scale;
}; };
scale.nice = function(m) { scale.nice = function(m) {
return scale.domain(d3_scale_nice(scale.domain(), function() { return scale.domain(d3_scale_nice(scale.domain(), function() {
return m; return m;
})); }));
}; };
scale.ticks = function(m, k) { scale.ticks = function(m, k) {
var extent = d3_time_scaleExtent(scale.domain()); var extent = d3_time_scaleExtent(scale.domain());
if (typeof m !== "function") { if (typeof m !== "function") {
var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target); var span = extent[1] - extent[0], target = span / m, i = d3.bisect(d3_time_scaleSteps, target);
if (i == d3_time_scaleSteps.length) return methods.year(extent, m); if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
if (!i) return linear.ticks(m).map(d3_time_scaleDate); if (!i) return linear.ticks(m).map(d3_time_scaleDate);
if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i; if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
m = methods[i]; m = methods[i];
k = m[1]; k = m[1];
m = m[0].range; m = m[0].range;
} }
return m(extent[0], new Date(+extent[1] + 1), k); return m(extent[0], new Date(+extent[1] + 1), k);
}; };
scale.tickFormat = function() { scale.tickFormat = function() {
return format; return format;
}; };
scale.copy = function() { scale.copy = function() {
return d3_time_scale(linear.copy(), methods, format); return d3_time_scale(linear.copy(), methods, format);
}; };
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp"); return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
} }
function d3_time_scaleExtent(domain) { function d3_time_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1]; var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [ start, stop ] : [ stop, start ]; return start < stop ? [ start, stop ] : [ stop, start ];
} }
function d3_time_scaleDate(t) { function d3_time_scaleDate(t) {
return new Date(t); return new Date(t);
} }
function d3_time_scaleFormat(formats) { function d3_time_scaleFormat(formats) {
return function(date) { return function(date) {
var i = formats.length - 1, f = formats[i]; var i = formats.length - 1, f = formats[i];
while (!f[1](date)) f = formats[--i]; while (!f[1](date)) f = formats[--i];
return f[0](date); return f[0](date);
}; };
} }
function d3_time_scaleSetYear(y) { function d3_time_scaleSetYear(y) {
var d = new Date(y, 0, 1); var d = new Date(y, 0, 1);
d.setFullYear(y); d.setFullYear(y);
return d; return d;
} }
function d3_time_scaleGetYear(d) { function d3_time_scaleGetYear(d) {
var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1); var y = d.getFullYear(), d0 = d3_time_scaleSetYear(y), d1 = d3_time_scaleSetYear(y + 1);
return y + (d - d0) / (d1 - d0); return y + (d - d0) / (d1 - d0);
} }
function d3_time_scaleUTCSetYear(y) { function d3_time_scaleUTCSetYear(y) {
var d = new Date(Date.UTC(y, 0, 1)); var d = new Date(Date.UTC(y, 0, 1));
d.setUTCFullYear(y); d.setUTCFullYear(y);
return d; return d;
} }
function d3_time_scaleUTCGetYear(d) { function d3_time_scaleUTCGetYear(d) {
var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1); var y = d.getUTCFullYear(), d0 = d3_time_scaleUTCSetYear(y), d1 = d3_time_scaleUTCSetYear(y + 1);
return y + (d - d0) / (d1 - d0); return y + (d - d0) / (d1 - d0);
} }
if (!Date.now) Date.now = function() { if (!Date.now) Date.now = function() {
return +(new Date); return +(new Date);
}; };
try { try {
document.createElement("div").style.setProperty("opacity", 0, ""); document.createElement("div").style.setProperty("opacity", 0, "");
} catch (error) { } catch (error) {
var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty; var d3_style_prototype = CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
d3_style_prototype.setProperty = function(name, value, priority) { d3_style_prototype.setProperty = function(name, value, priority) {
d3_style_setProperty.call(this, name, value + "", priority); d3_style_setProperty.call(this, name, value + "", priority);
}; };
} }
d3 = { d3 = {
version: "2.10.3" version: "2.10.3"
}; };
var d3_array = d3_arraySlice; var d3_array = d3_arraySlice;
try { try {
d3_array(document.documentElement.childNodes)[0].nodeType; d3_array(document.documentElement.childNodes)[0].nodeType;
} catch (e) { } catch (e) {
d3_array = d3_arrayCopy; d3_array = d3_arrayCopy;
} }
var d3_arraySubclass = [].__proto__ ? function(array, prototype) { var d3_arraySubclass = [].__proto__ ? function(array, prototype) {
array.__proto__ = prototype; array.__proto__ = prototype;
} : function(array, prototype) { } : function(array, prototype) {
for (var property in prototype) array[property] = prototype[property]; for (var property in prototype) array[property] = prototype[property];
}; };
d3.map = function(object) { d3.map = function(object) {
var map = new d3_Map; var map = new d3_Map;
for (var key in object) map.set(key, object[key]); for (var key in object) map.set(key, object[key]);
return map; return map;
}; };
d3_class(d3_Map, { d3_class(d3_Map, {
has: function(key) { has: function(key) {
return d3_map_prefix + key in this; return d3_map_prefix + key in this;
}, },
get: function(key) { get: function(key) {
return this[d3_map_prefix + key]; return this[d3_map_prefix + key];
}, },
set: function(key, value) { set: function(key, value) {
return this[d3_map_prefix + key] = value; return this[d3_map_prefix + key] = value;
}, },
remove: function(key) { remove: function(key) {
key = d3_map_prefix + key; key = d3_map_prefix + key;
return key in this && delete this[key]; return key in this && delete this[key];
}, },
keys: function() { keys: function() {
var keys = []; var keys = [];
this.forEach(function(key) { this.forEach(function(key) {
keys.push(key); keys.push(key);
}); });
return keys; return keys;
}, },
values: function() { values: function() {
var values = []; var values = [];
this.forEach(function(key, value) { this.forEach(function(key, value) {
values.push(value); values.push(value);
}); });
return values; return values;
}, },
entries: function() { entries: function() {
var entries = []; var entries = [];
this.forEach(function(key, value) { this.forEach(function(key, value) {
entries.push({ entries.push({
key: key, key: key,
value: value value: value
}); });
}); });
return entries; return entries;
}, },
forEach: function(f) { forEach: function(f) {
for (var key in this) { for (var key in this) {
if (key.charCodeAt(0) === d3_map_prefixCode) { if (key.charCodeAt(0) === d3_map_prefixCode) {
f.call(this, key.substring(1), this[key]); f.call(this, key.substring(1), this[key]);
} }
} }
} }
}); });
var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0); var d3_map_prefix = "\0", d3_map_prefixCode = d3_map_prefix.charCodeAt(0);
d3.functor = d3_functor; d3.functor = d3_functor;
d3.rebind = function(target, source) { d3.rebind = function(target, source) {
var i = 1, n = arguments.length, method; var i = 1, n = arguments.length, method;
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
return target; return target;
}; };
d3.ascending = function(a, b) { d3.ascending = function(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}; };
d3.descending = function(a, b) { d3.descending = function(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}; };
d3.mean = function(array, f) { d3.mean = function(array, f) {
var n = array.length, a, m = 0, i = -1, j = 0; var n = array.length, a, m = 0, i = -1, j = 0;
if (arguments.length === 1) { if (arguments.length === 1) {
while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j; while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
} else { } else {
while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j; while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
} }
return j ? m : undefined; return j ? m : undefined;
}; };
d3.median = function(array, f) { d3.median = function(array, f) {
if (arguments.length > 1) array = array.map(f); if (arguments.length > 1) array = array.map(f);
array = array.filter(d3_number); array = array.filter(d3_number);
return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
}; };
d3.min = function(array, f) { d3.min = function(array, f) {
var i = -1, n = array.length, a, b; var i = -1, n = array.length, a, b;
if (arguments.length === 1) { if (arguments.length === 1) {
while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
while (++i < n) if ((b = array[i]) != null && a > b) a = b; while (++i < n) if ((b = array[i]) != null && a > b) a = b;
} else { } else {
while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
} }
return a; return a;
}; };
d3.max = function(array, f) { d3.max = function(array, f) {
var i = -1, n = array.length, a, b; var i = -1, n = array.length, a, b;
if (arguments.length === 1) { if (arguments.length === 1) {
while (++i < n && ((a = array[i]) == null || a != a)) a = undefined; while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
while (++i < n) if ((b = array[i]) != null && b > a) a = b; while (++i < n) if ((b = array[i]) != null && b > a) a = b;
} else { } else {
while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined; while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
} }
return a; return a;
}; };
d3.extent = function(array, f) { d3.extent = function(array, f) {
var i = -1, n = array.length, a, b, c; var i = -1, n = array.length, a, b, c;
if (arguments.length === 1) { if (arguments.length === 1) {
while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined; while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
while (++i < n) if ((b = array[i]) != null) { while (++i < n) if ((b = array[i]) != null) {
if (a > b) a = b; if (a > b) a = b;
if (c < b) c = b; if (c < b) c = b;
} }
} else { } else {
while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined; while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
while (++i < n) if ((b = f.call(array, array[i], i)) != null) { while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
if (a > b) a = b; if (a > b) a = b;
if (c < b) c = b; if (c < b) c = b;
} }
} }
return [ a, c ]; return [ a, c ];
}; };
d3.random = { d3.random = {
normal: function(µ, σ) { normal: function(µ, σ) {
var n = arguments.length; var n = arguments.length;
if (n < 2) σ = 1; if (n < 2) σ = 1;
if (n < 1) µ = 0; if (n < 1) µ = 0;
return function() { return function() {
var x, y, r; var x, y, r;
do { do {
x = Math.random() * 2 - 1; x = Math.random() * 2 - 1;
y = Math.random() * 2 - 1; y = Math.random() * 2 - 1;
r = x * x + y * y; r = x * x + y * y;
} while (!r || r > 1); } while (!r || r > 1);
return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r); return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
}; };
}, },
logNormal: function(µ, σ) { logNormal: function(µ, σ) {
var n = arguments.length; var n = arguments.length;
if (n < 2) σ = 1; if (n < 2) σ = 1;
if (n < 1) µ = 0; if (n < 1) µ = 0;
var random = d3.random.normal(); var random = d3.random.normal();
return function() { return function() {
return Math.exp(µ + σ * random()); return Math.exp(µ + σ * random());
}; };
}, },
irwinHall: function(m) { irwinHall: function(m) {
return function() { return function() {
for (var s = 0, j = 0; j < m; j++) s += Math.random(); for (var s = 0, j = 0; j < m; j++) s += Math.random();
return s / m; return s / m;
}; };
} }
}; };
d3.sum = function(array, f) { d3.sum = function(array, f) {
var s = 0, n = array.length, a, i = -1; var s = 0, n = array.length, a, i = -1;
if (arguments.length === 1) { if (arguments.length === 1) {
while (++i < n) if (!isNaN(a = +array[i])) s += a; while (++i < n) if (!isNaN(a = +array[i])) s += a;
} else { } else {
while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a; while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
} }
return s; return s;
}; };
d3.quantile = function(values, p) { d3.quantile = function(values, p) {
var H = (values.length - 1) * p + 1, h = Math.floor(H), v = values[h - 1], e = H - h; var H = (values.length - 1) * p + 1, h = Math.floor(H), v = values[h - 1], e = H - h;
return e ? v + e * (values[h] - v) : v; return e ? v + e * (values[h] - v) : v;
}; };
d3.transpose = function(matrix) { d3.transpose = function(matrix) {
return d3.zip.apply(d3, matrix); return d3.zip.apply(d3, matrix);
}; };
d3.zip = function() { d3.zip = function() {
if (!(n = arguments.length)) return []; if (!(n = arguments.length)) return [];
for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) { for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m; ) {
for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) { for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n; ) {
zip[j] = arguments[j][i]; zip[j] = arguments[j][i];
} }
} }
return zips; return zips;
}; };
d3.bisector = function(f) { d3.bisector = function(f) {
return { return {
left: function(a, x, lo, hi) { left: function(a, x, lo, hi) {
if (arguments.length < 3) lo = 0; if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length; if (arguments.length < 4) hi = a.length;
while (lo < hi) { while (lo < hi) {
var mid = lo + hi >>> 1; var mid = lo + hi >>> 1;
if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid; if (f.call(a, a[mid], mid) < x) lo = mid + 1; else hi = mid;
} }
return lo; return lo;
}, },
right: function(a, x, lo, hi) { right: function(a, x, lo, hi) {
if (arguments.length < 3) lo = 0; if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length; if (arguments.length < 4) hi = a.length;
while (lo < hi) { while (lo < hi) {
var mid = lo + hi >>> 1; var mid = lo + hi >>> 1;
if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1; if (x < f.call(a, a[mid], mid)) hi = mid; else lo = mid + 1;
} }
return lo; return lo;
} }
}; };
}; };
var d3_bisector = d3.bisector(function(d) { var d3_bisector = d3.bisector(function(d) {
return d; return d;
}); });
d3.bisectLeft = d3_bisector.left; d3.bisectLeft = d3_bisector.left;
d3.bisect = d3.bisectRight = d3_bisector.right; d3.bisect = d3.bisectRight = d3_bisector.right;
d3.first = function(array, f) { d3.first = function(array, f) {
var i = 0, n = array.length, a = array[0], b; var i = 0, n = array.length, a = array[0], b;
if (arguments.length === 1) f = d3.ascending; if (arguments.length === 1) f = d3.ascending;
while (++i < n) { while (++i < n) {
if (f.call(array, a, b = array[i]) > 0) { if (f.call(array, a, b = array[i]) > 0) {
a = b; a = b;
} }
} }
return a; return a;
}; };
d3.last = function(array, f) { d3.last = function(array, f) {
var i = 0, n = array.length, a = array[0], b; var i = 0, n = array.length, a = array[0], b;
if (arguments.length === 1) f = d3.ascending; if (arguments.length === 1) f = d3.ascending;
while (++i < n) { while (++i < n) {
if (f.call(array, a, b = array[i]) <= 0) { if (f.call(array, a, b = array[i]) <= 0) {
a = b; a = b;
} }
} }
return a; return a;
}; };
d3.nest = function() { d3.nest = function() {
function map(array, depth) { function map(array, depth) {
if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array; if (depth >= keys.length) return rollup ? rollup.call(nest, array) : sortValues ? array.sort(sortValues) : array;
var i = -1, n = array.length, key = keys[depth++], keyValue, object, valuesByKey = new d3_Map, values, o = {}; var i = -1, n = array.length, key = keys[depth++], keyValue, object, valuesByKey = new d3_Map, values, o = {};
while (++i < n) { while (++i < n) {
if (values = valuesByKey.get(keyValue = key(object = array[i]))) { if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
values.push(object); values.push(object);
} else { } else {
valuesByKey.set(keyValue, [ object ]); valuesByKey.set(keyValue, [ object ]);
} }
} }
valuesByKey.forEach(function(keyValue, values) { valuesByKey.forEach(function(keyValue, values) {
o[keyValue] = map(values, depth); o[keyValue] = map(values, depth);
}); });
return o; return o;
} }
function entries(map, depth) { function entries(map, depth) {
if (depth >= keys.length) return map; if (depth >= keys.length) return map;
var a = [], sortKey = sortKeys[depth++], key; var a = [], sortKey = sortKeys[depth++], key;
for (key in map) { for (key in map) {
a.push({ a.push({
key: key, key: key,
values: entries(map[key], depth) values: entries(map[key], depth)
}); });
} }
if (sortKey) a.sort(function(a, b) { if (sortKey) a.sort(function(a, b) {
return sortKey(a.key, b.key); return sortKey(a.key, b.key);
}); });
return a; return a;
} }
var nest = {}, keys = [], sortKeys = [], sortValues, rollup; var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
nest.map = function(array) { nest.map = function(array) {
return map(array, 0); return map(array, 0);
}; };
nest.entries = function(array) { nest.entries = function(array) {
return entries(map(array, 0), 0); return entries(map(array, 0), 0);
}; };
nest.key = function(d) { nest.key = function(d) {
keys.push(d); keys.push(d);
return nest; return nest;
}; };
nest.sortKeys = function(order) { nest.sortKeys = function(order) {
sortKeys[keys.length - 1] = order; sortKeys[keys.length - 1] = order;
return nest; return nest;
}; };
nest.sortValues = function(order) { nest.sortValues = function(order) {
sortValues = order; sortValues = order;
return nest; return nest;
}; };
nest.rollup = function(f) { nest.rollup = function(f) {
rollup = f; rollup = f;
return nest; return nest;
}; };
return nest; return nest;
}; };
d3.keys = function(map) { d3.keys = function(map) {
var keys = []; var keys = [];
for (var key in map) keys.push(key); for (var key in map) keys.push(key);
return keys; return keys;
}; };
d3.values = function(map) { d3.values = function(map) {
var values = []; var values = [];
for (var key in map) values.push(map[key]); for (var key in map) values.push(map[key]);
return values; return values;
}; };
d3.entries = function(map) { d3.entries = function(map) {
var entries = []; var entries = [];
for (var key in map) entries.push({ for (var key in map) entries.push({
key: key, key: key,
value: map[key] value: map[key]
}); });
return entries; return entries;
}; };
d3.permute = function(array, indexes) { d3.permute = function(array, indexes) {
var permutes = [], i = -1, n = indexes.length; var permutes = [], i = -1, n = indexes.length;
while (++i < n) permutes[i] = array[indexes[i]]; while (++i < n) permutes[i] = array[indexes[i]];
return permutes; return permutes;
}; };
d3.merge = function(arrays) { d3.merge = function(arrays) {
return Array.prototype.concat.apply([], arrays); return Array.prototype.concat.apply([], arrays);
}; };
d3.split = function(array, f) { d3.split = function(array, f) {
var arrays = [], values = [], value, i = -1, n = array.length; var arrays = [], values = [], value, i = -1, n = array.length;
if (arguments.length < 2) f = d3_splitter; if (arguments.length < 2) f = d3_splitter;
while (++i < n) { while (++i < n) {
if (f.call(values, value = array[i], i)) { if (f.call(values, value = array[i], i)) {
values = []; values = [];
} else { } else {
if (!values.length) arrays.push(values); if (!values.length) arrays.push(values);
values.push(value); values.push(value);
} }
} }
return arrays; return arrays;
}; };
d3.range = function(start, stop, step) { d3.range = function(start, stop, step) {
if (arguments.length < 3) { if (arguments.length < 3) {
step = 1; step = 1;
if (arguments.length < 2) { if (arguments.length < 2) {
stop = start; stop = start;
start = 0; start = 0;
} }
} }
if ((stop - start) / step === Infinity) throw new Error("infinite range"); if ((stop - start) / step === Infinity) throw new Error("infinite range");
var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j; var range = [], k = d3_range_integerScale(Math.abs(step)), i = -1, j;
start *= k, stop *= k, step *= k; start *= k, stop *= k, step *= k;
if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k); if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); else while ((j = start + step * ++i) < stop) range.push(j / k);
return range; return range;
}; };
d3.requote = function(s) { d3.requote = function(s) {
return s.replace(d3_requote_re, "\\$&"); return s.replace(d3_requote_re, "\\$&");
}; };
var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
d3.round = function(x, n) { d3.round = function(x, n) {
return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x); return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
}; };
d3.xhr = function(url, mime, callback) { d3.xhr = function(url, mime, callback) {
var req = new XMLHttpRequest; var req = new XMLHttpRequest;
if (arguments.length < 3) callback = mime, mime = null; else if (mime && req.overrideMimeType) req.overrideMimeType(mime); if (arguments.length < 3) callback = mime, mime = null; else if (mime && req.overrideMimeType) req.overrideMimeType(mime);
req.open("GET", url, true); req.open("GET", url, true);
if (mime) req.setRequestHeader("Accept", mime); if (mime) req.setRequestHeader("Accept", mime);
req.onreadystatechange = function() { req.onreadystatechange = function() {
if (req.readyState === 4) { if (req.readyState === 4) {
var s = req.status; var s = req.status;
callback(!s && req.response || s >= 200 && s < 300 || s === 304 ? req : null); callback(!s && req.response || s >= 200 && s < 300 || s === 304 ? req : null);
} }
}; };
req.send(null); req.send(null);
}; };
d3.text = function(url, mime, callback) { d3.text = function(url, mime, callback) {
function ready(req) { function ready(req) {
callback(req && req.responseText); callback(req && req.responseText);
} }
if (arguments.length < 3) { if (arguments.length < 3) {
callback = mime; callback = mime;
mime = null; mime = null;
} }
d3.xhr(url, mime, ready); d3.xhr(url, mime, ready);
}; };
d3.json = function(url, callback) { d3.json = function(url, callback) {
d3.text(url, "application/json", function(text) { d3.text(url, "application/json", function(text) {
callback(text ? JSON.parse(text) : null); callback(text ? JSON.parse(text) : null);
}); });
}; };
d3.html = function(url, callback) { d3.html = function(url, callback) {
d3.text(url, "text/html", function(text) { d3.text(url, "text/html", function(text) {
if (text != null) { if (text != null) {
var range = document.createRange(); var range = document.createRange();
range.selectNode(document.body); range.selectNode(document.body);
text = range.createContextualFragment(text); text = range.createContextualFragment(text);
} }
callback(text); callback(text);
}); });
}; };
d3.xml = function(url, mime, callback) { d3.xml = function(url, mime, callback) {
function ready(req) { function ready(req) {
callback(req && req.responseXML); callback(req && req.responseXML);
} }
if (arguments.length < 3) { if (arguments.length < 3) {
callback = mime; callback = mime;
mime = null; mime = null;
} }
d3.xhr(url, mime, ready); d3.xhr(url, mime, ready);
}; };
var d3_nsPrefix = { var d3_nsPrefix = {
svg: "http://www.w3.org/2000/svg", svg: "http://www.w3.org/2000/svg",
xhtml: "http://www.w3.org/1999/xhtml", xhtml: "http://www.w3.org/1999/xhtml",
xlink: "http://www.w3.org/1999/xlink", xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace", xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/" xmlns: "http://www.w3.org/2000/xmlns/"
}; };
d3.ns = { d3.ns = {
prefix: d3_nsPrefix, prefix: d3_nsPrefix,
qualify: function(name) { qualify: function(name) {
var i = name.indexOf(":"), prefix = name; var i = name.indexOf(":"), prefix = name;
if (i >= 0) { if (i >= 0) {
prefix = name.substring(0, i); prefix = name.substring(0, i);
name = name.substring(i + 1); name = name.substring(i + 1);
} }
return d3_nsPrefix.hasOwnProperty(prefix) ? { return d3_nsPrefix.hasOwnProperty(prefix) ? {
space: d3_nsPrefix[prefix], space: d3_nsPrefix[prefix],
local: name local: name
} : name; } : name;
} }
}; };
d3.dispatch = function() { d3.dispatch = function() {
var dispatch = new d3_dispatch, i = -1, n = arguments.length; var dispatch = new d3_dispatch, i = -1, n = arguments.length;
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
return dispatch; return dispatch;
}; };
d3_dispatch.prototype.on = function(type, listener) { d3_dispatch.prototype.on = function(type, listener) {
var i = type.indexOf("."), name = ""; var i = type.indexOf("."), name = "";
if (i > 0) { if (i > 0) {
name = type.substring(i + 1); name = type.substring(i + 1);
type = type.substring(0, i); type = type.substring(0, i);
} }
return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener); return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
}; };
d3.format = function(specifier) { d3.format = function(specifier) {
var match = d3_format_re.exec(specifier), fill = match[1] || " ", sign = match[3] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false; var match = d3_format_re.exec(specifier), fill = match[1] || " ", sign = match[3] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, suffix = "", integer = false;
if (precision) precision = +precision.substring(1); if (precision) precision = +precision.substring(1);
if (zfill) { if (zfill) {
fill = "0"; fill = "0";
if (comma) width -= Math.floor((width - 1) / 4); if (comma) width -= Math.floor((width - 1) / 4);
} }
switch (type) { switch (type) {
case "n": case "n":
comma = true; comma = true;
type = "g"; type = "g";
break; break;
case "%": case "%":
scale = 100; scale = 100;
suffix = "%"; suffix = "%";
type = "f"; type = "f";
break; break;
case "p": case "p":
scale = 100; scale = 100;
suffix = "%"; suffix = "%";
type = "r"; type = "r";
break; break;
case "d": case "d":
integer = true; integer = true;
precision = 0; precision = 0;
break; break;
case "s": case "s":
scale = -1; scale = -1;
type = "r"; type = "r";
break; break;
} }
if (type == "r" && !precision) type = "g"; if (type == "r" && !precision) type = "g";
type = d3_format_types.get(type) || d3_format_typeDefault; type = d3_format_types.get(type) || d3_format_typeDefault;
return function(value) { return function(value) {
if (integer && value % 1) return ""; if (integer && value % 1) return "";
var negative = value < 0 && (value = -value) ? "-" : sign; var negative = value < 0 && (value = -value) ? "-" : sign;
if (scale < 0) { if (scale < 0) {
var prefix = d3.formatPrefix(value, precision); var prefix = d3.formatPrefix(value, precision);
value = prefix.scale(value); value = prefix.scale(value);
suffix = prefix.symbol; suffix = prefix.symbol;
} else { } else {
value *= scale; value *= scale;
} }
value = type(value, precision); value = type(value, precision);
if (zfill) { if (zfill) {
var length = value.length + negative.length; var length = value.length + negative.length;
if (length < width) value = (new Array(width - length + 1)).join(fill) + value; if (length < width) value = (new Array(width - length + 1)).join(fill) + value;
if (comma) value = d3_format_group(value); if (comma) value = d3_format_group(value);
value = negative + value; value = negative + value;
} else { } else {
if (comma) value = d3_format_group(value); if (comma) value = d3_format_group(value);
value = negative + value; value = negative + value;
var length = value.length; var length = value.length;
if (length < width) value = (new Array(width - length + 1)).join(fill) + value; if (length < width) value = (new Array(width - length + 1)).join(fill) + value;
} }
return value + suffix; return value + suffix;
}; };
}; };
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/; var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
var d3_format_types = d3.map({ var d3_format_types = d3.map({
g: function(x, p) { g: function(x, p) {
return x.toPrecision(p); return x.toPrecision(p);
}, },
e: function(x, p) { e: function(x, p) {
return x.toExponential(p); return x.toExponential(p);
}, },
f: function(x, p) { f: function(x, p) {
return x.toFixed(p); return x.toFixed(p);
}, },
r: function(x, p) { r: function(x, p) {
return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p)));
} }
}); });
var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix); var d3_formatPrefixes = [ "y", "z", "a", "f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y" ].map(d3_formatPrefix);
d3.formatPrefix = function(value, precision) { d3.formatPrefix = function(value, precision) {
var i = 0; var i = 0;
if (value) { if (value) {
if (value < 0) value *= -1; if (value < 0) value *= -1;
if (precision) value = d3.round(value, d3_format_precision(value, precision)); if (precision) value = d3.round(value, d3_format_precision(value, precision));
i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10); i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3)); i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
} }
return d3_formatPrefixes[8 + i / 3]; return d3_formatPrefixes[8 + i / 3];
}; };
var d3_ease_quad = d3_ease_poly(2), d3_ease_cubic = d3_ease_poly(3), d3_ease_default = function() { var d3_ease_quad = d3_ease_poly(2), d3_ease_cubic = d3_ease_poly(3), d3_ease_default = function() {
return d3_ease_identity; return d3_ease_identity;
}; };
var d3_ease = d3.map({ var d3_ease = d3.map({
linear: d3_ease_default, linear: d3_ease_default,
poly: d3_ease_poly, poly: d3_ease_poly,
quad: function() { quad: function() {
return d3_ease_quad; return d3_ease_quad;
}, },
cubic: function() { cubic: function() {
return d3_ease_cubic; return d3_ease_cubic;
}, },
sin: function() { sin: function() {
return d3_ease_sin; return d3_ease_sin;
}, },
exp: function() { exp: function() {
return d3_ease_exp; return d3_ease_exp;
}, },
circle: function() { circle: function() {
return d3_ease_circle; return d3_ease_circle;
}, },
elastic: d3_ease_elastic, elastic: d3_ease_elastic,
back: d3_ease_back, back: d3_ease_back,
bounce: function() { bounce: function() {
return d3_ease_bounce; return d3_ease_bounce;
} }
}); });
var d3_ease_mode = d3.map({ var d3_ease_mode = d3.map({
"in": d3_ease_identity, "in": d3_ease_identity,
out: d3_ease_reverse, out: d3_ease_reverse,
"in-out": d3_ease_reflect, "in-out": d3_ease_reflect,
"out-in": function(f) { "out-in": function(f) {
return d3_ease_reflect(d3_ease_reverse(f)); return d3_ease_reflect(d3_ease_reverse(f));
} }
}); });
d3.ease = function(name) { d3.ease = function(name) {
var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in"; var i = name.indexOf("-"), t = i >= 0 ? name.substring(0, i) : name, m = i >= 0 ? name.substring(i + 1) : "in";
t = d3_ease.get(t) || d3_ease_default; t = d3_ease.get(t) || d3_ease_default;
m = d3_ease_mode.get(m) || d3_ease_identity; m = d3_ease_mode.get(m) || d3_ease_identity;
return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1)))); return d3_ease_clamp(m(t.apply(null, Array.prototype.slice.call(arguments, 1))));
}; };
d3.event = null; d3.event = null;
d3.transform = function(string) { d3.transform = function(string) {
var g = document.createElementNS(d3.ns.prefix.svg, "g"); var g = document.createElementNS(d3.ns.prefix.svg, "g");
return (d3.transform = function(string) { return (d3.transform = function(string) {
g.setAttribute("transform", string); g.setAttribute("transform", string);
var t = g.transform.baseVal.consolidate(); var t = g.transform.baseVal.consolidate();
return new d3_transform(t ? t.matrix : d3_transformIdentity); return new d3_transform(t ? t.matrix : d3_transformIdentity);
})(string); })(string);
}; };
d3_transform.prototype.toString = function() { d3_transform.prototype.toString = function() {
return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")"; return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
}; };
var d3_transformDegrees = 180 / Math.PI, d3_transformIdentity = { var d3_transformDegrees = 180 / Math.PI, d3_transformIdentity = {
a: 1, a: 1,
b: 0, b: 0,
c: 0, c: 0,
d: 1, d: 1,
e: 0, e: 0,
f: 0 f: 0
}; };
d3.interpolate = function(a, b) { d3.interpolate = function(a, b) {
var i = d3.interpolators.length, f; var i = d3.interpolators.length, f;
while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ; while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
return f; return f;
}; };
d3.interpolateNumber = function(a, b) { d3.interpolateNumber = function(a, b) {
b -= a; b -= a;
return function(t) { return function(t) {
return a + b * t; return a + b * t;
}; };
}; };
d3.interpolateRound = function(a, b) { d3.interpolateRound = function(a, b) {
b -= a; b -= a;
return function(t) { return function(t) {
return Math.round(a + b * t); return Math.round(a + b * t);
}; };
}; };
d3.interpolateString = function(a, b) { d3.interpolateString = function(a, b) {
var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o;
d3_interpolate_number.lastIndex = 0; d3_interpolate_number.lastIndex = 0;
for (i = 0; m = d3_interpolate_number.exec(b); ++i) { for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
if (m.index) s.push(b.substring(s0, s1 = m.index)); if (m.index) s.push(b.substring(s0, s1 = m.index));
q.push({ q.push({
i: s.length, i: s.length,
x: m[0] x: m[0]
}); });
s.push(null); s.push(null);
s0 = d3_interpolate_number.lastIndex; s0 = d3_interpolate_number.lastIndex;
} }
if (s0 < b.length) s.push(b.substring(s0)); if (s0 < b.length) s.push(b.substring(s0));
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
o = q[i]; o = q[i];
if (o.x == m[0]) { if (o.x == m[0]) {
if (o.i) { if (o.i) {
if (s[o.i + 1] == null) { if (s[o.i + 1] == null) {
s[o.i - 1] += o.x; s[o.i - 1] += o.x;
s.splice(o.i, 1); s.splice(o.i, 1);
for (j = i + 1; j < n; ++j) q[j].i--; for (j = i + 1; j < n; ++j) q[j].i--;
} else { } else {
s[o.i - 1] += o.x + s[o.i + 1]; s[o.i - 1] += o.x + s[o.i + 1];
s.splice(o.i, 2); s.splice(o.i, 2);
for (j = i + 1; j < n; ++j) q[j].i -= 2; for (j = i + 1; j < n; ++j) q[j].i -= 2;
} }
} else { } else {
if (s[o.i + 1] == null) { if (s[o.i + 1] == null) {
s[o.i] = o.x; s[o.i] = o.x;
} else { } else {
s[o.i] = o.x + s[o.i + 1]; s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1); s.splice(o.i + 1, 1);
for (j = i + 1; j < n; ++j) q[j].i--; for (j = i + 1; j < n; ++j) q[j].i--;
} }
} }
q.splice(i, 1); q.splice(i, 1);
n--; n--;
i--; i--;
} else { } else {
o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x)); o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
} }
} }
while (i < n) { while (i < n) {
o = q.pop(); o = q.pop();
if (s[o.i + 1] == null) { if (s[o.i + 1] == null) {
s[o.i] = o.x; s[o.i] = o.x;
} else { } else {
s[o.i] = o.x + s[o.i + 1]; s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1); s.splice(o.i + 1, 1);
} }
n--; n--;
} }
if (s.length === 1) { if (s.length === 1) {
return s[0] == null ? q[0].x : function() { return s[0] == null ? q[0].x : function() {
return b; return b;
}; };
} }
return function(t) { return function(t) {
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
return s.join(""); return s.join("");
}; };
}; };
d3.interpolateTransform = function(a, b) { d3.interpolateTransform = function(a, b) {
var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale; var s = [], q = [], n, A = d3.transform(a), B = d3.transform(b), ta = A.translate, tb = B.translate, ra = A.rotate, rb = B.rotate, wa = A.skew, wb = B.skew, ka = A.scale, kb = B.scale;
if (ta[0] != tb[0] || ta[1] != tb[1]) { if (ta[0] != tb[0] || ta[1] != tb[1]) {
s.push("translate(", null, ",", null, ")"); s.push("translate(", null, ",", null, ")");
q.push({ q.push({
i: 1, i: 1,
x: d3.interpolateNumber(ta[0], tb[0]) x: d3.interpolateNumber(ta[0], tb[0])
}, { }, {
i: 3, i: 3,
x: d3.interpolateNumber(ta[1], tb[1]) x: d3.interpolateNumber(ta[1], tb[1])
}); });
} else if (tb[0] || tb[1]) { } else if (tb[0] || tb[1]) {
s.push("translate(" + tb + ")"); s.push("translate(" + tb + ")");
} else { } else {
s.push(""); s.push("");
} }
if (ra != rb) { if (ra != rb) {
if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
q.push({ q.push({
i: s.push(s.pop() + "rotate(", null, ")") - 2, i: s.push(s.pop() + "rotate(", null, ")") - 2,
x: d3.interpolateNumber(ra, rb) x: d3.interpolateNumber(ra, rb)
}); });
} else if (rb) { } else if (rb) {
s.push(s.pop() + "rotate(" + rb + ")"); s.push(s.pop() + "rotate(" + rb + ")");
} }
if (wa != wb) { if (wa != wb) {
q.push({ q.push({
i: s.push(s.pop() + "skewX(", null, ")") - 2, i: s.push(s.pop() + "skewX(", null, ")") - 2,
x: d3.interpolateNumber(wa, wb) x: d3.interpolateNumber(wa, wb)
}); });
} else if (wb) { } else if (wb) {
s.push(s.pop() + "skewX(" + wb + ")"); s.push(s.pop() + "skewX(" + wb + ")");
} }
if (ka[0] != kb[0] || ka[1] != kb[1]) { if (ka[0] != kb[0] || ka[1] != kb[1]) {
n = s.push(s.pop() + "scale(", null, ",", null, ")"); n = s.push(s.pop() + "scale(", null, ",", null, ")");
q.push({ q.push({
i: n - 4, i: n - 4,
x: d3.interpolateNumber(ka[0], kb[0]) x: d3.interpolateNumber(ka[0], kb[0])
}, { }, {
i: n - 2, i: n - 2,
x: d3.interpolateNumber(ka[1], kb[1]) x: d3.interpolateNumber(ka[1], kb[1])
}); });
} else if (kb[0] != 1 || kb[1] != 1) { } else if (kb[0] != 1 || kb[1] != 1) {
s.push(s.pop() + "scale(" + kb + ")"); s.push(s.pop() + "scale(" + kb + ")");
} }
n = q.length; n = q.length;
return function(t) { return function(t) {
var i = -1, o; var i = -1, o;
while (++i < n) s[(o = q[i]).i] = o.x(t); while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join(""); return s.join("");
}; };
}; };
d3.interpolateRgb = function(a, b) { d3.interpolateRgb = function(a, b) {
a = d3.rgb(a); a = d3.rgb(a);
b = d3.rgb(b); b = d3.rgb(b);
var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab;
return function(t) { return function(t) {
return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t)); return "#" + d3_rgb_hex(Math.round(ar + br * t)) + d3_rgb_hex(Math.round(ag + bg * t)) + d3_rgb_hex(Math.round(ab + bb * t));
}; };
}; };
d3.interpolateHsl = function(a, b) { d3.interpolateHsl = function(a, b) {
a = d3.hsl(a); a = d3.hsl(a);
b = d3.hsl(b); b = d3.hsl(b);
var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0; var h0 = a.h, s0 = a.s, l0 = a.l, h1 = b.h - h0, s1 = b.s - s0, l1 = b.l - l0;
if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360; if (h1 > 180) h1 -= 360; else if (h1 < -180) h1 += 360;
return function(t) { return function(t) {
return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + ""; return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t) + "";
}; };
}; };
d3.interpolateLab = function(a, b) { d3.interpolateLab = function(a, b) {
a = d3.lab(a); a = d3.lab(a);
b = d3.lab(b); b = d3.lab(b);
var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab; var al = a.l, aa = a.a, ab = a.b, bl = b.l - al, ba = b.a - aa, bb = b.b - ab;
return function(t) { return function(t) {
return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + ""; return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
}; };
}; };
d3.interpolateHcl = function(a, b) { d3.interpolateHcl = function(a, b) {
a = d3.hcl(a); a = d3.hcl(a);
b = d3.hcl(b); b = d3.hcl(b);
var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al; var ah = a.h, ac = a.c, al = a.l, bh = b.h - ah, bc = b.c - ac, bl = b.l - al;
if (bh > 180) bh -= 360; else if (bh < -180) bh += 360; if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
return function(t) { return function(t) {
return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + ""; return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
}; };
}; };
d3.interpolateArray = function(a, b) { d3.interpolateArray = function(a, b) {
var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i; var x = [], c = [], na = a.length, nb = b.length, n0 = Math.min(a.length, b.length), i;
for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i])); for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i]));
for (; i < na; ++i) c[i] = a[i]; for (; i < na; ++i) c[i] = a[i];
for (; i < nb; ++i) c[i] = b[i]; for (; i < nb; ++i) c[i] = b[i];
return function(t) { return function(t) {
for (i = 0; i < n0; ++i) c[i] = x[i](t); for (i = 0; i < n0; ++i) c[i] = x[i](t);
return c; return c;
}; };
}; };
d3.interpolateObject = function(a, b) { d3.interpolateObject = function(a, b) {
var i = {}, c = {}, k; var i = {}, c = {}, k;
for (k in a) { for (k in a) {
if (k in b) { if (k in b) {
i[k] = d3_interpolateByName(k)(a[k], b[k]); i[k] = d3_interpolateByName(k)(a[k], b[k]);
} else { } else {
c[k] = a[k]; c[k] = a[k];
} }
} }
for (k in b) { for (k in b) {
if (!(k in a)) { if (!(k in a)) {
c[k] = b[k]; c[k] = b[k];
} }
} }
return function(t) { return function(t) {
for (k in i) c[k] = i[k](t); for (k in i) c[k] = i[k](t);
return c; return c;
}; };
}; };
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
d3.interpolators = [ d3.interpolateObject, function(a, b) { d3.interpolators = [ d3.interpolateObject, function(a, b) {
return b instanceof Array && d3.interpolateArray(a, b); return b instanceof Array && d3.interpolateArray(a, b);
}, function(a, b) { }, function(a, b) {
return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + ""); return (typeof a === "string" || typeof b === "string") && d3.interpolateString(a + "", b + "");
}, function(a, b) { }, function(a, b) {
return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b); return (typeof b === "string" ? d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Color) && d3.interpolateRgb(a, b);
}, function(a, b) { }, function(a, b) {
return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b); return !isNaN(a = +a) && !isNaN(b = +b) && d3.interpolateNumber(a, b);
} ]; } ];
d3_Color.prototype.toString = function() { d3_Color.prototype.toString = function() {
return this.rgb() + ""; return this.rgb() + "";
}; };
d3.rgb = function(r, g, b) { d3.rgb = function(r, g, b) {
return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b); return arguments.length === 1 ? r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : d3_rgb(~~r, ~~g, ~~b);
}; };
var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color; var d3_rgbPrototype = d3_Rgb.prototype = new d3_Color;
d3_rgbPrototype.brighter = function(k) { d3_rgbPrototype.brighter = function(k) {
k = Math.pow(.7, arguments.length ? k : 1); k = Math.pow(.7, arguments.length ? k : 1);
var r = this.r, g = this.g, b = this.b, i = 30; var r = this.r, g = this.g, b = this.b, i = 30;
if (!r && !g && !b) return d3_rgb(i, i, i); if (!r && !g && !b) return d3_rgb(i, i, i);
if (r && r < i) r = i; if (r && r < i) r = i;
if (g && g < i) g = i; if (g && g < i) g = i;
if (b && b < i) b = i; if (b && b < i) b = i;
return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k))); return d3_rgb(Math.min(255, Math.floor(r / k)), Math.min(255, Math.floor(g / k)), Math.min(255, Math.floor(b / k)));
}; };
d3_rgbPrototype.darker = function(k) { d3_rgbPrototype.darker = function(k) {
k = Math.pow(.7, arguments.length ? k : 1); k = Math.pow(.7, arguments.length ? k : 1);
return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b)); return d3_rgb(Math.floor(k * this.r), Math.floor(k * this.g), Math.floor(k * this.b));
}; };
d3_rgbPrototype.hsl = function() { d3_rgbPrototype.hsl = function() {
return d3_rgb_hsl(this.r, this.g, this.b); return d3_rgb_hsl(this.r, this.g, this.b);
}; };
d3_rgbPrototype.toString = function() { d3_rgbPrototype.toString = function() {
return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
}; };
var d3_rgb_names = d3.map({ var d3_rgb_names = d3.map({
aliceblue: "#f0f8ff", aliceblue: "#f0f8ff",
antiquewhite: "#faebd7", antiquewhite: "#faebd7",
aqua: "#00ffff", aqua: "#00ffff",
aquamarine: "#7fffd4", aquamarine: "#7fffd4",
azure: "#f0ffff", azure: "#f0ffff",
beige: "#f5f5dc", beige: "#f5f5dc",
bisque: "#ffe4c4", bisque: "#ffe4c4",
black: "#000000", black: "#000000",
blanchedalmond: "#ffebcd", blanchedalmond: "#ffebcd",
blue: "#0000ff", blue: "#0000ff",
blueviolet: "#8a2be2", blueviolet: "#8a2be2",
brown: "#a52a2a", brown: "#a52a2a",
burlywood: "#deb887", burlywood: "#deb887",
cadetblue: "#5f9ea0", cadetblue: "#5f9ea0",
chartreuse: "#7fff00", chartreuse: "#7fff00",
chocolate: "#d2691e", chocolate: "#d2691e",
coral: "#ff7f50", coral: "#ff7f50",
cornflowerblue: "#6495ed", cornflowerblue: "#6495ed",
cornsilk: "#fff8dc", cornsilk: "#fff8dc",
crimson: "#dc143c", crimson: "#dc143c",
cyan: "#00ffff", cyan: "#00ffff",
darkblue: "#00008b", darkblue: "#00008b",
darkcyan: "#008b8b", darkcyan: "#008b8b",
darkgoldenrod: "#b8860b", darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9", darkgray: "#a9a9a9",
darkgreen: "#006400", darkgreen: "#006400",
darkgrey: "#a9a9a9", darkgrey: "#a9a9a9",
darkkhaki: "#bdb76b", darkkhaki: "#bdb76b",
darkmagenta: "#8b008b", darkmagenta: "#8b008b",
darkolivegreen: "#556b2f", darkolivegreen: "#556b2f",
darkorange: "#ff8c00", darkorange: "#ff8c00",
darkorchid: "#9932cc", darkorchid: "#9932cc",
darkred: "#8b0000", darkred: "#8b0000",
darksalmon: "#e9967a", darksalmon: "#e9967a",
darkseagreen: "#8fbc8f", darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b", darkslateblue: "#483d8b",
darkslategray: "#2f4f4f", darkslategray: "#2f4f4f",
darkslategrey: "#2f4f4f", darkslategrey: "#2f4f4f",
darkturquoise: "#00ced1", darkturquoise: "#00ced1",
darkviolet: "#9400d3", darkviolet: "#9400d3",
deeppink: "#ff1493", deeppink: "#ff1493",
deepskyblue: "#00bfff", deepskyblue: "#00bfff",
dimgray: "#696969", dimgray: "#696969",
dimgrey: "#696969", dimgrey: "#696969",
dodgerblue: "#1e90ff", dodgerblue: "#1e90ff",
firebrick: "#b22222", firebrick: "#b22222",
floralwhite: "#fffaf0", floralwhite: "#fffaf0",
forestgreen: "#228b22", forestgreen: "#228b22",
fuchsia: "#ff00ff", fuchsia: "#ff00ff",
gainsboro: "#dcdcdc", gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff", ghostwhite: "#f8f8ff",
gold: "#ffd700", gold: "#ffd700",
goldenrod: "#daa520", goldenrod: "#daa520",
gray: "#808080", gray: "#808080",
green: "#008000", green: "#008000",
greenyellow: "#adff2f", greenyellow: "#adff2f",
grey: "#808080", grey: "#808080",
honeydew: "#f0fff0", honeydew: "#f0fff0",
hotpink: "#ff69b4", hotpink: "#ff69b4",
indianred: "#cd5c5c", indianred: "#cd5c5c",
indigo: "#4b0082", indigo: "#4b0082",
ivory: "#fffff0", ivory: "#fffff0",
khaki: "#f0e68c", khaki: "#f0e68c",
lavender: "#e6e6fa", lavender: "#e6e6fa",
lavenderblush: "#fff0f5", lavenderblush: "#fff0f5",
lawngreen: "#7cfc00", lawngreen: "#7cfc00",
lemonchiffon: "#fffacd", lemonchiffon: "#fffacd",
lightblue: "#add8e6", lightblue: "#add8e6",
lightcoral: "#f08080", lightcoral: "#f08080",
lightcyan: "#e0ffff", lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2", lightgoldenrodyellow: "#fafad2",
lightgray: "#d3d3d3", lightgray: "#d3d3d3",
lightgreen: "#90ee90", lightgreen: "#90ee90",
lightgrey: "#d3d3d3", lightgrey: "#d3d3d3",
lightpink: "#ffb6c1", lightpink: "#ffb6c1",
lightsalmon: "#ffa07a", lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa", lightseagreen: "#20b2aa",
lightskyblue: "#87cefa", lightskyblue: "#87cefa",
lightslategray: "#778899", lightslategray: "#778899",
lightslategrey: "#778899", lightslategrey: "#778899",
lightsteelblue: "#b0c4de", lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0", lightyellow: "#ffffe0",
lime: "#00ff00", lime: "#00ff00",
limegreen: "#32cd32", limegreen: "#32cd32",
linen: "#faf0e6", linen: "#faf0e6",
magenta: "#ff00ff", magenta: "#ff00ff",
maroon: "#800000", maroon: "#800000",
mediumaquamarine: "#66cdaa", mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd", mediumblue: "#0000cd",
mediumorchid: "#ba55d3", mediumorchid: "#ba55d3",
mediumpurple: "#9370db", mediumpurple: "#9370db",
mediumseagreen: "#3cb371", mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee", mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a", mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc", mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585", mediumvioletred: "#c71585",
midnightblue: "#191970", midnightblue: "#191970",
mintcream: "#f5fffa", mintcream: "#f5fffa",
mistyrose: "#ffe4e1", mistyrose: "#ffe4e1",
moccasin: "#ffe4b5", moccasin: "#ffe4b5",
navajowhite: "#ffdead", navajowhite: "#ffdead",
navy: "#000080", navy: "#000080",
oldlace: "#fdf5e6", oldlace: "#fdf5e6",
olive: "#808000", olive: "#808000",
olivedrab: "#6b8e23", olivedrab: "#6b8e23",
orange: "#ffa500", orange: "#ffa500",
orangered: "#ff4500", orangered: "#ff4500",
orchid: "#da70d6", orchid: "#da70d6",
palegoldenrod: "#eee8aa", palegoldenrod: "#eee8aa",
palegreen: "#98fb98", palegreen: "#98fb98",
paleturquoise: "#afeeee", paleturquoise: "#afeeee",
palevioletred: "#db7093", palevioletred: "#db7093",
papayawhip: "#ffefd5", papayawhip: "#ffefd5",
peachpuff: "#ffdab9", peachpuff: "#ffdab9",
peru: "#cd853f", peru: "#cd853f",
pink: "#ffc0cb", pink: "#ffc0cb",
plum: "#dda0dd", plum: "#dda0dd",
powderblue: "#b0e0e6", powderblue: "#b0e0e6",
purple: "#800080", purple: "#800080",
red: "#ff0000", red: "#ff0000",
rosybrown: "#bc8f8f", rosybrown: "#bc8f8f",
royalblue: "#4169e1", royalblue: "#4169e1",
saddlebrown: "#8b4513", saddlebrown: "#8b4513",
salmon: "#fa8072", salmon: "#fa8072",
sandybrown: "#f4a460", sandybrown: "#f4a460",
seagreen: "#2e8b57", seagreen: "#2e8b57",
seashell: "#fff5ee", seashell: "#fff5ee",
sienna: "#a0522d", sienna: "#a0522d",
silver: "#c0c0c0", silver: "#c0c0c0",
skyblue: "#87ceeb", skyblue: "#87ceeb",
slateblue: "#6a5acd", slateblue: "#6a5acd",
slategray: "#708090", slategray: "#708090",
slategrey: "#708090", slategrey: "#708090",
snow: "#fffafa", snow: "#fffafa",
springgreen: "#00ff7f", springgreen: "#00ff7f",
steelblue: "#4682b4", steelblue: "#4682b4",
tan: "#d2b48c", tan: "#d2b48c",
teal: "#008080", teal: "#008080",
thistle: "#d8bfd8", thistle: "#d8bfd8",
tomato: "#ff6347", tomato: "#ff6347",
turquoise: "#40e0d0", turquoise: "#40e0d0",
violet: "#ee82ee", violet: "#ee82ee",
wheat: "#f5deb3", wheat: "#f5deb3",
white: "#ffffff", white: "#ffffff",
whitesmoke: "#f5f5f5", whitesmoke: "#f5f5f5",
yellow: "#ffff00", yellow: "#ffff00",
yellowgreen: "#9acd32" yellowgreen: "#9acd32"
}); });
d3_rgb_names.forEach(function(key, value) { d3_rgb_names.forEach(function(key, value) {
d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb)); d3_rgb_names.set(key, d3_rgb_parse(value, d3_rgb, d3_hsl_rgb));
}); });
d3.hsl = function(h, s, l) { d3.hsl = function(h, s, l) {
return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l); return arguments.length === 1 ? h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : d3_hsl(+h, +s, +l);
}; };
var d3_hslPrototype = d3_Hsl.prototype = new d3_Color; var d3_hslPrototype = d3_Hsl.prototype = new d3_Color;
d3_hslPrototype.brighter = function(k) { d3_hslPrototype.brighter = function(k) {
k = Math.pow(.7, arguments.length ? k : 1); k = Math.pow(.7, arguments.length ? k : 1);
return d3_hsl(this.h, this.s, this.l / k); return d3_hsl(this.h, this.s, this.l / k);
}; };
d3_hslPrototype.darker = function(k) { d3_hslPrototype.darker = function(k) {
k = Math.pow(.7, arguments.length ? k : 1); k = Math.pow(.7, arguments.length ? k : 1);
return d3_hsl(this.h, this.s, k * this.l); return d3_hsl(this.h, this.s, k * this.l);
}; };
d3_hslPrototype.rgb = function() { d3_hslPrototype.rgb = function() {
return d3_hsl_rgb(this.h, this.s, this.l); return d3_hsl_rgb(this.h, this.s, this.l);
}; };
d3.hcl = function(h, c, l) { d3.hcl = function(h, c, l) {
return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l); return arguments.length === 1 ? h instanceof d3_Hcl ? d3_hcl(h.h, h.c, h.l) : h instanceof d3_Lab ? d3_lab_hcl(h.l, h.a, h.b) : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b) : d3_hcl(+h, +c, +l);
}; };
var d3_hclPrototype = d3_Hcl.prototype = new d3_Color; var d3_hclPrototype = d3_Hcl.prototype = new d3_Color;
d3_hclPrototype.brighter = function(k) { d3_hclPrototype.brighter = function(k) {
return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); return d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
}; };
d3_hclPrototype.darker = function(k) { d3_hclPrototype.darker = function(k) {
return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); return d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
}; };
d3_hclPrototype.rgb = function() { d3_hclPrototype.rgb = function() {
return d3_hcl_lab(this.h, this.c, this.l).rgb(); return d3_hcl_lab(this.h, this.c, this.l).rgb();
}; };
d3.lab = function(l, a, b) { d3.lab = function(l, a, b) {
return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b); return arguments.length === 1 ? l instanceof d3_Lab ? d3_lab(l.l, l.a, l.b) : l instanceof d3_Hcl ? d3_hcl_lab(l.l, l.c, l.h) : d3_rgb_lab((l = d3.rgb(l)).r, l.g, l.b) : d3_lab(+l, +a, +b);
}; };
var d3_lab_K = 18; var d3_lab_K = 18;
var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883; var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
var d3_labPrototype = d3_Lab.prototype = new d3_Color; var d3_labPrototype = d3_Lab.prototype = new d3_Color;
d3_labPrototype.brighter = function(k) { d3_labPrototype.brighter = function(k) {
return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); return d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
}; };
d3_labPrototype.darker = function(k) { d3_labPrototype.darker = function(k) {
return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); return d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
}; };
d3_labPrototype.rgb = function() { d3_labPrototype.rgb = function() {
return d3_lab_rgb(this.l, this.a, this.b); return d3_lab_rgb(this.l, this.a, this.b);
}; };
var d3_select = function(s, n) { var d3_select = function(s, n) {
return n.querySelector(s); return n.querySelector(s);
}, d3_selectAll = function(s, n) { }, d3_selectAll = function(s, n) {
return n.querySelectorAll(s); return n.querySelectorAll(s);
}, d3_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) { }, d3_selectRoot = document.documentElement, d3_selectMatcher = d3_selectRoot.matchesSelector || d3_selectRoot.webkitMatchesSelector || d3_selectRoot.mozMatchesSelector || d3_selectRoot.msMatchesSelector || d3_selectRoot.oMatchesSelector, d3_selectMatches = function(n, s) {
return d3_selectMatcher.call(n, s); return d3_selectMatcher.call(n, s);
}; };
if (typeof Sizzle === "function") { if (typeof Sizzle === "function") {
d3_select = function(s, n) { d3_select = function(s, n) {
return Sizzle(s, n)[0] || null; return Sizzle(s, n)[0] || null;
}; };
d3_selectAll = function(s, n) { d3_selectAll = function(s, n) {
return Sizzle.uniqueSort(Sizzle(s, n)); return Sizzle.uniqueSort(Sizzle(s, n));
}; };
d3_selectMatches = Sizzle.matchesSelector; d3_selectMatches = Sizzle.matchesSelector;
} }
var d3_selectionPrototype = []; var d3_selectionPrototype = [];
d3.selection = function() { d3.selection = function() {
return d3_selectionRoot; return d3_selectionRoot;
}; };
d3.selection.prototype = d3_selectionPrototype; d3.selection.prototype = d3_selectionPrototype;
d3_selectionPrototype.select = function(selector) { d3_selectionPrototype.select = function(selector) {
var subgroups = [], subgroup, subnode, group, node; var subgroups = [], subgroup, subnode, group, node;
if (typeof selector !== "function") selector = d3_selection_selector(selector); if (typeof selector !== "function") selector = d3_selection_selector(selector);
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
subgroup.parentNode = (group = this[j]).parentNode; subgroup.parentNode = (group = this[j]).parentNode;
for (var i = -1, n = group.length; ++i < n; ) { for (var i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) { if (node = group[i]) {
subgroup.push(subnode = selector.call(node, node.__data__, i)); subgroup.push(subnode = selector.call(node, node.__data__, i));
if (subnode && "__data__" in node) subnode.__data__ = node.__data__; if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
} else { } else {
subgroup.push(null); subgroup.push(null);
} }
} }
} }
return d3_selection(subgroups); return d3_selection(subgroups);
}; };
d3_selectionPrototype.selectAll = function(selector) { d3_selectionPrototype.selectAll = function(selector) {
var subgroups = [], subgroup, node; var subgroups = [], subgroup, node;
if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) { if (node = group[i]) {
subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i))); subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
subgroup.parentNode = node; subgroup.parentNode = node;
} }
} }
} }
return d3_selection(subgroups); return d3_selection(subgroups);
}; };
d3_selectionPrototype.attr = function(name, value) { d3_selectionPrototype.attr = function(name, value) {
if (arguments.length < 2) { if (arguments.length < 2) {
if (typeof name === "string") { if (typeof name === "string") {
var node = this.node(); var node = this.node();
name = d3.ns.qualify(name); name = d3.ns.qualify(name);
return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
} }
for (value in name) this.each(d3_selection_attr(value, name[value])); for (value in name) this.each(d3_selection_attr(value, name[value]));
return this; return this;
} }
return this.each(d3_selection_attr(name, value)); return this.each(d3_selection_attr(name, value));
}; };
d3_selectionPrototype.classed = function(name, value) { d3_selectionPrototype.classed = function(name, value) {
if (arguments.length < 2) { if (arguments.length < 2) {
if (typeof name === "string") { if (typeof name === "string") {
var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1; var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
if (value = node.classList) { if (value = node.classList) {
while (++i < n) if (!value.contains(name[i])) return false; while (++i < n) if (!value.contains(name[i])) return false;
} else { } else {
value = node.className; value = node.className;
if (value.baseVal != null) value = value.baseVal; if (value.baseVal != null) value = value.baseVal;
while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
} }
return true; return true;
} }
for (value in name) this.each(d3_selection_classed(value, name[value])); for (value in name) this.each(d3_selection_classed(value, name[value]));
return this; return this;
} }
return this.each(d3_selection_classed(name, value)); return this.each(d3_selection_classed(name, value));
}; };
d3_selectionPrototype.style = function(name, value, priority) { d3_selectionPrototype.style = function(name, value, priority) {
var n = arguments.length; var n = arguments.length;
if (n < 3) { if (n < 3) {
if (typeof name !== "string") { if (typeof name !== "string") {
if (n < 2) value = ""; if (n < 2) value = "";
for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
return this; return this;
} }
if (n < 2) return window.getComputedStyle(this.node(), null).getPropertyValue(name); if (n < 2) return window.getComputedStyle(this.node(), null).getPropertyValue(name);
priority = ""; priority = "";
} }
return this.each(d3_selection_style(name, value, priority)); return this.each(d3_selection_style(name, value, priority));
}; };
d3_selectionPrototype.property = function(name, value) { d3_selectionPrototype.property = function(name, value) {
if (arguments.length < 2) { if (arguments.length < 2) {
if (typeof name === "string") return this.node()[name]; if (typeof name === "string") return this.node()[name];
for (value in name) this.each(d3_selection_property(value, name[value])); for (value in name) this.each(d3_selection_property(value, name[value]));
return this; return this;
} }
return this.each(d3_selection_property(name, value)); return this.each(d3_selection_property(name, value));
}; };
d3_selectionPrototype.text = function(value) { d3_selectionPrototype.text = function(value) {
return arguments.length < 1 ? this.node().textContent : this.each(typeof value === "function" ? function() { return arguments.length < 1 ? this.node().textContent : this.each(typeof value === "function" ? function() {
var v = value.apply(this, arguments); var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v; this.textContent = v == null ? "" : v;
} : value == null ? function() { } : value == null ? function() {
this.textContent = ""; this.textContent = "";
} : function() { } : function() {
this.textContent = value; this.textContent = value;
}); });
}; };
d3_selectionPrototype.html = function(value) { d3_selectionPrototype.html = function(value) {
return arguments.length < 1 ? this.node().innerHTML : this.each(typeof value === "function" ? function() { return arguments.length < 1 ? this.node().innerHTML : this.each(typeof value === "function" ? function() {
var v = value.apply(this, arguments); var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v; this.innerHTML = v == null ? "" : v;
} : value == null ? function() { } : value == null ? function() {
this.innerHTML = ""; this.innerHTML = "";
} : function() { } : function() {
this.innerHTML = value; this.innerHTML = value;
}); });
}; };
d3_selectionPrototype.append = function(name) { d3_selectionPrototype.append = function(name) {
function append() { function append() {
return this.appendChild(document.createElementNS(this.namespaceURI, name)); return this.appendChild(document.createElementNS(this.namespaceURI, name));
} }
function appendNS() { function appendNS() {
return this.appendChild(document.createElementNS(name.space, name.local)); return this.appendChild(document.createElementNS(name.space, name.local));
} }
name = d3.ns.qualify(name); name = d3.ns.qualify(name);
return this.select(name.local ? appendNS : append); return this.select(name.local ? appendNS : append);
}; };
d3_selectionPrototype.insert = function(name, before) { d3_selectionPrototype.insert = function(name, before) {
function insert() { function insert() {
return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this)); return this.insertBefore(document.createElementNS(this.namespaceURI, name), d3_select(before, this));
} }
function insertNS() { function insertNS() {
return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this)); return this.insertBefore(document.createElementNS(name.space, name.local), d3_select(before, this));
} }
name = d3.ns.qualify(name); name = d3.ns.qualify(name);
return this.select(name.local ? insertNS : insert); return this.select(name.local ? insertNS : insert);
}; };
d3_selectionPrototype.remove = function() { d3_selectionPrototype.remove = function() {
return this.each(function() { return this.each(function() {
var parent = this.parentNode; var parent = this.parentNode;
if (parent) parent.removeChild(this); if (parent) parent.removeChild(this);
}); });
}; };
d3_selectionPrototype.data = function(value, key) { d3_selectionPrototype.data = function(value, key) {
function bind(group, groupData) { function bind(group, groupData) {
var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), n1 = Math.max(n, m), updateNodes = [], enterNodes = [], exitNodes = [], node, nodeData; var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), n1 = Math.max(n, m), updateNodes = [], enterNodes = [], exitNodes = [], node, nodeData;
if (key) { if (key) {
var nodeByKeyValue = new d3_Map, keyValues = [], keyValue, j = groupData.length; var nodeByKeyValue = new d3_Map, keyValues = [], keyValue, j = groupData.length;
for (i = -1; ++i < n; ) { for (i = -1; ++i < n; ) {
keyValue = key.call(node = group[i], node.__data__, i); keyValue = key.call(node = group[i], node.__data__, i);
if (nodeByKeyValue.has(keyValue)) { if (nodeByKeyValue.has(keyValue)) {
exitNodes[j++] = node; exitNodes[j++] = node;
} else { } else {
nodeByKeyValue.set(keyValue, node); nodeByKeyValue.set(keyValue, node);
} }
keyValues.push(keyValue); keyValues.push(keyValue);
} }
for (i = -1; ++i < m; ) { for (i = -1; ++i < m; ) {
keyValue = key.call(groupData, nodeData = groupData[i], i); keyValue = key.call(groupData, nodeData = groupData[i], i);
if (nodeByKeyValue.has(keyValue)) { if (nodeByKeyValue.has(keyValue)) {
updateNodes[i] = node = nodeByKeyValue.get(keyValue); updateNodes[i] = node = nodeByKeyValue.get(keyValue);
node.__data__ = nodeData; node.__data__ = nodeData;
enterNodes[i] = exitNodes[i] = null; enterNodes[i] = exitNodes[i] = null;
} else { } else {
enterNodes[i] = d3_selection_dataNode(nodeData); enterNodes[i] = d3_selection_dataNode(nodeData);
updateNodes[i] = exitNodes[i] = null; updateNodes[i] = exitNodes[i] = null;
} }
nodeByKeyValue.remove(keyValue); nodeByKeyValue.remove(keyValue);
} }
for (i = -1; ++i < n; ) { for (i = -1; ++i < n; ) {
if (nodeByKeyValue.has(keyValues[i])) { if (nodeByKeyValue.has(keyValues[i])) {
exitNodes[i] = group[i]; exitNodes[i] = group[i];
} }
} }
} else { } else {
for (i = -1; ++i < n0; ) { for (i = -1; ++i < n0; ) {
node = group[i]; node = group[i];
nodeData = groupData[i]; nodeData = groupData[i];
if (node) { if (node) {
node.__data__ = nodeData; node.__data__ = nodeData;
updateNodes[i] = node; updateNodes[i] = node;
enterNodes[i] = exitNodes[i] = null; enterNodes[i] = exitNodes[i] = null;
} else { } else {
enterNodes[i] = d3_selection_dataNode(nodeData); enterNodes[i] = d3_selection_dataNode(nodeData);
updateNodes[i] = exitNodes[i] = null; updateNodes[i] = exitNodes[i] = null;
} }
} }
for (; i < m; ++i) { for (; i < m; ++i) {
enterNodes[i] = d3_selection_dataNode(groupData[i]); enterNodes[i] = d3_selection_dataNode(groupData[i]);
updateNodes[i] = exitNodes[i] = null; updateNodes[i] = exitNodes[i] = null;
} }
for (; i < n1; ++i) { for (; i < n1; ++i) {
exitNodes[i] = group[i]; exitNodes[i] = group[i];
enterNodes[i] = updateNodes[i] = null; enterNodes[i] = updateNodes[i] = null;
} }
} }
enterNodes.update = updateNodes; enterNodes.update = updateNodes;
enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode; enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
enter.push(enterNodes); enter.push(enterNodes);
update.push(updateNodes); update.push(updateNodes);
exit.push(exitNodes); exit.push(exitNodes);
} }
var i = -1, n = this.length, group, node; var i = -1, n = this.length, group, node;
if (!arguments.length) { if (!arguments.length) {
value = new Array(n = (group = this[0]).length); value = new Array(n = (group = this[0]).length);
while (++i < n) { while (++i < n) {
if (node = group[i]) { if (node = group[i]) {
value[i] = node.__data__; value[i] = node.__data__;
} }
} }
return value; return value;
} }
var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]); var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
if (typeof value === "function") { if (typeof value === "function") {
while (++i < n) { while (++i < n) {
bind(group = this[i], value.call(group, group.parentNode.__data__, i)); bind(group = this[i], value.call(group, group.parentNode.__data__, i));
} }
} else { } else {
while (++i < n) { while (++i < n) {
bind(group = this[i], value); bind(group = this[i], value);
} }
} }
update.enter = function() { update.enter = function() {
return enter; return enter;
}; };
update.exit = function() { update.exit = function() {
return exit; return exit;
}; };
return update; return update;
}; };
d3_selectionPrototype.datum = d3_selectionPrototype.map = function(value) { d3_selectionPrototype.datum = d3_selectionPrototype.map = function(value) {
return arguments.length < 1 ? this.property("__data__") : this.property("__data__", value); return arguments.length < 1 ? this.property("__data__") : this.property("__data__", value);
}; };
d3_selectionPrototype.filter = function(filter) { d3_selectionPrototype.filter = function(filter) {
var subgroups = [], subgroup, group, node; var subgroups = [], subgroup, group, node;
if (typeof filter !== "function") filter = d3_selection_filter(filter); if (typeof filter !== "function") filter = d3_selection_filter(filter);
for (var j = 0, m = this.length; j < m; j++) { for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
subgroup.parentNode = (group = this[j]).parentNode; subgroup.parentNode = (group = this[j]).parentNode;
for (var i = 0, n = group.length; i < n; i++) { for (var i = 0, n = group.length; i < n; i++) {
if ((node = group[i]) && filter.call(node, node.__data__, i)) { if ((node = group[i]) && filter.call(node, node.__data__, i)) {
subgroup.push(node); subgroup.push(node);
} }
} }
} }
return d3_selection(subgroups); return d3_selection(subgroups);
}; };
d3_selectionPrototype.order = function() { d3_selectionPrototype.order = function() {
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) { for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
if (node = group[i]) { if (node = group[i]) {
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
next = node; next = node;
} }
} }
} }
return this; return this;
}; };
d3_selectionPrototype.sort = function(comparator) { d3_selectionPrototype.sort = function(comparator) {
comparator = d3_selection_sortComparator.apply(this, arguments); comparator = d3_selection_sortComparator.apply(this, arguments);
for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator); for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
return this.order(); return this.order();
}; };
d3_selectionPrototype.on = function(type, listener, capture) { d3_selectionPrototype.on = function(type, listener, capture) {
var n = arguments.length; var n = arguments.length;
if (n < 3) { if (n < 3) {
if (typeof type !== "string") { if (typeof type !== "string") {
if (n < 2) listener = false; if (n < 2) listener = false;
for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
return this; return this;
} }
if (n < 2) return (n = this.node()["__on" + type]) && n._; if (n < 2) return (n = this.node()["__on" + type]) && n._;
capture = false; capture = false;
} }
return this.each(d3_selection_on(type, listener, capture)); return this.each(d3_selection_on(type, listener, capture));
}; };
d3_selectionPrototype.each = function(callback) { d3_selectionPrototype.each = function(callback) {
return d3_selection_each(this, function(node, i, j) { return d3_selection_each(this, function(node, i, j) {
callback.call(node, node.__data__, i, j); callback.call(node, node.__data__, i, j);
}); });
}; };
d3_selectionPrototype.call = function(callback) { d3_selectionPrototype.call = function(callback) {
callback.apply(this, (arguments[0] = this, arguments)); callback.apply(this, (arguments[0] = this, arguments));
return this; return this;
}; };
d3_selectionPrototype.empty = function() { d3_selectionPrototype.empty = function() {
return !this.node(); return !this.node();
}; };
d3_selectionPrototype.node = function(callback) { d3_selectionPrototype.node = function(callback) {
for (var j = 0, m = this.length; j < m; j++) { for (var j = 0, m = this.length; j < m; j++) {
for (var group = this[j], i = 0, n = group.length; i < n; i++) { for (var group = this[j], i = 0, n = group.length; i < n; i++) {
var node = group[i]; var node = group[i];
if (node) return node; if (node) return node;
} }
} }
return null; return null;
}; };
d3_selectionPrototype.transition = function() { d3_selectionPrototype.transition = function() {
var subgroups = [], subgroup, node; var subgroups = [], subgroup, node;
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
subgroup.push((node = group[i]) ? { subgroup.push((node = group[i]) ? {
node: node, node: node,
delay: d3_transitionDelay, delay: d3_transitionDelay,
duration: d3_transitionDuration duration: d3_transitionDuration
} : null); } : null);
} }
} }
return d3_transition(subgroups, d3_transitionId || ++d3_transitionNextId, Date.now()); return d3_transition(subgroups, d3_transitionId || ++d3_transitionNextId, Date.now());
}; };
var d3_selectionRoot = d3_selection([ [ document ] ]); var d3_selectionRoot = d3_selection([ [ document ] ]);
d3_selectionRoot[0].parentNode = d3_selectRoot; d3_selectionRoot[0].parentNode = d3_selectRoot;
d3.select = function(selector) { d3.select = function(selector) {
return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]); return typeof selector === "string" ? d3_selectionRoot.select(selector) : d3_selection([ [ selector ] ]);
}; };
d3.selectAll = function(selector) { d3.selectAll = function(selector) {
return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]); return typeof selector === "string" ? d3_selectionRoot.selectAll(selector) : d3_selection([ d3_array(selector) ]);
}; };
var d3_selection_enterPrototype = []; var d3_selection_enterPrototype = [];
d3.selection.enter = d3_selection_enter; d3.selection.enter = d3_selection_enter;
d3.selection.enter.prototype = d3_selection_enterPrototype; d3.selection.enter.prototype = d3_selection_enterPrototype;
d3_selection_enterPrototype.append = d3_selectionPrototype.append; d3_selection_enterPrototype.append = d3_selectionPrototype.append;
d3_selection_enterPrototype.insert = d3_selectionPrototype.insert; d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
d3_selection_enterPrototype.node = d3_selectionPrototype.node; d3_selection_enterPrototype.node = d3_selectionPrototype.node;
d3_selection_enterPrototype.select = function(selector) { d3_selection_enterPrototype.select = function(selector) {
var subgroups = [], subgroup, subnode, upgroup, group, node; var subgroups = [], subgroup, subnode, upgroup, group, node;
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
upgroup = (group = this[j]).update; upgroup = (group = this[j]).update;
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
subgroup.parentNode = group.parentNode; subgroup.parentNode = group.parentNode;
for (var i = -1, n = group.length; ++i < n; ) { for (var i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) { if (node = group[i]) {
subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i)); subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
subnode.__data__ = node.__data__; subnode.__data__ = node.__data__;
} else { } else {
subgroup.push(null); subgroup.push(null);
} }
} }
} }
return d3_selection(subgroups); return d3_selection(subgroups);
}; };
var d3_transitionPrototype = [], d3_transitionNextId = 0, d3_transitionId = 0, d3_transitionDefaultDelay = 0, d3_transitionDefaultDuration = 250, d3_transitionDefaultEase = d3.ease("cubic-in-out"), d3_transitionDelay = d3_transitionDefaultDelay, d3_transitionDuration = d3_transitionDefaultDuration, d3_transitionEase = d3_transitionDefaultEase; var d3_transitionPrototype = [], d3_transitionNextId = 0, d3_transitionId = 0, d3_transitionDefaultDelay = 0, d3_transitionDefaultDuration = 250, d3_transitionDefaultEase = d3.ease("cubic-in-out"), d3_transitionDelay = d3_transitionDefaultDelay, d3_transitionDuration = d3_transitionDefaultDuration, d3_transitionEase = d3_transitionDefaultEase;
d3_transitionPrototype.call = d3_selectionPrototype.call; d3_transitionPrototype.call = d3_selectionPrototype.call;
d3.transition = function(selection) { d3.transition = function(selection) {
return arguments.length ? d3_transitionId ? selection.transition() : selection : d3_selectionRoot.transition(); return arguments.length ? d3_transitionId ? selection.transition() : selection : d3_selectionRoot.transition();
}; };
d3.transition.prototype = d3_transitionPrototype; d3.transition.prototype = d3_transitionPrototype;
d3_transitionPrototype.select = function(selector) { d3_transitionPrototype.select = function(selector) {
var subgroups = [], subgroup, subnode, node; var subgroups = [], subgroup, subnode, node;
if (typeof selector !== "function") selector = d3_selection_selector(selector); if (typeof selector !== "function") selector = d3_selection_selector(selector);
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) { if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) {
if ("__data__" in node.node) subnode.__data__ = node.node.__data__; if ("__data__" in node.node) subnode.__data__ = node.node.__data__;
subgroup.push({ subgroup.push({
node: subnode, node: subnode,
delay: node.delay, delay: node.delay,
duration: node.duration duration: node.duration
}); });
} else { } else {
subgroup.push(null); subgroup.push(null);
} }
} }
} }
return d3_transition(subgroups, this.id, this.time).ease(this.ease()); return d3_transition(subgroups, this.id, this.time).ease(this.ease());
}; };
d3_transitionPrototype.selectAll = function(selector) { d3_transitionPrototype.selectAll = function(selector) {
var subgroups = [], subgroup, subnodes, node; var subgroups = [], subgroup, subnodes, node;
if (typeof selector !== "function") selector = d3_selection_selectorAll(selector); if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
for (var j = -1, m = this.length; ++j < m; ) { for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = -1, n = group.length; ++i < n; ) { for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) { if (node = group[i]) {
subnodes = selector.call(node.node, node.node.__data__, i); subnodes = selector.call(node.node, node.node.__data__, i);
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
for (var k = -1, o = subnodes.length; ++k < o; ) { for (var k = -1, o = subnodes.length; ++k < o; ) {
subgroup.push({ subgroup.push({
node: subnodes[k], node: subnodes[k],
delay: node.delay, delay: node.delay,
duration: node.duration duration: node.duration
}); });
} }
} }
} }
} }
return d3_transition(subgroups, this.id, this.time).ease(this.ease()); return d3_transition(subgroups, this.id, this.time).ease(this.ease());
}; };
d3_transitionPrototype.filter = function(filter) { d3_transitionPrototype.filter = function(filter) {
var subgroups = [], subgroup, group, node; var subgroups = [], subgroup, group, node;
if (typeof filter !== "function") filter = d3_selection_filter(filter); if (typeof filter !== "function") filter = d3_selection_filter(filter);
for (var j = 0, m = this.length; j < m; j++) { for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []); subgroups.push(subgroup = []);
for (var group = this[j], i = 0, n = group.length; i < n; i++) { for (var group = this[j], i = 0, n = group.length; i < n; i++) {
if ((node = group[i]) && filter.call(node.node, node.node.__data__, i)) { if ((node = group[i]) && filter.call(node.node, node.node.__data__, i)) {
subgroup.push(node); subgroup.push(node);
} }
} }
} }
return d3_transition(subgroups, this.id, this.time).ease(this.ease()); return d3_transition(subgroups, this.id, this.time).ease(this.ease());
}; };
d3_transitionPrototype.attr = function(name, value) { d3_transitionPrototype.attr = function(name, value) {
if (arguments.length < 2) { if (arguments.length < 2) {
for (value in name) this.attrTween(value, d3_tweenByName(name[value], value)); for (value in name) this.attrTween(value, d3_tweenByName(name[value], value));
return this; return this;
} }
return this.attrTween(name, d3_tweenByName(value, name)); return this.attrTween(name, d3_tweenByName(value, name));
}; };
d3_transitionPrototype.attrTween = function(nameNS, tween) { d3_transitionPrototype.attrTween = function(nameNS, tween) {
function attrTween(d, i) { function attrTween(d, i) {
var f = tween.call(this, d, i, this.getAttribute(name)); var f = tween.call(this, d, i, this.getAttribute(name));
return f === d3_tweenRemove ? (this.removeAttribute(name), null) : f && function(t) { return f === d3_tweenRemove ? (this.removeAttribute(name), null) : f && function(t) {
this.setAttribute(name, f(t)); this.setAttribute(name, f(t));
}; };
} }
function attrTweenNS(d, i) { function attrTweenNS(d, i) {
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
return f === d3_tweenRemove ? (this.removeAttributeNS(name.space, name.local), null) : f && function(t) { return f === d3_tweenRemove ? (this.removeAttributeNS(name.space, name.local), null) : f && function(t) {
this.setAttributeNS(name.space, name.local, f(t)); this.setAttributeNS(name.space, name.local, f(t));
}; };
} }
var name = d3.ns.qualify(nameNS); var name = d3.ns.qualify(nameNS);
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
}; };
d3_transitionPrototype.style = function(name, value, priority) { d3_transitionPrototype.style = function(name, value, priority) {
var n = arguments.length; var n = arguments.length;
if (n < 3) { if (n < 3) {
if (typeof name !== "string") { if (typeof name !== "string") {
if (n < 2) value = ""; if (n < 2) value = "";
for (priority in name) this.styleTween(priority, d3_tweenByName(name[priority], priority), value); for (priority in name) this.styleTween(priority, d3_tweenByName(name[priority], priority), value);
return this; return this;
} }
priority = ""; priority = "";
} }
return this.styleTween(name, d3_tweenByName(value, name), priority); return this.styleTween(name, d3_tweenByName(value, name), priority);
}; };
d3_transitionPrototype.styleTween = function(name, tween, priority) { d3_transitionPrototype.styleTween = function(name, tween, priority) {
if (arguments.length < 3) priority = ""; if (arguments.length < 3) priority = "";
return this.tween("style." + name, function(d, i) { return this.tween("style." + name, function(d, i) {
var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name)); var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
return f === d3_tweenRemove ? (this.style.removeProperty(name), null) : f && function(t) { return f === d3_tweenRemove ? (this.style.removeProperty(name), null) : f && function(t) {
this.style.setProperty(name, f(t), priority); this.style.setProperty(name, f(t), priority);
}; };
}); });
}; };
d3_transitionPrototype.text = function(value) { d3_transitionPrototype.text = function(value) {
return this.tween("text", function(d, i) { return this.tween("text", function(d, i) {
this.textContent = typeof value === "function" ? value.call(this, d, i) : value; this.textContent = typeof value === "function" ? value.call(this, d, i) : value;
}); });
}; };
d3_transitionPrototype.remove = function() { d3_transitionPrototype.remove = function() {
return this.each("end.transition", function() { return this.each("end.transition", function() {
var p; var p;
if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this); if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
}); });
}; };
d3_transitionPrototype.delay = function(value) { d3_transitionPrototype.delay = function(value) {
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
node.delay = value.call(node = node.node, node.__data__, i, j) | 0; node.delay = value.call(node = node.node, node.__data__, i, j) | 0;
} : (value = value | 0, function(node) { } : (value = value | 0, function(node) {
node.delay = value; node.delay = value;
})); }));
}; };
d3_transitionPrototype.duration = function(value) { d3_transitionPrototype.duration = function(value) {
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) { return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
node.duration = Math.max(1, value.call(node = node.node, node.__data__, i, j) | 0); node.duration = Math.max(1, value.call(node = node.node, node.__data__, i, j) | 0);
} : (value = Math.max(1, value | 0), function(node) { } : (value = Math.max(1, value | 0), function(node) {
node.duration = value; node.duration = value;
})); }));
}; };
d3_transitionPrototype.transition = function() { d3_transitionPrototype.transition = function() {
return this.select(d3_this); return this.select(d3_this);
}; };
d3.tween = function(b, interpolate) { d3.tween = function(b, interpolate) {
function tweenFunction(d, i, a) { function tweenFunction(d, i, a) {
var v = b.call(this, d, i); var v = b.call(this, d, i);
return v == null ? a != "" && d3_tweenRemove : a != v && interpolate(a, v + ""); return v == null ? a != "" && d3_tweenRemove : a != v && interpolate(a, v + "");
} }
function tweenString(d, i, a) { function tweenString(d, i, a) {
return a != b && interpolate(a, b); return a != b && interpolate(a, b);
} }
return typeof b === "function" ? tweenFunction : b == null ? d3_tweenNull : (b += "", tweenString); return typeof b === "function" ? tweenFunction : b == null ? d3_tweenNull : (b += "", tweenString);
}; };
var d3_tweenRemove = {}; var d3_tweenRemove = {};
var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout; var d3_timer_id = 0, d3_timer_byId = {}, d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
d3.timer = function(callback, delay, then) { d3.timer = function(callback, delay, then) {
if (arguments.length < 3) { if (arguments.length < 3) {
if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return; if (arguments.length < 2) delay = 0; else if (!isFinite(delay)) return;
then = Date.now(); then = Date.now();
} }
var timer = d3_timer_byId[callback.id]; var timer = d3_timer_byId[callback.id];
if (timer && timer.callback === callback) { if (timer && timer.callback === callback) {
timer.then = then; timer.then = then;
timer.delay = delay; timer.delay = delay;
} else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = { } else d3_timer_byId[callback.id = ++d3_timer_id] = d3_timer_queue = {
callback: callback, callback: callback,
then: then, then: then,
delay: delay, delay: delay,
next: d3_timer_queue next: d3_timer_queue
}; };
if (!d3_timer_interval) { if (!d3_timer_interval) {
d3_timer_timeout = clearTimeout(d3_timer_timeout); d3_timer_timeout = clearTimeout(d3_timer_timeout);
d3_timer_interval = 1; d3_timer_interval = 1;
d3_timer_frame(d3_timer_step); d3_timer_frame(d3_timer_step);
} }
}; };
d3.timer.flush = function() { d3.timer.flush = function() {
var elapsed, now = Date.now(), t1 = d3_timer_queue; var elapsed, now = Date.now(), t1 = d3_timer_queue;
while (t1) { while (t1) {
elapsed = now - t1.then; elapsed = now - t1.then;
if (!t1.delay) t1.flush = t1.callback(elapsed); if (!t1.delay) t1.flush = t1.callback(elapsed);
t1 = t1.next; t1 = t1.next;
} }
d3_timer_flush(); d3_timer_flush();
}; };
var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { var d3_timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
setTimeout(callback, 17); setTimeout(callback, 17);
}; };
d3.mouse = function(container) { d3.mouse = function(container) {
return d3_mousePoint(container, d3_eventSource()); return d3_mousePoint(container, d3_eventSource());
}; };
var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0; var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;
d3.touches = function(container, touches) { d3.touches = function(container, touches) {
if (arguments.length < 2) touches = d3_eventSource().touches; if (arguments.length < 2) touches = d3_eventSource().touches;
return touches ? d3_array(touches).map(function(touch) { return touches ? d3_array(touches).map(function(touch) {
var point = d3_mousePoint(container, touch); var point = d3_mousePoint(container, touch);
point.identifier = touch.identifier; point.identifier = touch.identifier;
return point; return point;
}) : []; }) : [];
}; };
d3.scale = {}; d3.scale = {};
d3.scale.linear = function() { d3.scale.linear = function() {
return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false); return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3.interpolate, false);
}; };
d3.scale.log = function() { d3.scale.log = function() {
return d3_scale_log(d3.scale.linear(), d3_scale_logp); return d3_scale_log(d3.scale.linear(), d3_scale_logp);
}; };
var d3_scale_logFormat = d3.format(".0e"); var d3_scale_logFormat = d3.format(".0e");
d3_scale_logp.pow = function(x) { d3_scale_logp.pow = function(x) {
return Math.pow(10, x); return Math.pow(10, x);
}; };
d3_scale_logn.pow = function(x) { d3_scale_logn.pow = function(x) {
return -Math.pow(10, -x); return -Math.pow(10, -x);
}; };
d3.scale.pow = function() { d3.scale.pow = function() {
return d3_scale_pow(d3.scale.linear(), 1); return d3_scale_pow(d3.scale.linear(), 1);
}; };
d3.scale.sqrt = function() { d3.scale.sqrt = function() {
return d3.scale.pow().exponent(.5); return d3.scale.pow().exponent(.5);
}; };
d3.scale.ordinal = function() { d3.scale.ordinal = function() {
return d3_scale_ordinal([], { return d3_scale_ordinal([], {
t: "range", t: "range",
a: [ [] ] a: [ [] ]
}); });
}; };
d3.scale.category10 = function() { d3.scale.category10 = function() {
return d3.scale.ordinal().range(d3_category10); return d3.scale.ordinal().range(d3_category10);
}; };
d3.scale.category20 = function() { d3.scale.category20 = function() {
return d3.scale.ordinal().range(d3_category20); return d3.scale.ordinal().range(d3_category20);
}; };
d3.scale.category20b = function() { d3.scale.category20b = function() {
return d3.scale.ordinal().range(d3_category20b); return d3.scale.ordinal().range(d3_category20b);
}; };
d3.scale.category20c = function() { d3.scale.category20c = function() {
return d3.scale.ordinal().range(d3_category20c); return d3.scale.ordinal().range(d3_category20c);
}; };
var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ]; var d3_category10 = [ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf" ];
var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ]; var d3_category20 = [ "#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5" ];
var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ]; var d3_category20b = [ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6" ];
var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ]; var d3_category20c = [ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9" ];
d3.scale.quantile = function() { d3.scale.quantile = function() {
return d3_scale_quantile([], []); return d3_scale_quantile([], []);
}; };
d3.scale.quantize = function() { d3.scale.quantize = function() {
return d3_scale_quantize(0, 1, [ 0, 1 ]); return d3_scale_quantize(0, 1, [ 0, 1 ]);
}; };
d3.scale.threshold = function() { d3.scale.threshold = function() {
return d3_scale_threshold([ .5 ], [ 0, 1 ]); return d3_scale_threshold([ .5 ], [ 0, 1 ]);
}; };
d3.scale.identity = function() { d3.scale.identity = function() {
return d3_scale_identity([ 0, 1 ]); return d3_scale_identity([ 0, 1 ]);
}; };
d3.svg = {}; d3.svg = {};
d3.svg.arc = function() { d3.svg.arc = function() {
function arc() { function arc() {
var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0), df = da < Math.PI ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1); var r0 = innerRadius.apply(this, arguments), r1 = outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset, a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset, da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0), df = da < Math.PI ? "0" : "1", c0 = Math.cos(a0), s0 = Math.sin(a0), c1 = Math.cos(a1), s1 = Math.sin(a1);
return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z"; return da >= d3_svg_arcMax ? r0 ? "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "M0," + r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + -r0 + "A" + r0 + "," + r0 + " 0 1,0 0," + r0 + "Z" : "M0," + r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + -r1 + "A" + r1 + "," + r1 + " 0 1,1 0," + r1 + "Z" : r0 ? "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L" + r0 * c1 + "," + r0 * s1 + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0 + "Z" : "M" + r1 * c0 + "," + r1 * s0 + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1 + "L0,0" + "Z";
} }
var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
arc.innerRadius = function(v) { arc.innerRadius = function(v) {
if (!arguments.length) return innerRadius; if (!arguments.length) return innerRadius;
innerRadius = d3_functor(v); innerRadius = d3_functor(v);
return arc; return arc;
}; };
arc.outerRadius = function(v) { arc.outerRadius = function(v) {
if (!arguments.length) return outerRadius; if (!arguments.length) return outerRadius;
outerRadius = d3_functor(v); outerRadius = d3_functor(v);
return arc; return arc;
}; };
arc.startAngle = function(v) { arc.startAngle = function(v) {
if (!arguments.length) return startAngle; if (!arguments.length) return startAngle;
startAngle = d3_functor(v); startAngle = d3_functor(v);
return arc; return arc;
}; };
arc.endAngle = function(v) { arc.endAngle = function(v) {
if (!arguments.length) return endAngle; if (!arguments.length) return endAngle;
endAngle = d3_functor(v); endAngle = d3_functor(v);
return arc; return arc;
}; };
arc.centroid = function() { arc.centroid = function() {
var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset; var r = (innerRadius.apply(this, arguments) + outerRadius.apply(this, arguments)) / 2, a = (startAngle.apply(this, arguments) + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
return [ Math.cos(a) * r, Math.sin(a) * r ]; return [ Math.cos(a) * r, Math.sin(a) * r ];
}; };
return arc; return arc;
}; };
var d3_svg_arcOffset = -Math.PI / 2, d3_svg_arcMax = 2 * Math.PI - 1e-6; var d3_svg_arcOffset = -Math.PI / 2, d3_svg_arcMax = 2 * Math.PI - 1e-6;
d3.svg.line = function() { d3.svg.line = function() {
return d3_svg_line(d3_identity); return d3_svg_line(d3_identity);
}; };
var d3_svg_lineInterpolators = d3.map({ var d3_svg_lineInterpolators = d3.map({
linear: d3_svg_lineLinear, linear: d3_svg_lineLinear,
"linear-closed": d3_svg_lineLinearClosed, "linear-closed": d3_svg_lineLinearClosed,
"step-before": d3_svg_lineStepBefore, "step-before": d3_svg_lineStepBefore,
"step-after": d3_svg_lineStepAfter, "step-after": d3_svg_lineStepAfter,
basis: d3_svg_lineBasis, basis: d3_svg_lineBasis,
"basis-open": d3_svg_lineBasisOpen, "basis-open": d3_svg_lineBasisOpen,
"basis-closed": d3_svg_lineBasisClosed, "basis-closed": d3_svg_lineBasisClosed,
bundle: d3_svg_lineBundle, bundle: d3_svg_lineBundle,
cardinal: d3_svg_lineCardinal, cardinal: d3_svg_lineCardinal,
"cardinal-open": d3_svg_lineCardinalOpen, "cardinal-open": d3_svg_lineCardinalOpen,
"cardinal-closed": d3_svg_lineCardinalClosed, "cardinal-closed": d3_svg_lineCardinalClosed,
monotone: d3_svg_lineMonotone monotone: d3_svg_lineMonotone
}); });
d3_svg_lineInterpolators.forEach(function(key, value) { d3_svg_lineInterpolators.forEach(function(key, value) {
value.key = key; value.key = key;
value.closed = /-closed$/.test(key); value.closed = /-closed$/.test(key);
}); });
var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ]; var d3_svg_lineBasisBezier1 = [ 0, 2 / 3, 1 / 3, 0 ], d3_svg_lineBasisBezier2 = [ 0, 1 / 3, 2 / 3, 0 ], d3_svg_lineBasisBezier3 = [ 0, 1 / 6, 2 / 3, 1 / 6 ];
d3.svg.line.radial = function() { d3.svg.line.radial = function() {
var line = d3_svg_line(d3_svg_lineRadial); var line = d3_svg_line(d3_svg_lineRadial);
line.radius = line.x, delete line.x; line.radius = line.x, delete line.x;
line.angle = line.y, delete line.y; line.angle = line.y, delete line.y;
return line; return line;
}; };
d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter; d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore; d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
d3.svg.area = function() { d3.svg.area = function() {
return d3_svg_area(d3_identity); return d3_svg_area(d3_identity);
}; };
d3.svg.area.radial = function() { d3.svg.area.radial = function() {
var area = d3_svg_area(d3_svg_lineRadial); var area = d3_svg_area(d3_svg_lineRadial);
area.radius = area.x, delete area.x; area.radius = area.x, delete area.x;
area.innerRadius = area.x0, delete area.x0; area.innerRadius = area.x0, delete area.x0;
area.outerRadius = area.x1, delete area.x1; area.outerRadius = area.x1, delete area.x1;
area.angle = area.y, delete area.y; area.angle = area.y, delete area.y;
area.startAngle = area.y0, delete area.y0; area.startAngle = area.y0, delete area.y0;
area.endAngle = area.y1, delete area.y1; area.endAngle = area.y1, delete area.y1;
return area; return area;
}; };
d3.svg.chord = function() { d3.svg.chord = function() {
function chord(d, i) { function chord(d, i) {
var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i); var s = subgroup(this, source, d, i), t = subgroup(this, target, d, i);
return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z"; return "M" + s.p0 + arc(s.r, s.p1, s.a1 - s.a0) + (equals(s, t) ? curve(s.r, s.p1, s.r, s.p0) : curve(s.r, s.p1, t.r, t.p0) + arc(t.r, t.p1, t.a1 - t.a0) + curve(t.r, t.p1, s.r, s.p0)) + "Z";
} }
function subgroup(self, f, d, i) { function subgroup(self, f, d, i) {
var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset; var subgroup = f.call(self, d, i), r = radius.call(self, subgroup, i), a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset, a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
return { return {
r: r, r: r,
a0: a0, a0: a0,
a1: a1, a1: a1,
p0: [ r * Math.cos(a0), r * Math.sin(a0) ], p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
p1: [ r * Math.cos(a1), r * Math.sin(a1) ] p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
}; };
} }
function equals(a, b) { function equals(a, b) {
return a.a0 == b.a0 && a.a1 == b.a1; return a.a0 == b.a0 && a.a1 == b.a1;
} }
function arc(r, p, a) { function arc(r, p, a) {
return "A" + r + "," + r + " 0 " + +(a > Math.PI) + ",1 " + p; return "A" + r + "," + r + " 0 " + +(a > Math.PI) + ",1 " + p;
} }
function curve(r0, p0, r1, p1) { function curve(r0, p0, r1, p1) {
return "Q 0,0 " + p1; return "Q 0,0 " + p1;
} }
var source = d3_svg_chordSource, target = d3_svg_chordTarget, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle; var source = d3_svg_chordSource, target = d3_svg_chordTarget, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
chord.radius = function(v) { chord.radius = function(v) {
if (!arguments.length) return radius; if (!arguments.length) return radius;
radius = d3_functor(v); radius = d3_functor(v);
return chord; return chord;
}; };
chord.source = function(v) { chord.source = function(v) {
if (!arguments.length) return source; if (!arguments.length) return source;
source = d3_functor(v); source = d3_functor(v);
return chord; return chord;
}; };
chord.target = function(v) { chord.target = function(v) {
if (!arguments.length) return target; if (!arguments.length) return target;
target = d3_functor(v); target = d3_functor(v);
return chord; return chord;
}; };
chord.startAngle = function(v) { chord.startAngle = function(v) {
if (!arguments.length) return startAngle; if (!arguments.length) return startAngle;
startAngle = d3_functor(v); startAngle = d3_functor(v);
return chord; return chord;
}; };
chord.endAngle = function(v) { chord.endAngle = function(v) {
if (!arguments.length) return endAngle; if (!arguments.length) return endAngle;
endAngle = d3_functor(v); endAngle = d3_functor(v);
return chord; return chord;
}; };
return chord; return chord;
}; };
d3.svg.diagonal = function() { d3.svg.diagonal = function() {
function diagonal(d, i) { function diagonal(d, i) {
var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, { var p0 = source.call(this, d, i), p3 = target.call(this, d, i), m = (p0.y + p3.y) / 2, p = [ p0, {
x: p0.x, x: p0.x,
y: m y: m
}, { }, {
x: p3.x, x: p3.x,
y: m y: m
}, p3 ]; }, p3 ];
p = p.map(projection); p = p.map(projection);
return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3]; return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
} }
var source = d3_svg_chordSource, target = d3_svg_chordTarget, projection = d3_svg_diagonalProjection; var source = d3_svg_chordSource, target = d3_svg_chordTarget, projection = d3_svg_diagonalProjection;
diagonal.source = function(x) { diagonal.source = function(x) {
if (!arguments.length) return source; if (!arguments.length) return source;
source = d3_functor(x); source = d3_functor(x);
return diagonal; return diagonal;
}; };
diagonal.target = function(x) { diagonal.target = function(x) {
if (!arguments.length) return target; if (!arguments.length) return target;
target = d3_functor(x); target = d3_functor(x);
return diagonal; return diagonal;
}; };
diagonal.projection = function(x) { diagonal.projection = function(x) {
if (!arguments.length) return projection; if (!arguments.length) return projection;
projection = x; projection = x;
return diagonal; return diagonal;
}; };
return diagonal; return diagonal;
}; };
d3.svg.diagonal.radial = function() { d3.svg.diagonal.radial = function() {
var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection; var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
diagonal.projection = function(x) { diagonal.projection = function(x) {
return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection; return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
}; };
return diagonal; return diagonal;
}; };
d3.svg.mouse = d3.mouse; d3.svg.mouse = d3.mouse;
d3.svg.touches = d3.touches; d3.svg.touches = d3.touches;
d3.svg.symbol = function() { d3.svg.symbol = function() {
function symbol(d, i) { function symbol(d, i) {
return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i)); return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
} }
var type = d3_svg_symbolType, size = d3_svg_symbolSize; var type = d3_svg_symbolType, size = d3_svg_symbolSize;
symbol.type = function(x) { symbol.type = function(x) {
if (!arguments.length) return type; if (!arguments.length) return type;
type = d3_functor(x); type = d3_functor(x);
return symbol; return symbol;
}; };
symbol.size = function(x) { symbol.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = d3_functor(x); size = d3_functor(x);
return symbol; return symbol;
}; };
return symbol; return symbol;
}; };
var d3_svg_symbols = d3.map({ var d3_svg_symbols = d3.map({
circle: d3_svg_symbolCircle, circle: d3_svg_symbolCircle,
cross: function(size) { cross: function(size) {
var r = Math.sqrt(size / 5) / 2; var r = Math.sqrt(size / 5) / 2;
return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z"; return "M" + -3 * r + "," + -r + "H" + -r + "V" + -3 * r + "H" + r + "V" + -r + "H" + 3 * r + "V" + r + "H" + r + "V" + 3 * r + "H" + -r + "V" + r + "H" + -3 * r + "Z";
}, },
diamond: function(size) { diamond: function(size) {
var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30; var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)), rx = ry * d3_svg_symbolTan30;
return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z"; return "M0," + -ry + "L" + rx + ",0" + " 0," + ry + " " + -rx + ",0" + "Z";
}, },
square: function(size) { square: function(size) {
var r = Math.sqrt(size) / 2; var r = Math.sqrt(size) / 2;
return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z"; return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
}, },
"triangle-down": function(size) { "triangle-down": function(size) {
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z"; return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
}, },
"triangle-up": function(size) { "triangle-up": function(size) {
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2; var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z"; return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
} }
}); });
d3.svg.symbolTypes = d3_svg_symbols.keys(); d3.svg.symbolTypes = d3_svg_symbols.keys();
var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180); var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180);
d3.svg.axis = function() { d3.svg.axis = function() {
function axis(g) { function axis(g) {
g.each(function() { g.each(function() {
var g = d3.select(this); var g = d3.select(this);
var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_; var ticks = tickValues == null ? scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain() : tickValues, tickFormat = tickFormat_ == null ? scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments_) : String : tickFormat_;
var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1); var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide), subtick = g.selectAll(".minor").data(subticks, String), subtickEnter = subtick.enter().insert("line", "g").attr("class", "tick minor").style("opacity", 1e-6), subtickExit = d3.transition(subtick.exit()).style("opacity", 1e-6).remove(), subtickUpdate = d3.transition(subtick).style("opacity", 1);
var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform; var tick = g.selectAll("g").data(ticks, String), tickEnter = tick.enter().insert("g", "path").style("opacity", 1e-6), tickExit = d3.transition(tick.exit()).style("opacity", 1e-6).remove(), tickUpdate = d3.transition(tick).style("opacity", 1), tickTransform;
var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathEnter = path.enter().append("path").attr("class", "domain"), pathUpdate = d3.transition(path); var range = d3_scaleRange(scale), path = g.selectAll(".domain").data([ 0 ]), pathEnter = path.enter().append("path").attr("class", "domain"), pathUpdate = d3.transition(path);
var scale1 = scale.copy(), scale0 = this.__chart__ || scale1; var scale1 = scale.copy(), scale0 = this.__chart__ || scale1;
this.__chart__ = scale1; this.__chart__ = scale1;
tickEnter.append("line").attr("class", "tick"); tickEnter.append("line").attr("class", "tick");
tickEnter.append("text"); tickEnter.append("text");
var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text"); var lineEnter = tickEnter.select("line"), lineUpdate = tickUpdate.select("line"), text = tick.select("text").text(tickFormat), textEnter = tickEnter.select("text"), textUpdate = tickUpdate.select("text");
switch (orient) { switch (orient) {
case "bottom": case "bottom":
{ {
tickTransform = d3_svg_axisX; tickTransform = d3_svg_axisX;
subtickEnter.attr("y2", tickMinorSize); subtickEnter.attr("y2", tickMinorSize);
subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize); subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
lineEnter.attr("y2", tickMajorSize); lineEnter.attr("y2", tickMajorSize);
textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding); textEnter.attr("y", Math.max(tickMajorSize, 0) + tickPadding);
lineUpdate.attr("x2", 0).attr("y2", tickMajorSize); lineUpdate.attr("x2", 0).attr("y2", tickMajorSize);
textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding); textUpdate.attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding);
text.attr("dy", ".71em").attr("text-anchor", "middle"); text.attr("dy", ".71em").attr("text-anchor", "middle");
pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize); pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
break; break;
} }
case "top": case "top":
{ {
tickTransform = d3_svg_axisX; tickTransform = d3_svg_axisX;
subtickEnter.attr("y2", -tickMinorSize); subtickEnter.attr("y2", -tickMinorSize);
subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize); subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
lineEnter.attr("y2", -tickMajorSize); lineEnter.attr("y2", -tickMajorSize);
textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); textEnter.attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize); lineUpdate.attr("x2", 0).attr("y2", -tickMajorSize);
textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)); textUpdate.attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding));
text.attr("dy", "0em").attr("text-anchor", "middle"); text.attr("dy", "0em").attr("text-anchor", "middle");
pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize); pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
break; break;
} }
case "left": case "left":
{ {
tickTransform = d3_svg_axisY; tickTransform = d3_svg_axisY;
subtickEnter.attr("x2", -tickMinorSize); subtickEnter.attr("x2", -tickMinorSize);
subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0); subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
lineEnter.attr("x2", -tickMajorSize); lineEnter.attr("x2", -tickMajorSize);
textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)); textEnter.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding));
lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0); lineUpdate.attr("x2", -tickMajorSize).attr("y2", 0);
textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0); textUpdate.attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0);
text.attr("dy", ".32em").attr("text-anchor", "end"); text.attr("dy", ".32em").attr("text-anchor", "end");
pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize); pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
break; break;
} }
case "right": case "right":
{ {
tickTransform = d3_svg_axisY; tickTransform = d3_svg_axisY;
subtickEnter.attr("x2", tickMinorSize); subtickEnter.attr("x2", tickMinorSize);
subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0); subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
lineEnter.attr("x2", tickMajorSize); lineEnter.attr("x2", tickMajorSize);
textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding); textEnter.attr("x", Math.max(tickMajorSize, 0) + tickPadding);
lineUpdate.attr("x2", tickMajorSize).attr("y2", 0); lineUpdate.attr("x2", tickMajorSize).attr("y2", 0);
textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0); textUpdate.attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0);
text.attr("dy", ".32em").attr("text-anchor", "start"); text.attr("dy", ".32em").attr("text-anchor", "start");
pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize); pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
break; break;
} }
} }
if (scale.ticks) { if (scale.ticks) {
tickEnter.call(tickTransform, scale0); tickEnter.call(tickTransform, scale0);
tickUpdate.call(tickTransform, scale1); tickUpdate.call(tickTransform, scale1);
tickExit.call(tickTransform, scale1); tickExit.call(tickTransform, scale1);
subtickEnter.call(tickTransform, scale0); subtickEnter.call(tickTransform, scale0);
subtickUpdate.call(tickTransform, scale1); subtickUpdate.call(tickTransform, scale1);
subtickExit.call(tickTransform, scale1); subtickExit.call(tickTransform, scale1);
} else { } else {
var dx = scale1.rangeBand() / 2, x = function(d) { var dx = scale1.rangeBand() / 2, x = function(d) {
return scale1(d) + dx; return scale1(d) + dx;
}; };
tickEnter.call(tickTransform, x); tickEnter.call(tickTransform, x);
tickUpdate.call(tickTransform, x); tickUpdate.call(tickTransform, x);
} }
}); });
} }
var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0; var scale = d3.scale.linear(), orient = "bottom", tickMajorSize = 6, tickMinorSize = 6, tickEndSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_, tickSubdivide = 0;
axis.scale = function(x) { axis.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = x; scale = x;
return axis; return axis;
}; };
axis.orient = function(x) { axis.orient = function(x) {
if (!arguments.length) return orient; if (!arguments.length) return orient;
orient = x; orient = x;
return axis; return axis;
}; };
axis.ticks = function() { axis.ticks = function() {
if (!arguments.length) return tickArguments_; if (!arguments.length) return tickArguments_;
tickArguments_ = arguments; tickArguments_ = arguments;
return axis; return axis;
}; };
axis.tickValues = function(x) { axis.tickValues = function(x) {
if (!arguments.length) return tickValues; if (!arguments.length) return tickValues;
tickValues = x; tickValues = x;
return axis; return axis;
}; };
axis.tickFormat = function(x) { axis.tickFormat = function(x) {
if (!arguments.length) return tickFormat_; if (!arguments.length) return tickFormat_;
tickFormat_ = x; tickFormat_ = x;
return axis; return axis;
}; };
axis.tickSize = function(x, y, z) { axis.tickSize = function(x, y, z) {
if (!arguments.length) return tickMajorSize; if (!arguments.length) return tickMajorSize;
var n = arguments.length - 1; var n = arguments.length - 1;
tickMajorSize = +x; tickMajorSize = +x;
tickMinorSize = n > 1 ? +y : tickMajorSize; tickMinorSize = n > 1 ? +y : tickMajorSize;
tickEndSize = n > 0 ? +arguments[n] : tickMajorSize; tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
return axis; return axis;
}; };
axis.tickPadding = function(x) { axis.tickPadding = function(x) {
if (!arguments.length) return tickPadding; if (!arguments.length) return tickPadding;
tickPadding = +x; tickPadding = +x;
return axis; return axis;
}; };
axis.tickSubdivide = function(x) { axis.tickSubdivide = function(x) {
if (!arguments.length) return tickSubdivide; if (!arguments.length) return tickSubdivide;
tickSubdivide = +x; tickSubdivide = +x;
return axis; return axis;
}; };
return axis; return axis;
}; };
d3.svg.brush = function() { d3.svg.brush = function() {
function brush(g) { function brush(g) {
g.each(function() { g.each(function() {
var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e; var g = d3.select(this), bg = g.selectAll(".background").data([ 0 ]), fg = g.selectAll(".extent").data([ 0 ]), tz = g.selectAll(".resize").data(resizes, String), e;
g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart); g.style("pointer-events", "all").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair"); bg.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
fg.enter().append("rect").attr("class", "extent").style("cursor", "move"); fg.enter().append("rect").attr("class", "extent").style("cursor", "move");
tz.enter().append("g").attr("class", function(d) { tz.enter().append("g").attr("class", function(d) {
return "resize " + d; return "resize " + d;
}).style("cursor", function(d) { }).style("cursor", function(d) {
return d3_svg_brushCursor[d]; return d3_svg_brushCursor[d];
}).append("rect").attr("x", function(d) { }).append("rect").attr("x", function(d) {
return /[ew]$/.test(d) ? -3 : null; return /[ew]$/.test(d) ? -3 : null;
}).attr("y", function(d) { }).attr("y", function(d) {
return /^[ns]/.test(d) ? -3 : null; return /^[ns]/.test(d) ? -3 : null;
}).attr("width", 6).attr("height", 6).style("visibility", "hidden"); }).attr("width", 6).attr("height", 6).style("visibility", "hidden");
tz.style("display", brush.empty() ? "none" : null); tz.style("display", brush.empty() ? "none" : null);
tz.exit().remove(); tz.exit().remove();
if (x) { if (x) {
e = d3_scaleRange(x); e = d3_scaleRange(x);
bg.attr("x", e[0]).attr("width", e[1] - e[0]); bg.attr("x", e[0]).attr("width", e[1] - e[0]);
redrawX(g); redrawX(g);
} }
if (y) { if (y) {
e = d3_scaleRange(y); e = d3_scaleRange(y);
bg.attr("y", e[0]).attr("height", e[1] - e[0]); bg.attr("y", e[0]).attr("height", e[1] - e[0]);
redrawY(g); redrawY(g);
} }
redraw(g); redraw(g);
}); });
} }
function redraw(g) { function redraw(g) {
g.selectAll(".resize").attr("transform", function(d) { g.selectAll(".resize").attr("transform", function(d) {
return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")"; return "translate(" + extent[+/e$/.test(d)][0] + "," + extent[+/^s/.test(d)][1] + ")";
}); });
} }
function redrawX(g) { function redrawX(g) {
g.select(".extent").attr("x", extent[0][0]); g.select(".extent").attr("x", extent[0][0]);
g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]); g.selectAll(".extent,.n>rect,.s>rect").attr("width", extent[1][0] - extent[0][0]);
} }
function redrawY(g) { function redrawY(g) {
g.select(".extent").attr("y", extent[0][1]); g.select(".extent").attr("y", extent[0][1]);
g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]); g.selectAll(".extent,.e>rect,.w>rect").attr("height", extent[1][1] - extent[0][1]);
} }
function brushstart() { function brushstart() {
function mouse() { function mouse() {
var touches = d3.event.changedTouches; var touches = d3.event.changedTouches;
return touches ? d3.touches(target, touches)[0] : d3.mouse(target); return touches ? d3.touches(target, touches)[0] : d3.mouse(target);
} }
function keydown() { function keydown() {
if (d3.event.keyCode == 32) { if (d3.event.keyCode == 32) {
if (!dragging) { if (!dragging) {
center = null; center = null;
origin[0] -= extent[1][0]; origin[0] -= extent[1][0];
origin[1] -= extent[1][1]; origin[1] -= extent[1][1];
dragging = 2; dragging = 2;
} }
d3_eventCancel(); d3_eventCancel();
} }
} }
function keyup() { function keyup() {
if (d3.event.keyCode == 32 && dragging == 2) { if (d3.event.keyCode == 32 && dragging == 2) {
origin[0] += extent[1][0]; origin[0] += extent[1][0];
origin[1] += extent[1][1]; origin[1] += extent[1][1];
dragging = 0; dragging = 0;
d3_eventCancel(); d3_eventCancel();
} }
} }
function brushmove() { function brushmove() {
var point = mouse(), moved = false; var point = mouse(), moved = false;
if (offset) { if (offset) {
point[0] += offset[0]; point[0] += offset[0];
point[1] += offset[1]; point[1] += offset[1];
} }
if (!dragging) { if (!dragging) {
if (d3.event.altKey) { if (d3.event.altKey) {
if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ]; if (!center) center = [ (extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2 ];
origin[0] = extent[+(point[0] < center[0])][0]; origin[0] = extent[+(point[0] < center[0])][0];
origin[1] = extent[+(point[1] < center[1])][1]; origin[1] = extent[+(point[1] < center[1])][1];
} else center = null; } else center = null;
} }
if (resizingX && move1(point, x, 0)) { if (resizingX && move1(point, x, 0)) {
redrawX(g); redrawX(g);
moved = true; moved = true;
} }
if (resizingY && move1(point, y, 1)) { if (resizingY && move1(point, y, 1)) {
redrawY(g); redrawY(g);
moved = true; moved = true;
} }
if (moved) { if (moved) {
redraw(g); redraw(g);
event_({ event_({
type: "brush", type: "brush",
mode: dragging ? "move" : "resize" mode: dragging ? "move" : "resize"
}); });
} }
} }
function move1(point, scale, i) { function move1(point, scale, i) {
var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max; var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], size = extent[1][i] - extent[0][i], min, max;
if (dragging) { if (dragging) {
r0 -= position; r0 -= position;
r1 -= size + position; r1 -= size + position;
} }
min = Math.max(r0, Math.min(r1, point[i])); min = Math.max(r0, Math.min(r1, point[i]));
if (dragging) { if (dragging) {
max = (min += position) + size; max = (min += position) + size;
} else { } else {
if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min)); if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
if (position < min) { if (position < min) {
max = min; max = min;
min = position; min = position;
} else { } else {
max = position; max = position;
} }
} }
if (extent[0][i] !== min || extent[1][i] !== max) { if (extent[0][i] !== min || extent[1][i] !== max) {
extentDomain = null; extentDomain = null;
extent[0][i] = min; extent[0][i] = min;
extent[1][i] = max; extent[1][i] = max;
return true; return true;
} }
} }
function brushend() { function brushend() {
brushmove(); brushmove();
g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null); g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : null);
d3.select("body").style("cursor", null); d3.select("body").style("cursor", null);
w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null); w.on("mousemove.brush", null).on("mouseup.brush", null).on("touchmove.brush", null).on("touchend.brush", null).on("keydown.brush", null).on("keyup.brush", null);
event_({ event_({
type: "brushend" type: "brushend"
}); });
d3_eventCancel(); d3_eventCancel();
} }
var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset; var target = this, eventTarget = d3.select(d3.event.target), event_ = event.of(target, arguments), g = d3.select(target), resizing = eventTarget.datum(), resizingX = !/^(n|s)$/.test(resizing) && x, resizingY = !/^(e|w)$/.test(resizing) && y, dragging = eventTarget.classed("extent"), center, origin = mouse(), offset;
var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup); var w = d3.select(window).on("mousemove.brush", brushmove).on("mouseup.brush", brushend).on("touchmove.brush", brushmove).on("touchend.brush", brushend).on("keydown.brush", keydown).on("keyup.brush", keyup);
if (dragging) { if (dragging) {
origin[0] = extent[0][0] - origin[0]; origin[0] = extent[0][0] - origin[0];
origin[1] = extent[0][1] - origin[1]; origin[1] = extent[0][1] - origin[1];
} else if (resizing) { } else if (resizing) {
var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing); var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ]; offset = [ extent[1 - ex][0] - origin[0], extent[1 - ey][1] - origin[1] ];
origin[0] = extent[ex][0]; origin[0] = extent[ex][0];
origin[1] = extent[ey][1]; origin[1] = extent[ey][1];
} else if (d3.event.altKey) center = origin.slice(); } else if (d3.event.altKey) center = origin.slice();
g.style("pointer-events", "none").selectAll(".resize").style("display", null); g.style("pointer-events", "none").selectAll(".resize").style("display", null);
d3.select("body").style("cursor", eventTarget.style("cursor")); d3.select("body").style("cursor", eventTarget.style("cursor"));
event_({ event_({
type: "brushstart" type: "brushstart"
}); });
brushmove(); brushmove();
d3_eventCancel(); d3_eventCancel();
} }
var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain; var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, resizes = d3_svg_brushResizes[0], extent = [ [ 0, 0 ], [ 0, 0 ] ], extentDomain;
brush.x = function(z) { brush.x = function(z) {
if (!arguments.length) return x; if (!arguments.length) return x;
x = z; x = z;
resizes = d3_svg_brushResizes[!x << 1 | !y]; resizes = d3_svg_brushResizes[!x << 1 | !y];
return brush; return brush;
}; };
brush.y = function(z) { brush.y = function(z) {
if (!arguments.length) return y; if (!arguments.length) return y;
y = z; y = z;
resizes = d3_svg_brushResizes[!x << 1 | !y]; resizes = d3_svg_brushResizes[!x << 1 | !y];
return brush; return brush;
}; };
brush.extent = function(z) { brush.extent = function(z) {
var x0, x1, y0, y1, t; var x0, x1, y0, y1, t;
if (!arguments.length) { if (!arguments.length) {
z = extentDomain || extent; z = extentDomain || extent;
if (x) { if (x) {
x0 = z[0][0], x1 = z[1][0]; x0 = z[0][0], x1 = z[1][0];
if (!extentDomain) { if (!extentDomain) {
x0 = extent[0][0], x1 = extent[1][0]; x0 = extent[0][0], x1 = extent[1][0];
if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1); if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
if (x1 < x0) t = x0, x0 = x1, x1 = t; if (x1 < x0) t = x0, x0 = x1, x1 = t;
} }
} }
if (y) { if (y) {
y0 = z[0][1], y1 = z[1][1]; y0 = z[0][1], y1 = z[1][1];
if (!extentDomain) { if (!extentDomain) {
y0 = extent[0][1], y1 = extent[1][1]; y0 = extent[0][1], y1 = extent[1][1];
if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1); if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
if (y1 < y0) t = y0, y0 = y1, y1 = t; if (y1 < y0) t = y0, y0 = y1, y1 = t;
} }
} }
return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ]; return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
} }
extentDomain = [ [ 0, 0 ], [ 0, 0 ] ]; extentDomain = [ [ 0, 0 ], [ 0, 0 ] ];
if (x) { if (x) {
x0 = z[0], x1 = z[1]; x0 = z[0], x1 = z[1];
if (y) x0 = x0[0], x1 = x1[0]; if (y) x0 = x0[0], x1 = x1[0];
extentDomain[0][0] = x0, extentDomain[1][0] = x1; extentDomain[0][0] = x0, extentDomain[1][0] = x1;
if (x.invert) x0 = x(x0), x1 = x(x1); if (x.invert) x0 = x(x0), x1 = x(x1);
if (x1 < x0) t = x0, x0 = x1, x1 = t; if (x1 < x0) t = x0, x0 = x1, x1 = t;
extent[0][0] = x0 | 0, extent[1][0] = x1 | 0; extent[0][0] = x0 | 0, extent[1][0] = x1 | 0;
} }
if (y) { if (y) {
y0 = z[0], y1 = z[1]; y0 = z[0], y1 = z[1];
if (x) y0 = y0[1], y1 = y1[1]; if (x) y0 = y0[1], y1 = y1[1];
extentDomain[0][1] = y0, extentDomain[1][1] = y1; extentDomain[0][1] = y0, extentDomain[1][1] = y1;
if (y.invert) y0 = y(y0), y1 = y(y1); if (y.invert) y0 = y(y0), y1 = y(y1);
if (y1 < y0) t = y0, y0 = y1, y1 = t; if (y1 < y0) t = y0, y0 = y1, y1 = t;
extent[0][1] = y0 | 0, extent[1][1] = y1 | 0; extent[0][1] = y0 | 0, extent[1][1] = y1 | 0;
} }
return brush; return brush;
}; };
brush.clear = function() { brush.clear = function() {
extentDomain = null; extentDomain = null;
extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0; extent[0][0] = extent[0][1] = extent[1][0] = extent[1][1] = 0;
return brush; return brush;
}; };
brush.empty = function() { brush.empty = function() {
return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1]; return x && extent[0][0] === extent[1][0] || y && extent[0][1] === extent[1][1];
}; };
return d3.rebind(brush, event, "on"); return d3.rebind(brush, event, "on");
}; };
var d3_svg_brushCursor = { var d3_svg_brushCursor = {
n: "ns-resize", n: "ns-resize",
e: "ew-resize", e: "ew-resize",
s: "ns-resize", s: "ns-resize",
w: "ew-resize", w: "ew-resize",
nw: "nwse-resize", nw: "nwse-resize",
ne: "nesw-resize", ne: "nesw-resize",
se: "nwse-resize", se: "nwse-resize",
sw: "nesw-resize" sw: "nesw-resize"
}; };
var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ]; var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
d3.behavior = {}; d3.behavior = {};
d3.behavior.drag = function() { d3.behavior.drag = function() {
function drag() { function drag() {
this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown); this.on("mousedown.drag", mousedown).on("touchstart.drag", mousedown);
} }
function mousedown() { function mousedown() {
function point() { function point() {
var p = target.parentNode; var p = target.parentNode;
return touchId ? d3.touches(p).filter(function(p) { return touchId ? d3.touches(p).filter(function(p) {
return p.identifier === touchId; return p.identifier === touchId;
})[0] : d3.mouse(p); })[0] : d3.mouse(p);
} }
function dragmove() { function dragmove() {
if (!target.parentNode) return dragend(); if (!target.parentNode) return dragend();
var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1]; var p = point(), dx = p[0] - origin_[0], dy = p[1] - origin_[1];
moved |= dx | dy; moved |= dx | dy;
origin_ = p; origin_ = p;
d3_eventCancel(); d3_eventCancel();
event_({ event_({
type: "drag", type: "drag",
x: p[0] + offset[0], x: p[0] + offset[0],
y: p[1] + offset[1], y: p[1] + offset[1],
dx: dx, dx: dx,
dy: dy dy: dy
}); });
} }
function dragend() { function dragend() {
event_({ event_({
type: "dragend" type: "dragend"
}); });
if (moved) { if (moved) {
d3_eventCancel(); d3_eventCancel();
if (d3.event.target === eventTarget) w.on("click.drag", click, true); if (d3.event.target === eventTarget) w.on("click.drag", click, true);
} }
w.on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", null); w.on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", null).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", null);
} }
function click() { function click() {
d3_eventCancel(); d3_eventCancel();
w.on("click.drag", null); w.on("click.drag", null);
} }
var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches && d3.event.changedTouches[0].identifier, offset, origin_ = point(), moved = 0; var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, touchId = d3.event.touches && d3.event.changedTouches[0].identifier, offset, origin_ = point(), moved = 0;
var w = d3.select(window).on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true); var w = d3.select(window).on(touchId ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove).on(touchId ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
if (origin) { if (origin) {
offset = origin.apply(target, arguments); offset = origin.apply(target, arguments);
offset = [ offset.x - origin_[0], offset.y - origin_[1] ]; offset = [ offset.x - origin_[0], offset.y - origin_[1] ];
} else { } else {
offset = [ 0, 0 ]; offset = [ 0, 0 ];
} }
if (!touchId) d3_eventCancel(); if (!touchId) d3_eventCancel();
event_({ event_({
type: "dragstart" type: "dragstart"
}); });
} }
var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null; var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null;
drag.origin = function(x) { drag.origin = function(x) {
if (!arguments.length) return origin; if (!arguments.length) return origin;
origin = x; origin = x;
return drag; return drag;
}; };
return d3.rebind(drag, event, "on"); return d3.rebind(drag, event, "on");
}; };
d3.behavior.zoom = function() { d3.behavior.zoom = function() {
function zoom() { function zoom() {
this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart); this.on("mousedown.zoom", mousedown).on("mousewheel.zoom", mousewheel).on("mousemove.zoom", mousemove).on("DOMMouseScroll.zoom", mousewheel).on("dblclick.zoom", dblclick).on("touchstart.zoom", touchstart).on("touchmove.zoom", touchmove).on("touchend.zoom", touchstart);
} }
function location(p) { function location(p) {
return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ]; return [ (p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale ];
} }
function point(l) { function point(l) {
return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ]; return [ l[0] * scale + translate[0], l[1] * scale + translate[1] ];
} }
function scaleTo(s) { function scaleTo(s) {
scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); scale = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
} }
function translateTo(p, l) { function translateTo(p, l) {
l = point(l); l = point(l);
translate[0] += p[0] - l[0]; translate[0] += p[0] - l[0];
translate[1] += p[1] - l[1]; translate[1] += p[1] - l[1];
} }
function dispatch(event) { function dispatch(event) {
if (x1) x1.domain(x0.range().map(function(x) { if (x1) x1.domain(x0.range().map(function(x) {
return (x - translate[0]) / scale; return (x - translate[0]) / scale;
}).map(x0.invert)); }).map(x0.invert));
if (y1) y1.domain(y0.range().map(function(y) { if (y1) y1.domain(y0.range().map(function(y) {
return (y - translate[1]) / scale; return (y - translate[1]) / scale;
}).map(y0.invert)); }).map(y0.invert));
d3.event.preventDefault(); d3.event.preventDefault();
event({ event({
type: "zoom", type: "zoom",
scale: scale, scale: scale,
translate: translate translate: translate
}); });
} }
function mousedown() { function mousedown() {
function mousemove() { function mousemove() {
moved = 1; moved = 1;
translateTo(d3.mouse(target), l); translateTo(d3.mouse(target), l);
dispatch(event_); dispatch(event_);
} }
function mouseup() { function mouseup() {
if (moved) d3_eventCancel(); if (moved) d3_eventCancel();
w.on("mousemove.zoom", null).on("mouseup.zoom", null); w.on("mousemove.zoom", null).on("mouseup.zoom", null);
if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true); if (moved && d3.event.target === eventTarget) w.on("click.zoom", click, true);
} }
function click() { function click() {
d3_eventCancel(); d3_eventCancel();
w.on("click.zoom", null); w.on("click.zoom", null);
} }
var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target)); var target = this, event_ = event.of(target, arguments), eventTarget = d3.event.target, moved = 0, w = d3.select(window).on("mousemove.zoom", mousemove).on("mouseup.zoom", mouseup), l = location(d3.mouse(target));
window.focus(); window.focus();
d3_eventCancel(); d3_eventCancel();
} }
function mousewheel() { function mousewheel() {
if (!translate0) translate0 = location(d3.mouse(this)); if (!translate0) translate0 = location(d3.mouse(this));
scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale); scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * scale);
translateTo(d3.mouse(this), translate0); translateTo(d3.mouse(this), translate0);
dispatch(event.of(this, arguments)); dispatch(event.of(this, arguments));
} }
function mousemove() { function mousemove() {
translate0 = null; translate0 = null;
} }
function dblclick() { function dblclick() {
var p = d3.mouse(this), l = location(p); var p = d3.mouse(this), l = location(p);
scaleTo(d3.event.shiftKey ? scale / 2 : scale * 2); scaleTo(d3.event.shiftKey ? scale / 2 : scale * 2);
translateTo(p, l); translateTo(p, l);
dispatch(event.of(this, arguments)); dispatch(event.of(this, arguments));
} }
function touchstart() { function touchstart() {
var touches = d3.touches(this), now = Date.now(); var touches = d3.touches(this), now = Date.now();
scale0 = scale; scale0 = scale;
translate0 = {}; translate0 = {};
touches.forEach(function(t) { touches.forEach(function(t) {
translate0[t.identifier] = location(t); translate0[t.identifier] = location(t);
}); });
d3_eventCancel(); d3_eventCancel();
if (touches.length === 1) { if (touches.length === 1) {
if (now - touchtime < 500) { if (now - touchtime < 500) {
var p = touches[0], l = location(touches[0]); var p = touches[0], l = location(touches[0]);
scaleTo(scale * 2); scaleTo(scale * 2);
translateTo(p, l); translateTo(p, l);
dispatch(event.of(this, arguments)); dispatch(event.of(this, arguments));
} }
touchtime = now; touchtime = now;
} }
} }
function touchmove() { function touchmove() {
var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier]; var touches = d3.touches(this), p0 = touches[0], l0 = translate0[p0.identifier];
if (p1 = touches[1]) { if (p1 = touches[1]) {
var p1, l1 = translate0[p1.identifier]; var p1, l1 = translate0[p1.identifier];
p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ]; p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ]; l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
scaleTo(d3.event.scale * scale0); scaleTo(d3.event.scale * scale0);
} }
translateTo(p0, l0); translateTo(p0, l0);
touchtime = null; touchtime = null;
dispatch(event.of(this, arguments)); dispatch(event.of(this, arguments));
} }
var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime; var translate = [ 0, 0 ], translate0, scale = 1, scale0, scaleExtent = d3_behavior_zoomInfinity, event = d3_eventDispatch(zoom, "zoom"), x0, x1, y0, y1, touchtime;
zoom.translate = function(x) { zoom.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = x.map(Number); translate = x.map(Number);
return zoom; return zoom;
}; };
zoom.scale = function(x) { zoom.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return zoom; return zoom;
}; };
zoom.scaleExtent = function(x) { zoom.scaleExtent = function(x) {
if (!arguments.length) return scaleExtent; if (!arguments.length) return scaleExtent;
scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number); scaleExtent = x == null ? d3_behavior_zoomInfinity : x.map(Number);
return zoom; return zoom;
}; };
zoom.x = function(z) { zoom.x = function(z) {
if (!arguments.length) return x1; if (!arguments.length) return x1;
x1 = z; x1 = z;
x0 = z.copy(); x0 = z.copy();
return zoom; return zoom;
}; };
zoom.y = function(z) { zoom.y = function(z) {
if (!arguments.length) return y1; if (!arguments.length) return y1;
y1 = z; y1 = z;
y0 = z.copy(); y0 = z.copy();
return zoom; return zoom;
}; };
return d3.rebind(zoom, event, "on"); return d3.rebind(zoom, event, "on");
}; };
var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ]; var d3_behavior_zoomDiv, d3_behavior_zoomInfinity = [ 0, Infinity ];
d3.layout = {}; d3.layout = {};
d3.layout.bundle = function() { d3.layout.bundle = function() {
return function(links) { return function(links) {
var paths = [], i = -1, n = links.length; var paths = [], i = -1, n = links.length;
while (++i < n) paths.push(d3_layout_bundlePath(links[i])); while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
return paths; return paths;
}; };
}; };
d3.layout.chord = function() { d3.layout.chord = function() {
function relayout() { function relayout() {
var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j; var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
chords = []; chords = [];
groups = []; groups = [];
k = 0, i = -1; k = 0, i = -1;
while (++i < n) { while (++i < n) {
x = 0, j = -1; x = 0, j = -1;
while (++j < n) { while (++j < n) {
x += matrix[i][j]; x += matrix[i][j];
} }
groupSums.push(x); groupSums.push(x);
subgroupIndex.push(d3.range(n)); subgroupIndex.push(d3.range(n));
k += x; k += x;
} }
if (sortGroups) { if (sortGroups) {
groupIndex.sort(function(a, b) { groupIndex.sort(function(a, b) {
return sortGroups(groupSums[a], groupSums[b]); return sortGroups(groupSums[a], groupSums[b]);
}); });
} }
if (sortSubgroups) { if (sortSubgroups) {
subgroupIndex.forEach(function(d, i) { subgroupIndex.forEach(function(d, i) {
d.sort(function(a, b) { d.sort(function(a, b) {
return sortSubgroups(matrix[i][a], matrix[i][b]); return sortSubgroups(matrix[i][a], matrix[i][b]);
}); });
}); });
} }
k = (2 * Math.PI - padding * n) / k; k = (2 * Math.PI - padding * n) / k;
x = 0, i = -1; x = 0, i = -1;
while (++i < n) { while (++i < n) {
x0 = x, j = -1; x0 = x, j = -1;
while (++j < n) { while (++j < n) {
var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k; var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
subgroups[di + "-" + dj] = { subgroups[di + "-" + dj] = {
index: di, index: di,
subindex: dj, subindex: dj,
startAngle: a0, startAngle: a0,
endAngle: a1, endAngle: a1,
value: v value: v
}; };
} }
groups[di] = { groups[di] = {
index: di, index: di,
startAngle: x0, startAngle: x0,
endAngle: x, endAngle: x,
value: (x - x0) / k value: (x - x0) / k
}; };
x += padding; x += padding;
} }
i = -1; i = -1;
while (++i < n) { while (++i < n) {
j = i - 1; j = i - 1;
while (++j < n) { while (++j < n) {
var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i]; var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
if (source.value || target.value) { if (source.value || target.value) {
chords.push(source.value < target.value ? { chords.push(source.value < target.value ? {
source: target, source: target,
target: source target: source
} : { } : {
source: source, source: source,
target: target target: target
}); });
} }
} }
} }
if (sortChords) resort(); if (sortChords) resort();
} }
function resort() { function resort() {
chords.sort(function(a, b) { chords.sort(function(a, b) {
return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2); return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
}); });
} }
var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords; var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
chord.matrix = function(x) { chord.matrix = function(x) {
if (!arguments.length) return matrix; if (!arguments.length) return matrix;
n = (matrix = x) && matrix.length; n = (matrix = x) && matrix.length;
chords = groups = null; chords = groups = null;
return chord; return chord;
}; };
chord.padding = function(x) { chord.padding = function(x) {
if (!arguments.length) return padding; if (!arguments.length) return padding;
padding = x; padding = x;
chords = groups = null; chords = groups = null;
return chord; return chord;
}; };
chord.sortGroups = function(x) { chord.sortGroups = function(x) {
if (!arguments.length) return sortGroups; if (!arguments.length) return sortGroups;
sortGroups = x; sortGroups = x;
chords = groups = null; chords = groups = null;
return chord; return chord;
}; };
chord.sortSubgroups = function(x) { chord.sortSubgroups = function(x) {
if (!arguments.length) return sortSubgroups; if (!arguments.length) return sortSubgroups;
sortSubgroups = x; sortSubgroups = x;
chords = null; chords = null;
return chord; return chord;
}; };
chord.sortChords = function(x) { chord.sortChords = function(x) {
if (!arguments.length) return sortChords; if (!arguments.length) return sortChords;
sortChords = x; sortChords = x;
if (chords) resort(); if (chords) resort();
return chord; return chord;
}; };
chord.chords = function() { chord.chords = function() {
if (!chords) relayout(); if (!chords) relayout();
return chords; return chords;
}; };
chord.groups = function() { chord.groups = function() {
if (!groups) relayout(); if (!groups) relayout();
return groups; return groups;
}; };
return chord; return chord;
}; };
d3.layout.force = function() { d3.layout.force = function() {
function repulse(node) { function repulse(node) {
return function(quad, x1, y1, x2, y2) { return function(quad, x1, y1, x2, y2) {
if (quad.point !== node) { if (quad.point !== node) {
var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy); var dx = quad.cx - node.x, dy = quad.cy - node.y, dn = 1 / Math.sqrt(dx * dx + dy * dy);
if ((x2 - x1) * dn < theta) { if ((x2 - x1) * dn < theta) {
var k = quad.charge * dn * dn; var k = quad.charge * dn * dn;
node.px -= dx * k; node.px -= dx * k;
node.py -= dy * k; node.py -= dy * k;
return true; return true;
} }
if (quad.point && isFinite(dn)) { if (quad.point && isFinite(dn)) {
var k = quad.pointCharge * dn * dn; var k = quad.pointCharge * dn * dn;
node.px -= dx * k; node.px -= dx * k;
node.py -= dy * k; node.py -= dy * k;
} }
} }
return !quad.charge; return !quad.charge;
}; };
} }
function dragmove(d) { function dragmove(d) {
d.px = d3.event.x; d.px = d3.event.x;
d.py = d3.event.y; d.py = d3.event.y;
force.resume(); force.resume();
} }
var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, interval, nodes = [], links = [], distances, strengths, charges; var force = {}, event = d3.dispatch("start", "tick", "end"), size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, gravity = .1, theta = .8, interval, nodes = [], links = [], distances, strengths, charges;
force.tick = function() { force.tick = function() {
if ((alpha *= .99) < .005) { if ((alpha *= .99) < .005) {
event.end({ event.end({
type: "end", type: "end",
alpha: alpha = 0 alpha: alpha = 0
}); });
return true; return true;
} }
var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y; var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
for (i = 0; i < m; ++i) { for (i = 0; i < m; ++i) {
o = links[i]; o = links[i];
s = o.source; s = o.source;
t = o.target; t = o.target;
x = t.x - s.x; x = t.x - s.x;
y = t.y - s.y; y = t.y - s.y;
if (l = x * x + y * y) { if (l = x * x + y * y) {
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l; l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
x *= l; x *= l;
y *= l; y *= l;
t.x -= x * (k = s.weight / (t.weight + s.weight)); t.x -= x * (k = s.weight / (t.weight + s.weight));
t.y -= y * k; t.y -= y * k;
s.x += x * (k = 1 - k); s.x += x * (k = 1 - k);
s.y += y * k; s.y += y * k;
} }
} }
if (k = alpha * gravity) { if (k = alpha * gravity) {
x = size[0] / 2; x = size[0] / 2;
y = size[1] / 2; y = size[1] / 2;
i = -1; i = -1;
if (k) while (++i < n) { if (k) while (++i < n) {
o = nodes[i]; o = nodes[i];
o.x += (x - o.x) * k; o.x += (x - o.x) * k;
o.y += (y - o.y) * k; o.y += (y - o.y) * k;
} }
} }
if (charge) { if (charge) {
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges); d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
i = -1; i = -1;
while (++i < n) { while (++i < n) {
if (!(o = nodes[i]).fixed) { if (!(o = nodes[i]).fixed) {
q.visit(repulse(o)); q.visit(repulse(o));
} }
} }
} }
i = -1; i = -1;
while (++i < n) { while (++i < n) {
o = nodes[i]; o = nodes[i];
if (o.fixed) { if (o.fixed) {
o.x = o.px; o.x = o.px;
o.y = o.py; o.y = o.py;
} else { } else {
o.x -= (o.px - (o.px = o.x)) * friction; o.x -= (o.px - (o.px = o.x)) * friction;
o.y -= (o.py - (o.py = o.y)) * friction; o.y -= (o.py - (o.py = o.y)) * friction;
} }
} }
event.tick({ event.tick({
type: "tick", type: "tick",
alpha: alpha alpha: alpha
}); });
}; };
force.nodes = function(x) { force.nodes = function(x) {
if (!arguments.length) return nodes; if (!arguments.length) return nodes;
nodes = x; nodes = x;
return force; return force;
}; };
force.links = function(x) { force.links = function(x) {
if (!arguments.length) return links; if (!arguments.length) return links;
links = x; links = x;
return force; return force;
}; };
force.size = function(x) { force.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return force; return force;
}; };
force.linkDistance = function(x) { force.linkDistance = function(x) {
if (!arguments.length) return linkDistance; if (!arguments.length) return linkDistance;
linkDistance = d3_functor(x); linkDistance = d3_functor(x);
return force; return force;
}; };
force.distance = force.linkDistance; force.distance = force.linkDistance;
force.linkStrength = function(x) { force.linkStrength = function(x) {
if (!arguments.length) return linkStrength; if (!arguments.length) return linkStrength;
linkStrength = d3_functor(x); linkStrength = d3_functor(x);
return force; return force;
}; };
force.friction = function(x) { force.friction = function(x) {
if (!arguments.length) return friction; if (!arguments.length) return friction;
friction = x; friction = x;
return force; return force;
}; };
force.charge = function(x) { force.charge = function(x) {
if (!arguments.length) return charge; if (!arguments.length) return charge;
charge = typeof x === "function" ? x : +x; charge = typeof x === "function" ? x : +x;
return force; return force;
}; };
force.gravity = function(x) { force.gravity = function(x) {
if (!arguments.length) return gravity; if (!arguments.length) return gravity;
gravity = x; gravity = x;
return force; return force;
}; };
force.theta = function(x) { force.theta = function(x) {
if (!arguments.length) return theta; if (!arguments.length) return theta;
theta = x; theta = x;
return force; return force;
}; };
force.alpha = function(x) { force.alpha = function(x) {
if (!arguments.length) return alpha; if (!arguments.length) return alpha;
if (alpha) { if (alpha) {
if (x > 0) alpha = x; else alpha = 0; if (x > 0) alpha = x; else alpha = 0;
} else if (x > 0) { } else if (x > 0) {
event.start({ event.start({
type: "start", type: "start",
alpha: alpha = x alpha: alpha = x
}); });
d3.timer(force.tick); d3.timer(force.tick);
} }
return force; return force;
}; };
force.start = function() { force.start = function() {
function position(dimension, size) { function position(dimension, size) {
var neighbors = neighbor(i), j = -1, m = neighbors.length, x; var neighbors = neighbor(i), j = -1, m = neighbors.length, x;
while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x; while (++j < m) if (!isNaN(x = neighbors[j][dimension])) return x;
return Math.random() * size; return Math.random() * size;
} }
function neighbor() { function neighbor() {
if (!neighbors) { if (!neighbors) {
neighbors = []; neighbors = [];
for (j = 0; j < n; ++j) { for (j = 0; j < n; ++j) {
neighbors[j] = []; neighbors[j] = [];
} }
for (j = 0; j < m; ++j) { for (j = 0; j < m; ++j) {
var o = links[j]; var o = links[j];
neighbors[o.source.index].push(o.target); neighbors[o.source.index].push(o.target);
neighbors[o.target.index].push(o.source); neighbors[o.target.index].push(o.source);
} }
} }
return neighbors[i]; return neighbors[i];
} }
var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o; var i, j, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
(o = nodes[i]).index = i; (o = nodes[i]).index = i;
o.weight = 0; o.weight = 0;
} }
distances = []; distances = [];
strengths = []; strengths = [];
for (i = 0; i < m; ++i) { for (i = 0; i < m; ++i) {
o = links[i]; o = links[i];
if (typeof o.source == "number") o.source = nodes[o.source]; if (typeof o.source == "number") o.source = nodes[o.source];
if (typeof o.target == "number") o.target = nodes[o.target]; if (typeof o.target == "number") o.target = nodes[o.target];
distances[i] = linkDistance.call(this, o, i); distances[i] = linkDistance.call(this, o, i);
strengths[i] = linkStrength.call(this, o, i); strengths[i] = linkStrength.call(this, o, i);
++o.source.weight; ++o.source.weight;
++o.target.weight; ++o.target.weight;
} }
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
o = nodes[i]; o = nodes[i];
if (isNaN(o.x)) o.x = position("x", w); if (isNaN(o.x)) o.x = position("x", w);
if (isNaN(o.y)) o.y = position("y", h); if (isNaN(o.y)) o.y = position("y", h);
if (isNaN(o.px)) o.px = o.x; if (isNaN(o.px)) o.px = o.x;
if (isNaN(o.py)) o.py = o.y; if (isNaN(o.py)) o.py = o.y;
} }
charges = []; charges = [];
if (typeof charge === "function") { if (typeof charge === "function") {
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
charges[i] = +charge.call(this, nodes[i], i); charges[i] = +charge.call(this, nodes[i], i);
} }
} else { } else {
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
charges[i] = charge; charges[i] = charge;
} }
} }
return force.resume(); return force.resume();
}; };
force.resume = function() { force.resume = function() {
return force.alpha(.1); return force.alpha(.1);
}; };
force.stop = function() { force.stop = function() {
return force.alpha(0); return force.alpha(0);
}; };
force.drag = function() { force.drag = function() {
if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend); if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart", d3_layout_forceDragstart).on("drag", dragmove).on("dragend", d3_layout_forceDragend);
this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag); this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
}; };
return d3.rebind(force, event, "on"); return d3.rebind(force, event, "on");
}; };
d3.layout.partition = function() { d3.layout.partition = function() {
function position(node, x, dx, dy) { function position(node, x, dx, dy) {
var children = node.children; var children = node.children;
node.x = x; node.x = x;
node.y = node.depth * dy; node.y = node.depth * dy;
node.dx = dx; node.dx = dx;
node.dy = dy; node.dy = dy;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var i = -1, n, c, d; var i = -1, n, c, d;
dx = node.value ? dx / node.value : 0; dx = node.value ? dx / node.value : 0;
while (++i < n) { while (++i < n) {
position(c = children[i], x, d = c.value * dx, dy); position(c = children[i], x, d = c.value * dx, dy);
x += d; x += d;
} }
} }
} }
function depth(node) { function depth(node) {
var children = node.children, d = 0; var children = node.children, d = 0;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var i = -1, n; var i = -1, n;
while (++i < n) d = Math.max(d, depth(children[i])); while (++i < n) d = Math.max(d, depth(children[i]));
} }
return 1 + d; return 1 + d;
} }
function partition(d, i) { function partition(d, i) {
var nodes = hierarchy.call(this, d, i); var nodes = hierarchy.call(this, d, i);
position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
return nodes; return nodes;
} }
var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
partition.size = function(x) { partition.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return partition; return partition;
}; };
return d3_layout_hierarchyRebind(partition, hierarchy); return d3_layout_hierarchyRebind(partition, hierarchy);
}; };
d3.layout.pie = function() { d3.layout.pie = function() {
function pie(data, i) { function pie(data, i) {
var values = data.map(function(d, i) { var values = data.map(function(d, i) {
return +value.call(pie, d, i); return +value.call(pie, d, i);
}); });
var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle); var a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle);
var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values); var k = ((typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - startAngle) / d3.sum(values);
var index = d3.range(data.length); var index = d3.range(data.length);
if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) { if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
return values[j] - values[i]; return values[j] - values[i];
} : function(i, j) { } : function(i, j) {
return sort(data[i], data[j]); return sort(data[i], data[j]);
}); });
var arcs = []; var arcs = [];
index.forEach(function(i) { index.forEach(function(i) {
var d; var d;
arcs[i] = { arcs[i] = {
data: data[i], data: data[i],
value: d = values[i], value: d = values[i],
startAngle: a, startAngle: a,
endAngle: a += d * k endAngle: a += d * k
}; };
}); });
return arcs; return arcs;
} }
var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * Math.PI; var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = 2 * Math.PI;
pie.value = function(x) { pie.value = function(x) {
if (!arguments.length) return value; if (!arguments.length) return value;
value = x; value = x;
return pie; return pie;
}; };
pie.sort = function(x) { pie.sort = function(x) {
if (!arguments.length) return sort; if (!arguments.length) return sort;
sort = x; sort = x;
return pie; return pie;
}; };
pie.startAngle = function(x) { pie.startAngle = function(x) {
if (!arguments.length) return startAngle; if (!arguments.length) return startAngle;
startAngle = x; startAngle = x;
return pie; return pie;
}; };
pie.endAngle = function(x) { pie.endAngle = function(x) {
if (!arguments.length) return endAngle; if (!arguments.length) return endAngle;
endAngle = x; endAngle = x;
return pie; return pie;
}; };
return pie; return pie;
}; };
var d3_layout_pieSortByValue = {}; var d3_layout_pieSortByValue = {};
d3.layout.stack = function() { d3.layout.stack = function() {
function stack(data, index) { function stack(data, index) {
var series = data.map(function(d, i) { var series = data.map(function(d, i) {
return values.call(stack, d, i); return values.call(stack, d, i);
}); });
var points = series.map(function(d, i) { var points = series.map(function(d, i) {
return d.map(function(v, i) { return d.map(function(v, i) {
return [ x.call(stack, v, i), y.call(stack, v, i) ]; return [ x.call(stack, v, i), y.call(stack, v, i) ];
}); });
}); });
var orders = order.call(stack, points, index); var orders = order.call(stack, points, index);
series = d3.permute(series, orders); series = d3.permute(series, orders);
points = d3.permute(points, orders); points = d3.permute(points, orders);
var offsets = offset.call(stack, points, index); var offsets = offset.call(stack, points, index);
var n = series.length, m = series[0].length, i, j, o; var n = series.length, m = series[0].length, i, j, o;
for (j = 0; j < m; ++j) { for (j = 0; j < m; ++j) {
out.call(stack, series[0][j], o = offsets[j], points[0][j][1]); out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
for (i = 1; i < n; ++i) { for (i = 1; i < n; ++i) {
out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]); out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
} }
} }
return data; return data;
} }
var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY; var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
stack.values = function(x) { stack.values = function(x) {
if (!arguments.length) return values; if (!arguments.length) return values;
values = x; values = x;
return stack; return stack;
}; };
stack.order = function(x) { stack.order = function(x) {
if (!arguments.length) return order; if (!arguments.length) return order;
order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault; order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
return stack; return stack;
}; };
stack.offset = function(x) { stack.offset = function(x) {
if (!arguments.length) return offset; if (!arguments.length) return offset;
offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero; offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
return stack; return stack;
}; };
stack.x = function(z) { stack.x = function(z) {
if (!arguments.length) return x; if (!arguments.length) return x;
x = z; x = z;
return stack; return stack;
}; };
stack.y = function(z) { stack.y = function(z) {
if (!arguments.length) return y; if (!arguments.length) return y;
y = z; y = z;
return stack; return stack;
}; };
stack.out = function(z) { stack.out = function(z) {
if (!arguments.length) return out; if (!arguments.length) return out;
out = z; out = z;
return stack; return stack;
}; };
return stack; return stack;
}; };
var d3_layout_stackOrders = d3.map({ var d3_layout_stackOrders = d3.map({
"inside-out": function(data) { "inside-out": function(data) {
var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) { var n = data.length, i, j, max = data.map(d3_layout_stackMaxIndex), sums = data.map(d3_layout_stackReduceSum), index = d3.range(n).sort(function(a, b) {
return max[a] - max[b]; return max[a] - max[b];
}), top = 0, bottom = 0, tops = [], bottoms = []; }), top = 0, bottom = 0, tops = [], bottoms = [];
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
j = index[i]; j = index[i];
if (top < bottom) { if (top < bottom) {
top += sums[j]; top += sums[j];
tops.push(j); tops.push(j);
} else { } else {
bottom += sums[j]; bottom += sums[j];
bottoms.push(j); bottoms.push(j);
} }
} }
return bottoms.reverse().concat(tops); return bottoms.reverse().concat(tops);
}, },
reverse: function(data) { reverse: function(data) {
return d3.range(data.length).reverse(); return d3.range(data.length).reverse();
}, },
"default": d3_layout_stackOrderDefault "default": d3_layout_stackOrderDefault
}); });
var d3_layout_stackOffsets = d3.map({ var d3_layout_stackOffsets = d3.map({
silhouette: function(data) { silhouette: function(data) {
var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = []; var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
for (j = 0; j < m; ++j) { for (j = 0; j < m; ++j) {
for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
if (o > max) max = o; if (o > max) max = o;
sums.push(o); sums.push(o);
} }
for (j = 0; j < m; ++j) { for (j = 0; j < m; ++j) {
y0[j] = (max - sums[j]) / 2; y0[j] = (max - sums[j]) / 2;
} }
return y0; return y0;
}, },
wiggle: function(data) { wiggle: function(data) {
var n = data.length, x = data[0], m = x.length, max = 0, i, j, k, s1, s2, s3, dx, o, o0, y0 = []; var n = data.length, x = data[0], m = x.length, max = 0, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
y0[0] = o = o0 = 0; y0[0] = o = o0 = 0;
for (j = 1; j < m; ++j) { for (j = 1; j < m; ++j) {
for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1]; for (i = 0, s1 = 0; i < n; ++i) s1 += data[i][j][1];
for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) { for (i = 0, s2 = 0, dx = x[j][0] - x[j - 1][0]; i < n; ++i) {
for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) { for (k = 0, s3 = (data[i][j][1] - data[i][j - 1][1]) / (2 * dx); k < i; ++k) {
s3 += (data[k][j][1] - data[k][j - 1][1]) / dx; s3 += (data[k][j][1] - data[k][j - 1][1]) / dx;
} }
s2 += s3 * data[i][j][1]; s2 += s3 * data[i][j][1];
} }
y0[j] = o -= s1 ? s2 / s1 * dx : 0; y0[j] = o -= s1 ? s2 / s1 * dx : 0;
if (o < o0) o0 = o; if (o < o0) o0 = o;
} }
for (j = 0; j < m; ++j) y0[j] -= o0; for (j = 0; j < m; ++j) y0[j] -= o0;
return y0; return y0;
}, },
expand: function(data) { expand: function(data) {
var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = []; var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
for (j = 0; j < m; ++j) { for (j = 0; j < m; ++j) {
for (i = 0, o = 0; i < n; i++) o += data[i][j][1]; for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k; if (o) for (i = 0; i < n; i++) data[i][j][1] /= o; else for (i = 0; i < n; i++) data[i][j][1] = k;
} }
for (j = 0; j < m; ++j) y0[j] = 0; for (j = 0; j < m; ++j) y0[j] = 0;
return y0; return y0;
}, },
zero: d3_layout_stackOffsetZero zero: d3_layout_stackOffsetZero
}); });
d3.layout.histogram = function() { d3.layout.histogram = function() {
function histogram(data, i) { function histogram(data, i) {
var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x; var bins = [], values = data.map(valuer, this), range = ranger.call(this, values, i), thresholds = binner.call(this, range, values, i), bin, i = -1, n = values.length, m = thresholds.length - 1, k = frequency ? 1 : 1 / n, x;
while (++i < m) { while (++i < m) {
bin = bins[i] = []; bin = bins[i] = [];
bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]); bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
bin.y = 0; bin.y = 0;
} }
if (m > 0) { if (m > 0) {
i = -1; i = -1;
while (++i < n) { while (++i < n) {
x = values[i]; x = values[i];
if (x >= range[0] && x <= range[1]) { if (x >= range[0] && x <= range[1]) {
bin = bins[d3.bisect(thresholds, x, 1, m) - 1]; bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
bin.y += k; bin.y += k;
bin.push(data[i]); bin.push(data[i]);
} }
} }
} }
return bins; return bins;
} }
var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges; var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
histogram.value = function(x) { histogram.value = function(x) {
if (!arguments.length) return valuer; if (!arguments.length) return valuer;
valuer = x; valuer = x;
return histogram; return histogram;
}; };
histogram.range = function(x) { histogram.range = function(x) {
if (!arguments.length) return ranger; if (!arguments.length) return ranger;
ranger = d3_functor(x); ranger = d3_functor(x);
return histogram; return histogram;
}; };
histogram.bins = function(x) { histogram.bins = function(x) {
if (!arguments.length) return binner; if (!arguments.length) return binner;
binner = typeof x === "number" ? function(range) { binner = typeof x === "number" ? function(range) {
return d3_layout_histogramBinFixed(range, x); return d3_layout_histogramBinFixed(range, x);
} : d3_functor(x); } : d3_functor(x);
return histogram; return histogram;
}; };
histogram.frequency = function(x) { histogram.frequency = function(x) {
if (!arguments.length) return frequency; if (!arguments.length) return frequency;
frequency = !!x; frequency = !!x;
return histogram; return histogram;
}; };
return histogram; return histogram;
}; };
d3.layout.hierarchy = function() { d3.layout.hierarchy = function() {
function recurse(data, depth, nodes) { function recurse(data, depth, nodes) {
var childs = children.call(hierarchy, data, depth), node = d3_layout_hierarchyInline ? data : { var childs = children.call(hierarchy, data, depth), node = d3_layout_hierarchyInline ? data : {
data: data data: data
}; };
node.depth = depth; node.depth = depth;
nodes.push(node); nodes.push(node);
if (childs && (n = childs.length)) { if (childs && (n = childs.length)) {
var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d; var i = -1, n, c = node.children = [], v = 0, j = depth + 1, d;
while (++i < n) { while (++i < n) {
d = recurse(childs[i], j, nodes); d = recurse(childs[i], j, nodes);
d.parent = node; d.parent = node;
c.push(d); c.push(d);
v += d.value; v += d.value;
} }
if (sort) c.sort(sort); if (sort) c.sort(sort);
if (value) node.value = v; if (value) node.value = v;
} else if (value) { } else if (value) {
node.value = +value.call(hierarchy, data, depth) || 0; node.value = +value.call(hierarchy, data, depth) || 0;
} }
return node; return node;
} }
function revalue(node, depth) { function revalue(node, depth) {
var children = node.children, v = 0; var children = node.children, v = 0;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var i = -1, n, j = depth + 1; var i = -1, n, j = depth + 1;
while (++i < n) v += revalue(children[i], j); while (++i < n) v += revalue(children[i], j);
} else if (value) { } else if (value) {
v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0; v = +value.call(hierarchy, d3_layout_hierarchyInline ? node : node.data, depth) || 0;
} }
if (value) node.value = v; if (value) node.value = v;
return v; return v;
} }
function hierarchy(d) { function hierarchy(d) {
var nodes = []; var nodes = [];
recurse(d, 0, nodes); recurse(d, 0, nodes);
return nodes; return nodes;
} }
var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
hierarchy.sort = function(x) { hierarchy.sort = function(x) {
if (!arguments.length) return sort; if (!arguments.length) return sort;
sort = x; sort = x;
return hierarchy; return hierarchy;
}; };
hierarchy.children = function(x) { hierarchy.children = function(x) {
if (!arguments.length) return children; if (!arguments.length) return children;
children = x; children = x;
return hierarchy; return hierarchy;
}; };
hierarchy.value = function(x) { hierarchy.value = function(x) {
if (!arguments.length) return value; if (!arguments.length) return value;
value = x; value = x;
return hierarchy; return hierarchy;
}; };
hierarchy.revalue = function(root) { hierarchy.revalue = function(root) {
revalue(root, 0); revalue(root, 0);
return root; return root;
}; };
return hierarchy; return hierarchy;
}; };
var d3_layout_hierarchyInline = false; var d3_layout_hierarchyInline = false;
d3.layout.pack = function() { d3.layout.pack = function() {
function pack(d, i) { function pack(d, i) {
var nodes = hierarchy.call(this, d, i), root = nodes[0]; var nodes = hierarchy.call(this, d, i), root = nodes[0];
root.x = 0; root.x = 0;
root.y = 0; root.y = 0;
d3_layout_treeVisitAfter(root, function(d) { d3_layout_treeVisitAfter(root, function(d) {
d.r = Math.sqrt(d.value); d.r = Math.sqrt(d.value);
}); });
d3_layout_treeVisitAfter(root, d3_layout_packSiblings); d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h); var w = size[0], h = size[1], k = Math.max(2 * root.r / w, 2 * root.r / h);
if (padding > 0) { if (padding > 0) {
var dr = padding * k / 2; var dr = padding * k / 2;
d3_layout_treeVisitAfter(root, function(d) { d3_layout_treeVisitAfter(root, function(d) {
d.r += dr; d.r += dr;
}); });
d3_layout_treeVisitAfter(root, d3_layout_packSiblings); d3_layout_treeVisitAfter(root, d3_layout_packSiblings);
d3_layout_treeVisitAfter(root, function(d) { d3_layout_treeVisitAfter(root, function(d) {
d.r -= dr; d.r -= dr;
}); });
k = Math.max(2 * root.r / w, 2 * root.r / h); k = Math.max(2 * root.r / w, 2 * root.r / h);
} }
d3_layout_packTransform(root, w / 2, h / 2, 1 / k); d3_layout_packTransform(root, w / 2, h / 2, 1 / k);
return nodes; return nodes;
} }
var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ]; var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ];
pack.size = function(x) { pack.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return pack; return pack;
}; };
pack.padding = function(_) { pack.padding = function(_) {
if (!arguments.length) return padding; if (!arguments.length) return padding;
padding = +_; padding = +_;
return pack; return pack;
}; };
return d3_layout_hierarchyRebind(pack, hierarchy); return d3_layout_hierarchyRebind(pack, hierarchy);
}; };
d3.layout.cluster = function() { d3.layout.cluster = function() {
function cluster(d, i) { function cluster(d, i) {
var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0, kx, ky; var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0, kx, ky;
d3_layout_treeVisitAfter(root, function(node) { d3_layout_treeVisitAfter(root, function(node) {
var children = node.children; var children = node.children;
if (children && children.length) { if (children && children.length) {
node.x = d3_layout_clusterX(children); node.x = d3_layout_clusterX(children);
node.y = d3_layout_clusterY(children); node.y = d3_layout_clusterY(children);
} else { } else {
node.x = previousNode ? x += separation(node, previousNode) : 0; node.x = previousNode ? x += separation(node, previousNode) : 0;
node.y = 0; node.y = 0;
previousNode = node; previousNode = node;
} }
}); });
var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2; var left = d3_layout_clusterLeft(root), right = d3_layout_clusterRight(root), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2;
d3_layout_treeVisitAfter(root, function(node) { d3_layout_treeVisitAfter(root, function(node) {
node.x = (node.x - x0) / (x1 - x0) * size[0]; node.x = (node.x - x0) / (x1 - x0) * size[0];
node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1]; node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
}); });
return nodes; return nodes;
} }
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
cluster.separation = function(x) { cluster.separation = function(x) {
if (!arguments.length) return separation; if (!arguments.length) return separation;
separation = x; separation = x;
return cluster; return cluster;
}; };
cluster.size = function(x) { cluster.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return cluster; return cluster;
}; };
return d3_layout_hierarchyRebind(cluster, hierarchy); return d3_layout_hierarchyRebind(cluster, hierarchy);
}; };
d3.layout.tree = function() { d3.layout.tree = function() {
function tree(d, i) { function tree(d, i) {
function firstWalk(node, previousSibling) { function firstWalk(node, previousSibling) {
var children = node.children, layout = node._tree; var children = node.children, layout = node._tree;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1; var n, firstChild = children[0], previousChild, ancestor = firstChild, child, i = -1;
while (++i < n) { while (++i < n) {
child = children[i]; child = children[i];
firstWalk(child, previousChild); firstWalk(child, previousChild);
ancestor = apportion(child, previousChild, ancestor); ancestor = apportion(child, previousChild, ancestor);
previousChild = child; previousChild = child;
} }
d3_layout_treeShift(node); d3_layout_treeShift(node);
var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim); var midpoint = .5 * (firstChild._tree.prelim + child._tree.prelim);
if (previousSibling) { if (previousSibling) {
layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
layout.mod = layout.prelim - midpoint; layout.mod = layout.prelim - midpoint;
} else { } else {
layout.prelim = midpoint; layout.prelim = midpoint;
} }
} else { } else {
if (previousSibling) { if (previousSibling) {
layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling); layout.prelim = previousSibling._tree.prelim + separation(node, previousSibling);
} }
} }
} }
function secondWalk(node, x) { function secondWalk(node, x) {
node.x = node._tree.prelim + x; node.x = node._tree.prelim + x;
var children = node.children; var children = node.children;
if (children && (n = children.length)) { if (children && (n = children.length)) {
var i = -1, n; var i = -1, n;
x += node._tree.mod; x += node._tree.mod;
while (++i < n) { while (++i < n) {
secondWalk(children[i], x); secondWalk(children[i], x);
} }
} }
} }
function apportion(node, previousSibling, ancestor) { function apportion(node, previousSibling, ancestor) {
if (previousSibling) { if (previousSibling) {
var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift; var vip = node, vop = node, vim = previousSibling, vom = node.parent.children[0], sip = vip._tree.mod, sop = vop._tree.mod, sim = vim._tree.mod, som = vom._tree.mod, shift;
while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) { while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
vom = d3_layout_treeLeft(vom); vom = d3_layout_treeLeft(vom);
vop = d3_layout_treeRight(vop); vop = d3_layout_treeRight(vop);
vop._tree.ancestor = node; vop._tree.ancestor = node;
shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip); shift = vim._tree.prelim + sim - vip._tree.prelim - sip + separation(vim, vip);
if (shift > 0) { if (shift > 0) {
d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift); d3_layout_treeMove(d3_layout_treeAncestor(vim, node, ancestor), node, shift);
sip += shift; sip += shift;
sop += shift; sop += shift;
} }
sim += vim._tree.mod; sim += vim._tree.mod;
sip += vip._tree.mod; sip += vip._tree.mod;
som += vom._tree.mod; som += vom._tree.mod;
sop += vop._tree.mod; sop += vop._tree.mod;
} }
if (vim && !d3_layout_treeRight(vop)) { if (vim && !d3_layout_treeRight(vop)) {
vop._tree.thread = vim; vop._tree.thread = vim;
vop._tree.mod += sim - sop; vop._tree.mod += sim - sop;
} }
if (vip && !d3_layout_treeLeft(vom)) { if (vip && !d3_layout_treeLeft(vom)) {
vom._tree.thread = vip; vom._tree.thread = vip;
vom._tree.mod += sip - som; vom._tree.mod += sip - som;
ancestor = node; ancestor = node;
} }
} }
return ancestor; return ancestor;
} }
var nodes = hierarchy.call(this, d, i), root = nodes[0]; var nodes = hierarchy.call(this, d, i), root = nodes[0];
d3_layout_treeVisitAfter(root, function(node, previousSibling) { d3_layout_treeVisitAfter(root, function(node, previousSibling) {
node._tree = { node._tree = {
ancestor: node, ancestor: node,
prelim: 0, prelim: 0,
mod: 0, mod: 0,
change: 0, change: 0,
shift: 0, shift: 0,
number: previousSibling ? previousSibling._tree.number + 1 : 0 number: previousSibling ? previousSibling._tree.number + 1 : 0
}; };
}); });
firstWalk(root); firstWalk(root);
secondWalk(root, -root._tree.prelim); secondWalk(root, -root._tree.prelim);
var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1; var left = d3_layout_treeSearch(root, d3_layout_treeLeftmost), right = d3_layout_treeSearch(root, d3_layout_treeRightmost), deep = d3_layout_treeSearch(root, d3_layout_treeDeepest), x0 = left.x - separation(left, right) / 2, x1 = right.x + separation(right, left) / 2, y1 = deep.depth || 1;
d3_layout_treeVisitAfter(root, function(node) { d3_layout_treeVisitAfter(root, function(node) {
node.x = (node.x - x0) / (x1 - x0) * size[0]; node.x = (node.x - x0) / (x1 - x0) * size[0];
node.y = node.depth / y1 * size[1]; node.y = node.depth / y1 * size[1];
delete node._tree; delete node._tree;
}); });
return nodes; return nodes;
} }
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ]; var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ];
tree.separation = function(x) { tree.separation = function(x) {
if (!arguments.length) return separation; if (!arguments.length) return separation;
separation = x; separation = x;
return tree; return tree;
}; };
tree.size = function(x) { tree.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return tree; return tree;
}; };
return d3_layout_hierarchyRebind(tree, hierarchy); return d3_layout_hierarchyRebind(tree, hierarchy);
}; };
d3.layout.treemap = function() { d3.layout.treemap = function() {
function scale(children, k) { function scale(children, k) {
var i = -1, n = children.length, child, area; var i = -1, n = children.length, child, area;
while (++i < n) { while (++i < n) {
area = (child = children[i]).value * (k < 0 ? 0 : k); area = (child = children[i]).value * (k < 0 ? 0 : k);
child.area = isNaN(area) || area <= 0 ? 0 : area; child.area = isNaN(area) || area <= 0 ? 0 : area;
} }
} }
function squarify(node) { function squarify(node) {
var children = node.children; var children = node.children;
if (children && children.length) { if (children && children.length) {
var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = Math.min(rect.dx, rect.dy), n; var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = Math.min(rect.dx, rect.dy), n;
scale(remaining, rect.dx * rect.dy / node.value); scale(remaining, rect.dx * rect.dy / node.value);
row.area = 0; row.area = 0;
while ((n = remaining.length) > 0) { while ((n = remaining.length) > 0) {
row.push(child = remaining[n - 1]); row.push(child = remaining[n - 1]);
row.area += child.area; row.area += child.area;
if ((score = worst(row, u)) <= best) { if ((score = worst(row, u)) <= best) {
remaining.pop(); remaining.pop();
best = score; best = score;
} else { } else {
row.area -= row.pop().area; row.area -= row.pop().area;
position(row, u, rect, false); position(row, u, rect, false);
u = Math.min(rect.dx, rect.dy); u = Math.min(rect.dx, rect.dy);
row.length = row.area = 0; row.length = row.area = 0;
best = Infinity; best = Infinity;
} }
} }
if (row.length) { if (row.length) {
position(row, u, rect, true); position(row, u, rect, true);
row.length = row.area = 0; row.length = row.area = 0;
} }
children.forEach(squarify); children.forEach(squarify);
} }
} }
function stickify(node) { function stickify(node) {
var children = node.children; var children = node.children;
if (children && children.length) { if (children && children.length) {
var rect = pad(node), remaining = children.slice(), child, row = []; var rect = pad(node), remaining = children.slice(), child, row = [];
scale(remaining, rect.dx * rect.dy / node.value); scale(remaining, rect.dx * rect.dy / node.value);
row.area = 0; row.area = 0;
while (child = remaining.pop()) { while (child = remaining.pop()) {
row.push(child); row.push(child);
row.area += child.area; row.area += child.area;
if (child.z != null) { if (child.z != null) {
position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
row.length = row.area = 0; row.length = row.area = 0;
} }
} }
children.forEach(stickify); children.forEach(stickify);
} }
} }
function worst(row, u) { function worst(row, u) {
var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
while (++i < n) { while (++i < n) {
if (!(r = row[i].area)) continue; if (!(r = row[i].area)) continue;
if (r < rmin) rmin = r; if (r < rmin) rmin = r;
if (r > rmax) rmax = r; if (r > rmax) rmax = r;
} }
s *= s; s *= s;
u *= u; u *= u;
return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
} }
function position(row, u, rect, flush) { function position(row, u, rect, flush) {
var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o;
if (u == rect.dx) { if (u == rect.dx) {
if (flush || v > rect.dy) v = rect.dy; if (flush || v > rect.dy) v = rect.dy;
while (++i < n) { while (++i < n) {
o = row[i]; o = row[i];
o.x = x; o.x = x;
o.y = y; o.y = y;
o.dy = v; o.dy = v;
x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
} }
o.z = true; o.z = true;
o.dx += rect.x + rect.dx - x; o.dx += rect.x + rect.dx - x;
rect.y += v; rect.y += v;
rect.dy -= v; rect.dy -= v;
} else { } else {
if (flush || v > rect.dx) v = rect.dx; if (flush || v > rect.dx) v = rect.dx;
while (++i < n) { while (++i < n) {
o = row[i]; o = row[i];
o.x = x; o.x = x;
o.y = y; o.y = y;
o.dx = v; o.dx = v;
y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
} }
o.z = false; o.z = false;
o.dy += rect.y + rect.dy - y; o.dy += rect.y + rect.dy - y;
rect.x += v; rect.x += v;
rect.dx -= v; rect.dx -= v;
} }
} }
function treemap(d) { function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0]; var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = 0; root.x = 0;
root.y = 0; root.y = 0;
root.dx = size[0]; root.dx = size[0];
root.dy = size[1]; root.dy = size[1];
if (stickies) hierarchy.revalue(root); if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value); scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root); (stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes; if (sticky) stickies = nodes;
return nodes; return nodes;
} }
var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, ratio = .5 * (1 + Math.sqrt(5)); var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, ratio = .5 * (1 + Math.sqrt(5));
treemap.size = function(x) { treemap.size = function(x) {
if (!arguments.length) return size; if (!arguments.length) return size;
size = x; size = x;
return treemap; return treemap;
}; };
treemap.padding = function(x) { treemap.padding = function(x) {
function padFunction(node) { function padFunction(node) {
var p = x.call(treemap, node, node.depth); var p = x.call(treemap, node, node.depth);
return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p);
} }
function padConstant(node) { function padConstant(node) {
return d3_layout_treemapPad(node, x); return d3_layout_treemapPad(node, x);
} }
if (!arguments.length) return padding; if (!arguments.length) return padding;
var type; var type;
pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], padConstant) : padConstant; pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], padConstant) : padConstant;
return treemap; return treemap;
}; };
treemap.round = function(x) { treemap.round = function(x) {
if (!arguments.length) return round != Number; if (!arguments.length) return round != Number;
round = x ? Math.round : Number; round = x ? Math.round : Number;
return treemap; return treemap;
}; };
treemap.sticky = function(x) { treemap.sticky = function(x) {
if (!arguments.length) return sticky; if (!arguments.length) return sticky;
sticky = x; sticky = x;
stickies = null; stickies = null;
return treemap; return treemap;
}; };
treemap.ratio = function(x) { treemap.ratio = function(x) {
if (!arguments.length) return ratio; if (!arguments.length) return ratio;
ratio = x; ratio = x;
return treemap; return treemap;
}; };
return d3_layout_hierarchyRebind(treemap, hierarchy); return d3_layout_hierarchyRebind(treemap, hierarchy);
}; };
d3.csv = d3_dsv(",", "text/csv"); d3.csv = d3_dsv(",", "text/csv");
d3.tsv = d3_dsv(" ", "text/tab-separated-values"); d3.tsv = d3_dsv(" ", "text/tab-separated-values");
d3.geo = {}; d3.geo = {};
var d3_geo_radians = Math.PI / 180; var d3_geo_radians = Math.PI / 180;
d3.geo.azimuthal = function() { d3.geo.azimuthal = function() {
function azimuthal(coordinates) { function azimuthal(coordinates) {
var x1 = coordinates[0] * d3_geo_radians - x0, y1 = coordinates[1] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1), cy1 = Math.cos(y1), sy1 = Math.sin(y1), cc = mode !== "orthographic" ? sy0 * sy1 + cy0 * cy1 * cx1 : null, c, k = mode === "stereographic" ? 1 / (1 + cc) : mode === "gnomonic" ? 1 / cc : mode === "equidistant" ? (c = Math.acos(cc), c ? c / Math.sin(c) : 0) : mode === "equalarea" ? Math.sqrt(2 / (1 + cc)) : 1, x = k * cy1 * sx1, y = k * (sy0 * cy1 * cx1 - cy0 * sy1); var x1 = coordinates[0] * d3_geo_radians - x0, y1 = coordinates[1] * d3_geo_radians, cx1 = Math.cos(x1), sx1 = Math.sin(x1), cy1 = Math.cos(y1), sy1 = Math.sin(y1), cc = mode !== "orthographic" ? sy0 * sy1 + cy0 * cy1 * cx1 : null, c, k = mode === "stereographic" ? 1 / (1 + cc) : mode === "gnomonic" ? 1 / cc : mode === "equidistant" ? (c = Math.acos(cc), c ? c / Math.sin(c) : 0) : mode === "equalarea" ? Math.sqrt(2 / (1 + cc)) : 1, x = k * cy1 * sx1, y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
return [ scale * x + translate[0], scale * y + translate[1] ]; return [ scale * x + translate[0], scale * y + translate[1] ];
} }
var mode = "orthographic", origin, scale = 200, translate = [ 480, 250 ], x0, y0, cy0, sy0; var mode = "orthographic", origin, scale = 200, translate = [ 480, 250 ], x0, y0, cy0, sy0;
azimuthal.invert = function(coordinates) { azimuthal.invert = function(coordinates) {
var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p = Math.sqrt(x * x + y * y), c = mode === "stereographic" ? 2 * Math.atan(p) : mode === "gnomonic" ? Math.atan(p) : mode === "equidistant" ? p : mode === "equalarea" ? 2 * Math.asin(.5 * p) : Math.asin(p), sc = Math.sin(c), cc = Math.cos(c); var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p = Math.sqrt(x * x + y * y), c = mode === "stereographic" ? 2 * Math.atan(p) : mode === "gnomonic" ? Math.atan(p) : mode === "equidistant" ? p : mode === "equalarea" ? 2 * Math.asin(.5 * p) : Math.asin(p), sc = Math.sin(c), cc = Math.cos(c);
return [ (x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_geo_radians, Math.asin(cc * sy0 - (p ? y * sc * cy0 / p : 0)) / d3_geo_radians ]; return [ (x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_geo_radians, Math.asin(cc * sy0 - (p ? y * sc * cy0 / p : 0)) / d3_geo_radians ];
}; };
azimuthal.mode = function(x) { azimuthal.mode = function(x) {
if (!arguments.length) return mode; if (!arguments.length) return mode;
mode = x + ""; mode = x + "";
return azimuthal; return azimuthal;
}; };
azimuthal.origin = function(x) { azimuthal.origin = function(x) {
if (!arguments.length) return origin; if (!arguments.length) return origin;
origin = x; origin = x;
x0 = origin[0] * d3_geo_radians; x0 = origin[0] * d3_geo_radians;
y0 = origin[1] * d3_geo_radians; y0 = origin[1] * d3_geo_radians;
cy0 = Math.cos(y0); cy0 = Math.cos(y0);
sy0 = Math.sin(y0); sy0 = Math.sin(y0);
return azimuthal; return azimuthal;
}; };
azimuthal.scale = function(x) { azimuthal.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return azimuthal; return azimuthal;
}; };
azimuthal.translate = function(x) { azimuthal.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = [ +x[0], +x[1] ]; translate = [ +x[0], +x[1] ];
return azimuthal; return azimuthal;
}; };
return azimuthal.origin([ 0, 0 ]); return azimuthal.origin([ 0, 0 ]);
}; };
d3.geo.albers = function() { d3.geo.albers = function() {
function albers(coordinates) { function albers(coordinates) {
var t = n * (d3_geo_radians * coordinates[0] - lng0), p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n; var t = n * (d3_geo_radians * coordinates[0] - lng0), p = Math.sqrt(C - 2 * n * Math.sin(d3_geo_radians * coordinates[1])) / n;
return [ scale * p * Math.sin(t) + translate[0], scale * (p * Math.cos(t) - p0) + translate[1] ]; return [ scale * p * Math.sin(t) + translate[0], scale * (p * Math.cos(t) - p0) + translate[1] ];
} }
function reload() { function reload() {
var phi1 = d3_geo_radians * parallels[0], phi2 = d3_geo_radians * parallels[1], lat0 = d3_geo_radians * origin[1], s = Math.sin(phi1), c = Math.cos(phi1); var phi1 = d3_geo_radians * parallels[0], phi2 = d3_geo_radians * parallels[1], lat0 = d3_geo_radians * origin[1], s = Math.sin(phi1), c = Math.cos(phi1);
lng0 = d3_geo_radians * origin[0]; lng0 = d3_geo_radians * origin[0];
n = .5 * (s + Math.sin(phi2)); n = .5 * (s + Math.sin(phi2));
C = c * c + 2 * n * s; C = c * c + 2 * n * s;
p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n; p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
return albers; return albers;
} }
var origin = [ -98, 38 ], parallels = [ 29.5, 45.5 ], scale = 1e3, translate = [ 480, 250 ], lng0, n, C, p0; var origin = [ -98, 38 ], parallels = [ 29.5, 45.5 ], scale = 1e3, translate = [ 480, 250 ], lng0, n, C, p0;
albers.invert = function(coordinates) { albers.invert = function(coordinates) {
var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p0y = p0 + y, t = Math.atan2(x, p0y), p = Math.sqrt(x * x + p0y * p0y); var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale, p0y = p0 + y, t = Math.atan2(x, p0y), p = Math.sqrt(x * x + p0y * p0y);
return [ (lng0 + t / n) / d3_geo_radians, Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians ]; return [ (lng0 + t / n) / d3_geo_radians, Math.asin((C - p * p * n * n) / (2 * n)) / d3_geo_radians ];
}; };
albers.origin = function(x) { albers.origin = function(x) {
if (!arguments.length) return origin; if (!arguments.length) return origin;
origin = [ +x[0], +x[1] ]; origin = [ +x[0], +x[1] ];
return reload(); return reload();
}; };
albers.parallels = function(x) { albers.parallels = function(x) {
if (!arguments.length) return parallels; if (!arguments.length) return parallels;
parallels = [ +x[0], +x[1] ]; parallels = [ +x[0], +x[1] ];
return reload(); return reload();
}; };
albers.scale = function(x) { albers.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return albers; return albers;
}; };
albers.translate = function(x) { albers.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = [ +x[0], +x[1] ]; translate = [ +x[0], +x[1] ];
return albers; return albers;
}; };
return reload(); return reload();
}; };
d3.geo.albersUsa = function() { d3.geo.albersUsa = function() {
function albersUsa(coordinates) { function albersUsa(coordinates) {
var lon = coordinates[0], lat = coordinates[1]; var lon = coordinates[0], lat = coordinates[1];
return (lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48)(coordinates); return (lat > 50 ? alaska : lon < -140 ? hawaii : lat < 21 ? puertoRico : lower48)(coordinates);
} }
var lower48 = d3.geo.albers(); var lower48 = d3.geo.albers();
var alaska = d3.geo.albers().origin([ -160, 60 ]).parallels([ 55, 65 ]); var alaska = d3.geo.albers().origin([ -160, 60 ]).parallels([ 55, 65 ]);
var hawaii = d3.geo.albers().origin([ -160, 20 ]).parallels([ 8, 18 ]); var hawaii = d3.geo.albers().origin([ -160, 20 ]).parallels([ 8, 18 ]);
var puertoRico = d3.geo.albers().origin([ -60, 10 ]).parallels([ 8, 18 ]); var puertoRico = d3.geo.albers().origin([ -60, 10 ]).parallels([ 8, 18 ]);
albersUsa.scale = function(x) { albersUsa.scale = function(x) {
if (!arguments.length) return lower48.scale(); if (!arguments.length) return lower48.scale();
lower48.scale(x); lower48.scale(x);
alaska.scale(x * .6); alaska.scale(x * .6);
hawaii.scale(x); hawaii.scale(x);
puertoRico.scale(x * 1.5); puertoRico.scale(x * 1.5);
return albersUsa.translate(lower48.translate()); return albersUsa.translate(lower48.translate());
}; };
albersUsa.translate = function(x) { albersUsa.translate = function(x) {
if (!arguments.length) return lower48.translate(); if (!arguments.length) return lower48.translate();
var dz = lower48.scale() / 1e3, dx = x[0], dy = x[1]; var dz = lower48.scale() / 1e3, dx = x[0], dy = x[1];
lower48.translate(x); lower48.translate(x);
alaska.translate([ dx - 400 * dz, dy + 170 * dz ]); alaska.translate([ dx - 400 * dz, dy + 170 * dz ]);
hawaii.translate([ dx - 190 * dz, dy + 200 * dz ]); hawaii.translate([ dx - 190 * dz, dy + 200 * dz ]);
puertoRico.translate([ dx + 580 * dz, dy + 430 * dz ]); puertoRico.translate([ dx + 580 * dz, dy + 430 * dz ]);
return albersUsa; return albersUsa;
}; };
return albersUsa.scale(lower48.scale()); return albersUsa.scale(lower48.scale());
}; };
d3.geo.bonne = function() { d3.geo.bonne = function() {
function bonne(coordinates) { function bonne(coordinates) {
var x = coordinates[0] * d3_geo_radians - x0, y = coordinates[1] * d3_geo_radians - y0; var x = coordinates[0] * d3_geo_radians - x0, y = coordinates[1] * d3_geo_radians - y0;
if (y1) { if (y1) {
var p = c1 + y1 - y, E = x * Math.cos(y) / p; var p = c1 + y1 - y, E = x * Math.cos(y) / p;
x = p * Math.sin(E); x = p * Math.sin(E);
y = p * Math.cos(E) - c1; y = p * Math.cos(E) - c1;
} else { } else {
x *= Math.cos(y); x *= Math.cos(y);
y *= -1; y *= -1;
} }
return [ scale * x + translate[0], scale * y + translate[1] ]; return [ scale * x + translate[0], scale * y + translate[1] ];
} }
var scale = 200, translate = [ 480, 250 ], x0, y0, y1, c1; var scale = 200, translate = [ 480, 250 ], x0, y0, y1, c1;
bonne.invert = function(coordinates) { bonne.invert = function(coordinates) {
var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale;
if (y1) { if (y1) {
var c = c1 + y, p = Math.sqrt(x * x + c * c); var c = c1 + y, p = Math.sqrt(x * x + c * c);
y = c1 + y1 - p; y = c1 + y1 - p;
x = x0 + p * Math.atan2(x, c) / Math.cos(y); x = x0 + p * Math.atan2(x, c) / Math.cos(y);
} else { } else {
y *= -1; y *= -1;
x /= Math.cos(y); x /= Math.cos(y);
} }
return [ x / d3_geo_radians, y / d3_geo_radians ]; return [ x / d3_geo_radians, y / d3_geo_radians ];
}; };
bonne.parallel = function(x) { bonne.parallel = function(x) {
if (!arguments.length) return y1 / d3_geo_radians; if (!arguments.length) return y1 / d3_geo_radians;
c1 = 1 / Math.tan(y1 = x * d3_geo_radians); c1 = 1 / Math.tan(y1 = x * d3_geo_radians);
return bonne; return bonne;
}; };
bonne.origin = function(x) { bonne.origin = function(x) {
if (!arguments.length) return [ x0 / d3_geo_radians, y0 / d3_geo_radians ]; if (!arguments.length) return [ x0 / d3_geo_radians, y0 / d3_geo_radians ];
x0 = x[0] * d3_geo_radians; x0 = x[0] * d3_geo_radians;
y0 = x[1] * d3_geo_radians; y0 = x[1] * d3_geo_radians;
return bonne; return bonne;
}; };
bonne.scale = function(x) { bonne.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return bonne; return bonne;
}; };
bonne.translate = function(x) { bonne.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = [ +x[0], +x[1] ]; translate = [ +x[0], +x[1] ];
return bonne; return bonne;
}; };
return bonne.origin([ 0, 0 ]).parallel(45); return bonne.origin([ 0, 0 ]).parallel(45);
}; };
d3.geo.equirectangular = function() { d3.geo.equirectangular = function() {
function equirectangular(coordinates) { function equirectangular(coordinates) {
var x = coordinates[0] / 360, y = -coordinates[1] / 360; var x = coordinates[0] / 360, y = -coordinates[1] / 360;
return [ scale * x + translate[0], scale * y + translate[1] ]; return [ scale * x + translate[0], scale * y + translate[1] ];
} }
var scale = 500, translate = [ 480, 250 ]; var scale = 500, translate = [ 480, 250 ];
equirectangular.invert = function(coordinates) { equirectangular.invert = function(coordinates) {
var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale;
return [ 360 * x, -360 * y ]; return [ 360 * x, -360 * y ];
}; };
equirectangular.scale = function(x) { equirectangular.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return equirectangular; return equirectangular;
}; };
equirectangular.translate = function(x) { equirectangular.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = [ +x[0], +x[1] ]; translate = [ +x[0], +x[1] ];
return equirectangular; return equirectangular;
}; };
return equirectangular; return equirectangular;
}; };
d3.geo.mercator = function() { d3.geo.mercator = function() {
function mercator(coordinates) { function mercator(coordinates) {
var x = coordinates[0] / 360, y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_geo_radians / 2)) / d3_geo_radians) / 360; var x = coordinates[0] / 360, y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_geo_radians / 2)) / d3_geo_radians) / 360;
return [ scale * x + translate[0], scale * Math.max(-.5, Math.min(.5, y)) + translate[1] ]; return [ scale * x + translate[0], scale * Math.max(-.5, Math.min(.5, y)) + translate[1] ];
} }
var scale = 500, translate = [ 480, 250 ]; var scale = 500, translate = [ 480, 250 ];
mercator.invert = function(coordinates) { mercator.invert = function(coordinates) {
var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale; var x = (coordinates[0] - translate[0]) / scale, y = (coordinates[1] - translate[1]) / scale;
return [ 360 * x, 2 * Math.atan(Math.exp(-360 * y * d3_geo_radians)) / d3_geo_radians - 90 ]; return [ 360 * x, 2 * Math.atan(Math.exp(-360 * y * d3_geo_radians)) / d3_geo_radians - 90 ];
}; };
mercator.scale = function(x) { mercator.scale = function(x) {
if (!arguments.length) return scale; if (!arguments.length) return scale;
scale = +x; scale = +x;
return mercator; return mercator;
}; };
mercator.translate = function(x) { mercator.translate = function(x) {
if (!arguments.length) return translate; if (!arguments.length) return translate;
translate = [ +x[0], +x[1] ]; translate = [ +x[0], +x[1] ];
return mercator; return mercator;
}; };
return mercator; return mercator;
}; };
d3.geo.path = function() { d3.geo.path = function() {
function path(d, i) { function path(d, i) {
if (typeof pointRadius === "function") pointCircle = d3_path_circle(pointRadius.apply(this, arguments)); if (typeof pointRadius === "function") pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
pathType(d); pathType(d);
var result = buffer.length ? buffer.join("") : null; var result = buffer.length ? buffer.join("") : null;
buffer = []; buffer = [];
return result; return result;
} }
function project(coordinates) { function project(coordinates) {
return projection(coordinates).join(","); return projection(coordinates).join(",");
} }
function polygonArea(coordinates) { function polygonArea(coordinates) {
var sum = area(coordinates[0]), i = 0, n = coordinates.length; var sum = area(coordinates[0]), i = 0, n = coordinates.length;
while (++i < n) sum -= area(coordinates[i]); while (++i < n) sum -= area(coordinates[i]);
return sum; return sum;
} }
function polygonCentroid(coordinates) { function polygonCentroid(coordinates) {
var polygon = d3.geom.polygon(coordinates[0].map(projection)), area = polygon.area(), centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1), x = centroid[0], y = centroid[1], z = area, i = 0, n = coordinates.length; var polygon = d3.geom.polygon(coordinates[0].map(projection)), area = polygon.area(), centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1), x = centroid[0], y = centroid[1], z = area, i = 0, n = coordinates.length;
while (++i < n) { while (++i < n) {
polygon = d3.geom.polygon(coordinates[i].map(projection)); polygon = d3.geom.polygon(coordinates[i].map(projection));
area = polygon.area(); area = polygon.area();
centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1); centroid = polygon.centroid(area < 0 ? (area *= -1, 1) : -1);
x -= centroid[0]; x -= centroid[0];
y -= centroid[1]; y -= centroid[1];
z -= area; z -= area;
} }
return [ x, y, 6 * z ]; return [ x, y, 6 * z ];
} }
function area(coordinates) { function area(coordinates) {
return Math.abs(d3.geom.polygon(coordinates.map(projection)).area()); return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
} }
var pointRadius = 4.5, pointCircle = d3_path_circle(pointRadius), projection = d3.geo.albersUsa(), buffer = []; var pointRadius = 4.5, pointCircle = d3_path_circle(pointRadius), projection = d3.geo.albersUsa(), buffer = [];
var pathType = d3_geo_type({ var pathType = d3_geo_type({
FeatureCollection: function(o) { FeatureCollection: function(o) {
var features = o.features, i = -1, n = features.length; var features = o.features, i = -1, n = features.length;
while (++i < n) buffer.push(pathType(features[i].geometry)); while (++i < n) buffer.push(pathType(features[i].geometry));
}, },
Feature: function(o) { Feature: function(o) {
pathType(o.geometry); pathType(o.geometry);
}, },
Point: function(o) { Point: function(o) {
buffer.push("M", project(o.coordinates), pointCircle); buffer.push("M", project(o.coordinates), pointCircle);
}, },
MultiPoint: function(o) { MultiPoint: function(o) {
var coordinates = o.coordinates, i = -1, n = coordinates.length; var coordinates = o.coordinates, i = -1, n = coordinates.length;
while (++i < n) buffer.push("M", project(coordinates[i]), pointCircle); while (++i < n) buffer.push("M", project(coordinates[i]), pointCircle);
}, },
LineString: function(o) { LineString: function(o) {
var coordinates = o.coordinates, i = -1, n = coordinates.length; var coordinates = o.coordinates, i = -1, n = coordinates.length;
buffer.push("M"); buffer.push("M");
while (++i < n) buffer.push(project(coordinates[i]), "L"); while (++i < n) buffer.push(project(coordinates[i]), "L");
buffer.pop(); buffer.pop();
}, },
MultiLineString: function(o) { MultiLineString: function(o) {
var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m; var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m;
while (++i < n) { while (++i < n) {
subcoordinates = coordinates[i]; subcoordinates = coordinates[i];
j = -1; j = -1;
m = subcoordinates.length; m = subcoordinates.length;
buffer.push("M"); buffer.push("M");
while (++j < m) buffer.push(project(subcoordinates[j]), "L"); while (++j < m) buffer.push(project(subcoordinates[j]), "L");
buffer.pop(); buffer.pop();
} }
}, },
Polygon: function(o) { Polygon: function(o) {
var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m; var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m;
while (++i < n) { while (++i < n) {
subcoordinates = coordinates[i]; subcoordinates = coordinates[i];
j = -1; j = -1;
if ((m = subcoordinates.length - 1) > 0) { if ((m = subcoordinates.length - 1) > 0) {
buffer.push("M"); buffer.push("M");
while (++j < m) buffer.push(project(subcoordinates[j]), "L"); while (++j < m) buffer.push(project(subcoordinates[j]), "L");
buffer[buffer.length - 1] = "Z"; buffer[buffer.length - 1] = "Z";
} }
} }
}, },
MultiPolygon: function(o) { MultiPolygon: function(o) {
var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m, subsubcoordinates, k, p; var coordinates = o.coordinates, i = -1, n = coordinates.length, subcoordinates, j, m, subsubcoordinates, k, p;
while (++i < n) { while (++i < n) {
subcoordinates = coordinates[i]; subcoordinates = coordinates[i];
j = -1; j = -1;
m = subcoordinates.length; m = subcoordinates.length;
while (++j < m) { while (++j < m) {
subsubcoordinates = subcoordinates[j]; subsubcoordinates = subcoordinates[j];
k = -1; k = -1;
if ((p = subsubcoordinates.length - 1) > 0) { if ((p = subsubcoordinates.length - 1) > 0) {
buffer.push("M"); buffer.push("M");
while (++k < p) buffer.push(project(subsubcoordinates[k]), "L"); while (++k < p) buffer.push(project(subsubcoordinates[k]), "L");
buffer[buffer.length - 1] = "Z"; buffer[buffer.length - 1] = "Z";
} }
} }
} }
}, },
GeometryCollection: function(o) { GeometryCollection: function(o) {
var geometries = o.geometries, i = -1, n = geometries.length; var geometries = o.geometries, i = -1, n = geometries.length;
while (++i < n) buffer.push(pathType(geometries[i])); while (++i < n) buffer.push(pathType(geometries[i]));
} }
}); });
var areaType = path.area = d3_geo_type({ var areaType = path.area = d3_geo_type({
FeatureCollection: function(o) { FeatureCollection: function(o) {
var area = 0, features = o.features, i = -1, n = features.length; var area = 0, features = o.features, i = -1, n = features.length;
while (++i < n) area += areaType(features[i]); while (++i < n) area += areaType(features[i]);
return area; return area;
}, },
Feature: function(o) { Feature: function(o) {
return areaType(o.geometry); return areaType(o.geometry);
}, },
Polygon: function(o) { Polygon: function(o) {
return polygonArea(o.coordinates); return polygonArea(o.coordinates);
}, },
MultiPolygon: function(o) { MultiPolygon: function(o) {
var sum = 0, coordinates = o.coordinates, i = -1, n = coordinates.length; var sum = 0, coordinates = o.coordinates, i = -1, n = coordinates.length;
while (++i < n) sum += polygonArea(coordinates[i]); while (++i < n) sum += polygonArea(coordinates[i]);
return sum; return sum;
}, },
GeometryCollection: function(o) { GeometryCollection: function(o) {
var sum = 0, geometries = o.geometries, i = -1, n = geometries.length; var sum = 0, geometries = o.geometries, i = -1, n = geometries.length;
while (++i < n) sum += areaType(geometries[i]); while (++i < n) sum += areaType(geometries[i]);
return sum; return sum;
} }
}, 0); }, 0);
var centroidType = path.centroid = d3_geo_type({ var centroidType = path.centroid = d3_geo_type({
Feature: function(o) { Feature: function(o) {
return centroidType(o.geometry); return centroidType(o.geometry);
}, },
Polygon: function(o) { Polygon: function(o) {
var centroid = polygonCentroid(o.coordinates); var centroid = polygonCentroid(o.coordinates);
return [ centroid[0] / centroid[2], centroid[1] / centroid[2] ]; return [ centroid[0] / centroid[2], centroid[1] / centroid[2] ];
}, },
MultiPolygon: function(o) { MultiPolygon: function(o) {
var area = 0, coordinates = o.coordinates, centroid, x = 0, y = 0, z = 0, i = -1, n = coordinates.length; var area = 0, coordinates = o.coordinates, centroid, x = 0, y = 0, z = 0, i = -1, n = coordinates.length;
while (++i < n) { while (++i < n) {
centroid = polygonCentroid(coordinates[i]); centroid = polygonCentroid(coordinates[i]);
x += centroid[0]; x += centroid[0];
y += centroid[1]; y += centroid[1];
z += centroid[2]; z += centroid[2];
} }
return [ x / z, y / z ]; return [ x / z, y / z ];
} }
}); });
path.projection = function(x) { path.projection = function(x) {
projection = x; projection = x;
return path; return path;
}; };
path.pointRadius = function(x) { path.pointRadius = function(x) {
if (typeof x === "function") pointRadius = x; else { if (typeof x === "function") pointRadius = x; else {
pointRadius = +x; pointRadius = +x;
pointCircle = d3_path_circle(pointRadius); pointCircle = d3_path_circle(pointRadius);
} }
return path; return path;
}; };
return path; return path;
}; };
d3.geo.bounds = function(feature) { d3.geo.bounds = function(feature) {
var left = Infinity, bottom = Infinity, right = -Infinity, top = -Infinity; var left = Infinity, bottom = Infinity, right = -Infinity, top = -Infinity;
d3_geo_bounds(feature, function(x, y) { d3_geo_bounds(feature, function(x, y) {
if (x < left) left = x; if (x < left) left = x;
if (x > right) right = x; if (x > right) right = x;
if (y < bottom) bottom = y; if (y < bottom) bottom = y;
if (y > top) top = y; if (y > top) top = y;
}); });
return [ [ left, bottom ], [ right, top ] ]; return [ [ left, bottom ], [ right, top ] ];
}; };
var d3_geo_boundsTypes = { var d3_geo_boundsTypes = {
Feature: d3_geo_boundsFeature, Feature: d3_geo_boundsFeature,
FeatureCollection: d3_geo_boundsFeatureCollection, FeatureCollection: d3_geo_boundsFeatureCollection,
GeometryCollection: d3_geo_boundsGeometryCollection, GeometryCollection: d3_geo_boundsGeometryCollection,
LineString: d3_geo_boundsLineString, LineString: d3_geo_boundsLineString,
MultiLineString: d3_geo_boundsMultiLineString, MultiLineString: d3_geo_boundsMultiLineString,
MultiPoint: d3_geo_boundsLineString, MultiPoint: d3_geo_boundsLineString,
MultiPolygon: d3_geo_boundsMultiPolygon, MultiPolygon: d3_geo_boundsMultiPolygon,
Point: d3_geo_boundsPoint, Point: d3_geo_boundsPoint,
Polygon: d3_geo_boundsPolygon Polygon: d3_geo_boundsPolygon
}; };
d3.geo.circle = function() { d3.geo.circle = function() {
function circle() {} function circle() {}
function visible(point) { function visible(point) {
return arc.distance(point) < radians; return arc.distance(point) < radians;
} }
function clip(coordinates) { function clip(coordinates) {
var i = -1, n = coordinates.length, clipped = [], p0, p1, p2, d0, d1; var i = -1, n = coordinates.length, clipped = [], p0, p1, p2, d0, d1;
while (++i < n) { while (++i < n) {
d1 = arc.distance(p2 = coordinates[i]); d1 = arc.distance(p2 = coordinates[i]);
if (d1 < radians) { if (d1 < radians) {
if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1))); if (p1) clipped.push(d3_geo_greatArcInterpolate(p1, p2)((d0 - radians) / (d0 - d1)));
clipped.push(p2); clipped.push(p2);
p0 = p1 = null; p0 = p1 = null;
} else { } else {
p1 = p2; p1 = p2;
if (!p0 && clipped.length) { if (!p0 && clipped.length) {
clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0))); clipped.push(d3_geo_greatArcInterpolate(clipped[clipped.length - 1], p1)((radians - d0) / (d1 - d0)));
p0 = p1; p0 = p1;
} }
} }
d0 = d1; d0 = d1;
} }
p0 = coordinates[0]; p0 = coordinates[0];
p1 = clipped[0]; p1 = clipped[0];
if (p1 && p2[0] === p0[0] && p2[1] === p0[1] && !(p2[0] === p1[0] && p2[1] === p1[1])) { if (p1 && p2[0] === p0[0] && p2[1] === p0[1] && !(p2[0] === p1[0] && p2[1] === p1[1])) {
clipped.push(p1); clipped.push(p1);
} }
return resample(clipped); return resample(clipped);
} }
function resample(coordinates) { function resample(coordinates) {
var i = 0, n = coordinates.length, j, m, resampled = n ? [ coordinates[0] ] : coordinates, resamples, origin = arc.source(); var i = 0, n = coordinates.length, j, m, resampled = n ? [ coordinates[0] ] : coordinates, resamples, origin = arc.source();
while (++i < n) { while (++i < n) {
resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates; resamples = arc.source(coordinates[i - 1])(coordinates[i]).coordinates;
for (j = 0, m = resamples.length; ++j < m; ) resampled.push(resamples[j]); for (j = 0, m = resamples.length; ++j < m; ) resampled.push(resamples[j]);
} }
arc.source(origin); arc.source(origin);
return resampled; return resampled;
} }
var origin = [ 0, 0 ], degrees = 90 - .01, radians = degrees * d3_geo_radians, arc = d3.geo.greatArc().source(origin).target(d3_identity); var origin = [ 0, 0 ], degrees = 90 - .01, radians = degrees * d3_geo_radians, arc = d3.geo.greatArc().source(origin).target(d3_identity);
circle.clip = function(d) { circle.clip = function(d) {
if (typeof origin === "function") arc.source(origin.apply(this, arguments)); if (typeof origin === "function") arc.source(origin.apply(this, arguments));
return clipType(d) || null; return clipType(d) || null;
}; };
var clipType = d3_geo_type({ var clipType = d3_geo_type({
FeatureCollection: function(o) { FeatureCollection: function(o) {
var features = o.features.map(clipType).filter(d3_identity); var features = o.features.map(clipType).filter(d3_identity);
return features && (o = Object.create(o), o.features = features, o); return features && (o = Object.create(o), o.features = features, o);
}, },
Feature: function(o) { Feature: function(o) {
var geometry = clipType(o.geometry); var geometry = clipType(o.geometry);
return geometry && (o = Object.create(o), o.geometry = geometry, o); return geometry && (o = Object.create(o), o.geometry = geometry, o);
}, },
Point: function(o) { Point: function(o) {
return visible(o.coordinates) && o; return visible(o.coordinates) && o;
}, },
MultiPoint: function(o) { MultiPoint: function(o) {
var coordinates = o.coordinates.filter(visible); var coordinates = o.coordinates.filter(visible);
return coordinates.length && { return coordinates.length && {
type: o.type, type: o.type,
coordinates: coordinates coordinates: coordinates
}; };
}, },
LineString: function(o) { LineString: function(o) {
var coordinates = clip(o.coordinates); var coordinates = clip(o.coordinates);
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
}, },
MultiLineString: function(o) { MultiLineString: function(o) {
var coordinates = o.coordinates.map(clip).filter(function(d) { var coordinates = o.coordinates.map(clip).filter(function(d) {
return d.length; return d.length;
}); });
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
}, },
Polygon: function(o) { Polygon: function(o) {
var coordinates = o.coordinates.map(clip); var coordinates = o.coordinates.map(clip);
return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o); return coordinates[0].length && (o = Object.create(o), o.coordinates = coordinates, o);
}, },
MultiPolygon: function(o) { MultiPolygon: function(o) {
var coordinates = o.coordinates.map(function(d) { var coordinates = o.coordinates.map(function(d) {
return d.map(clip); return d.map(clip);
}).filter(function(d) { }).filter(function(d) {
return d[0].length; return d[0].length;
}); });
return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o); return coordinates.length && (o = Object.create(o), o.coordinates = coordinates, o);
}, },
GeometryCollection: function(o) { GeometryCollection: function(o) {
var geometries = o.geometries.map(clipType).filter(d3_identity); var geometries = o.geometries.map(clipType).filter(d3_identity);
return geometries.length && (o = Object.create(o), o.geometries = geometries, o); return geometries.length && (o = Object.create(o), o.geometries = geometries, o);
} }
}); });
circle.origin = function(x) { circle.origin = function(x) {
if (!arguments.length) return origin; if (!arguments.length) return origin;
origin = x; origin = x;
if (typeof origin !== "function") arc.source(origin); if (typeof origin !== "function") arc.source(origin);
return circle; return circle;
}; };
circle.angle = function(x) { circle.angle = function(x) {
if (!arguments.length) return degrees; if (!arguments.length) return degrees;
radians = (degrees = +x) * d3_geo_radians; radians = (degrees = +x) * d3_geo_radians;
return circle; return circle;
}; };
return d3.rebind(circle, arc, "precision"); return d3.rebind(circle, arc, "precision");
}; };
d3.geo.greatArc = function() { d3.geo.greatArc = function() {
function greatArc() { function greatArc() {
var d = greatArc.distance.apply(this, arguments), t = 0, dt = precision / d, coordinates = [ p0 ]; var d = greatArc.distance.apply(this, arguments), t = 0, dt = precision / d, coordinates = [ p0 ];
while ((t += dt) < 1) coordinates.push(interpolate(t)); while ((t += dt) < 1) coordinates.push(interpolate(t));
coordinates.push(p1); coordinates.push(p1);
return { return {
type: "LineString", type: "LineString",
coordinates: coordinates coordinates: coordinates
}; };
} }
var source = d3_geo_greatArcSource, p0, target = d3_geo_greatArcTarget, p1, precision = 6 * d3_geo_radians, interpolate = d3_geo_greatArcInterpolator(); var source = d3_geo_greatArcSource, p0, target = d3_geo_greatArcTarget, p1, precision = 6 * d3_geo_radians, interpolate = d3_geo_greatArcInterpolator();
greatArc.distance = function() { greatArc.distance = function() {
if (typeof source === "function") interpolate.source(p0 = source.apply(this, arguments)); if (typeof source === "function") interpolate.source(p0 = source.apply(this, arguments));
if (typeof target === "function") interpolate.target(p1 = target.apply(this, arguments)); if (typeof target === "function") interpolate.target(p1 = target.apply(this, arguments));
return interpolate.distance(); return interpolate.distance();
}; };
greatArc.source = function(_) { greatArc.source = function(_) {
if (!arguments.length) return source; if (!arguments.length) return source;
source = _; source = _;
if (typeof source !== "function") interpolate.source(p0 = source); if (typeof source !== "function") interpolate.source(p0 = source);
return greatArc; return greatArc;
}; };
greatArc.target = function(_) { greatArc.target = function(_) {
if (!arguments.length) return target; if (!arguments.length) return target;
target = _; target = _;
if (typeof target !== "function") interpolate.target(p1 = target); if (typeof target !== "function") interpolate.target(p1 = target);
return greatArc; return greatArc;
}; };
greatArc.precision = function(_) { greatArc.precision = function(_) {
if (!arguments.length) return precision / d3_geo_radians; if (!arguments.length) return precision / d3_geo_radians;
precision = _ * d3_geo_radians; precision = _ * d3_geo_radians;
return greatArc; return greatArc;
}; };
return greatArc; return greatArc;
}; };
d3.geo.greatCircle = d3.geo.circle; d3.geo.greatCircle = d3.geo.circle;
d3.geom = {}; d3.geom = {};
d3.geom.contour = function(grid, start) { d3.geom.contour = function(grid, start) {
var s = start || d3_geom_contourStart(grid), c = [], x = s[0], y = s[1], dx = 0, dy = 0, pdx = NaN, pdy = NaN, i = 0; var s = start || d3_geom_contourStart(grid), c = [], x = s[0], y = s[1], dx = 0, dy = 0, pdx = NaN, pdy = NaN, i = 0;
do { do {
i = 0; i = 0;
if (grid(x - 1, y - 1)) i += 1; if (grid(x - 1, y - 1)) i += 1;
if (grid(x, y - 1)) i += 2; if (grid(x, y - 1)) i += 2;
if (grid(x - 1, y)) i += 4; if (grid(x - 1, y)) i += 4;
if (grid(x, y)) i += 8; if (grid(x, y)) i += 8;
if (i === 6) { if (i === 6) {
dx = pdy === -1 ? -1 : 1; dx = pdy === -1 ? -1 : 1;
dy = 0; dy = 0;
} else if (i === 9) { } else if (i === 9) {
dx = 0; dx = 0;
dy = pdx === 1 ? -1 : 1; dy = pdx === 1 ? -1 : 1;
} else { } else {
dx = d3_geom_contourDx[i]; dx = d3_geom_contourDx[i];
dy = d3_geom_contourDy[i]; dy = d3_geom_contourDy[i];
} }
if (dx != pdx && dy != pdy) { if (dx != pdx && dy != pdy) {
c.push([ x, y ]); c.push([ x, y ]);
pdx = dx; pdx = dx;
pdy = dy; pdy = dy;
} }
x += dx; x += dx;
y += dy; y += dy;
} while (s[0] != x || s[1] != y); } while (s[0] != x || s[1] != y);
return c; return c;
}; };
var d3_geom_contourDx = [ 1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 0, 0, -1, 0, -1, NaN ], d3_geom_contourDy = [ 0, -1, 0, 0, 0, -1, 0, 0, 1, -1, 1, 1, 0, -1, 0, NaN ]; var d3_geom_contourDx = [ 1, 0, 1, 1, -1, 0, -1, 1, 0, 0, 0, 0, -1, 0, -1, NaN ], d3_geom_contourDy = [ 0, -1, 0, 0, 0, -1, 0, 0, 1, -1, 1, 1, 0, -1, 0, NaN ];
d3.geom.hull = function(vertices) { d3.geom.hull = function(vertices) {
if (vertices.length < 3) return []; if (vertices.length < 3) return [];
var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp; var len = vertices.length, plen = len - 1, points = [], stack = [], i, j, h = 0, x1, y1, x2, y2, u, v, a, sp;
for (i = 1; i < len; ++i) { for (i = 1; i < len; ++i) {
if (vertices[i][1] < vertices[h][1]) { if (vertices[i][1] < vertices[h][1]) {
h = i; h = i;
} else if (vertices[i][1] == vertices[h][1]) { } else if (vertices[i][1] == vertices[h][1]) {
h = vertices[i][0] < vertices[h][0] ? i : h; h = vertices[i][0] < vertices[h][0] ? i : h;
} }
} }
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if (i === h) continue; if (i === h) continue;
y1 = vertices[i][1] - vertices[h][1]; y1 = vertices[i][1] - vertices[h][1];
x1 = vertices[i][0] - vertices[h][0]; x1 = vertices[i][0] - vertices[h][0];
points.push({ points.push({
angle: Math.atan2(y1, x1), angle: Math.atan2(y1, x1),
index: i index: i
}); });
} }
points.sort(function(a, b) { points.sort(function(a, b) {
return a.angle - b.angle; return a.angle - b.angle;
}); });
a = points[0].angle; a = points[0].angle;
v = points[0].index; v = points[0].index;
u = 0; u = 0;
for (i = 1; i < plen; ++i) { for (i = 1; i < plen; ++i) {
j = points[i].index; j = points[i].index;
if (a == points[i].angle) { if (a == points[i].angle) {
x1 = vertices[v][0] - vertices[h][0]; x1 = vertices[v][0] - vertices[h][0];
y1 = vertices[v][1] - vertices[h][1]; y1 = vertices[v][1] - vertices[h][1];
x2 = vertices[j][0] - vertices[h][0]; x2 = vertices[j][0] - vertices[h][0];
y2 = vertices[j][1] - vertices[h][1]; y2 = vertices[j][1] - vertices[h][1];
if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) { if (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) {
points[i].index = -1; points[i].index = -1;
} else { } else {
points[u].index = -1; points[u].index = -1;
a = points[i].angle; a = points[i].angle;
u = i; u = i;
v = j; v = j;
} }
} else { } else {
a = points[i].angle; a = points[i].angle;
u = i; u = i;
v = j; v = j;
} }
} }
stack.push(h); stack.push(h);
for (i = 0, j = 0; i < 2; ++j) { for (i = 0, j = 0; i < 2; ++j) {
if (points[j].index !== -1) { if (points[j].index !== -1) {
stack.push(points[j].index); stack.push(points[j].index);
i++; i++;
} }
} }
sp = stack.length; sp = stack.length;
for (; j < plen; ++j) { for (; j < plen; ++j) {
if (points[j].index === -1) continue; if (points[j].index === -1) continue;
while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) { while (!d3_geom_hullCCW(stack[sp - 2], stack[sp - 1], points[j].index, vertices)) {
--sp; --sp;
} }
stack[sp++] = points[j].index; stack[sp++] = points[j].index;
} }
var poly = []; var poly = [];
for (i = 0; i < sp; ++i) { for (i = 0; i < sp; ++i) {
poly.push(vertices[stack[i]]); poly.push(vertices[stack[i]]);
} }
return poly; return poly;
}; };
d3.geom.polygon = function(coordinates) { d3.geom.polygon = function(coordinates) {
coordinates.area = function() { coordinates.area = function() {
var i = 0, n = coordinates.length, a = coordinates[n - 1][0] * coordinates[0][1], b = coordinates[n - 1][1] * coordinates[0][0]; var i = 0, n = coordinates.length, a = coordinates[n - 1][0] * coordinates[0][1], b = coordinates[n - 1][1] * coordinates[0][0];
while (++i < n) { while (++i < n) {
a += coordinates[i - 1][0] * coordinates[i][1]; a += coordinates[i - 1][0] * coordinates[i][1];
b += coordinates[i - 1][1] * coordinates[i][0]; b += coordinates[i - 1][1] * coordinates[i][0];
} }
return (b - a) * .5; return (b - a) * .5;
}; };
coordinates.centroid = function(k) { coordinates.centroid = function(k) {
var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c; var i = -1, n = coordinates.length, x = 0, y = 0, a, b = coordinates[n - 1], c;
if (!arguments.length) k = -1 / (6 * coordinates.area()); if (!arguments.length) k = -1 / (6 * coordinates.area());
while (++i < n) { while (++i < n) {
a = b; a = b;
b = coordinates[i]; b = coordinates[i];
c = a[0] * b[1] - b[0] * a[1]; c = a[0] * b[1] - b[0] * a[1];
x += (a[0] + b[0]) * c; x += (a[0] + b[0]) * c;
y += (a[1] + b[1]) * c; y += (a[1] + b[1]) * c;
} }
return [ x * k, y * k ]; return [ x * k, y * k ];
}; };
coordinates.clip = function(subject) { coordinates.clip = function(subject) {
var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d; var input, i = -1, n = coordinates.length, j, m, a = coordinates[n - 1], b, c, d;
while (++i < n) { while (++i < n) {
input = subject.slice(); input = subject.slice();
subject.length = 0; subject.length = 0;
b = coordinates[i]; b = coordinates[i];
c = input[(m = input.length) - 1]; c = input[(m = input.length) - 1];
j = -1; j = -1;
while (++j < m) { while (++j < m) {
d = input[j]; d = input[j];
if (d3_geom_polygonInside(d, a, b)) { if (d3_geom_polygonInside(d, a, b)) {
if (!d3_geom_polygonInside(c, a, b)) { if (!d3_geom_polygonInside(c, a, b)) {
subject.push(d3_geom_polygonIntersect(c, d, a, b)); subject.push(d3_geom_polygonIntersect(c, d, a, b));
} }
subject.push(d); subject.push(d);
} else if (d3_geom_polygonInside(c, a, b)) { } else if (d3_geom_polygonInside(c, a, b)) {
subject.push(d3_geom_polygonIntersect(c, d, a, b)); subject.push(d3_geom_polygonIntersect(c, d, a, b));
} }
c = d; c = d;
} }
a = b; a = b;
} }
return subject; return subject;
}; };
return coordinates; return coordinates;
}; };
d3.geom.voronoi = function(vertices) { d3.geom.voronoi = function(vertices) {
var polygons = vertices.map(function() { var polygons = vertices.map(function() {
return []; return [];
}); });
d3_voronoi_tessellate(vertices, function(e) { d3_voronoi_tessellate(vertices, function(e) {
var s1, s2, x1, x2, y1, y2; var s1, s2, x1, x2, y1, y2;
if (e.a === 1 && e.b >= 0) { if (e.a === 1 && e.b >= 0) {
s1 = e.ep.r; s1 = e.ep.r;
s2 = e.ep.l; s2 = e.ep.l;
} else { } else {
s1 = e.ep.l; s1 = e.ep.l;
s2 = e.ep.r; s2 = e.ep.r;
} }
if (e.a === 1) { if (e.a === 1) {
y1 = s1 ? s1.y : -1e6; y1 = s1 ? s1.y : -1e6;
x1 = e.c - e.b * y1; x1 = e.c - e.b * y1;
y2 = s2 ? s2.y : 1e6; y2 = s2 ? s2.y : 1e6;
x2 = e.c - e.b * y2; x2 = e.c - e.b * y2;
} else { } else {
x1 = s1 ? s1.x : -1e6; x1 = s1 ? s1.x : -1e6;
y1 = e.c - e.a * x1; y1 = e.c - e.a * x1;
x2 = s2 ? s2.x : 1e6; x2 = s2 ? s2.x : 1e6;
y2 = e.c - e.a * x2; y2 = e.c - e.a * x2;
} }
var v1 = [ x1, y1 ], v2 = [ x2, y2 ]; var v1 = [ x1, y1 ], v2 = [ x2, y2 ];
polygons[e.region.l.index].push(v1, v2); polygons[e.region.l.index].push(v1, v2);
polygons[e.region.r.index].push(v1, v2); polygons[e.region.r.index].push(v1, v2);
}); });
return polygons.map(function(polygon, i) { return polygons.map(function(polygon, i) {
var cx = vertices[i][0], cy = vertices[i][1]; var cx = vertices[i][0], cy = vertices[i][1];
polygon.forEach(function(v) { polygon.forEach(function(v) {
v.angle = Math.atan2(v[0] - cx, v[1] - cy); v.angle = Math.atan2(v[0] - cx, v[1] - cy);
}); });
return polygon.sort(function(a, b) { return polygon.sort(function(a, b) {
return a.angle - b.angle; return a.angle - b.angle;
}).filter(function(d, i) { }).filter(function(d, i) {
return !i || d.angle - polygon[i - 1].angle > 1e-10; return !i || d.angle - polygon[i - 1].angle > 1e-10;
}); });
}); });
}; };
var d3_voronoi_opposite = { var d3_voronoi_opposite = {
l: "r", l: "r",
r: "l" r: "l"
}; };
d3.geom.delaunay = function(vertices) { d3.geom.delaunay = function(vertices) {
var edges = vertices.map(function() { var edges = vertices.map(function() {
return []; return [];
}), triangles = []; }), triangles = [];
d3_voronoi_tessellate(vertices, function(e) { d3_voronoi_tessellate(vertices, function(e) {
edges[e.region.l.index].push(vertices[e.region.r.index]); edges[e.region.l.index].push(vertices[e.region.r.index]);
}); });
edges.forEach(function(edge, i) { edges.forEach(function(edge, i) {
var v = vertices[i], cx = v[0], cy = v[1]; var v = vertices[i], cx = v[0], cy = v[1];
edge.forEach(function(v) { edge.forEach(function(v) {
v.angle = Math.atan2(v[0] - cx, v[1] - cy); v.angle = Math.atan2(v[0] - cx, v[1] - cy);
}); });
edge.sort(function(a, b) { edge.sort(function(a, b) {
return a.angle - b.angle; return a.angle - b.angle;
}); });
for (var j = 0, m = edge.length - 1; j < m; j++) { for (var j = 0, m = edge.length - 1; j < m; j++) {
triangles.push([ v, edge[j], edge[j + 1] ]); triangles.push([ v, edge[j], edge[j + 1] ]);
} }
}); });
return triangles; return triangles;
}; };
d3.geom.quadtree = function(points, x1, y1, x2, y2) { d3.geom.quadtree = function(points, x1, y1, x2, y2) {
function insert(n, p, x1, y1, x2, y2) { function insert(n, p, x1, y1, x2, y2) {
if (isNaN(p.x) || isNaN(p.y)) return; if (isNaN(p.x) || isNaN(p.y)) return;
if (n.leaf) { if (n.leaf) {
var v = n.point; var v = n.point;
if (v) { if (v) {
if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) { if (Math.abs(v.x - p.x) + Math.abs(v.y - p.y) < .01) {
insertChild(n, p, x1, y1, x2, y2); insertChild(n, p, x1, y1, x2, y2);
} else { } else {
n.point = null; n.point = null;
insertChild(n, v, x1, y1, x2, y2); insertChild(n, v, x1, y1, x2, y2);
insertChild(n, p, x1, y1, x2, y2); insertChild(n, p, x1, y1, x2, y2);
} }
} else { } else {
n.point = p; n.point = p;
} }
} else { } else {
insertChild(n, p, x1, y1, x2, y2); insertChild(n, p, x1, y1, x2, y2);
} }
} }
function insertChild(n, p, x1, y1, x2, y2) { function insertChild(n, p, x1, y1, x2, y2) {
var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right; var sx = (x1 + x2) * .5, sy = (y1 + y2) * .5, right = p.x >= sx, bottom = p.y >= sy, i = (bottom << 1) + right;
n.leaf = false; n.leaf = false;
n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode()); n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
if (right) x1 = sx; else x2 = sx; if (right) x1 = sx; else x2 = sx;
if (bottom) y1 = sy; else y2 = sy; if (bottom) y1 = sy; else y2 = sy;
insert(n, p, x1, y1, x2, y2); insert(n, p, x1, y1, x2, y2);
} }
var p, i = -1, n = points.length; var p, i = -1, n = points.length;
if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint); if (n && isNaN(points[0].x)) points = points.map(d3_geom_quadtreePoint);
if (arguments.length < 5) { if (arguments.length < 5) {
if (arguments.length === 3) { if (arguments.length === 3) {
y2 = x2 = y1; y2 = x2 = y1;
y1 = x1; y1 = x1;
} else { } else {
x1 = y1 = Infinity; x1 = y1 = Infinity;
x2 = y2 = -Infinity; x2 = y2 = -Infinity;
while (++i < n) { while (++i < n) {
p = points[i]; p = points[i];
if (p.x < x1) x1 = p.x; if (p.x < x1) x1 = p.x;
if (p.y < y1) y1 = p.y; if (p.y < y1) y1 = p.y;
if (p.x > x2) x2 = p.x; if (p.x > x2) x2 = p.x;
if (p.y > y2) y2 = p.y; if (p.y > y2) y2 = p.y;
} }
var dx = x2 - x1, dy = y2 - y1; var dx = x2 - x1, dy = y2 - y1;
if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy; if (dx > dy) y2 = y1 + dx; else x2 = x1 + dy;
} }
} }
var root = d3_geom_quadtreeNode(); var root = d3_geom_quadtreeNode();
root.add = function(p) { root.add = function(p) {
insert(root, p, x1, y1, x2, y2); insert(root, p, x1, y1, x2, y2);
}; };
root.visit = function(f) { root.visit = function(f) {
d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2); d3_geom_quadtreeVisit(f, root, x1, y1, x2, y2);
}; };
points.forEach(root.add); points.forEach(root.add);
return root; return root;
}; };
d3.time = {}; d3.time = {};
var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; var d3_time = Date, d3_time_daySymbols = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ];
d3_time_utc.prototype = { d3_time_utc.prototype = {
getDate: function() { getDate: function() {
return this._.getUTCDate(); return this._.getUTCDate();
}, },
getDay: function() { getDay: function() {
return this._.getUTCDay(); return this._.getUTCDay();
}, },
getFullYear: function() { getFullYear: function() {
return this._.getUTCFullYear(); return this._.getUTCFullYear();
}, },
getHours: function() { getHours: function() {
return this._.getUTCHours(); return this._.getUTCHours();
}, },
getMilliseconds: function() { getMilliseconds: function() {
return this._.getUTCMilliseconds(); return this._.getUTCMilliseconds();
}, },
getMinutes: function() { getMinutes: function() {
return this._.getUTCMinutes(); return this._.getUTCMinutes();
}, },
getMonth: function() { getMonth: function() {
return this._.getUTCMonth(); return this._.getUTCMonth();
}, },
getSeconds: function() { getSeconds: function() {
return this._.getUTCSeconds(); return this._.getUTCSeconds();
}, },
getTime: function() { getTime: function() {
return this._.getTime(); return this._.getTime();
}, },
getTimezoneOffset: function() { getTimezoneOffset: function() {
return 0; return 0;
}, },
valueOf: function() { valueOf: function() {
return this._.valueOf(); return this._.valueOf();
}, },
setDate: function() { setDate: function() {
d3_time_prototype.setUTCDate.apply(this._, arguments); d3_time_prototype.setUTCDate.apply(this._, arguments);
}, },
setDay: function() { setDay: function() {
d3_time_prototype.setUTCDay.apply(this._, arguments); d3_time_prototype.setUTCDay.apply(this._, arguments);
}, },
setFullYear: function() { setFullYear: function() {
d3_time_prototype.setUTCFullYear.apply(this._, arguments); d3_time_prototype.setUTCFullYear.apply(this._, arguments);
}, },
setHours: function() { setHours: function() {
d3_time_prototype.setUTCHours.apply(this._, arguments); d3_time_prototype.setUTCHours.apply(this._, arguments);
}, },
setMilliseconds: function() { setMilliseconds: function() {
d3_time_prototype.setUTCMilliseconds.apply(this._, arguments); d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
}, },
setMinutes: function() { setMinutes: function() {
d3_time_prototype.setUTCMinutes.apply(this._, arguments); d3_time_prototype.setUTCMinutes.apply(this._, arguments);
}, },
setMonth: function() { setMonth: function() {
d3_time_prototype.setUTCMonth.apply(this._, arguments); d3_time_prototype.setUTCMonth.apply(this._, arguments);
}, },
setSeconds: function() { setSeconds: function() {
d3_time_prototype.setUTCSeconds.apply(this._, arguments); d3_time_prototype.setUTCSeconds.apply(this._, arguments);
}, },
setTime: function() { setTime: function() {
d3_time_prototype.setTime.apply(this._, arguments); d3_time_prototype.setTime.apply(this._, arguments);
} }
}; };
var d3_time_prototype = Date.prototype; var d3_time_prototype = Date.prototype;
var d3_time_formatDateTime = "%a %b %e %H:%M:%S %Y", d3_time_formatDate = "%m/%d/%y", d3_time_formatTime = "%H:%M:%S"; var d3_time_formatDateTime = "%a %b %e %H:%M:%S %Y", d3_time_formatDate = "%m/%d/%y", d3_time_formatTime = "%H:%M:%S";
var d3_time_days = d3_time_daySymbols, d3_time_dayAbbreviations = d3_time_days.map(d3_time_formatAbbreviate), d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = d3_time_months.map(d3_time_formatAbbreviate); var d3_time_days = d3_time_daySymbols, d3_time_dayAbbreviations = d3_time_days.map(d3_time_formatAbbreviate), d3_time_months = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], d3_time_monthAbbreviations = d3_time_months.map(d3_time_formatAbbreviate);
d3.time.format = function(template) { d3.time.format = function(template) {
function format(date) { function format(date) {
var string = [], i = -1, j = 0, c, f; var string = [], i = -1, j = 0, c, f;
while (++i < n) { while (++i < n) {
if (template.charCodeAt(i) == 37) { if (template.charCodeAt(i) == 37) {
string.push(template.substring(j, i), (f = d3_time_formats[c = template.charAt(++i)]) ? f(date) : c); string.push(template.substring(j, i), (f = d3_time_formats[c = template.charAt(++i)]) ? f(date) : c);
j = i + 1; j = i + 1;
} }
} }
string.push(template.substring(j, i)); string.push(template.substring(j, i));
return string.join(""); return string.join("");
} }
var n = template.length; var n = template.length;
format.parse = function(string) { format.parse = function(string) {
var d = { var d = {
y: 1900, y: 1900,
m: 0, m: 0,
d: 1, d: 1,
H: 0, H: 0,
M: 0, M: 0,
S: 0, S: 0,
L: 0 L: 0
}, i = d3_time_parse(d, template, string, 0); }, i = d3_time_parse(d, template, string, 0);
if (i != string.length) return null; if (i != string.length) return null;
if ("p" in d) d.H = d.H % 12 + d.p * 12; if ("p" in d) d.H = d.H % 12 + d.p * 12;
var date = new d3_time; var date = new d3_time;
date.setFullYear(d.y, d.m, d.d); date.setFullYear(d.y, d.m, d.d);
date.setHours(d.H, d.M, d.S, d.L); date.setHours(d.H, d.M, d.S, d.L);
return date; return date;
}; };
format.toString = function() { format.toString = function() {
return template; return template;
}; };
return format; return format;
}; };
var d3_time_zfill2 = d3.format("02d"), d3_time_zfill3 = d3.format("03d"), d3_time_zfill4 = d3.format("04d"), d3_time_sfill2 = d3.format("2d"); var d3_time_zfill2 = d3.format("02d"), d3_time_zfill3 = d3.format("03d"), d3_time_zfill4 = d3.format("04d"), d3_time_sfill2 = d3.format("2d");
var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations); var d3_time_dayRe = d3_time_formatRe(d3_time_days), d3_time_dayAbbrevRe = d3_time_formatRe(d3_time_dayAbbreviations), d3_time_monthRe = d3_time_formatRe(d3_time_months), d3_time_monthLookup = d3_time_formatLookup(d3_time_months), d3_time_monthAbbrevRe = d3_time_formatRe(d3_time_monthAbbreviations), d3_time_monthAbbrevLookup = d3_time_formatLookup(d3_time_monthAbbreviations);
var d3_time_formats = { var d3_time_formats = {
a: function(d) { a: function(d) {
return d3_time_dayAbbreviations[d.getDay()]; return d3_time_dayAbbreviations[d.getDay()];
}, },
A: function(d) { A: function(d) {
return d3_time_days[d.getDay()]; return d3_time_days[d.getDay()];
}, },
b: function(d) { b: function(d) {
return d3_time_monthAbbreviations[d.getMonth()]; return d3_time_monthAbbreviations[d.getMonth()];
}, },
B: function(d) { B: function(d) {
return d3_time_months[d.getMonth()]; return d3_time_months[d.getMonth()];
}, },
c: d3.time.format(d3_time_formatDateTime), c: d3.time.format(d3_time_formatDateTime),
d: function(d) { d: function(d) {
return d3_time_zfill2(d.getDate()); return d3_time_zfill2(d.getDate());
}, },
e: function(d) { e: function(d) {
return d3_time_sfill2(d.getDate()); return d3_time_sfill2(d.getDate());
}, },
H: function(d) { H: function(d) {
return d3_time_zfill2(d.getHours()); return d3_time_zfill2(d.getHours());
}, },
I: function(d) { I: function(d) {
return d3_time_zfill2(d.getHours() % 12 || 12); return d3_time_zfill2(d.getHours() % 12 || 12);
}, },
j: function(d) { j: function(d) {
return d3_time_zfill3(1 + d3.time.dayOfYear(d)); return d3_time_zfill3(1 + d3.time.dayOfYear(d));
}, },
L: function(d) { L: function(d) {
return d3_time_zfill3(d.getMilliseconds()); return d3_time_zfill3(d.getMilliseconds());
}, },
m: function(d) { m: function(d) {
return d3_time_zfill2(d.getMonth() + 1); return d3_time_zfill2(d.getMonth() + 1);
}, },
M: function(d) { M: function(d) {
return d3_time_zfill2(d.getMinutes()); return d3_time_zfill2(d.getMinutes());
}, },
p: function(d) { p: function(d) {
return d.getHours() >= 12 ? "PM" : "AM"; return d.getHours() >= 12 ? "PM" : "AM";
}, },
S: function(d) { S: function(d) {
return d3_time_zfill2(d.getSeconds()); return d3_time_zfill2(d.getSeconds());
}, },
U: function(d) { U: function(d) {
return d3_time_zfill2(d3.time.sundayOfYear(d)); return d3_time_zfill2(d3.time.sundayOfYear(d));
}, },
w: function(d) { w: function(d) {
return d.getDay(); return d.getDay();
}, },
W: function(d) { W: function(d) {
return d3_time_zfill2(d3.time.mondayOfYear(d)); return d3_time_zfill2(d3.time.mondayOfYear(d));
}, },
x: d3.time.format(d3_time_formatDate), x: d3.time.format(d3_time_formatDate),
X: d3.time.format(d3_time_formatTime), X: d3.time.format(d3_time_formatTime),
y: function(d) { y: function(d) {
return d3_time_zfill2(d.getFullYear() % 100); return d3_time_zfill2(d.getFullYear() % 100);
}, },
Y: function(d) { Y: function(d) {
return d3_time_zfill4(d.getFullYear() % 1e4); return d3_time_zfill4(d.getFullYear() % 1e4);
}, },
Z: d3_time_zone, Z: d3_time_zone,
"%": function(d) { "%": function(d) {
return "%"; return "%";
} }
}; };
var d3_time_parsers = { var d3_time_parsers = {
a: d3_time_parseWeekdayAbbrev, a: d3_time_parseWeekdayAbbrev,
A: d3_time_parseWeekday, A: d3_time_parseWeekday,
b: d3_time_parseMonthAbbrev, b: d3_time_parseMonthAbbrev,
B: d3_time_parseMonth, B: d3_time_parseMonth,
c: d3_time_parseLocaleFull, c: d3_time_parseLocaleFull,
d: d3_time_parseDay, d: d3_time_parseDay,
e: d3_time_parseDay, e: d3_time_parseDay,
H: d3_time_parseHour24, H: d3_time_parseHour24,
I: d3_time_parseHour24, I: d3_time_parseHour24,
L: d3_time_parseMilliseconds, L: d3_time_parseMilliseconds,
m: d3_time_parseMonthNumber, m: d3_time_parseMonthNumber,
M: d3_time_parseMinutes, M: d3_time_parseMinutes,
p: d3_time_parseAmPm, p: d3_time_parseAmPm,
S: d3_time_parseSeconds, S: d3_time_parseSeconds,
x: d3_time_parseLocaleDate, x: d3_time_parseLocaleDate,
X: d3_time_parseLocaleTime, X: d3_time_parseLocaleTime,
y: d3_time_parseYear, y: d3_time_parseYear,
Y: d3_time_parseFullYear Y: d3_time_parseFullYear
}; };
var d3_time_numberRe = /^\s*\d+/; var d3_time_numberRe = /^\s*\d+/;
var d3_time_amPmLookup = d3.map({ var d3_time_amPmLookup = d3.map({
am: 0, am: 0,
pm: 1 pm: 1
}); });
d3.time.format.utc = function(template) { d3.time.format.utc = function(template) {
function format(date) { function format(date) {
try { try {
d3_time = d3_time_utc; d3_time = d3_time_utc;
var utc = new d3_time; var utc = new d3_time;
utc._ = date; utc._ = date;
return local(utc); return local(utc);
} finally { } finally {
d3_time = Date; d3_time = Date;
} }
} }
var local = d3.time.format(template); var local = d3.time.format(template);
format.parse = function(string) { format.parse = function(string) {
try { try {
d3_time = d3_time_utc; d3_time = d3_time_utc;
var date = local.parse(string); var date = local.parse(string);
return date && date._; return date && date._;
} finally { } finally {
d3_time = Date; d3_time = Date;
} }
}; };
format.toString = local.toString; format.toString = local.toString;
return format; return format;
}; };
var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ"); var d3_time_formatIso = d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");
d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso; d3.time.format.iso = Date.prototype.toISOString ? d3_time_formatIsoNative : d3_time_formatIso;
d3_time_formatIsoNative.parse = function(string) { d3_time_formatIsoNative.parse = function(string) {
var date = new Date(string); var date = new Date(string);
return isNaN(date) ? null : date; return isNaN(date) ? null : date;
}; };
d3_time_formatIsoNative.toString = d3_time_formatIso.toString; d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
d3.time.second = d3_time_interval(function(date) { d3.time.second = d3_time_interval(function(date) {
return new d3_time(Math.floor(date / 1e3) * 1e3); return new d3_time(Math.floor(date / 1e3) * 1e3);
}, function(date, offset) { }, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 1e3); date.setTime(date.getTime() + Math.floor(offset) * 1e3);
}, function(date) { }, function(date) {
return date.getSeconds(); return date.getSeconds();
}); });
d3.time.seconds = d3.time.second.range; d3.time.seconds = d3.time.second.range;
d3.time.seconds.utc = d3.time.second.utc.range; d3.time.seconds.utc = d3.time.second.utc.range;
d3.time.minute = d3_time_interval(function(date) { d3.time.minute = d3_time_interval(function(date) {
return new d3_time(Math.floor(date / 6e4) * 6e4); return new d3_time(Math.floor(date / 6e4) * 6e4);
}, function(date, offset) { }, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 6e4); date.setTime(date.getTime() + Math.floor(offset) * 6e4);
}, function(date) { }, function(date) {
return date.getMinutes(); return date.getMinutes();
}); });
d3.time.minutes = d3.time.minute.range; d3.time.minutes = d3.time.minute.range;
d3.time.minutes.utc = d3.time.minute.utc.range; d3.time.minutes.utc = d3.time.minute.utc.range;
d3.time.hour = d3_time_interval(function(date) { d3.time.hour = d3_time_interval(function(date) {
var timezone = date.getTimezoneOffset() / 60; var timezone = date.getTimezoneOffset() / 60;
return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5); return new d3_time((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
}, function(date, offset) { }, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 36e5); date.setTime(date.getTime() + Math.floor(offset) * 36e5);
}, function(date) { }, function(date) {
return date.getHours(); return date.getHours();
}); });
d3.time.hours = d3.time.hour.range; d3.time.hours = d3.time.hour.range;
d3.time.hours.utc = d3.time.hour.utc.range; d3.time.hours.utc = d3.time.hour.utc.range;
d3.time.day = d3_time_interval(function(date) { d3.time.day = d3_time_interval(function(date) {
var day = new d3_time(1970, 0); var day = new d3_time(1970, 0);
day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate()); day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
return day; return day;
}, function(date, offset) { }, function(date, offset) {
date.setDate(date.getDate() + offset); date.setDate(date.getDate() + offset);
}, function(date) { }, function(date) {
return date.getDate() - 1; return date.getDate() - 1;
}); });
d3.time.days = d3.time.day.range; d3.time.days = d3.time.day.range;
d3.time.days.utc = d3.time.day.utc.range; d3.time.days.utc = d3.time.day.utc.range;
d3.time.dayOfYear = function(date) { d3.time.dayOfYear = function(date) {
var year = d3.time.year(date); var year = d3.time.year(date);
return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5); return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
}; };
d3_time_daySymbols.forEach(function(day, i) { d3_time_daySymbols.forEach(function(day, i) {
day = day.toLowerCase(); day = day.toLowerCase();
i = 7 - i; i = 7 - i;
var interval = d3.time[day] = d3_time_interval(function(date) { var interval = d3.time[day] = d3_time_interval(function(date) {
(date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7); (date = d3.time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
return date; return date;
}, function(date, offset) { }, function(date, offset) {
date.setDate(date.getDate() + Math.floor(offset) * 7); date.setDate(date.getDate() + Math.floor(offset) * 7);
}, function(date) { }, function(date) {
var day = d3.time.year(date).getDay(); var day = d3.time.year(date).getDay();
return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i); return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
}); });
d3.time[day + "s"] = interval.range; d3.time[day + "s"] = interval.range;
d3.time[day + "s"].utc = interval.utc.range; d3.time[day + "s"].utc = interval.utc.range;
d3.time[day + "OfYear"] = function(date) { d3.time[day + "OfYear"] = function(date) {
var day = d3.time.year(date).getDay(); var day = d3.time.year(date).getDay();
return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7); return Math.floor((d3.time.dayOfYear(date) + (day + i) % 7) / 7);
}; };
}); });
d3.time.week = d3.time.sunday; d3.time.week = d3.time.sunday;
d3.time.weeks = d3.time.sunday.range; d3.time.weeks = d3.time.sunday.range;
d3.time.weeks.utc = d3.time.sunday.utc.range; d3.time.weeks.utc = d3.time.sunday.utc.range;
d3.time.weekOfYear = d3.time.sundayOfYear; d3.time.weekOfYear = d3.time.sundayOfYear;
d3.time.month = d3_time_interval(function(date) { d3.time.month = d3_time_interval(function(date) {
date = d3.time.day(date); date = d3.time.day(date);
date.setDate(1); date.setDate(1);
return date; return date;
}, function(date, offset) { }, function(date, offset) {
date.setMonth(date.getMonth() + offset); date.setMonth(date.getMonth() + offset);
}, function(date) { }, function(date) {
return date.getMonth(); return date.getMonth();
}); });
d3.time.months = d3.time.month.range; d3.time.months = d3.time.month.range;
d3.time.months.utc = d3.time.month.utc.range; d3.time.months.utc = d3.time.month.utc.range;
d3.time.year = d3_time_interval(function(date) { d3.time.year = d3_time_interval(function(date) {
date = d3.time.day(date); date = d3.time.day(date);
date.setMonth(0, 1); date.setMonth(0, 1);
return date; return date;
}, function(date, offset) { }, function(date, offset) {
date.setFullYear(date.getFullYear() + offset); date.setFullYear(date.getFullYear() + offset);
}, function(date) { }, function(date) {
return date.getFullYear(); return date.getFullYear();
}); });
d3.time.years = d3.time.year.range; d3.time.years = d3.time.year.range;
d3.time.years.utc = d3.time.year.utc.range; d3.time.years.utc = d3.time.year.utc.range;
var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ]; var d3_time_scaleSteps = [ 1e3, 5e3, 15e3, 3e4, 6e4, 3e5, 9e5, 18e5, 36e5, 108e5, 216e5, 432e5, 864e5, 1728e5, 6048e5, 2592e6, 7776e6, 31536e6 ];
var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ]; var d3_time_scaleLocalMethods = [ [ d3.time.second, 1 ], [ d3.time.second, 5 ], [ d3.time.second, 15 ], [ d3.time.second, 30 ], [ d3.time.minute, 1 ], [ d3.time.minute, 5 ], [ d3.time.minute, 15 ], [ d3.time.minute, 30 ], [ d3.time.hour, 1 ], [ d3.time.hour, 3 ], [ d3.time.hour, 6 ], [ d3.time.hour, 12 ], [ d3.time.day, 1 ], [ d3.time.day, 2 ], [ d3.time.week, 1 ], [ d3.time.month, 1 ], [ d3.time.month, 3 ], [ d3.time.year, 1 ] ];
var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), function(d) { var d3_time_scaleLocalFormats = [ [ d3.time.format("%Y"), function(d) {
return true; return true;
} ], [ d3.time.format("%B"), function(d) { } ], [ d3.time.format("%B"), function(d) {
return d.getMonth(); return d.getMonth();
} ], [ d3.time.format("%b %d"), function(d) { } ], [ d3.time.format("%b %d"), function(d) {
return d.getDate() != 1; return d.getDate() != 1;
} ], [ d3.time.format("%a %d"), function(d) { } ], [ d3.time.format("%a %d"), function(d) {
return d.getDay() && d.getDate() != 1; return d.getDay() && d.getDate() != 1;
} ], [ d3.time.format("%I %p"), function(d) { } ], [ d3.time.format("%I %p"), function(d) {
return d.getHours(); return d.getHours();
} ], [ d3.time.format("%I:%M"), function(d) { } ], [ d3.time.format("%I:%M"), function(d) {
return d.getMinutes(); return d.getMinutes();
} ], [ d3.time.format(":%S"), function(d) { } ], [ d3.time.format(":%S"), function(d) {
return d.getSeconds(); return d.getSeconds();
} ], [ d3.time.format(".%L"), function(d) { } ], [ d3.time.format(".%L"), function(d) {
return d.getMilliseconds(); return d.getMilliseconds();
} ] ]; } ] ];
var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats); var d3_time_scaleLinear = d3.scale.linear(), d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);
d3_time_scaleLocalMethods.year = function(extent, m) { d3_time_scaleLocalMethods.year = function(extent, m) {
return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear); return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);
}; };
d3.time.scale = function() { d3.time.scale = function() {
return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat); return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
}; };
var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) { var d3_time_scaleUTCMethods = d3_time_scaleLocalMethods.map(function(m) {
return [ m[0].utc, m[1] ]; return [ m[0].utc, m[1] ];
}); });
var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), function(d) { var d3_time_scaleUTCFormats = [ [ d3.time.format.utc("%Y"), function(d) {
return true; return true;
} ], [ d3.time.format.utc("%B"), function(d) { } ], [ d3.time.format.utc("%B"), function(d) {
return d.getUTCMonth(); return d.getUTCMonth();
} ], [ d3.time.format.utc("%b %d"), function(d) { } ], [ d3.time.format.utc("%b %d"), function(d) {
return d.getUTCDate() != 1; return d.getUTCDate() != 1;
} ], [ d3.time.format.utc("%a %d"), function(d) { } ], [ d3.time.format.utc("%a %d"), function(d) {
return d.getUTCDay() && d.getUTCDate() != 1; return d.getUTCDay() && d.getUTCDate() != 1;
} ], [ d3.time.format.utc("%I %p"), function(d) { } ], [ d3.time.format.utc("%I %p"), function(d) {
return d.getUTCHours(); return d.getUTCHours();
} ], [ d3.time.format.utc("%I:%M"), function(d) { } ], [ d3.time.format.utc("%I:%M"), function(d) {
return d.getUTCMinutes(); return d.getUTCMinutes();
} ], [ d3.time.format.utc(":%S"), function(d) { } ], [ d3.time.format.utc(":%S"), function(d) {
return d.getUTCSeconds(); return d.getUTCSeconds();
} ], [ d3.time.format.utc(".%L"), function(d) { } ], [ d3.time.format.utc(".%L"), function(d) {
return d.getUTCMilliseconds(); return d.getUTCMilliseconds();
} ] ]; } ] ];
var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats); var d3_time_scaleUTCFormat = d3_time_scaleFormat(d3_time_scaleUTCFormats);
d3_time_scaleUTCMethods.year = function(extent, m) { d3_time_scaleUTCMethods.year = function(extent, m) {
return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear); return d3_time_scaleLinear.domain(extent.map(d3_time_scaleUTCGetYear)).ticks(m).map(d3_time_scaleUTCSetYear);
}; };
d3.time.scale.utc = function() { d3.time.scale.utc = function() {
return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat); return d3_time_scale(d3.scale.linear(), d3_time_scaleUTCMethods, d3_time_scaleUTCFormat);
}; };
})(); })();}
   
  if (Modernizr.svg){
var Rickshaw={namespace:function(a,b){var c=a.split("."),d=Rickshaw;for(var e=1,f=c.length;e<f;e++)currentPart=c[e],d[currentPart]=d[currentPart]||{},d=d[currentPart];return d},keys:function(a){var b=[];for(var c in a)b.push(c);return b},extend:function(a,b){for(var c in b)a[c]=b[c];return a}};if(typeof module!="undefined"&&module.exports){var d3=require("d3");module.exports=Rickshaw}(function(a){function j(a){return b.call(a)===i}function k(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function l(a){if(m(a)!==h)throw new TypeError;var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b}function m(a){switch(a){case null:return c;case void 0:return d}var b=typeof a;switch(b){case"boolean":return e;case"number":return f;case"string":return g}return h}function n(a){return typeof a=="undefined"}function p(a){var b=a.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g,"").replace(/\s+/g,"").split(",");return b.length==1&&!b[0]?[]:b}function q(a,b){var c=a;return function(){var a=r([t(c,this)],arguments);return b.apply(this,a)}}function r(a,b){var c=a.length,d=b.length;while(d--)a[c+d]=b[d];return a}function s(a,b){return a=o.call(a,0),r(a,b)}function t(a,b){if(arguments.length<2&&n(arguments[0]))return this;var c=a,d=o.call(arguments,2);return function(){var a=s(d,arguments);return c.apply(b,a)}}var b=Object.prototype.toString,c="Null",d="Undefined",e="Boolean",f="Number",g="String",h="Object",i="[object Function]",o=Array.prototype.slice,u=function(){},v=function(){function b(){}function c(){function d(){this.initialize.apply(this,arguments)}var a=null,c=[].slice.apply(arguments);j(c[0])&&(a=c.shift()),k(d,v.Methods),d.superclass=a,d.subclasses=[];if(a){b.prototype=a.prototype,d.prototype=new b;try{a.subclasses.push(d)}catch(e){}}for(var f=0,g=c.length;f<g;f++)d.addMethods(c[f]);return d.prototype.initialize||(d.prototype.initialize=u),d.prototype.constructor=d,d}function d(b){var c=this.superclass&&this.superclass.prototype,d=l(b);a&&(b.toString!=Object.prototype.toString&&d.push("toString"),b.valueOf!=Object.prototype.valueOf&&d.push("valueOf"));for(var e=0,f=d.length;e<f;e++){var g=d[e],h=b[g];if(c&&j(h)&&p(h)[0]=="$super"){var i=h;h=q(function(a){return function(){return c[a].apply(this,arguments)}}(g),i),h.valueOf=t(i.valueOf,i),h.toString=t(i.toString,i)}this.prototype[g]=h}return this}var a=function(){for(var a in{toString:1})if(a==="toString")return!1;return!0}();return{create:c,Methods:{addMethods:d}}}();a.exports?a.exports.Class=v:a.Class=v})(Rickshaw),Rickshaw.namespace("Rickshaw.Compat.ClassList"),Rickshaw.Compat.ClassList=function(){typeof document!="undefined"&&!("classList"in document.createElement("a"))&&function(a){"use strict";var b="classList",c="prototype",d=(a.HTMLElement||a.Element)[c],e=Object,f=String[c].trim||function(){return this.replace(/^\s+|\s+$/g,"")},g=Array[c].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(b in this&&this[b]===a)return b;return-1},h=function(a,b){this.name=a,this.code=DOMException[a],this.message=b},i=function(a,b){if(b==="")throw new h("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(b))throw new h("INVALID_CHARACTER_ERR","String contains an invalid character");return g.call(a,b)},j=function(a){var b=f.call(a.className),c=b?b.split(/\s+/):[],d=0,e=c.length;for(;d<e;d++)this.push(c[d]);this._updateClassName=function(){a.className=this.toString()}},k=j[c]=[],l=function(){return new j(this)};h[c]=Error[c],k.item=function(a){return this[a]||null},k.contains=function(a){return a+="",i(this,a)!==-1},k.add=function(a){a+="",i(this,a)===-1&&(this.push(a),this._updateClassName())},k.remove=function(a){a+="";var b=i(this,a);b!==-1&&(this.splice(b,1),this._updateClassName())},k.toggle=function(a){a+="",i(this,a)===-1?this.add(a):this.remove(a)},k.toString=function(){return this.join(" ")};if(e.defineProperty){var m={get:l,enumerable:!0,configurable:!0};try{e.defineProperty(d,b,m)}catch(n){n.number===-2146823252&&(m.enumerable=!1,e.defineProperty(d,b,m))}}else e[c].__defineGetter__&&d.__defineGetter__(b,l)}(window)},(typeof RICKSHAW_NO_COMPAT!="undefined"&&!RICKSHAW_NO_COMPAT||typeof RICKSHAW_NO_COMPAT=="undefined")&&new Rickshaw.Compat.ClassList,Rickshaw.namespace("Rickshaw.Graph"),Rickshaw.Graph=function(a){this.element=a.element,this.series=a.series,this.defaults={interpolation:"cardinal",offset:"zero",min:undefined,max:undefined},Rickshaw.keys(this.defaults).forEach(function(b){this[b]=a[b]||this.defaults[b]},this),this.window={},this.updateCallbacks=[];var b=this;this.initialize=function(a){this.validateSeries(a.series),this.series.active=function(){return b.series.filter(function(a){return!a.disabled})},this.setSize({width:a.width,height:a.height}),this.element.classList.add("rickshaw_graph"),this.vis=d3.select(this.element).append("svg:svg").attr("width",this.width).attr("height",this.height);var c=[Rickshaw.Graph.Renderer.Stack,Rickshaw.Graph.Renderer.Line,Rickshaw.Graph.Renderer.Bar,Rickshaw.Graph.Renderer.Area,Rickshaw.Graph.Renderer.ScatterPlot];c.forEach(function(a){if(!a)return;b.registerRenderer(new a({graph:b}))}),this.setRenderer(a.renderer||"stack",a),this.discoverRange()},this.validateSeries=function(a){if(!(a instanceof Array||a instanceof Rickshaw.Series)){var b=Object.prototype.toString.apply(a);throw"series is not an array: "+b}var c;a.forEach(function(a){if(!(a instanceof Object))throw"series element is not an object: "+a;if(!a.data)throw"series has no data: "+JSON.stringify(a);if(!(a.data instanceof Array))throw"series data is not an array: "+JSON.stringify(a.data);c=c||a.data.length;if(c&&a.data.length!=c)throw"series cannot have differing numbers of points: "+c+" vs "+a.data.length+"; see Rickshaw.Series.zeroFill()";var b=typeof a.data[0].x,d=typeof a.data[0].y;if(b!="number"||d!="number")throw"x and y properties of points should be numbers instead of "+b+" and "+d})},this.dataDomain=function(){var a=this.series[0].data;return[a[0].x,a.slice(-1).shift().x]},this.discoverRange=function(){var a=this.renderer.domain();this.x=d3.scale.linear().domain(a.x).range([0,this.width]),this.y=d3.scale.linear().domain(a.y).range([this.height,0]),this.y.magnitude=d3.scale.linear().domain([a.y[0]-a.y[0],a.y[1]-a.y[0]]).range([0,this.height])},this.render=function(){var a=this.stackData();this.discoverRange(),this.renderer.render(),this.updateCallbacks.forEach(function(a){a()})},this.update=this.render,this.stackData=function(){var a=this.series.active().map(function(a){return a.data}).map(function(a){return a.filter(function(a){return this._slice(a)},this)},this);this.stackData.hooks.data.forEach(function(c){a=c.f.apply(b,[a])});var c=d3.layout.stack();c.offset(b.offset);var d=c(a);this.stackData.hooks.after.forEach(function(c){d=c.f.apply(b,[a])});var e=0;return this.series.forEach(function(a){if(a.disabled)return;a.stack=d[e++]}),this.stackedData=d,d},this.stackData.hooks={data:[],after:[]},this._slice=function(a){if(this.window.xMin||this.window.xMax){var b=!0;return this.window.xMin&&a.x<this.window.xMin&&(b=!1),this.window.xMax&&a.x>this.window.xMax&&(b=!1),b}return!0},this.onUpdate=function(a){this.updateCallbacks.push(a)},this.registerRenderer=function(a){this._renderers=this._renderers||{},this._renderers[a.name]=a},this.configure=function(a){(a.width||a.height)&&this.setSize(a),Rickshaw.keys(this.defaults).forEach(function(b){this[b]=b in a?a[b]:b in this?this[b]:this.defaults[b]},this),this.setRenderer(a.renderer||this.renderer.name,a)},this.setRenderer=function(a,b){if(!this._renderers[a])throw"couldn't find renderer "+a;this.renderer=this._renderers[a],typeof b=="object"&&this.renderer.configure(b)},this.setSize=function(a){a=a||{};if(typeof window!==undefined)var b=window.getComputedStyle(this.element,null),c=parseInt(b.getPropertyValue("width")),d=parseInt(b.getPropertyValue("height"));this.width=a.width||c||400,this.height=a.height||d||250,this.vis&&this.vis.attr("width",this.width).attr("height",this.height)},this.initialize(a)},Rickshaw.namespace("Rickshaw.Fixtures.Color"),Rickshaw.Fixtures.Color=function(){this.schemes={},this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse(),this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"],this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"],this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse(),this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"},this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse(),this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"],this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]},Rickshaw.namespace("Rickshaw.Fixtures.RandomData"),Rickshaw.Fixtures.RandomData=function(a){var b;a=a||1;var c=200,d=Math.floor((new Date).getTime()/1e3);this.addData=function(b){var e=Math.random()*100+15+c,f=b[0].length,g=1;b.forEach(function(b){var c=Math.random()*20,h=e/25+g++ +(Math.cos(f*g*11/960)+2)*15+(Math.cos(f/7)+2)*7+(Math.cos(f/17)+2)*1;b.push({x:f*a+d,y:h+c})}),c=e*.85}},Rickshaw.namespace("Rickshaw.Fixtures.Time"),Rickshaw.Fixtures.Time=function(){var a=(new Date).getTimezoneOffset()*60,b=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],this.units=[{name:"decade",seconds:315576e3,formatter:function(a){return parseInt(a.getUTCFullYear()/10)*10}},{name:"year",seconds:31557600,formatter:function(a){return a.getUTCFullYear()}},{name:"month",seconds:2635200,formatter:function(a){return b.months[a.getUTCMonth()]}},{name:"week",seconds:604800,formatter:function(a){return b.formatDate(a)}},{name:"day",seconds:86400,formatter:function(a){return a.getUTCDate()}},{name:"6 hour",seconds:21600,formatter:function(a){return b.formatTime(a)}},{name:"hour",seconds:3600,formatter:function(a){return b.formatTime(a)}},{name:"15 minute",seconds:900,formatter:function(a){return b.formatTime(a)}},{name:"minute",seconds:60,formatter:function(a){return a.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(a){return a.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(a){return a.getUTCSeconds()+"s"}}],this.unit=function(a){return this.units.filter(function(b){return a==b.name}).shift()},this.formatDate=function(a){return a.toUTCString().match(/, (\w+ \w+ \w+)/)[1]},this.formatTime=function(a){return a.toUTCString().match(/(\d+:\d+):/)[1]},this.ceil=function(a,b){if(b.name=="month"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(c.getUTCMonth()),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}if(b.name=="year"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(0),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}return Math.ceil(a/b.seconds)*b.seconds}},Rickshaw.namespace("Rickshaw.Fixtures.Number"),Rickshaw.Fixtures.Number.formatKMBT=function(a){return a>=1e12?a/1e12+"T":a>=1e9?a/1e9+"B":a>=1e6?a/1e6+"M":a>=1e3?a/1e3+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(a){return a>=0x4000000000000?a/0x4000000000000+"P":a>=1099511627776?a/1099511627776+"T":a>=1073741824?a/1073741824+"G":a>=1048576?a/1048576+"M":a>=1024?a/1024+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.namespace("Rickshaw.Color.Palette"),Rickshaw.Color.Palette=function(a){var b=new Rickshaw.Fixtures.Color;a=a||{},this.schemes={},this.scheme=b.schemes[a.scheme]||a.scheme||b.schemes.colorwheel,this.runningIndex=0,this.generatorIndex=0;if(a.interpolatedStopCount){var c=this.scheme.length-1,d,e,f=[];for(d=0;d<c;d++){f.push(this.scheme[d]);var g=d3.interpolateHsl(this.scheme[d],this.scheme[d+1]);for(e=1;e<a.interpolatedStopCount;e++)f.push(g(1/a.interpolatedStopCount*e))}f.push(this.scheme[this.scheme.length-1]),this.scheme=f}this.rotateCount=this.scheme.length,this.color=function(a){return this.scheme[a]||this.scheme[this.runningIndex++]||this.interpolateColor()||"#808080"},this.interpolateColor=function(){if(!Array.isArray(this.scheme))return;var a;return this.generatorIndex==this.rotateCount*2-1?(a=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[0])(.5),this.generatorIndex=0,this.rotateCount*=2):(a=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[this.generatorIndex+1])(.5),this.generatorIndex++),this.scheme.push(a),a}},Rickshaw.namespace("Rickshaw.Graph.Ajax"),Rickshaw.Graph.Ajax=Rickshaw.Class.create({initialize:function(a){this.dataURL=a.dataURL,this.onData=a.onData||function(a){return a},this.onComplete=a.onComplete||function(){},this.onError=a.onError||function(){},this.args=a,this.request()},request:function(){$.ajax({url:this.dataURL,dataType:"json",success:this.success.bind(this),error:this.error.bind(this)})},error:function(){console.log("error loading dataURL: "+this.dataURL),this.onError(this)},success:function(a,b){a=this.onData(a),this.args.series=this._splice({data:a,series:this.args.series}),this.graph=new Rickshaw.Graph(this.args),this.graph.render(),this.onComplete(this)},_splice:function(a){var b=a.data,c=a.series;return a.series?(c.forEach(function(a){var c=a.key||a.name;if(!c)throw"series needs a key or a name";b.forEach(function(b){var d=b.key||b.name;if(!d)throw"data needs a key or a name";if(c==d){var e=["color","name","data"];e.forEach(function(c){a[c]=a[c]||b[c]})}})}),c):b}}),Rickshaw.namespace("Rickshaw.Graph.Annotate"),Rickshaw.Graph.Annotate=function(a){var b=this.graph=a.graph;this.elements={timeline:a.element};var c=this;this.data={},this.elements.timeline.classList.add("rickshaw_annotation_timeline"),this.add=function(a,b,d){c.data[a]=c.data[a]||{boxes:[]},c.data[a].boxes.push({content:b,end:d})},this.update=function(){Rickshaw.keys(c.data).forEach(function(a){var b=c.data[a],d=c.graph.x(a);if(d<0||d>c.graph.x.range()[1]){b.element&&(b.line.classList.add("offscreen"),b.element.style.display="none"),b.boxes.forEach(function(a){a.rangeElement&&a.rangeElement.classList.add("offscreen")});return}if(!b.element){var e=b.element=document.createElement("div");e.classList.add("annotation"),this.elements.timeline.appendChild(e),e.addEventListener("click",function(a){e.classList.toggle("active"),b.line.classList.toggle("active"),b.boxes.forEach(function(a){a.rangeElement&&a.rangeElement.classList.toggle("active")})},!1)}b.element.style.left=d+"px",b.element.style.display="block",b.boxes.forEach(function(a){var e=a.element;e||(e=a.element=document.createElement("div"),e.classList.add("content"),e.innerHTML=a.content,b.element.appendChild(e),b.line=document.createElement("div"),b.line.classList.add("annotation_line"),c.graph.element.appendChild(b.line),a.end&&(a.rangeElement=document.createElement("div"),a.rangeElement.classList.add("annotation_range"),c.graph.element.appendChild(a.rangeElement)));if(a.end){var f=d,g=Math.min(c.graph.x(a.end),c.graph.x.range()[1]);f>g&&(g=d,f=Math.max(c.graph.x(a.end),c.graph.x.range()[0]));var h=g-f;a.rangeElement.style.left=f+"px",a.rangeElement.style.width=h+"px",a.rangeElement.classList.remove("offscreen")}b.line.classList.remove("offscreen"),b.line.style.left=d+"px"})},this)},this.graph.onUpdate(function(){c.update()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Time"),Rickshaw.Graph.Axis.Time=function(a){var b=this;this.graph=a.graph,this.elements=[],this.ticksTreatment=a.ticksTreatment||"plain",this.fixedTimeUnit=a.timeUnit;var c=new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var a,b=c.units,d=this.graph.x.domain(),e=d[1]-d[0];return b.forEach(function(b){Math.floor(e/b.seconds)>=2&&(a=a||b)}),a||c.units[c.units.length-1]},this.tickOffsets=function(){var a=this.graph.x.domain(),b=this.fixedTimeUnit||this.appropriateTimeUnit(),d=Math.ceil((a[1]-a[0])/b.seconds),e=a[0],f=[];for(var g=0;g<d;g++)tickValue=c.ceil(e,b),e=tickValue+b.seconds/2,f.push({value:tickValue,unit:b});return f},this.render=function(){this.elements.forEach(function(a){a.parentNode.removeChild(a)}),this.elements=[];var a=this.tickOffsets();a.forEach(function(a){if(b.graph.x(a.value)>b.graph.x.range()[1])return;var c=document.createElement("div");c.style.left=b.graph.x(a.value)+"px",c.classList.add("x_tick"),c.classList.add(b.ticksTreatment);var d=document.createElement("div");d.classList.add("title"),d.innerHTML=a.unit.formatter(new Date(a.value*1e3)),c.appendChild(d),b.graph.element.appendChild(c),b.elements.push(c)})},this.graph.onUpdate(function(){b.render()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Y"),Rickshaw.Graph.Axis.Y=function(a){var b=this,c=.1;this.initialize=function(a){this.graph=a.graph,this.orientation=a.orientation||"right";var c=a.pixelsPerTick||75;this.ticks=a.ticks||Math.floor(this.graph.height/c),this.tickSize=a.tickSize||4,this.ticksTreatment=a.ticksTreatment||"plain",a.element?(this.element=a.element,this.vis=d3.select(a.element).append("svg:svg").attr("class","rickshaw_graph y_axis"),this.element=this.vis[0][0],this.element.style.position="relative",this.setSize({width:a.width,height:a.height})):this.vis=this.graph.vis,this.graph.onUpdate(function(){b.render()})},this.setSize=function(a){a=a||{};if(!this.element)return;if(typeof window!="undefined"){var b=window.getComputedStyle(this.element.parentNode,null),d=parseInt(b.getPropertyValue("width"));if(!a.auto)var e=parseInt(b.getPropertyValue("height"))}this.width=a.width||d||this.graph.width*c,this.height=a.height||e||this.graph.height,this.vis.attr("width",this.width).attr("height",this.height*(1+c));var f=this.height*c;this.element.style.top=-1*f+"px"},this.render=function(){this.graph.height!==this._renderHeight&&this.setSize({auto:!0});var b=d3.svg.axis().scale(this.graph.y).orient(this.orientation);b.tickFormat(a.tickFormat||function(a){return a});if(this.orientation=="left")var d=this.height*c,e="translate("+this.width+", "+d+")";this.element&&this.vis.selectAll("*").remove(),this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",e).call(b.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var f=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(b.ticks(this.ticks).tickSubdivide(0).tickSize(f)),this._renderHeight=this.graph.height},this.initialize(a)},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight"),Rickshaw.Graph.Behavior.Series.Highlight=function(a){this.graph=a.graph,this.legend=a.legend;var b=this,c={};this.addHighlightEvents=function(a){a.element.addEventListener("mouseover",function(d){b.legend.lines.forEach(function(b){if(a===b)return;c[b.series.name]=c[b.series.name]||b.series.color,b.series.color=d3.interpolateRgb(b.series.color,d3.rgb("#d8d8d8"))(.8).toString()}),b.graph.update()},!1),a.element.addEventListener("mouseout",function(a){b.legend.lines.forEach(function(a){c[a.series.name]&&(a.series.color=c[a.series.name])}),b.graph.update()},!1)},this.legend&&this.legend.lines.forEach(function(a){b.addHighlightEvents(a)})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order"),Rickshaw.Graph.Behavior.Series.Order=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;$(function(){$(b.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(a,c){var d=[];$(b.legend.list).find("li").each(function(a,b){if(!b.series)return;d.push(b.series)});for(var e=b.graph.series.length-1;e>=0;e--)b.graph.series[e]=d.shift();b.graph.update()}}),$(b.legend.list).disableSelection()}),this.graph.onUpdate(function(){var a=window.getComputedStyle(b.legend.element).height;b.legend.element.style.height=a})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle"),Rickshaw.Graph.Behavior.Series.Toggle=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;this.addAnchor=function(a){var c=document.createElement("a");c.innerHTML="&#10004;",c.classList.add("action"),a.element.insertBefore(c,a.element.firstChild),c.onclick=function(b){a.series.disabled?(a.series.enable(),a.element.classList.remove("disabled")):(a.series.disable(),a.element.classList.add("disabled"))};var d=a.element.getElementsByTagName("span")[0];d.onclick=function(c){var d=a.series.disabled;if(!d)for(var e=0;e<b.legend.lines.length;e++){var f=b.legend.lines[e];if(a.series!==f.series&&!f.series.disabled){d=!0;break}}d?(a.series.enable(),a.element.classList.remove("disabled"),b.legend.lines.forEach(function(b){a.series!==b.series&&(b.series.disable(),b.element.classList.add("disabled"))})):b.legend.lines.forEach(function(a){a.series.enable(),a.element.classList.remove("disabled")})}},this.legend&&($(this.legend.list).sortable({start:function(a,b){b.item.bind("no.onclick",function(a){a.preventDefault()})},stop:function(a,b){setTimeout(function(){b.item.unbind("no.onclick")},250)}}),this.legend.lines.forEach(function(a){b.addAnchor(a)})),this._addBehavior=function(){this.graph.series.forEach(function(a){a.disable=function(){if(b.graph.series.length<=1)throw"only one series left";a.disabled=!0,b.graph.update()},a.enable=function(){a.disabled=!1,b.graph.update()}})},this._addBehavior(),this.updateBehaviour=function(){this._addBehavior()}},Rickshaw.namespace("Rickshaw.Graph.HoverDetail"),Rickshaw.Graph.HoverDetail=Rickshaw.Class.create({initialize:function(a){var b=this.graph=a.graph;this.xFormatter=a.xFormatter||function(a){return(new Date(a*1e3)).toUTCString()},this.yFormatter=a.yFormatter||function(a){return a.toFixed(2)};var c=this.element=document.createElement("div");c.className="detail",this.visible=!0,b.element.appendChild(c),this.lastEvent=null,this._addListeners(),this.onShow=a.onShow,this.onHide=a.onHide,this.onRender=a.onRender,this.formatter=a.formatter||this.formatter},formatter:function(a,b,c,d,e,f){return a.name+":&nbsp;"+e},update:function(a){a=a||this.lastEvent;if(!a)return;this.lastEvent=a;if(!a.target.nodeName.match(/^(path|svg|rect)$/))return;var b=this.graph,c=a.offsetX||a.layerX,d=a.offsetY||a.layerY,e=b.x.invert(c),f=b.stackedData,g=f.slice(-1).shift(),h=d3.scale.linear().domain([g[0].x,g.slice(-1).shift().x]).range([0,g.length]),i=Math.floor(h(e)),j=Math.min(i||0,f[0].length-1);for(var k=i;k<f[0].length-1;){if(!f[0][k]||!f[0][k+1])break;if(f[0][k].x<=e&&f[0][k+1].x>e){j=k;break}f[0][k+1]<=e?k++:k--}var e=f[0][j].x,l=this.xFormatter(e),m=b.x(e),n=0,o=b.series.active().map(function(a){return{order:n++,series:a,name:a.name,value:a.stack[j]}}),p,q=function(a,b){return a.value.y0+a.value.y-(b.value.y0+b.value.y)},r=b.y.magnitude.invert(b.element.offsetHeight-d);o.sort(q).forEach(function(a){a.formattedYValue=this.yFormatter.constructor==Array?this.yFormatter[o.indexOf(a)](a.value.y):this.yFormatter(a.value.y),a.graphX=m,a.graphY=b.y(a.value.y0+a.value.y),r>a.value.y0&&r<a.value.y0+a.value.y&&!p&&(p=a,a.active=!0)},this),this.element.innerHTML="",this.element.style.left=b.x(e)+"px",this.visible&&this.render({detail:o,domainX:e,formattedXValue:l,mouseX:c,mouseY:d})},hide:function(){this.visible=!1,this.element.classList.add("inactive"),typeof this.onHide=="function"&&this.onHide()},show:function(){this.visible=!0,this.element.classList.remove("inactive"),typeof this.onShow=="function"&&this.onShow()},render:function(a){var b=a.detail,c=a.domainX,d=a.mouseX,e=a.mouseY,f=a.formattedXValue,g=document.createElement("div");g.className="x_label",g.innerHTML=f,this.element.appendChild(g),b.forEach(function(a){var b=document.createElement("div");b.className="item",b.innerHTML=this.formatter(a.series,c,a.value.y,f,a.formattedYValue,a),b.style.top=this.graph.y(a.value.y0+a.value.y)+"px",this.element.appendChild(b);var d=document.createElement("div");d.className="dot",d.style.top=b.style.top,d.style.borderColor=a.series.color,this.element.appendChild(d),a.active&&(b.className="item active",d.className="dot active")},this),this.show(),typeof this.onRender=="function"&&this.onRender(a)},_addListeners:function(){this.graph.element.addEventListener("mousemove",function(a){this.visible=!0,this.update(a)}.bind(this),!1),this.graph.onUpdate(function(){this.update()}.bind(this)),this.graph.element.addEventListener("mouseout",function(a){a.relatedTarget&&!(a.relatedTarget.compareDocumentPosition(this.graph.element)&Node.DOCUMENT_POSITION_CONTAINS)&&this.hide()}.bind(this),!1)}}),Rickshaw.namespace("Rickshaw.Graph.JSONP"),Rickshaw.Graph.JSONP=Rickshaw.Class.create(Rickshaw.Graph.Ajax,{request:function(){$.ajax({url:this.dataURL,dataType:"jsonp",success:this.success.bind(this),error:this.error.bind(this)})}}),Rickshaw.namespace("Rickshaw.Graph.Legend"),Rickshaw.Graph.Legend=function(a){var b=this.element=a.element,c=this.graph=a.graph,d=this;b.classList.add("rickshaw_legend");var e=this.list=document.createElement("ul");b.appendChild(e);var f=c.series.map(function(a){return a}).reverse();this.lines=[],this.addLine=function(a){var b=document.createElement("li");b.className="line";var c=document.createElement("div");c.className="swatch",c.style.backgroundColor=a.color,b.appendChild(c);var f=document.createElement("span");f.className="label",f.innerHTML=a.name,b.appendChild(f),e.appendChild(b),b.series=a,a.noLegend&&(b.style.display="none");var g={element:b,series:a};d.shelving&&(d.shelving.addAnchor(g),d.shelving.updateBehaviour()),d.highlighter&&d.highlighter.addHighlightEvents(g),d.lines.push(g)},f.forEach(function(a){d.addLine(a)}),c.onUpdate(function(){})},Rickshaw.namespace("Rickshaw.Graph.RangeSlider"),Rickshaw.Graph.RangeSlider=function(a){var b=this.element=a.element,c=this.graph=a.graph;$(function(){$(b).slider({range:!0,min:c.dataDomain()[0],max:c.dataDomain()[1],values:[c.dataDomain()[0],c.dataDomain()[1]],slide:function(a,b){c.window.xMin=b.values[0],c.window.xMax=b.values[1],c.update(),c.dataDomain()[0]==b.values[0]&&(c.window.xMin=undefined),c.dataDomain()[1]==b.values[1]&&(c.window.xMax=undefined)}})}),b[0].style.width=c.width+"px",c.onUpdate(function(){var a=$(b).slider("option","values");$(b).slider("option","min",c.dataDomain()[0]),$(b).slider("option","max",c.dataDomain()[1]),c.window.xMin==undefined&&(a[0]=c.dataDomain()[0]),c.window.xMax==undefined&&(a[1]=c.dataDomain()[1]),$(b).slider("option","values",a)})},Rickshaw.namespace("Rickshaw.Graph.Renderer"),Rickshaw.Graph.Renderer=Rickshaw.Class.create({initialize:function(a){this.graph=a.graph,this.tension=a.tension||this.tension,this.graph.unstacker=this.graph.unstacker||new Rickshaw.Graph.Unstacker({graph:this.graph}),this.configure(a)},seriesPathFactory:function(){},seriesStrokeFactory:function(){},defaults:function(){return{tension:.8,strokeWidth:2,unstack:!0,padding:{top:.01,right:0,bottom:.01,left:0},stroke:!1,fill:!1}},domain:function(){var a=[],b=this.graph.stackedData||this.graph.stackData(),c=this.unstack?b:[b.slice(-1).shift()];c.forEach(function(b){b.forEach(function(b){a.push(b.y+b.y0)})});var d=b[0][0].x,e=b[0][b[0].length-1].x;d-=(e-d)*this.padding.left,e+=(e-d)*this.padding.right;var f=this.graph.min==="auto"?d3.min(a):this.graph.min||0,g=this.graph.max||d3.max(a);if(this.graph.min==="auto"||f<0)f-=(g-f)*this.padding.bottom;return this.graph.max===undefined&&(g+=(g-f)*this.padding.top),{x:[d,e],y:[f,g]}},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=a.vis.selectAll("path").data(this.graph.stackedData).enter().append("svg:path").attr("d",this.seriesPathFactory()),c=0;a.series.forEach(function(a){if(a.disabled)return;a.path=b[0][c++],this._styleSeries(a)},this)},_styleSeries:function(a){var b=this.fill?a.color:"none",c=this.stroke?a.color:"none";a.path.setAttribute("fill",b),a.path.setAttribute("stroke",c),a.path.setAttribute("stroke-width",this.strokeWidth),a.path.setAttribute("class",a.className)},configure:function(a){a=a||{},Rickshaw.keys(this.defaults()).forEach(function(b){if(!a.hasOwnProperty(b)){this[b]=this[b]||this.graph[b]||this.defaults()[b];return}typeof this.defaults()[b]=="object"?Rickshaw.keys(this.defaults()[b]).forEach(function(c){this[b][c]=a[b][c]!==undefined?a[b][c]:this[b][c]!==undefined?this[b][c]:this.defaults()[b][c]},this):this[b]=a[b]!==undefined?a[b]:this[b]!==undefined?this[b]:this.graph[b]!==undefined?this.graph[b]:this.defaults()[b]},this)},setStrokeWidth:function(a){a!==undefined&&(this.strokeWidth=a)},setTension:function(a){a!==undefined&&(this.tension=a)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Line"),Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:!0,fill:!1,stroke:!0})},seriesPathFactory:function(){var a=this.graph;return d3.svg.line().x(function(b){return a.x(b.x)}).y(function(b){return a.y(b.y)}).interpolate(this.graph.interpolation).tension(this.tension)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack"),Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:!0,stroke:!1,unstack:!1})},seriesPathFactory:function(){var a=this.graph;return d3.svg.area().x(function(b){return a.x(b.x)}).y0(function(b){return a.y(b.y0)}).y1(function(b){return a.y(b.y+b.y0)}).interpolate(this.graph.interpolation).tension(this.tension)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar"),Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var a=Rickshaw.extend($super(),{gapSize:.05,unstack:!1});return delete a.tension,a},initialize:function($super,a){a=a||{},this.gapSize=a.gapSize||this.gapSize,$super(a)},domain:function($super){var a=$super(),b=this._frequentInterval();return a.x[1]+=parseInt(b.magnitude),a},barWidth:function(){var a=this.graph.stackedData||this.graph.stackData(),b=a.slice(-1).shift(),c=this._frequentInterval(),d=this.graph.x(b[0].x+c.magnitude*(1-this.gapSize));return d},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=this.barWidth(),c=0,d=a.series.filter(function(a){return!a.disabled}).length,e=this.unstack?b/d:b,f=function(b){var c=[1,0,0,b.y<0?-1:1,0,b.y<0?a.y.magnitude(Math.abs(b.y))*2:0];return"matrix("+c.join(",")+")"};a.series.forEach(function(b){if(b.disabled)return;var d=a.vis.selectAll("path").data(b.stack).enter().append("svg:rect").attr("x",function(b){return a.x(b.x)+c}).attr("y",function(b){return a.y(b.y0+Math.abs(b.y))*(b.y<0?-1:1)}).attr("width",e).attr("height",function(b){return a.y.magnitude(Math.abs(b.y))}).attr("transform",f);Array.prototype.forEach.call(d[0],function(a){a.setAttribute("fill",b.color)}),this.unstack&&(c+=e)},this)},_frequentInterval:function(){var a=this.graph.stackedData||this.graph.stackData(),b=a.slice(-1).shift(),c={};for(var d=0;d<b.length-1;d++){var e=b[d+1].x-b[d].x;c[e]=c[e]||0,c[e]++}var f={count:0};return Rickshaw.keys(c).forEach(function(a){f.count<c[a]&&(f={count:c[a],magnitude:a})}),this._frequentInterval=function(){return f},f}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Area"),Rickshaw.Graph.Renderer.Area=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"area",defaults:function($super){return Rickshaw.extend($super(),{unstack:!1,fill:!1,stroke:!1})},seriesPathFactory:function(){var a=this.graph;return d3.svg.area().x(function(b){return a.x(b.x)}).y0(function(b){return a.y(b.y0)}).y1(function(b){return a.y(b.y+b.y0)}).interpolate(a.interpolation).tension(this.tension)},seriesStrokeFactory:function(){var a=this.graph;return d3.svg.line().x(function(b){return a.x(b.x)}).y(function(b){return a.y(b.y+b.y0)}).interpolate(a.interpolation).tension(this.tension)},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=a.vis.selectAll("path").data(this.graph.stackedData).enter().insert("svg:g","g");b.append("svg:path").attr("d", var Rickshaw={namespace:function(a,b){var c=a.split("."),d=Rickshaw;for(var e=1,f=c.length;e<f;e++)currentPart=c[e],d[currentPart]=d[currentPart]||{},d=d[currentPart];return d},keys:function(a){var b=[];for(var c in a)b.push(c);return b},extend:function(a,b){for(var c in b)a[c]=b[c];return a}};if(typeof module!="undefined"&&module.exports){var d3=require("d3");module.exports=Rickshaw}(function(a){function j(a){return b.call(a)===i}function k(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}function l(a){if(m(a)!==h)throw new TypeError;var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b}function m(a){switch(a){case null:return c;case void 0:return d}var b=typeof a;switch(b){case"boolean":return e;case"number":return f;case"string":return g}return h}function n(a){return typeof a=="undefined"}function p(a){var b=a.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g,"").replace(/\s+/g,"").split(",");return b.length==1&&!b[0]?[]:b}function q(a,b){var c=a;return function(){var a=r([t(c,this)],arguments);return b.apply(this,a)}}function r(a,b){var c=a.length,d=b.length;while(d--)a[c+d]=b[d];return a}function s(a,b){return a=o.call(a,0),r(a,b)}function t(a,b){if(arguments.length<2&&n(arguments[0]))return this;var c=a,d=o.call(arguments,2);return function(){var a=s(d,arguments);return c.apply(b,a)}}var b=Object.prototype.toString,c="Null",d="Undefined",e="Boolean",f="Number",g="String",h="Object",i="[object Function]",o=Array.prototype.slice,u=function(){},v=function(){function b(){}function c(){function d(){this.initialize.apply(this,arguments)}var a=null,c=[].slice.apply(arguments);j(c[0])&&(a=c.shift()),k(d,v.Methods),d.superclass=a,d.subclasses=[];if(a){b.prototype=a.prototype,d.prototype=new b;try{a.subclasses.push(d)}catch(e){}}for(var f=0,g=c.length;f<g;f++)d.addMethods(c[f]);return d.prototype.initialize||(d.prototype.initialize=u),d.prototype.constructor=d,d}function d(b){var c=this.superclass&&this.superclass.prototype,d=l(b);a&&(b.toString!=Object.prototype.toString&&d.push("toString"),b.valueOf!=Object.prototype.valueOf&&d.push("valueOf"));for(var e=0,f=d.length;e<f;e++){var g=d[e],h=b[g];if(c&&j(h)&&p(h)[0]=="$super"){var i=h;h=q(function(a){return function(){return c[a].apply(this,arguments)}}(g),i),h.valueOf=t(i.valueOf,i),h.toString=t(i.toString,i)}this.prototype[g]=h}return this}var a=function(){for(var a in{toString:1})if(a==="toString")return!1;return!0}();return{create:c,Methods:{addMethods:d}}}();a.exports?a.exports.Class=v:a.Class=v})(Rickshaw),Rickshaw.namespace("Rickshaw.Compat.ClassList"),Rickshaw.Compat.ClassList=function(){typeof document!="undefined"&&!("classList"in document.createElement("a"))&&function(a){"use strict";var b="classList",c="prototype",d=(a.HTMLElement||a.Element)[c],e=Object,f=String[c].trim||function(){return this.replace(/^\s+|\s+$/g,"")},g=Array[c].indexOf||function(a){var b=0,c=this.length;for(;b<c;b++)if(b in this&&this[b]===a)return b;return-1},h=function(a,b){this.name=a,this.code=DOMException[a],this.message=b},i=function(a,b){if(b==="")throw new h("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(b))throw new h("INVALID_CHARACTER_ERR","String contains an invalid character");return g.call(a,b)},j=function(a){var b=f.call(a.className),c=b?b.split(/\s+/):[],d=0,e=c.length;for(;d<e;d++)this.push(c[d]);this._updateClassName=function(){a.className=this.toString()}},k=j[c]=[],l=function(){return new j(this)};h[c]=Error[c],k.item=function(a){return this[a]||null},k.contains=function(a){return a+="",i(this,a)!==-1},k.add=function(a){a+="",i(this,a)===-1&&(this.push(a),this._updateClassName())},k.remove=function(a){a+="";var b=i(this,a);b!==-1&&(this.splice(b,1),this._updateClassName())},k.toggle=function(a){a+="",i(this,a)===-1?this.add(a):this.remove(a)},k.toString=function(){return this.join(" ")};if(e.defineProperty){var m={get:l,enumerable:!0,configurable:!0};try{e.defineProperty(d,b,m)}catch(n){n.number===-2146823252&&(m.enumerable=!1,e.defineProperty(d,b,m))}}else e[c].__defineGetter__&&d.__defineGetter__(b,l)}(window)},(typeof RICKSHAW_NO_COMPAT!="undefined"&&!RICKSHAW_NO_COMPAT||typeof RICKSHAW_NO_COMPAT=="undefined")&&new Rickshaw.Compat.ClassList,Rickshaw.namespace("Rickshaw.Graph"),Rickshaw.Graph=function(a){this.element=a.element,this.series=a.series,this.defaults={interpolation:"cardinal",offset:"zero",min:undefined,max:undefined},Rickshaw.keys(this.defaults).forEach(function(b){this[b]=a[b]||this.defaults[b]},this),this.window={},this.updateCallbacks=[];var b=this;this.initialize=function(a){this.validateSeries(a.series),this.series.active=function(){return b.series.filter(function(a){return!a.disabled})},this.setSize({width:a.width,height:a.height}),this.element.classList.add("rickshaw_graph"),this.vis=d3.select(this.element).append("svg:svg").attr("width",this.width).attr("height",this.height);var c=[Rickshaw.Graph.Renderer.Stack,Rickshaw.Graph.Renderer.Line,Rickshaw.Graph.Renderer.Bar,Rickshaw.Graph.Renderer.Area,Rickshaw.Graph.Renderer.ScatterPlot];c.forEach(function(a){if(!a)return;b.registerRenderer(new a({graph:b}))}),this.setRenderer(a.renderer||"stack",a),this.discoverRange()},this.validateSeries=function(a){if(!(a instanceof Array||a instanceof Rickshaw.Series)){var b=Object.prototype.toString.apply(a);throw"series is not an array: "+b}var c;a.forEach(function(a){if(!(a instanceof Object))throw"series element is not an object: "+a;if(!a.data)throw"series has no data: "+JSON.stringify(a);if(!(a.data instanceof Array))throw"series data is not an array: "+JSON.stringify(a.data);c=c||a.data.length;if(c&&a.data.length!=c)throw"series cannot have differing numbers of points: "+c+" vs "+a.data.length+"; see Rickshaw.Series.zeroFill()";var b=typeof a.data[0].x,d=typeof a.data[0].y;if(b!="number"||d!="number")throw"x and y properties of points should be numbers instead of "+b+" and "+d})},this.dataDomain=function(){var a=this.series[0].data;return[a[0].x,a.slice(-1).shift().x]},this.discoverRange=function(){var a=this.renderer.domain();this.x=d3.scale.linear().domain(a.x).range([0,this.width]),this.y=d3.scale.linear().domain(a.y).range([this.height,0]),this.y.magnitude=d3.scale.linear().domain([a.y[0]-a.y[0],a.y[1]-a.y[0]]).range([0,this.height])},this.render=function(){var a=this.stackData();this.discoverRange(),this.renderer.render(),this.updateCallbacks.forEach(function(a){a()})},this.update=this.render,this.stackData=function(){var a=this.series.active().map(function(a){return a.data}).map(function(a){return a.filter(function(a){return this._slice(a)},this)},this);this.stackData.hooks.data.forEach(function(c){a=c.f.apply(b,[a])});var c=d3.layout.stack();c.offset(b.offset);var d=c(a);this.stackData.hooks.after.forEach(function(c){d=c.f.apply(b,[a])});var e=0;return this.series.forEach(function(a){if(a.disabled)return;a.stack=d[e++]}),this.stackedData=d,d},this.stackData.hooks={data:[],after:[]},this._slice=function(a){if(this.window.xMin||this.window.xMax){var b=!0;return this.window.xMin&&a.x<this.window.xMin&&(b=!1),this.window.xMax&&a.x>this.window.xMax&&(b=!1),b}return!0},this.onUpdate=function(a){this.updateCallbacks.push(a)},this.registerRenderer=function(a){this._renderers=this._renderers||{},this._renderers[a.name]=a},this.configure=function(a){(a.width||a.height)&&this.setSize(a),Rickshaw.keys(this.defaults).forEach(function(b){this[b]=b in a?a[b]:b in this?this[b]:this.defaults[b]},this),this.setRenderer(a.renderer||this.renderer.name,a)},this.setRenderer=function(a,b){if(!this._renderers[a])throw"couldn't find renderer "+a;this.renderer=this._renderers[a],typeof b=="object"&&this.renderer.configure(b)},this.setSize=function(a){a=a||{};if(typeof window!==undefined)var b=window.getComputedStyle(this.element,null),c=parseInt(b.getPropertyValue("width")),d=parseInt(b.getPropertyValue("height"));this.width=a.width||c||400,this.height=a.height||d||250,this.vis&&this.vis.attr("width",this.width).attr("height",this.height)},this.initialize(a)},Rickshaw.namespace("Rickshaw.Fixtures.Color"),Rickshaw.Fixtures.Color=function(){this.schemes={},this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse(),this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"],this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"],this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse(),this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"},this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse(),this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"],this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]},Rickshaw.namespace("Rickshaw.Fixtures.RandomData"),Rickshaw.Fixtures.RandomData=function(a){var b;a=a||1;var c=200,d=Math.floor((new Date).getTime()/1e3);this.addData=function(b){var e=Math.random()*100+15+c,f=b[0].length,g=1;b.forEach(function(b){var c=Math.random()*20,h=e/25+g++ +(Math.cos(f*g*11/960)+2)*15+(Math.cos(f/7)+2)*7+(Math.cos(f/17)+2)*1;b.push({x:f*a+d,y:h+c})}),c=e*.85}},Rickshaw.namespace("Rickshaw.Fixtures.Time"),Rickshaw.Fixtures.Time=function(){var a=(new Date).getTimezoneOffset()*60,b=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],this.units=[{name:"decade",seconds:315576e3,formatter:function(a){return parseInt(a.getUTCFullYear()/10)*10}},{name:"year",seconds:31557600,formatter:function(a){return a.getUTCFullYear()}},{name:"month",seconds:2635200,formatter:function(a){return b.months[a.getUTCMonth()]}},{name:"week",seconds:604800,formatter:function(a){return b.formatDate(a)}},{name:"day",seconds:86400,formatter:function(a){return a.getUTCDate()}},{name:"6 hour",seconds:21600,formatter:function(a){return b.formatTime(a)}},{name:"hour",seconds:3600,formatter:function(a){return b.formatTime(a)}},{name:"15 minute",seconds:900,formatter:function(a){return b.formatTime(a)}},{name:"minute",seconds:60,formatter:function(a){return a.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(a){return a.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(a){return a.getUTCSeconds()+"s"}}],this.unit=function(a){return this.units.filter(function(b){return a==b.name}).shift()},this.formatDate=function(a){return a.toUTCString().match(/, (\w+ \w+ \w+)/)[1]},this.formatTime=function(a){return a.toUTCString().match(/(\d+:\d+):/)[1]},this.ceil=function(a,b){if(b.name=="month"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(c.getUTCMonth()),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}if(b.name=="year"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(0),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}return Math.ceil(a/b.seconds)*b.seconds}},Rickshaw.namespace("Rickshaw.Fixtures.Number"),Rickshaw.Fixtures.Number.formatKMBT=function(a){return a>=1e12?a/1e12+"T":a>=1e9?a/1e9+"B":a>=1e6?a/1e6+"M":a>=1e3?a/1e3+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(a){return a>=0x4000000000000?a/0x4000000000000+"P":a>=1099511627776?a/1099511627776+"T":a>=1073741824?a/1073741824+"G":a>=1048576?a/1048576+"M":a>=1024?a/1024+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.namespace("Rickshaw.Color.Palette"),Rickshaw.Color.Palette=function(a){var b=new Rickshaw.Fixtures.Color;a=a||{},this.schemes={},this.scheme=b.schemes[a.scheme]||a.scheme||b.schemes.colorwheel,this.runningIndex=0,this.generatorIndex=0;if(a.interpolatedStopCount){var c=this.scheme.length-1,d,e,f=[];for(d=0;d<c;d++){f.push(this.scheme[d]);var g=d3.interpolateHsl(this.scheme[d],this.scheme[d+1]);for(e=1;e<a.interpolatedStopCount;e++)f.push(g(1/a.interpolatedStopCount*e))}f.push(this.scheme[this.scheme.length-1]),this.scheme=f}this.rotateCount=this.scheme.length,this.color=function(a){return this.scheme[a]||this.scheme[this.runningIndex++]||this.interpolateColor()||"#808080"},this.interpolateColor=function(){if(!Array.isArray(this.scheme))return;var a;return this.generatorIndex==this.rotateCount*2-1?(a=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[0])(.5),this.generatorIndex=0,this.rotateCount*=2):(a=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[this.generatorIndex+1])(.5),this.generatorIndex++),this.scheme.push(a),a}},Rickshaw.namespace("Rickshaw.Graph.Ajax"),Rickshaw.Graph.Ajax=Rickshaw.Class.create({initialize:function(a){this.dataURL=a.dataURL,this.onData=a.onData||function(a){return a},this.onComplete=a.onComplete||function(){},this.onError=a.onError||function(){},this.args=a,this.request()},request:function(){$.ajax({url:this.dataURL,dataType:"json",success:this.success.bind(this),error:this.error.bind(this)})},error:function(){console.log("error loading dataURL: "+this.dataURL),this.onError(this)},success:function(a,b){a=this.onData(a),this.args.series=this._splice({data:a,series:this.args.series}),this.graph=new Rickshaw.Graph(this.args),this.graph.render(),this.onComplete(this)},_splice:function(a){var b=a.data,c=a.series;return a.series?(c.forEach(function(a){var c=a.key||a.name;if(!c)throw"series needs a key or a name";b.forEach(function(b){var d=b.key||b.name;if(!d)throw"data needs a key or a name";if(c==d){var e=["color","name","data"];e.forEach(function(c){a[c]=a[c]||b[c]})}})}),c):b}}),Rickshaw.namespace("Rickshaw.Graph.Annotate"),Rickshaw.Graph.Annotate=function(a){var b=this.graph=a.graph;this.elements={timeline:a.element};var c=this;this.data={},this.elements.timeline.classList.add("rickshaw_annotation_timeline"),this.add=function(a,b,d){c.data[a]=c.data[a]||{boxes:[]},c.data[a].boxes.push({content:b,end:d})},this.update=function(){Rickshaw.keys(c.data).forEach(function(a){var b=c.data[a],d=c.graph.x(a);if(d<0||d>c.graph.x.range()[1]){b.element&&(b.line.classList.add("offscreen"),b.element.style.display="none"),b.boxes.forEach(function(a){a.rangeElement&&a.rangeElement.classList.add("offscreen")});return}if(!b.element){var e=b.element=document.createElement("div");e.classList.add("annotation"),this.elements.timeline.appendChild(e),e.addEventListener("click",function(a){e.classList.toggle("active"),b.line.classList.toggle("active"),b.boxes.forEach(function(a){a.rangeElement&&a.rangeElement.classList.toggle("active")})},!1)}b.element.style.left=d+"px",b.element.style.display="block",b.boxes.forEach(function(a){var e=a.element;e||(e=a.element=document.createElement("div"),e.classList.add("content"),e.innerHTML=a.content,b.element.appendChild(e),b.line=document.createElement("div"),b.line.classList.add("annotation_line"),c.graph.element.appendChild(b.line),a.end&&(a.rangeElement=document.createElement("div"),a.rangeElement.classList.add("annotation_range"),c.graph.element.appendChild(a.rangeElement)));if(a.end){var f=d,g=Math.min(c.graph.x(a.end),c.graph.x.range()[1]);f>g&&(g=d,f=Math.max(c.graph.x(a.end),c.graph.x.range()[0]));var h=g-f;a.rangeElement.style.left=f+"px",a.rangeElement.style.width=h+"px",a.rangeElement.classList.remove("offscreen")}b.line.classList.remove("offscreen"),b.line.style.left=d+"px"})},this)},this.graph.onUpdate(function(){c.update()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Time"),Rickshaw.Graph.Axis.Time=function(a){var b=this;this.graph=a.graph,this.elements=[],this.ticksTreatment=a.ticksTreatment||"plain",this.fixedTimeUnit=a.timeUnit;var c=new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var a,b=c.units,d=this.graph.x.domain(),e=d[1]-d[0];return b.forEach(function(b){Math.floor(e/b.seconds)>=2&&(a=a||b)}),a||c.units[c.units.length-1]},this.tickOffsets=function(){var a=this.graph.x.domain(),b=this.fixedTimeUnit||this.appropriateTimeUnit(),d=Math.ceil((a[1]-a[0])/b.seconds),e=a[0],f=[];for(var g=0;g<d;g++)tickValue=c.ceil(e,b),e=tickValue+b.seconds/2,f.push({value:tickValue,unit:b});return f},this.render=function(){this.elements.forEach(function(a){a.parentNode.removeChild(a)}),this.elements=[];var a=this.tickOffsets();a.forEach(function(a){if(b.graph.x(a.value)>b.graph.x.range()[1])return;var c=document.createElement("div");c.style.left=b.graph.x(a.value)+"px",c.classList.add("x_tick"),c.classList.add(b.ticksTreatment);var d=document.createElement("div");d.classList.add("title"),d.innerHTML=a.unit.formatter(new Date(a.value*1e3)),c.appendChild(d),b.graph.element.appendChild(c),b.elements.push(c)})},this.graph.onUpdate(function(){b.render()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Y"),Rickshaw.Graph.Axis.Y=function(a){var b=this,c=.1;this.initialize=function(a){this.graph=a.graph,this.orientation=a.orientation||"right";var c=a.pixelsPerTick||75;this.ticks=a.ticks||Math.floor(this.graph.height/c),this.tickSize=a.tickSize||4,this.ticksTreatment=a.ticksTreatment||"plain",a.element?(this.element=a.element,this.vis=d3.select(a.element).append("svg:svg").attr("class","rickshaw_graph y_axis"),this.element=this.vis[0][0],this.element.style.position="relative",this.setSize({width:a.width,height:a.height})):this.vis=this.graph.vis,this.graph.onUpdate(function(){b.render()})},this.setSize=function(a){a=a||{};if(!this.element)return;if(typeof window!="undefined"){var b=window.getComputedStyle(this.element.parentNode,null),d=parseInt(b.getPropertyValue("width"));if(!a.auto)var e=parseInt(b.getPropertyValue("height"))}this.width=a.width||d||this.graph.width*c,this.height=a.height||e||this.graph.height,this.vis.attr("width",this.width).attr("height",this.height*(1+c));var f=this.height*c;this.element.style.top=-1*f+"px"},this.render=function(){this.graph.height!==this._renderHeight&&this.setSize({auto:!0});var b=d3.svg.axis().scale(this.graph.y).orient(this.orientation);b.tickFormat(a.tickFormat||function(a){return a});if(this.orientation=="left")var d=this.height*c,e="translate("+this.width+", "+d+")";this.element&&this.vis.selectAll("*").remove(),this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",e).call(b.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var f=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(b.ticks(this.ticks).tickSubdivide(0).tickSize(f)),this._renderHeight=this.graph.height},this.initialize(a)},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight"),Rickshaw.Graph.Behavior.Series.Highlight=function(a){this.graph=a.graph,this.legend=a.legend;var b=this,c={};this.addHighlightEvents=function(a){a.element.addEventListener("mouseover",function(d){b.legend.lines.forEach(function(b){if(a===b)return;c[b.series.name]=c[b.series.name]||b.series.color,b.series.color=d3.interpolateRgb(b.series.color,d3.rgb("#d8d8d8"))(.8).toString()}),b.graph.update()},!1),a.element.addEventListener("mouseout",function(a){b.legend.lines.forEach(function(a){c[a.series.name]&&(a.series.color=c[a.series.name])}),b.graph.update()},!1)},this.legend&&this.legend.lines.forEach(function(a){b.addHighlightEvents(a)})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order"),Rickshaw.Graph.Behavior.Series.Order=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;$(function(){$(b.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(a,c){var d=[];$(b.legend.list).find("li").each(function(a,b){if(!b.series)return;d.push(b.series)});for(var e=b.graph.series.length-1;e>=0;e--)b.graph.series[e]=d.shift();b.graph.update()}}),$(b.legend.list).disableSelection()}),this.graph.onUpdate(function(){var a=window.getComputedStyle(b.legend.element).height;b.legend.element.style.height=a})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle"),Rickshaw.Graph.Behavior.Series.Toggle=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;this.addAnchor=function(a){var c=document.createElement("a");c.innerHTML="&#10004;",c.classList.add("action"),a.element.insertBefore(c,a.element.firstChild),c.onclick=function(b){a.series.disabled?(a.series.enable(),a.element.classList.remove("disabled")):(a.series.disable(),a.element.classList.add("disabled"))};var d=a.element.getElementsByTagName("span")[0];d.onclick=function(c){var d=a.series.disabled;if(!d)for(var e=0;e<b.legend.lines.length;e++){var f=b.legend.lines[e];if(a.series!==f.series&&!f.series.disabled){d=!0;break}}d?(a.series.enable(),a.element.classList.remove("disabled"),b.legend.lines.forEach(function(b){a.series!==b.series&&(b.series.disable(),b.element.classList.add("disabled"))})):b.legend.lines.forEach(function(a){a.series.enable(),a.element.classList.remove("disabled")})}},this.legend&&($(this.legend.list).sortable({start:function(a,b){b.item.bind("no.onclick",function(a){a.preventDefault()})},stop:function(a,b){setTimeout(function(){b.item.unbind("no.onclick")},250)}}),this.legend.lines.forEach(function(a){b.addAnchor(a)})),this._addBehavior=function(){this.graph.series.forEach(function(a){a.disable=function(){if(b.graph.series.length<=1)throw"only one series left";a.disabled=!0,b.graph.update()},a.enable=function(){a.disabled=!1,b.graph.update()}})},this._addBehavior(),this.updateBehaviour=function(){this._addBehavior()}},Rickshaw.namespace("Rickshaw.Graph.HoverDetail"),Rickshaw.Graph.HoverDetail=Rickshaw.Class.create({initialize:function(a){var b=this.graph=a.graph;this.xFormatter=a.xFormatter||function(a){return(new Date(a*1e3)).toUTCString()},this.yFormatter=a.yFormatter||function(a){return a.toFixed(2)};var c=this.element=document.createElement("div");c.className="detail",this.visible=!0,b.element.appendChild(c),this.lastEvent=null,this._addListeners(),this.onShow=a.onShow,this.onHide=a.onHide,this.onRender=a.onRender,this.formatter=a.formatter||this.formatter},formatter:function(a,b,c,d,e,f){return a.name+":&nbsp;"+e},update:function(a){a=a||this.lastEvent;if(!a)return;this.lastEvent=a;if(!a.target.nodeName.match(/^(path|svg|rect)$/))return;var b=this.graph,c=a.offsetX||a.layerX,d=a.offsetY||a.layerY,e=b.x.invert(c),f=b.stackedData,g=f.slice(-1).shift(),h=d3.scale.linear().domain([g[0].x,g.slice(-1).shift().x]).range([0,g.length]),i=Math.floor(h(e)),j=Math.min(i||0,f[0].length-1);for(var k=i;k<f[0].length-1;){if(!f[0][k]||!f[0][k+1])break;if(f[0][k].x<=e&&f[0][k+1].x>e){j=k;break}f[0][k+1]<=e?k++:k--}var e=f[0][j].x,l=this.xFormatter(e),m=b.x(e),n=0,o=b.series.active().map(function(a){return{order:n++,series:a,name:a.name,value:a.stack[j]}}),p,q=function(a,b){return a.value.y0+a.value.y-(b.value.y0+b.value.y)},r=b.y.magnitude.invert(b.element.offsetHeight-d);o.sort(q).forEach(function(a){a.formattedYValue=this.yFormatter.constructor==Array?this.yFormatter[o.indexOf(a)](a.value.y):this.yFormatter(a.value.y),a.graphX=m,a.graphY=b.y(a.value.y0+a.value.y),r>a.value.y0&&r<a.value.y0+a.value.y&&!p&&(p=a,a.active=!0)},this),this.element.innerHTML="",this.element.style.left=b.x(e)+"px",this.visible&&this.render({detail:o,domainX:e,formattedXValue:l,mouseX:c,mouseY:d})},hide:function(){this.visible=!1,this.element.classList.add("inactive"),typeof this.onHide=="function"&&this.onHide()},show:function(){this.visible=!0,this.element.classList.remove("inactive"),typeof this.onShow=="function"&&this.onShow()},render:function(a){var b=a.detail,c=a.domainX,d=a.mouseX,e=a.mouseY,f=a.formattedXValue,g=document.createElement("div");g.className="x_label",g.innerHTML=f,this.element.appendChild(g),b.forEach(function(a){var b=document.createElement("div");b.className="item",b.innerHTML=this.formatter(a.series,c,a.value.y,f,a.formattedYValue,a),b.style.top=this.graph.y(a.value.y0+a.value.y)+"px",this.element.appendChild(b);var d=document.createElement("div");d.className="dot",d.style.top=b.style.top,d.style.borderColor=a.series.color,this.element.appendChild(d),a.active&&(b.className="item active",d.className="dot active")},this),this.show(),typeof this.onRender=="function"&&this.onRender(a)},_addListeners:function(){this.graph.element.addEventListener("mousemove",function(a){this.visible=!0,this.update(a)}.bind(this),!1),this.graph.onUpdate(function(){this.update()}.bind(this)),this.graph.element.addEventListener("mouseout",function(a){a.relatedTarget&&!(a.relatedTarget.compareDocumentPosition(this.graph.element)&Node.DOCUMENT_POSITION_CONTAINS)&&this.hide()}.bind(this),!1)}}),Rickshaw.namespace("Rickshaw.Graph.JSONP"),Rickshaw.Graph.JSONP=Rickshaw.Class.create(Rickshaw.Graph.Ajax,{request:function(){$.ajax({url:this.dataURL,dataType:"jsonp",success:this.success.bind(this),error:this.error.bind(this)})}}),Rickshaw.namespace("Rickshaw.Graph.Legend"),Rickshaw.Graph.Legend=function(a){var b=this.element=a.element,c=this.graph=a.graph,d=this;b.classList.add("rickshaw_legend");var e=this.list=document.createElement("ul");b.appendChild(e);var f=c.series.map(function(a){return a}).reverse();this.lines=[],this.addLine=function(a){var b=document.createElement("li");b.className="line";var c=document.createElement("div");c.className="swatch",c.style.backgroundColor=a.color,b.appendChild(c);var f=document.createElement("span");f.className="label",f.innerHTML=a.name,b.appendChild(f),e.appendChild(b),b.series=a,a.noLegend&&(b.style.display="none");var g={element:b,series:a};d.shelving&&(d.shelving.addAnchor(g),d.shelving.updateBehaviour()),d.highlighter&&d.highlighter.addHighlightEvents(g),d.lines.push(g)},f.forEach(function(a){d.addLine(a)}),c.onUpdate(function(){})},Rickshaw.namespace("Rickshaw.Graph.RangeSlider"),Rickshaw.Graph.RangeSlider=function(a){var b=this.element=a.element,c=this.graph=a.graph;$(function(){$(b).slider({range:!0,min:c.dataDomain()[0],max:c.dataDomain()[1],values:[c.dataDomain()[0],c.dataDomain()[1]],slide:function(a,b){c.window.xMin=b.values[0],c.window.xMax=b.values[1],c.update(),c.dataDomain()[0]==b.values[0]&&(c.window.xMin=undefined),c.dataDomain()[1]==b.values[1]&&(c.window.xMax=undefined)}})}),b[0].style.width=c.width+"px",c.onUpdate(function(){var a=$(b).slider("option","values");$(b).slider("option","min",c.dataDomain()[0]),$(b).slider("option","max",c.dataDomain()[1]),c.window.xMin==undefined&&(a[0]=c.dataDomain()[0]),c.window.xMax==undefined&&(a[1]=c.dataDomain()[1]),$(b).slider("option","values",a)})},Rickshaw.namespace("Rickshaw.Graph.Renderer"),Rickshaw.Graph.Renderer=Rickshaw.Class.create({initialize:function(a){this.graph=a.graph,this.tension=a.tension||this.tension,this.graph.unstacker=this.graph.unstacker||new Rickshaw.Graph.Unstacker({graph:this.graph}),this.configure(a)},seriesPathFactory:function(){},seriesStrokeFactory:function(){},defaults:function(){return{tension:.8,strokeWidth:2,unstack:!0,padding:{top:.01,right:0,bottom:.01,left:0},stroke:!1,fill:!1}},domain:function(){var a=[],b=this.graph.stackedData||this.graph.stackData(),c=this.unstack?b:[b.slice(-1).shift()];c.forEach(function(b){b.forEach(function(b){a.push(b.y+b.y0)})});var d=b[0][0].x,e=b[0][b[0].length-1].x;d-=(e-d)*this.padding.left,e+=(e-d)*this.padding.right;var f=this.graph.min==="auto"?d3.min(a):this.graph.min||0,g=this.graph.max||d3.max(a);if(this.graph.min==="auto"||f<0)f-=(g-f)*this.padding.bottom;return this.graph.max===undefined&&(g+=(g-f)*this.padding.top),{x:[d,e],y:[f,g]}},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=a.vis.selectAll("path").data(this.graph.stackedData).enter().append("svg:path").attr("d",this.seriesPathFactory()),c=0;a.series.forEach(function(a){if(a.disabled)return;a.path=b[0][c++],this._styleSeries(a)},this)},_styleSeries:function(a){var b=this.fill?a.color:"none",c=this.stroke?a.color:"none";a.path.setAttribute("fill",b),a.path.setAttribute("stroke",c),a.path.setAttribute("stroke-width",this.strokeWidth),a.path.setAttribute("class",a.className)},configure:function(a){a=a||{},Rickshaw.keys(this.defaults()).forEach(function(b){if(!a.hasOwnProperty(b)){this[b]=this[b]||this.graph[b]||this.defaults()[b];return}typeof this.defaults()[b]=="object"?Rickshaw.keys(this.defaults()[b]).forEach(function(c){this[b][c]=a[b][c]!==undefined?a[b][c]:this[b][c]!==undefined?this[b][c]:this.defaults()[b][c]},this):this[b]=a[b]!==undefined?a[b]:this[b]!==undefined?this[b]:this.graph[b]!==undefined?this.graph[b]:this.defaults()[b]},this)},setStrokeWidth:function(a){a!==undefined&&(this.strokeWidth=a)},setTension:function(a){a!==undefined&&(this.tension=a)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Line"),Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:!0,fill:!1,stroke:!0})},seriesPathFactory:function(){var a=this.graph;return d3.svg.line().x(function(b){return a.x(b.x)}).y(function(b){return a.y(b.y)}).interpolate(this.graph.interpolation).tension(this.tension)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack"),Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:!0,stroke:!1,unstack:!1})},seriesPathFactory:function(){var a=this.graph;return d3.svg.area().x(function(b){return a.x(b.x)}).y0(function(b){return a.y(b.y0)}).y1(function(b){return a.y(b.y+b.y0)}).interpolate(this.graph.interpolation).tension(this.tension)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar"),Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var a=Rickshaw.extend($super(),{gapSize:.05,unstack:!1});return delete a.tension,a},initialize:function($super,a){a=a||{},this.gapSize=a.gapSize||this.gapSize,$super(a)},domain:function($super){var a=$super(),b=this._frequentInterval();return a.x[1]+=parseInt(b.magnitude),a},barWidth:function(){var a=this.graph.stackedData||this.graph.stackData(),b=a.slice(-1).shift(),c=this._frequentInterval(),d=this.graph.x(b[0].x+c.magnitude*(1-this.gapSize));return d},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=this.barWidth(),c=0,d=a.series.filter(function(a){return!a.disabled}).length,e=this.unstack?b/d:b,f=function(b){var c=[1,0,0,b.y<0?-1:1,0,b.y<0?a.y.magnitude(Math.abs(b.y))*2:0];return"matrix("+c.join(",")+")"};a.series.forEach(function(b){if(b.disabled)return;var d=a.vis.selectAll("path").data(b.stack).enter().append("svg:rect").attr("x",function(b){return a.x(b.x)+c}).attr("y",function(b){return a.y(b.y0+Math.abs(b.y))*(b.y<0?-1:1)}).attr("width",e).attr("height",function(b){return a.y.magnitude(Math.abs(b.y))}).attr("transform",f);Array.prototype.forEach.call(d[0],function(a){a.setAttribute("fill",b.color)}),this.unstack&&(c+=e)},this)},_frequentInterval:function(){var a=this.graph.stackedData||this.graph.stackData(),b=a.slice(-1).shift(),c={};for(var d=0;d<b.length-1;d++){var e=b[d+1].x-b[d].x;c[e]=c[e]||0,c[e]++}var f={count:0};return Rickshaw.keys(c).forEach(function(a){f.count<c[a]&&(f={count:c[a],magnitude:a})}),this._frequentInterval=function(){return f},f}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.Area"),Rickshaw.Graph.Renderer.Area=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"area",defaults:function($super){return Rickshaw.extend($super(),{unstack:!1,fill:!1,stroke:!1})},seriesPathFactory:function(){var a=this.graph;return d3.svg.area().x(function(b){return a.x(b.x)}).y0(function(b){return a.y(b.y0)}).y1(function(b){return a.y(b.y+b.y0)}).interpolate(a.interpolation).tension(this.tension)},seriesStrokeFactory:function(){var a=this.graph;return d3.svg.line().x(function(b){return a.x(b.x)}).y(function(b){return a.y(b.y+b.y0)}).interpolate(a.interpolation).tension(this.tension)},render:function(){var a=this.graph;a.vis.selectAll("*").remove();var b=a.vis.selectAll("path").data(this.graph.stackedData).enter().insert("svg:g","g");b.append("svg:path").attr("d",
this.seriesPathFactory()).attr("class","area"),this.stroke&&b.append("svg:path").attr("d",this.seriesStrokeFactory()).attr("class","line");var c=0;a.series.forEach(function(a){if(a.disabled)return;a.path=b[0][c++],this._styleSeries(a)},this)},_styleSeries:function(a){if(!a.path)return;d3.select(a.path).select(".area").attr("fill",a.color),this.stroke&&d3.select(a.path).select(".line").attr("fill","none").attr("stroke",a.stroke||d3.interpolateRgb(a.color,"black")(.125)).attr("stroke-width",this.strokeWidth),a.className&&a.path.setAttribute("class",a.className)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.ScatterPlot"),Rickshaw.Graph.Renderer.ScatterPlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"scatterplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:!0,fill:!0,stroke:!1,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:4})},initialize:function($super,a){$super(a)},render:function(){var a=this.graph;a.vis.selectAll("*").remove(),a.series.forEach(function(b){if(b.disabled)return;var c=a.vis.selectAll("path").data(b.stack).enter().append("svg:circle").attr("cx",function(b){return a.x(b.x)}).attr("cy",function(b){return a.y(b.y)}).attr("r",function(b){return"r"in b?b.r:a.renderer.dotSize});Array.prototype.forEach.call(c[0],function(a){a.setAttribute("fill",b.color)})},this)}}),Rickshaw.namespace("Rickshaw.Graph.Smoother"),Rickshaw.Graph.Smoother=function(a){this.graph=a.graph,this.element=a.element;var b=this;this.aggregationScale=1,this.element&&$(function(){$(b.element).slider({min:1,max:100,slide:function(a,c){b.setScale(c.value),b.graph.update()}})}),b.graph.stackData.hooks.data.push({name:"smoother",orderPosition:50,f:function(a){var c=[];return a.forEach(function(a){var d=[];while(a.length){var e=0,f=0,g=a.splice(0,b.aggregationScale);g.forEach(function(a){e+=a.x/g.length,f+=a.y/g.length}),d.push({x:e,y:f})}c.push(d)}),c}}),this.setScale=function(a){if(a<1)throw"scale out of range: "+a;this.aggregationScale=a,this.graph.update()}},Rickshaw.namespace("Rickshaw.Graph.Unstacker"),Rickshaw.Graph.Unstacker=function(a){this.graph=a.graph;var b=this;this.graph.stackData.hooks.after.push({name:"unstacker",f:function(a){return b.graph.renderer.unstack?(a.forEach(function(a){a.forEach(function(a){a.y0=0})}),a):a}})},Rickshaw.namespace("Rickshaw.Series"),Rickshaw.Series=Rickshaw.Class.create(Array,{initialize:function(a,b,c){c=c||{},this.palette=new Rickshaw.Color.Palette(b),this.timeBase=typeof c.timeBase=="undefined"?Math.floor((new Date).getTime()/1e3):c.timeBase;var d=typeof c.timeInterval=="undefined"?1e3:c.timeInterval;this.setTimeInterval(d),a&&typeof a=="object"&&a instanceof Array&&a.forEach(function(a){this.addItem(a)},this)},addItem:function(a){if(typeof a.name=="undefined")throw"addItem() needs a name";a.color=a.color||this.palette.color(a.name),a.data=a.data||[],a.data.length==0&&this.length&&this.getIndex()>0?this[0].data.forEach(function(b){a.data.push({x:b.x,y:0})}):a.data.length==0&&a.data.push({x:this.timeBase-(this.timeInterval||0),y:0}),this.push(a),this.legend&&this.legend.addLine(this.itemByName(a.name))},addData:function(a){var b=this.getIndex();Rickshaw.keys(a).forEach(function(a){this.itemByName(a)||this.addItem({name:a})},this),this.forEach(function(c){c.data.push({x:(b*this.timeInterval||1)+this.timeBase,y:a[c.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(a){for(var b=0;b<this.length;b++)if(this[b].name==a)return this[b]},setTimeInterval:function(a){this.timeInterval=a/1e3},setTimeBase:function(a){this.timeBase=a},dump:function(){var a={timeBase:this.timeBase,timeInterval:this.timeInterval,items:[]};return this.forEach(function(b){var c={color:b.color,name:b.name,data:[]};b.data.forEach(function(a){c.data.push({x:a.x,y:a.y})}),a.items.push(c)}),a},load:function(a){a.timeInterval&&(this.timeInterval=a.timeInterval),a.timeBase&&(this.timeBase=a.timeBase),a.items&&a.items.forEach(function(a){this.push(a),this.legend&&this.legend.addLine(this.itemByName(a.name))},this)}}),Rickshaw.Series.zeroFill=function(a){var b,c=0,d=a.map(function(a){return a.data});while(c<Math.max.apply(null,d.map(function(a){return a.length})))b=Math.min.apply(null,d.filter(function(a){return a[c]}).map(function(a){return a[c].x})),d.forEach(function(a){(!a[c]||a[c].x!=b)&&a.splice(c,0,{x:b,y:0})}),c++},Rickshaw.namespace("Rickshaw.Series.FixedDuration"),Rickshaw.Series.FixedDuration=Rickshaw.Class.create(Rickshaw.Series,{initialize:function(a,b,c){var c=c||{};if(typeof c.timeInterval=="undefined")throw new Error("FixedDuration series requires timeInterval");if(typeof c.maxDataPoints=="undefined")throw new Error("FixedDuration series requires maxDataPoints");this.palette=new Rickshaw.Color.Palette(b),this.timeBase=typeof c.timeBase=="undefined"?Math.floor((new Date).getTime()/1e3):c.timeBase,this.setTimeInterval(c.timeInterval),this[0]&&this[0].data&&this[0].data.length?(this.currentSize=this[0].data.length,this.currentIndex=this[0].data.length):(this.currentSize=0,this.currentIndex=0),this.maxDataPoints=c.maxDataPoints,a&&typeof a=="object"&&a instanceof Array&&(a.forEach(function(a){this.addItem(a)},this),this.currentSize+=1,this.currentIndex+=1),this.timeBase-=(this.maxDataPoints-this.currentSize)*this.timeInterval;if(typeof this.maxDataPoints!="undefined"&&this.currentSize<this.maxDataPoints)for(var d=this.maxDataPoints-this.currentSize-1;d>0;d--)this.currentSize+=1,this.currentIndex+=1,this.forEach(function(a){a.data.unshift({x:((d-1)*this.timeInterval||1)+this.timeBase,y:0,i:d})},this)},addData:function($super,a){$super(a),this.currentSize+=1,this.currentIndex+=1;if(this.maxDataPoints!==undefined)while(this.currentSize>this.maxDataPoints)this.dropData()},dropData:function(){this.forEach(function(a){a.data.splice(0,1)}),this.currentSize-=1},getIndex:function(){return this.currentIndex}}); this.seriesPathFactory()).attr("class","area"),this.stroke&&b.append("svg:path").attr("d",this.seriesStrokeFactory()).attr("class","line");var c=0;a.series.forEach(function(a){if(a.disabled)return;a.path=b[0][c++],this._styleSeries(a)},this)},_styleSeries:function(a){if(!a.path)return;d3.select(a.path).select(".area").attr("fill",a.color),this.stroke&&d3.select(a.path).select(".line").attr("fill","none").attr("stroke",a.stroke||d3.interpolateRgb(a.color,"black")(.125)).attr("stroke-width",this.strokeWidth),a.className&&a.path.setAttribute("class",a.className)}}),Rickshaw.namespace("Rickshaw.Graph.Renderer.ScatterPlot"),Rickshaw.Graph.Renderer.ScatterPlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"scatterplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:!0,fill:!0,stroke:!1,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:4})},initialize:function($super,a){$super(a)},render:function(){var a=this.graph;a.vis.selectAll("*").remove(),a.series.forEach(function(b){if(b.disabled)return;var c=a.vis.selectAll("path").data(b.stack).enter().append("svg:circle").attr("cx",function(b){return a.x(b.x)}).attr("cy",function(b){return a.y(b.y)}).attr("r",function(b){return"r"in b?b.r:a.renderer.dotSize});Array.prototype.forEach.call(c[0],function(a){a.setAttribute("fill",b.color)})},this)}}),Rickshaw.namespace("Rickshaw.Graph.Smoother"),Rickshaw.Graph.Smoother=function(a){this.graph=a.graph,this.element=a.element;var b=this;this.aggregationScale=1,this.element&&$(function(){$(b.element).slider({min:1,max:100,slide:function(a,c){b.setScale(c.value),b.graph.update()}})}),b.graph.stackData.hooks.data.push({name:"smoother",orderPosition:50,f:function(a){var c=[];return a.forEach(function(a){var d=[];while(a.length){var e=0,f=0,g=a.splice(0,b.aggregationScale);g.forEach(function(a){e+=a.x/g.length,f+=a.y/g.length}),d.push({x:e,y:f})}c.push(d)}),c}}),this.setScale=function(a){if(a<1)throw"scale out of range: "+a;this.aggregationScale=a,this.graph.update()}},Rickshaw.namespace("Rickshaw.Graph.Unstacker"),Rickshaw.Graph.Unstacker=function(a){this.graph=a.graph;var b=this;this.graph.stackData.hooks.after.push({name:"unstacker",f:function(a){return b.graph.renderer.unstack?(a.forEach(function(a){a.forEach(function(a){a.y0=0})}),a):a}})},Rickshaw.namespace("Rickshaw.Series"),Rickshaw.Series=Rickshaw.Class.create(Array,{initialize:function(a,b,c){c=c||{},this.palette=new Rickshaw.Color.Palette(b),this.timeBase=typeof c.timeBase=="undefined"?Math.floor((new Date).getTime()/1e3):c.timeBase;var d=typeof c.timeInterval=="undefined"?1e3:c.timeInterval;this.setTimeInterval(d),a&&typeof a=="object"&&a instanceof Array&&a.forEach(function(a){this.addItem(a)},this)},addItem:function(a){if(typeof a.name=="undefined")throw"addItem() needs a name";a.color=a.color||this.palette.color(a.name),a.data=a.data||[],a.data.length==0&&this.length&&this.getIndex()>0?this[0].data.forEach(function(b){a.data.push({x:b.x,y:0})}):a.data.length==0&&a.data.push({x:this.timeBase-(this.timeInterval||0),y:0}),this.push(a),this.legend&&this.legend.addLine(this.itemByName(a.name))},addData:function(a){var b=this.getIndex();Rickshaw.keys(a).forEach(function(a){this.itemByName(a)||this.addItem({name:a})},this),this.forEach(function(c){c.data.push({x:(b*this.timeInterval||1)+this.timeBase,y:a[c.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(a){for(var b=0;b<this.length;b++)if(this[b].name==a)return this[b]},setTimeInterval:function(a){this.timeInterval=a/1e3},setTimeBase:function(a){this.timeBase=a},dump:function(){var a={timeBase:this.timeBase,timeInterval:this.timeInterval,items:[]};return this.forEach(function(b){var c={color:b.color,name:b.name,data:[]};b.data.forEach(function(a){c.data.push({x:a.x,y:a.y})}),a.items.push(c)}),a},load:function(a){a.timeInterval&&(this.timeInterval=a.timeInterval),a.timeBase&&(this.timeBase=a.timeBase),a.items&&a.items.forEach(function(a){this.push(a),this.legend&&this.legend.addLine(this.itemByName(a.name))},this)}}),Rickshaw.Series.zeroFill=function(a){var b,c=0,d=a.map(function(a){return a.data});while(c<Math.max.apply(null,d.map(function(a){return a.length})))b=Math.min.apply(null,d.filter(function(a){return a[c]}).map(function(a){return a[c].x})),d.forEach(function(a){(!a[c]||a[c].x!=b)&&a.splice(c,0,{x:b,y:0})}),c++},Rickshaw.namespace("Rickshaw.Series.FixedDuration"),Rickshaw.Series.FixedDuration=Rickshaw.Class.create(Rickshaw.Series,{initialize:function(a,b,c){var c=c||{};if(typeof c.timeInterval=="undefined")throw new Error("FixedDuration series requires timeInterval");if(typeof c.maxDataPoints=="undefined")throw new Error("FixedDuration series requires maxDataPoints");this.palette=new Rickshaw.Color.Palette(b),this.timeBase=typeof c.timeBase=="undefined"?Math.floor((new Date).getTime()/1e3):c.timeBase,this.setTimeInterval(c.timeInterval),this[0]&&this[0].data&&this[0].data.length?(this.currentSize=this[0].data.length,this.currentIndex=this[0].data.length):(this.currentSize=0,this.currentIndex=0),this.maxDataPoints=c.maxDataPoints,a&&typeof a=="object"&&a instanceof Array&&(a.forEach(function(a){this.addItem(a)},this),this.currentSize+=1,this.currentIndex+=1),this.timeBase-=(this.maxDataPoints-this.currentSize)*this.timeInterval;if(typeof this.maxDataPoints!="undefined"&&this.currentSize<this.maxDataPoints)for(var d=this.maxDataPoints-this.currentSize-1;d>0;d--)this.currentSize+=1,this.currentIndex+=1,this.forEach(function(a){a.data.unshift({x:((d-1)*this.timeInterval||1)+this.timeBase,y:0,i:d})},this)},addData:function($super,a){$super(a),this.currentSize+=1,this.currentIndex+=1;if(this.maxDataPoints!==undefined)while(this.currentSize>this.maxDataPoints)this.dropData()},dropData:function(){this.forEach(function(a){a.data.splice(0,1)}),this.currentSize-=1},getIndex:function(){return this.currentIndex}});
  }
   
<html <html
xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="" py:strip=""
> >
   
<select name="month" py:def="month_selector(current_month, months, day)"> <select name="month" py:def="month_selector(current_month, months, day)">
<option value='' py:attrs="{'selected': 'selected' if not current_month else None}">All months</option> <option value='' py:attrs="{'selected': 'selected' if not current_month else None}">All months</option>
<py:for each="i, (val,desc) in enumerate(months)"> <py:for each="i, (val,desc) in enumerate(months)">
<option value='${val}' py:attrs="{'selected': 'selected' if current_month == val else None}">${desc}<py:if test="i == 0 and day"> (up to ${day})</py:if></option> <option value='${val}' py:attrs="{'selected': 'selected' if current_month == val else None}">${desc}<py:if test="i == 0 and day"> (up to ${day})</py:if></option>
</py:for> </py:for>
</select> </select>
   
   
<table py:def="social_table(items, with_source=False)" class="table table-condensed table-bordered table-striped"> <table py:def="social_table(items, with_source=False)" class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Name</th> <th>Name</th>
<th py:if="with_source">Source</th> <th py:if="with_source">Source</th>
<th>Visits</th> <th>Visits</th>
</tr> </tr>
<py:for each="name, url, source, count in items"> <py:for each="name, url, source, count in items">
<tr> <tr>
<td><a href="${url}">${name}</a></td> <td><a href="${url}">${name}</a></td>
<td py:if="with_source">${source}</td> <td py:if="with_source">${source}</td>
<td>${count}</td> <td>${count}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
   
   
<div py:def="rickshaw_graph(items_json,id,mode='line',colorscheme='munin')"> <div py:def="rickshaw_graph(items_json,id,mode='line',colorscheme='munin')">
<div id="chart_container_$id" class="rickshaw_chart_container"> <div id="chart_container_$id" class="rickshaw_chart_container">
<div id="y_axis_$id" class="rickshaw_y_axis"></div> <div id="y_axis_$id" class="rickshaw_y_axis"></div>
<div id="chart_$id" class="rickshaw_chart"></div> <div id="chart_$id" class="rickshaw_chart"></div>
<div id="legend_$id" class="rickshaw_legend"></div>  
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
var all_series = ${items_json}; CKAN.GA_Reports.render_rickshaw('$id', $items_json, '$mode', '$colorscheme');
var palette = new Rickshaw.Color.Palette( { scheme: '$colorscheme' } );  
$.each(all_series, function(i, object) {  
object['color'] = palette.color();  
});  
var graph = new Rickshaw.Graph( {  
element: document.querySelector("#chart_$id"),  
renderer: '$mode',  
series: all_series ,  
height: 328  
});  
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );  
var y_axis = new Rickshaw.Graph.Axis.Y( {  
graph: graph,  
orientation: 'left',  
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,  
element: document.getElementById('y_axis_$id'),  
} );  
var legend = new Rickshaw.Graph.Legend( {  
element: document.querySelector('#legend_$id'),  
graph: graph  
} );  
graph.render();  
}); });
</script> </script>
</div> </div>
</div> </div>
   
   
<table py:def="stat_table(items, title='Views')" class="table table-condensed table-bordered table-striped"> <table py:def="stat_table(items, title='Views')" class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>% ${title}</th> <th>% ${title}</th>
</tr> </tr>
<py:for each="name, value in items"> <py:for each="name, value in items">
<tr> <tr>
<td>${name}</td> <td>${name}</td>
<td>${value}</td> <td>${value}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
   
   
<div py:def="usage_nav(active_name)" id="minornavigation"> <div py:def="usage_nav(active_name)" id="minornavigation">
<div id="minornavigation-bg-left"> <div id="minornavigation-bg-left">
<div id="minornavigation-bg-right"> <div id="minornavigation-bg-right">
<ul class="nav nav-pills"> <ul class="nav nav-pills">
<li py:attrs="{'class': 'active' if active_name=='Site-wide' else None}"><a py:attrs="{'class': 'active' if active_name=='Site-wide' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Site-wide</a></li> <li py:attrs="{'class': 'active' if active_name=='Site-wide' else None}"><a py:attrs="{'class': 'active' if active_name=='Site-wide' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Site-wide</a></li>
<li py:attrs="{'class': 'active' if active_name=='Publishers' else None}"> <li py:attrs="{'class': 'active' if active_name=='Publishers' else None}">
<a py:attrs="{'class': 'active' if active_name=='Publishers' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Publishers</a> <a py:attrs="{'class': 'active' if active_name=='Publishers' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Publishers</a>
</li> </li>
<li py:attrs="{'class': 'active' if active_name=='Datasets' else None}"> <li py:attrs="{'class': 'active' if active_name=='Datasets' else None}">
<a py:attrs="{'class': 'active' if active_name=='Datasets' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Datasets</a> <a py:attrs="{'class': 'active' if active_name=='Datasets' else None}" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}"><img src="/images/icons/page_white.png" height="16px" width="16px" alt="None" class="inline-icon "/> Datasets</a>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
   
   
</html> </html>
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Notes</h4> <h4>Notes</h4>
<ul> <ul>
<li>"Views" is the number of times a page was loaded in users' browsers.</li> <li>"Views" is the number of times a page was loaded in users' browsers.</li>
<li>"Downloads" is the number of times a user has clicked to download either an original or cached resource for a particular dataset since December 2012</li> <li>"Downloads" is the number of times a user has clicked to download either an original or cached resource for a particular dataset. Download information is only available from 2nd December 2012; 'No data' is shown for records before that date.</li>
<li>These usage statistics are confined to users with javascript enabled, which excludes web crawlers and API calls.</li> <li>These usage statistics are confined to users with javascript enabled, which excludes web crawlers and API calls.</li>
<li>The results are not shown when the number of views/visits is tiny. Where these relate to site pages, results are available in full in the CSV download. Where these relate to users' web browser information, results are not disclosed, for privacy reasons.</li> <li>The results are not shown when the number of views/visits is tiny. Where these relate to site pages, results are available in full in the CSV download. Where these relate to users' web browser information, results are not disclosed, for privacy reasons.</li>
</ul> </ul>
</li> </li>
</html> </html>
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<xi:include href="../ga_util.html" /> <xi:include href="../ga_util.html" />
   
<py:def function="page_title">Usage by Publisher</py:def> <py:def function="page_title">Usage by Publisher</py:def>
   
<py:match path="primarysidebar"> <py:match path="primarysidebar">
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Download</h4> <h4>Download</h4>
<p><center> <p><center>
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center> <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center>
</p> </p>
</li> </li>
  <li class="widget-container boxed widget_text">
  <h4>Graph Legend</h4>
  <div id="graph-legend-container">
  </div>
  </li>
<xi:include href="../notes.html" /> <xi:include href="../notes.html" />
</py:match> </py:match>
   
<py:def function="optional_head"> <py:def function="optional_head">
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> <link rel="stylesheet" type="text/css" href="/css/ga_report.css"/>
  <script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script>
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script>
</py:def> </py:def>
   
<div py:match="content"> <div py:match="content">
   
<h1>Site Usage</h1> <h1>Site Usage</h1>
   
${usage_nav('Publishers')} ${usage_nav('Publishers')}
   
   
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get"> <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get">
<div class="controls"> <div class="controls">
   
${month_selector(c.month, c.months, c.day)} ${month_selector(c.month, c.months, c.day)}
   
<input class="btn button btn-primary" type='submit' value="Update"/> <input class="btn button btn-primary" type='submit' value="Update"/>
</div> </div>
</form> </form>
   
${rickshaw_graph(c.top_publishers_graph,'publishers')} ${rickshaw_graph(c.top_publishers_graph,'publishers')}
<table class="table table-condensed table-bordered table-striped"> <table class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Publisher</th> <th>Publisher</th>
<th>Dataset Views</th> <th>Dataset Views</th>
</tr> </tr>
<py:for each="publisher, views, visits in c.top_publishers"> <py:for each="publisher, views, visits in c.top_publishers">
<tr> <tr>
<td> <td>
${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))} ${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))}
</td> </td>
<td>${views}</td> <td>${views}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
   
   
</div> </div>
   
<xi:include href="../../layout.html" /> <xi:include href="../../layout.html" />
   
<py:def function="optional_footer"> <py:def function="optional_footer">
<script type='text/javascript'> <script type='text/javascript'>
$('.nav-tabs li a').click(function (e) { $('.nav-tabs li a').click(function (e) {
e.preventDefault(); e.preventDefault();
$(this).tab('show'); $(this).tab('show');
}) })
</script> </script>
</py:def> </py:def>
   
</html> </html>
   
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<xi:include href="../ga_util.html" /> <xi:include href="../ga_util.html" />
   
<py:def function="page_title">Usage by Dataset</py:def> <py:def function="page_title">Usage by Dataset</py:def>
   
<py:def function="optional_head"> <py:def function="optional_head">
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> <link rel="stylesheet" type="text/css" href="/css/ga_report.css"/>
  <script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script>
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script>
</py:def> </py:def>
   
<py:match path="primarysidebar"> <py:match path="primarysidebar">
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Download</h4> <h4>Download</h4>
<p><center> <p><center>
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center> <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center>
</p> </p>
  </li>
  <li class="widget-container boxed widget_text">
  <h4>Graph Legend</h4>
  <div id="graph-legend-container">
  </div>
</li> </li>
<xi:include href="../notes.html" /> <xi:include href="../notes.html" />
</py:match> </py:match>
   
   
<div py:match="content"> <div py:match="content">
<h1>Site Usage</h1> <h1>Site Usage</h1>
   
${usage_nav('Datasets')} ${usage_nav('Datasets')}
   
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}" method="get"> <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='read')}" method="get">
<div class="controls"> <div class="controls">
   
${month_selector(c.month, c.months, c.day)} ${month_selector(c.month, c.months, c.day)}
   
<select name="publisher"> <select name="publisher">
<option value='' py:attrs="{'selected': 'selected' if not c.publisher else None}">All publishers</option> <option value='' py:attrs="{'selected': 'selected' if not c.publisher else None}">All publishers</option>
<py:for each="val,desc in c.publishers"> <py:for each="val,desc in c.publishers">
<option value='${val}' py:attrs="{'selected': 'selected' if c.publisher_name == val else None}">${desc}</option> <option value='${val}' py:attrs="{'selected': 'selected' if c.publisher_name == val else None}">${desc}</option>
</py:for> </py:for>
</select> </select>
<input class="btn button btn-primary" type='submit' value="Update"/> <input class="btn button btn-primary" type='submit' value="Update"/>
</div> </div>
</form> </form>
   
<h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3> <h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3>
   
<p py:if="not c.top_packages">No page views in this period</p> <p py:if="not c.top_packages">No page views in this period</p>
   
<py:if test="c.top_packages"> <py:if test="c.top_packages">
${rickshaw_graph(c.graph_data,'dataset-downloads',debug=True)} ${rickshaw_graph(c.graph_data,'dataset-downloads',debug=True)}
<table class="table table-condensed table-bordered table-striped"> <table class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Dataset</th> <th>Dataset</th>
<th>Views</th> <th>Views</th>
<th>Downloads</th> <th>Downloads</th>
</tr> </tr>
<py:for each="package, views, visits,downloads in c.top_packages"> <py:for each="package, views, visits,downloads in c.top_packages">
<tr> <tr>
<td> <td>
${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))} ${h.link_to(package.title or package.name, h.url_for(controller='package', action='read', id=package.name))}
</td> </td>
<td>${views}</td> <td>${views}</td>
<td>${downloads}</td> <td>${downloads}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
</py:if> </py:if>
   
   
</div> </div>
   
<xi:include href="../../layout.html" /> <xi:include href="../../layout.html" />
</html> </html>
   
   
   
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<xi:include href="../ga_util.html" /> <xi:include href="../ga_util.html" />
   
<py:def function="page_title">Site usage</py:def> <py:def function="page_title">Site usage</py:def>
   
<py:def function="optional_head"> <py:def function="optional_head">
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> <link rel="stylesheet" type="text/css" href="/css/ga_report.css"/>
  <script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script>
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script>
</py:def> </py:def>
   
<py:match path="primarysidebar"> <py:match path="primarysidebar">
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Download</h4> <h4>Download</h4>
<p><center> <p><center>
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center> <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center>
</p> </p>
  </li>
  <li class="widget-container boxed widget_text">
  <h4>Graph Legend</h4>
  <div id="graph-legend-container">
  <div id="legend_none">(No graph loaded)</div>
  </div>
</li> </li>
<xi:include href="../notes.html" /> <xi:include href="../notes.html" />
   
</py:match> </py:match>
   
<div py:match="content"> <div py:match="content">
<h1>Site Usage</h1> <h1>Site Usage</h1>
${usage_nav('Site-wide')} ${usage_nav('Site-wide')}
   
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get"> <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='index')}" method="get">
<div class="controls"> <div class="controls">
   
${month_selector(c.month, c.months, c.day)} ${month_selector(c.month, c.months, c.day)}
   
<input class="btn button btn-primary" type='submit' value="Update"/> <input class="btn button btn-primary" type='submit' value="Update"/>
</div> </div>
</form> </form>
   
<div class="tabbable"> <div class="tabbable">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#totals" data-toggle="tab">Totals</a></li> <li><a href="#totals" data-toggle="hashchange">Totals</a></li>
<li class="dropdown"> <li class="dropdown">
<a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Browsers <a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers
<b class="caret"></b></a> <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#browsers_names" data-toggle="tab">Browsers</a></li> <li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li>
<li><a href="#browsers_versions" data-toggle="tab">Versions</a></li> <li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown">
<a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Operating<br/>Systems <a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems
<b class="caret"></b></a> <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#os" data-toggle="tab">Operating Systems</a></li> <li><a href="#os" data-toggle="hashchange">Operating Systems</a></li>
<li><a href="#os_versions" data-toggle="tab">Versions</a></li> <li><a href="#os_versions" data-toggle="hashchange">Versions</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown"> <li class="dropdown">
<a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Social Networks <a href="#" class="dropdown-toggle" data-toggle="dropdown">Social
<b class="caret"></b></a> <b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#social_networks" data-toggle="tab">All networks</a></li> <li><a href="#social_networks" data-toggle="hashchange">All networks</a></li>
<li><a href="#social_referrals_totals" data-toggle="tab">Referral links</a></li> <li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li>
</ul> </ul>
</li> </li>
  <li><a href="#languages" data-toggle="hashchange">Languages</a></li>
<li><a href="#social_networks" data-toggle="tab"></a></li> <li><a href="#country" data-toggle="hashchange">Country</a></li>
<li><a href="#languages" data-toggle="tab">Languages</a></li>  
<li><a href="#country" data-toggle="tab">Country</a></li>  
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="totals"> <div class="tab-pane" id="totals">
<table class="table table-condensed table-bordered table-striped"> <table class="table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Value</th> <th>Value</th>
<th>History</th> <th>History</th>
</tr> </tr>
<py:for each="name, value, graph in c.global_totals"> <py:for each="name, value, graph in c.global_totals">
<tr> <tr>
<td>${name}</td> <td>${name}</td>
<td>${value}</td> <td>${value}</td>
<td class="sparkline-cell"> <td class="sparkline-cell">
<span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}"> <span class="sparkline" sparkTooltips="${','.join([x for x,y in graph])}">
${','.join([y for x,y in graph])} ${','.join([y for x,y in graph])}
</span> </span>
</td> </td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
</div> </div>
<div class="tab-pane" id="browsers_versions"> <div class="tab-pane" id="browsers_versions">
${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')} ${rickshaw_graph(c.browser_versions_graph,'browser-versions',mode='stack')}
<p>Note: Where a browser has a large number of versions, these have been grouped together.</p> <p>Note: Where a browser has a large number of versions, these have been grouped together.</p>
${stat_table(c.browser_versions)} ${stat_table(c.browser_versions)}
</div> </div>
<div class="tab-pane" id="browsers_names"> <div class="tab-pane" id="browsers_names">
${rickshaw_graph(c.browsers_graph,'browsers',mode='stack')} ${rickshaw_graph(c.browsers_graph,'browsers',mode='stack')}
${stat_table(c.browsers)} ${stat_table(c.browsers)}
</div> </div>
<div class="tab-pane" id="os"> <div class="tab-pane" id="os">
${rickshaw_graph(c.os_graph,'os',mode='stack')} ${rickshaw_graph(c.os_graph,'os',mode='stack')}
${stat_table(c.os)} ${stat_table(c.os)}
</div> </div>
<div class="tab-pane" id="os_versions"> <div class="tab-pane" id="os_versions">
${rickshaw_graph(c.os_versions_graph,'os_versions',mode='stack')} ${rickshaw_graph(c.os_versions_graph,'os_versions',mode='stack')}
${stat_table(c.os_versions)} ${stat_table(c.os_versions)}
</div> </div>
<div class="tab-pane" id="social_referrals_totals"> <div class="tab-pane" id="social_referrals_totals">
<p>Number of visits that were referred from social networks</p> <p>Number of visits that were referred from social networks</p>
${social_table(c.social_referrer_totals)} ${social_table(c.social_referrer_totals)}
</div> </div>
<div class="tab-pane" id="social_networks"> <div class="tab-pane" id="social_networks">
${rickshaw_graph(c.social_networks_graph, 'social_networks',mode='stack')} ${rickshaw_graph(c.social_networks_graph, 'social_networks',mode='stack')}
<p>Percentage of visits that were referred from these social networks</p> <p>Percentage of visits that were referred from these social networks</p>
${stat_table(c.social_networks, 'Visits')} ${stat_table(c.social_networks, 'Visits')}
</div> </div>
<div class="tab-pane" id="languages"> <div class="tab-pane" id="languages">
${rickshaw_graph(c.languages_graph,'languages',mode='stack')} ${rickshaw_graph(c.languages_graph,'languages',mode='stack')}
${stat_table(c.languages)} ${stat_table(c.languages)}
</div> </div>
<div class="tab-pane" id="country"> <div class="tab-pane" id="country">
${rickshaw_graph(c.country_graph,'country',mode='stack')} ${rickshaw_graph(c.country_graph,'country',mode='stack')}
${stat_table(c.country)} ${stat_table(c.country)}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
   
   
<py:def function="optional_footer"> <py:def function="optional_footer">
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
var sparkOptions = { CKAN.GA_Reports.bind_sparklines();
enableTagOptions: true, CKAN.GA_Reports.bind_sidebar();
type: 'line', if (!window.location.hash) {
width: 100, window.location.hash='totals';
height: 26, }
chartRangeMin: 0, else {
spotColor: '', $(window).trigger('hashchange');
maxSpotColor: '', }
minSpotColor: '',  
highlightSpotColor: '000000',  
lineColor: '3F8E6D',  
fillColor: 'B7E66B'  
};  
$('.sparkline').sparkline('html',sparkOptions);  
}); });
</script> </script>
</py:def> </py:def>
   
<xi:include href="../../layout.html" /> <xi:include href="../../layout.html" />
</html> </html>