Repository: schollz/howmanypeoplearearound
Branch: master
Commit: b05e06a78c81
Files: 13
Total size: 5.3 MB
Directory structure:
gitextract_0ao9inqw/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .travis.yml
├── Dockerfile
├── LICENSE
├── README.md
├── howmanypeoplearearound/
│ ├── __init__.py
│ ├── __main__.py
│ ├── analysis.py
│ ├── colors.py
│ ├── oui.py
│ └── plotlyjs.py
└── setup.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: schollz
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
index.html
__pycache__/
*.py[cod]
*$py.class
.vscode
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# Pycharm
.idea
================================================
FILE: .travis.yml
================================================
sudo: false
dist: trusty
language: python
cache: pip
python:
- 2.7.13
- 3.6
install:
- pip install --upgrade pip setuptools
- pip install flake8
before_script:
flake8 . --count --exclude=./howmanypeoplearearound/plotlyjs.py --exit-zero --max-line-length=127 --statistics # 127 == GitHub editor width
script:
flake8 . --exclude=./howmanypeoplearearound/plotlyjs.py --select=E999,F821,F822,F823 --statistics # Stop build on syntax errors
notifications:
on_success: change
on_failure: always
================================================
FILE: Dockerfile
================================================
# Dockerfile for howmanypeoplearearound
# Usage: docker build -t howmanypeoplearearound .
FROM python:3
LABEL "repo"="https://github.com/schollz/howmanypeoplearearound"
RUN apt-get update \
&& apt-get upgrade --yes \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y tshark \
&& yes | dpkg-reconfigure -f noninteractive wireshark-common \
&& addgroup wireshark \
&& usermod -a -G wireshark ${USER:-root} \
&& newgrp wireshark \
&& pip install howmanypeoplearearound \
&& echo "===========================================================================================" \
&& echo "Please type: docker run -it --net=host --name howmanypeoplearearound howmanypeoplearearound"
CMD [ "howmanypeoplearearound" ]
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Zack
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# howmanypeoplearearound
Count the number of people around you :family_man_man_boy: by monitoring wifi signals :satellite:.
*howmanypeoplearearound* calculates the number of people in the vicinity
using the approximate number of smartphones as a proxy (since [~70% of people have smartphones nowadays](https://twitter.com/conradhackett/status/701798230619590656)).
A cellphone is determined to be in proximity to the computer based on sniffing WiFi probe
requests. Possible uses of *howmanypeoplearearound* include: monitoring foot traffic in your house
with Raspberry Pis, seeing if your roommates are home, etc.
Tested on Linux (Raspbian and Ubuntu) and Mac OS X.
### **It may be illegal** to monitor networks for MAC addresses, especially on networks that *you do not own*. Please check your country's laws (for US [Section 18 U.S. Code § 2511](https://www.law.cornell.edu/uscode/text/18/2511)) - [discussion](https://github.com/schollz/howmanypeoplearearound/issues/4).
Getting started
===============
For a video walkthrough on how to install, checkout [PNPtutorials](https://youtu.be/dLzouUfJyMM?t=3m2s).
## Dependencies
Python 2.7 or preferably Python 3 must be installed on your machine with the `pip` command also available.
```
python -V
pip -V
```
### WiFi adapter that supports monitor mode
There are a number of possible USB WiFi adapters that support monitor mode. Here's a list that are popular:
- [USB Rt3070 $14](https://www.amazon.com/gp/product/B00NAXX40C/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B00NAXX40C&linkId=b72d3a481799c15e483ea93c551742f4)
- [Panda PAU5 $14](https://www.amazon.com/gp/product/B00EQT0YK2/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B00EQT0YK2&linkId=e5b954672d93f1e9ce9c9981331515c4)
- [Panda PAU6 $15](https://www.amazon.com/gp/product/B00JDVRCI0/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B00JDVRCI0&linkId=e73e93e020941cada0e64b92186a2546)
- [Panda PAU9 $36](https://www.amazon.com/gp/product/B01LY35HGO/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B01LY35HGO&linkId=e63f3beda9855abd59009d6173234918)
- [Alfa AWUSO36NH $33](https://www.amazon.com/gp/product/B0035APGP6/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B0035APGP6&linkId=b4e25ba82357ca6f1a33cb23941befb3)
- [Alfa AWUS036NHA $40](https://www.amazon.com/gp/product/B004Y6MIXS/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B004Y6MIXS&linkId=0277ca161967134a7f75dd7b3443bded)
- [Alfa AWUS036NEH $40](https://www.amazon.com/gp/product/B0035OCVO6/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B0035OCVO6&linkId=bd45697540120291a2f6e169dcf81b96)
- [Sabrent NT-WGHU $15 (b/g) only](https://www.amazon.com/gp/product/B003EVO9U4/ref=as_li_tl?ie=UTF8&tag=scholl-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B003EVO9U4&linkId=06d4784d38b6bcef5957f3f6e74af8c8)
Namely you want to find a USB adapter with one of the following chipsets: Atheros AR9271, Ralink RT3070, Ralink RT3572, or Ralink RT5572.
### Mac OS X
```
brew install wireshark
brew cask install wireshark-chmodbpf
```
You need to dissociate from any AP before initiating the scanning:
```
sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -z
```
### Linux [tshark](https://www.wireshark.org/docs/man-pages/tshark.html)
```
sudo apt-get install tshark
```
Then update it so it can be run as non-root:
```
sudo dpkg-reconfigure wireshark-common (select YES)
sudo usermod -a -G wireshark ${USER:-root}
newgrp wireshark
```
## Install
```
pip install howmanypeoplearearound
```
## Run
### Quickstart
To run, simply type in
```bash
$ howmanypeoplearearound
Using wlan1 adapter and scanning for 60 seconds...
[==================================================] 100% 0s left
There are about 3 people around.
```
You will be prompted for the WiFi adapter to use for scanning. Make sure to use
an adapter that supports "monitor" mode.
### Docker alternative
If Docker is installed locally and you want to take *howmanypeoplearearound* out for a quick spin, you can try the following:
1. Copy Dockerfile from this repo in your current working directory
2. `docker build -t howmanypeoplearearound .` # that . at the end is important
3. `docker run -it --net=host --name howmanypeoplearearound howmanypeoplearearound`
NOTE: This Docker alternative is known to work on Ubuntu but *not* on Mac OS X. Feedback on other platforms would be appreciated.
### Options
You can modify the scan time, designate the adapter, or modify the output using some command-line options.
```bash
$ howmanypeoplearearound --help
Options:
-a, --adapter TEXT adapter to use
-z, --analyze TEXT analyze file
-s, --scantime TEXT time in seconds to scan
-o, --out TEXT output cellphone data to file
-v, --verbose verbose mode
--number just print the number
-j, --jsonprint print JSON of cellphone data
-n, --nearby only quantify signals that are nearby (rssi > -70)
--nocorrection do not apply correction
--loop loop forever
--sort sort cellphone data by distance (rssi)
```
### Print JSON
You can generate an JSON-formatted output to see what kind of phones are around:
```bash
$ howmanypeoplearearound -o test.json -a wlan1
[==================================================] 100% 0s left
There are about 4 people around.
$ cat test.json | python3 -m json.tool
[
{
"rssi": -86.0,
"mac": "90:e7:c4:xx:xx:xx",
"company": "HTC Corporation"
},
{
"rssi": -84.0,
"mac": "80:e6:50:xx:xx:xx",
"company": "Apple, Inc."
},
{
"rssi": -49.0,
"mac": "ac:37:43:xx:xx:xx",
"company": "HTC Corporation"
}
]
```
A higher rssi means closer (one of these phones is mine, and the other two are my roommates' who were upstairs).
### Run forever
You can add `--loop` to make this run forever and append new lines an output file, `test.json`:
```bash
$ howmanypeoplearearound -o test.json -a wlan1 --loop
```
### Visualize
You can visualize the output from a looped command via a browser using:
```bash
$ howmanypeoplearearound --analyze test.json
Wrote index.html
Open browser to http://localhost:8001
Type Ctl+C to exit
```
Then just open up `index.html` in a browser and you should see plots. The first plot shows the number of people over time. Here you can see that people start arriving at work place around 8-9am (when work starts!).

The second plot shows the RSSI values for the mac addresses seen. You can double-click on one of them in particular to highlight that trajectory, as I have done here for my phone (you can see when I leave from and when I arrive to work!):

How does it work?
==================
*howmanypeoplearearound* counts up the number of probe requests coming from cellphones in a given amount of time.
The probe requests can be "sniffed" from a monitor-mode enabled WiFi adapter using `tshark`. An accurate count does
depend on everyone having cellphone and also scanning long enough (1 - 10 minutes) to capture the packet when
a phone pings the WiFi network (which happens every 1 to 10 minutes unless the phone is off or WiFi is disabled).
This is a simplification of another program I wrote, [find-lf](https://github.com/schollz/find-lf) which uses a similar idea with a cluster of Raspberry Pis to geolocate positions of cellphones within the vicinity.
License
=======
MIT
================================================
FILE: howmanypeoplearearound/__init__.py
================================================
================================================
FILE: howmanypeoplearearound/__main__.py
================================================
import threading
import sys
import os
import os.path
import platform
import subprocess
import json
import time
import netifaces
import click
from howmanypeoplearearound.oui import load_dictionary, download_oui
from howmanypeoplearearound.analysis import analyze_file
from howmanypeoplearearound.colors import *
if os.name != 'nt':
from pick import pick
import curses
def which(program):
"""Determines whether program exists
"""
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
raise
def showTimer(timeleft):
"""Shows a countdown timer"""
total = int(timeleft) * 10
for i in range(total):
sys.stdout.write('\r')
# the exact output you're looking for:
timeleft_string = '%ds left' % int((total - i + 1) / 10)
if (total - i + 1) > 600:
timeleft_string = '%dmin %ds left' % (
int((total - i + 1) / 600), int((total - i + 1) / 10 % 60))
sys.stdout.write("[%-50s] %d%% %15s" %
('=' * int(50.5 * i / total), 101 * i / total, timeleft_string))
sys.stdout.flush()
time.sleep(0.1)
print("")
def fileToMacSet(path):
with open(path, 'r') as f:
maclist = f.readlines()
return set([x.strip() for x in maclist])
@click.command()
@click.option('-a', '--adapter', default='', help='adapter to use')
@click.option('-z', '--analyze', default='', help='analyze file')
@click.option('-s', '--scantime', default='60', help='time in seconds to scan')
@click.option('-o', '--out', default='', help='output cellphone data to file')
@click.option('-d', '--dictionary', default='oui.txt', help='OUI dictionary')
@click.option('-v', '--verbose', help='verbose mode', is_flag=True)
@click.option('--number', help='just print the number', is_flag=True)
@click.option('-j', '--jsonprint', help='print JSON of cellphone data', is_flag=True)
@click.option('-n', '--nearby', help='only quantify signals that are nearby (rssi > -70)', is_flag=True)
@click.option('--allmacaddresses', help='do not check MAC addresses against the OUI database to only recognize known cellphone manufacturers', is_flag=True) # noqa
@click.option('-m', '--manufacturers', default='', help='read list of known manufacturers from file')
@click.option('--nocorrection', help='do not apply correction', is_flag=True)
@click.option('--loop', help='loop forever', is_flag=True)
@click.option('--port', default=8001, help='port to use when serving analysis')
@click.option('--sort', help='sort cellphone data by distance (rssi)', is_flag=True)
@click.option('--targetmacs', help='read a file that contains target MAC addresses', default='')
@click.option('-f', '--pcap', help='read a pcap file instead of capturing')
def main(adapter, scantime, verbose, dictionary, number, nearby, jsonprint, out, allmacaddresses, manufacturers, nocorrection, loop, analyze, port, sort, targetmacs, pcap):
if analyze != '':
analyze_file(analyze, port)
return
if loop:
while True:
adapter = scan(adapter, scantime, verbose, dictionary, number,
nearby, jsonprint, out, allmacaddresses, manufacturers, nocorrection, loop, sort, targetmacs, pcap)
else:
scan(adapter, scantime, verbose, dictionary, number,
nearby, jsonprint, out, allmacaddresses, manufacturers, nocorrection, loop, sort, targetmacs, pcap)
def scan(adapter, scantime, verbose, dictionary, number, nearby, jsonprint, out, allmacaddresses, manufacturers, nocorrection, loop, sort, targetmacs, pcap):
"""Monitor wifi signals to count the number of people around you"""
# print("OS: " + os.name)
# print("Platform: " + platform.system())
if (not os.path.isfile(dictionary)) or (not os.access(dictionary, os.R_OK)):
download_oui(dictionary)
oui = load_dictionary(dictionary)
if not oui:
print('couldn\'t load [%s]' % dictionary)
sys.exit(1)
try:
tshark = which("tshark")
except:
if platform.system() != 'Darwin':
print('tshark not found, install using\n\napt-get install tshark\n')
else:
print('wireshark not found, install using: \n\tbrew install wireshark')
print(
'you may also need to execute: \n\tbrew cask install wireshark-chmodbpf')
sys.exit(1)
if jsonprint:
number = True
if number:
verbose = False
if not pcap:
if len(adapter) == 0:
if os.name == 'nt':
print('You must specify the adapter with -a ADAPTER')
print('Choose from the following: ' +
', '.join(netifaces.interfaces()))
sys.exit(1)
title = 'Please choose the adapter you want to use: '
try:
adapter, index = pick(netifaces.interfaces(), title)
except curses.error as e:
print('Please check your $TERM settings: %s' % (e))
sys.exit(1)
print("Using %s adapter and scanning for %s seconds..." %
(adapter, scantime))
if not number:
# Start timer
t1 = threading.Thread(target=showTimer, args=(scantime,))
t1.daemon = True
t1.start()
dump_file = '/tmp/tshark-temp'
# Scan with tshark
command = [tshark, '-I', '-i', adapter, '-a',
'duration:' + scantime, '-w', dump_file]
if verbose:
print(' '.join(command))
run_tshark = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, nothing = run_tshark.communicate()
if not number:
t1.join()
else:
dump_file = pcap
# Read tshark output
command = [
tshark, '-r',
dump_file, '-T',
'fields', '-e',
'wlan.sa', '-e',
'wlan.bssid', '-e',
'radiotap.dbm_antsignal'
]
if verbose:
print(' '.join(command))
run_tshark = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, nothing = run_tshark.communicate()
# read target MAC address
targetmacset = set()
if targetmacs != '':
targetmacset = fileToMacSet(targetmacs)
foundMacs = {}
for line in output.decode('utf-8').split('\n'):
if verbose:
print(line)
if line.strip() == '':
continue
mac = line.split()[0].strip().split(',')[0]
dats = line.split()
if len(dats) == 3:
if ':' not in dats[0] or len(dats) != 3:
continue
if mac not in foundMacs:
foundMacs[mac] = []
dats_2_split = dats[2].split(',')
if len(dats_2_split) > 1:
rssi = float(dats_2_split[0]) / 2 + float(dats_2_split[1]) / 2
else:
rssi = float(dats_2_split[0])
foundMacs[mac].append(rssi)
if not foundMacs:
print("Found no signals, are you sure %s supports monitor mode?" % adapter)
sys.exit(1)
for key, value in foundMacs.items():
foundMacs[key] = float(sum(value)) / float(len(value))
# Find target MAC address in foundMacs
if targetmacset:
sys.stdout.write(RED)
for mac in foundMacs:
if mac in targetmacset:
print("Found MAC address: %s" % mac)
print("rssi: %s" % str(foundMacs[mac]))
sys.stdout.write(RESET)
if manufacturers:
f = open(manufacturers,'r')
cellphone = [line.rstrip('\n') for line in f.readlines()]
f.close()
else:
cellphone = [
'Motorola Mobility LLC, a Lenovo Company',
'GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD',
'Huawei Symantec Technologies Co.,Ltd.',
'Microsoft',
'HTC Corporation',
'Samsung Electronics Co.,Ltd',
'SAMSUNG ELECTRO-MECHANICS(THAILAND)',
'BlackBerry RTS',
'LG ELECTRONICS INC',
'Apple, Inc.',
'LG Electronics',
'OnePlus Tech (Shenzhen) Ltd',
'Xiaomi Communications Co Ltd',
'LG Electronics (Mobile Communications)']
cellphone_people = []
for mac in foundMacs:
oui_id = 'Not in OUI'
if mac[:8] in oui:
oui_id = oui[mac[:8]]
if verbose:
print(mac, oui_id, oui_id in cellphone)
if allmacaddresses or oui_id in cellphone:
if not nearby or (nearby and foundMacs[mac] > -70):
cellphone_people.append(
{'company': oui_id, 'rssi': foundMacs[mac], 'mac': mac})
if sort:
cellphone_people.sort(key=lambda x: x['rssi'], reverse=True)
if verbose:
print(json.dumps(cellphone_people, indent=2))
# US / Canada: https://twitter.com/conradhackett/status/701798230619590656
percentage_of_people_with_phones = 0.7
if nocorrection:
percentage_of_people_with_phones = 1
num_people = int(round(len(cellphone_people) /
percentage_of_people_with_phones))
if number and not jsonprint:
print(num_people)
elif jsonprint:
print(json.dumps(cellphone_people, indent=2))
else:
if num_people == 0:
print("No one around (not even you!).")
elif num_people == 1:
print("No one around, but you.")
else:
print("There are about %d people around." % num_people)
if out:
with open(out, 'a') as f:
data_dump = {'cellphones': cellphone_people, 'time': time.time()}
f.write(json.dumps(data_dump) + "\n")
if verbose:
print("Wrote %d records to %s" % (len(cellphone_people), out))
if not pcap:
os.remove(dump_file)
return adapter
if __name__ == '__main__':
main()
================================================
FILE: howmanypeoplearearound/analysis.py
================================================
import copy
import datetime
import json
import sys
from howmanypeoplearearound.plotlyjs import *
def analyze_file(fname, port):
lines = []
with open(fname, 'r') as f:
for line in f:
try:
lines.append(json.loads(line))
except:
pass
lines = sorted(lines, key=lambda k: k['time'])
macs_to_add = []
for data in lines:
for c in data['cellphones']:
if c['rssi'] > -80 and c['mac'] not in macs_to_add:
macs_to_add.append(c['mac'])
mac_data = {mac: {'y': []} for mac in macs_to_add}
num = {'x': [], 'y': []}
for data in lines:
rssi = {}
for mac in macs_to_add:
rssi[mac] = -100
for c in data['cellphones']:
if c['mac'] in rssi:
rssi[c['mac']] = c['rssi']
for mac in mac_data:
mac_data[mac]['y'].append(str(rssi[mac] + 100))
num['x'].append("'" + datetime.datetime.fromtimestamp(
data['time']).isoformat().split('.')[0].replace('T', ' ') + "'")
num['y'].append(str(len(data['cellphones'])))
mac_names = copy.deepcopy(macs_to_add)
for i, mac in enumerate(mac_names):
mac_names[i] = 'mac' + mac.replace(':', '')
# remove pings
for mac in mac_data:
for i, y in enumerate(mac_data[mac]['y']):
if y == "0" and i > 2:
if mac_data[mac]['y'][i - 3] == "0" and (mac_data[mac]['y'][i - 1] != "0" or mac_data[mac]['y'][i - 2] != "0"):
mac_data[mac]['y'][i - 1] = "0"
mac_data[mac]['y'][i - 2] = "0"
js = ""
js += ('timex = [%s]' % ', '.join(num['x']))
for i, mac in enumerate(macs_to_add):
js += ('\nvar %s = {' % mac_names[i])
js += ('\n x: timex,')
js += ('\n y: [%s],' % ', '.join(mac_data[mac]['y']))
js += ("\n name: '%s', mode: 'lines', type:'scatter' };\n\n" % mac)
js += ('\n\nvar data = [%s];' % ', '.join(mac_names))
js += ("\n\nPlotly.newPlot('myDiv',data,layout2);")
js += ('\nvar num_cellphones = {')
js += ('\n x: timex,')
js += ('\n y: [%s],' % ', '.join(num['y']))
js += ("\n name: 'N', mode: 'lines', type:'scatter' };\n\n")
js += ("\n\nPlotly.newPlot('myDiv2',[num_cellphones],layout1);")
with open('index.html', 'w') as f:
f.write("""
""" % (js))
print("Wrote index.html")
print("Open browser to http://localhost:" + str(port))
print("Type Ctl+C to exit")
if sys.version_info >= (3, 0):
# Python 3 code in this block
from http.server import HTTPServer, SimpleHTTPRequestHandler
httpd = HTTPServer(('localhost', port), SimpleHTTPRequestHandler)
httpd.serve_forever()
else:
# Python 2 code in this block
import SimpleHTTPServer
import SocketServer
httpd = SocketServer.TCPServer(("", port), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.serve_forever()
================================================
FILE: howmanypeoplearearound/colors.py
================================================
# Output colored text in terminal
# Define colors
RED = "\033[1;31m"
BLUE = "\033[1;34m"
CYAN = "\033[1;36m"
GREEN = "\033[0;32m"
RESET = "\033[0;0m"
BOLD = "\033[;1m"
REVERSE = "\033[;7m"
================================================
FILE: howmanypeoplearearound/oui.py
================================================
try: #python3
from urllib.request import urlopen
except: #python2
from urllib2 import urlopen
def load_dictionary(file):
oui = {}
with open(file, 'r') as f:
for line in f:
if '(hex)' in line:
data = line.split('(hex)')
key = data[0].replace('-', ':').lower().strip()
company = data[1].strip()
oui[key] = company
return oui
def download_oui(to_file):
uri = 'http://standards-oui.ieee.org/oui/oui.txt'
print("Trying to download current version of oui.txt from [%s] to file [%s]" % (uri, to_file))
oui_data = urlopen(uri, timeout=10).read()
with open(to_file, 'wb') as oui_file:
oui_file.write(oui_data)
================================================
FILE: howmanypeoplearearound/plotlyjs.py
================================================
plotlyjs = r"""
/**
* plotly.js v1.27.1
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
* Licensed under the MIT license
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Plotly = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o Math.abs(dy)) {
view.rotate(t, 0, 0, -dx * flipX * Math.PI * camera.rotateSpeed / window.innerWidth)
} else {
var kzoom = camera.zoomSpeed * flipY * dy / window.innerHeight * (t - view.lastT()) / 100.0
view.pan(t, 0, 0, distance * (Math.exp(kzoom) - 1))
}
}, true)
return camera
}
},{"3d-view":35,"mouse-change":445,"mouse-event-offset":446,"mouse-wheel":448,"right-now":494}],35:[function(require,module,exports){
'use strict'
module.exports = createViewController
var createTurntable = require('turntable-camera-controller')
var createOrbit = require('orbit-camera-controller')
var createMatrix = require('matrix-camera-controller')
function ViewController(controllers, mode) {
this._controllerNames = Object.keys(controllers)
this._controllerList = this._controllerNames.map(function(n) {
return controllers[n]
})
this._mode = mode
this._active = controllers[mode]
if(!this._active) {
this._mode = 'turntable'
this._active = controllers.turntable
}
this.modes = this._controllerNames
this.computedMatrix = this._active.computedMatrix
this.computedEye = this._active.computedEye
this.computedUp = this._active.computedUp
this.computedCenter = this._active.computedCenter
this.computedRadius = this._active.computedRadius
}
var proto = ViewController.prototype
var COMMON_METHODS = [
['flush', 1],
['idle', 1],
['lookAt', 4],
['rotate', 4],
['pan', 4],
['translate', 4],
['setMatrix', 2],
['setDistanceLimits', 2],
['setDistance', 2]
]
COMMON_METHODS.forEach(function(method) {
var name = method[0]
var argNames = []
for(var i=0; i 0; --iterations) {
relaxRightToLeft(alpha *= .99);
resolveCollisions();
relaxLeftToRight(alpha);
resolveCollisions();
}
function initializeNodeDepth() {
var ky = d3Array.min(nodesByBreadth, function(nodes) {
return (size[1] - (nodes.length - 1) * nodePadding) / d3Array.sum(nodes, value);
});
nodesByBreadth.forEach(function(nodes) {
nodes.forEach(function(node, i) {
node.y = i;
node.dy = node.value * ky;
});
});
links.forEach(function(link) {
link.dy = link.value * ky;
});
}
function relaxLeftToRight(alpha) {
nodesByBreadth.forEach(function(nodes) {
nodes.forEach(function(node) {
if (node.targetLinks.length) {
var y = d3Array.sum(node.targetLinks, weightedSource) / d3Array.sum(node.targetLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedSource(link) {
return center(link.source) * link.value;
}
}
function relaxRightToLeft(alpha) {
nodesByBreadth.slice().reverse().forEach(function(nodes) {
nodes.forEach(function(node) {
if (node.sourceLinks.length) {
var y = d3Array.sum(node.sourceLinks, weightedTarget) / d3Array.sum(node.sourceLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedTarget(link) {
return center(link.target) * link.value;
}
}
function resolveCollisions() {
nodesByBreadth.forEach(function(nodes) {
var node,
dy,
y0 = 0,
n = nodes.length,
i;
// Push any overlapping nodes down.
nodes.sort(ascendingDepth);
for (i = 0; i < n; ++i) {
node = nodes[i];
dy = y0 - node.y;
if (dy > 0) node.y += dy;
y0 = node.y + node.dy + nodePadding;
}
// If the bottommost node goes outside the bounds, push it back up.
dy = y0 - nodePadding - size[1];
if (dy > 0) {
y0 = node.y -= dy;
// Push any overlapping nodes back up.
for (i = n - 2; i >= 0; --i) {
node = nodes[i];
dy = node.y + node.dy + nodePadding - y0;
if (dy > 0) node.y -= dy;
y0 = node.y;
}
}
});
}
function ascendingDepth(a, b) {
return a.y - b.y;
}
}
function computeLinkDepths() {
nodes.forEach(function(node) {
node.sourceLinks.sort(ascendingTargetDepth);
node.targetLinks.sort(ascendingSourceDepth);
});
nodes.forEach(function(node) {
var sy = 0, ty = 0;
node.sourceLinks.forEach(function(link) {
link.sy = sy;
sy += link.dy;
});
node.targetLinks.forEach(function(link) {
link.ty = ty;
ty += link.dy;
});
});
function ascendingSourceDepth(a, b) {
return (a.source.y - b.source.y) || (a.originalIndex - b.originalIndex);
}
function ascendingTargetDepth(a, b) {
return (a.target.y - b.target.y) || (a.originalIndex - b.originalIndex);
}
}
function center(node) {
return node.y + node.dy / 2;
}
function value(link) {
return link.value;
}
return sankey;
};
exports.sankey = sankey;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{"d3-array":110,"d3-collection":111,"d3-interpolate":115}],37:[function(require,module,exports){
'use strict'
var weakMap = typeof WeakMap === 'undefined' ? require('weak-map') : WeakMap
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var TriangleCache = new weakMap()
function createABigTriangle(gl) {
var triangleVAO = TriangleCache.get(gl)
var handle = triangleVAO && (triangleVAO._triangleBuffer.handle || triangleVAO._triangleBuffer.buffer)
if(!handle || !gl.isBuffer(handle)) {
var buf = createBuffer(gl, new Float32Array([-1, -1, -1, 4, 4, -1]))
triangleVAO = createVAO(gl, [
{ buffer: buf,
type: gl.FLOAT,
size: 2
}
])
triangleVAO._triangleBuffer = buf
TriangleCache.set(gl, triangleVAO)
}
triangleVAO.bind()
gl.drawArrays(gl.TRIANGLES, 0, 3)
triangleVAO.unbind()
}
module.exports = createABigTriangle
},{"gl-buffer":152,"gl-vao":266,"weak-map":551}],38:[function(require,module,exports){
var padLeft = require('pad-left')
module.exports = addLineNumbers
function addLineNumbers (string, start, delim) {
start = typeof start === 'number' ? start : 1
delim = delim || ': '
var lines = string.split(/\r?\n/)
var totalDigits = String(lines.length + start - 1).length
return lines.map(function (line, i) {
var c = i + start
var digits = String(c).length
var prefix = padLeft(c, totalDigits - digits)
return prefix + delim + line
}).join('\n')
}
},{"pad-left":466}],39:[function(require,module,exports){
'use strict'
module.exports = affineHull
var orient = require('robust-orientation')
function linearlyIndependent(points, d) {
var nhull = new Array(d+1)
for(var i=0; i1 or 0->255 rgb array
var rgb,
match;
if (typeof str !== 'string') return str;
rgb = [];
// hex notation
if (str[0] === '#') {
str = str.substr(1) // remove hash
if (str.length === 3) str += str // fff -> ffffff
match = parseInt(str, 16);
rgb[0] = ((match >> 16) & 255);
rgb[1] = ((match >> 8) & 255);
rgb[2] = (match & 255);
}
// rgb(34, 34, 127) or rgba(34, 34, 127, 0.1) notation
else if (RGB_REGEX.test(str)) {
match = str.match(RGB_GROUP_REGEX);
rgb[0] = parseInt(match[1]);
rgb[1] = parseInt(match[2]);
rgb[2] = parseInt(match[3]);
}
if (!twoFiftySix) {
for (var j=0; j<3; ++j) rgb[j] = rgb[j]/255
}
return rgb;
}
function str2RgbaArray(str, twoFiftySix) {
// convert hex or rbg strings to 0->1 or 0->255 rgb array
var rgb,
match;
if (typeof str !== 'string') return str;
rgb = [];
// hex notation
if (str[0] === '#') {
str = str.substr(1) // remove hash
if (str.length === 3) str += str // fff -> ffffff
match = parseInt(str, 16);
rgb[0] = ((match >> 16) & 255);
rgb[1] = ((match >> 8) & 255);
rgb[2] = (match & 255);
}
// rgb(34, 34, 127) or rgba(34, 34, 127, 0.1) notation
else if (RGB_REGEX.test(str)) {
match = str.match(RGB_GROUP_REGEX);
rgb[0] = parseInt(match[1]);
rgb[1] = parseInt(match[2]);
rgb[2] = parseInt(match[3]);
if (match[4]) rgb[3] = parseFloat(match[4]);
else rgb[3] = 1.0;
}
if (!twoFiftySix) {
for (var j=0; j<3; ++j) rgb[j] = rgb[j]/255
}
return rgb;
}
that.isPlainObject = isPlainObject;
that.linspace = linspace;
that.zip3 = zip3;
that.sum = sum;
that.zip = zip;
that.isEqual = isEqual;
that.copy2D = copy2D;
that.copy1D = copy1D;
that.str2RgbArray = str2RgbArray;
that.str2RgbaArray = str2RgbaArray;
return that
}
module.exports = arraytools();
},{}],43:[function(require,module,exports){
(function (global){
'use strict';
// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js
// original notice:
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh
* @license MIT
*/
function compare(a, b) {
if (a === b) {
return 0;
}
var x = a.length;
var y = b.length;
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
if (a[i] !== b[i]) {
x = a[i];
y = b[i];
break;
}
}
if (x < y) {
return -1;
}
if (y < x) {
return 1;
}
return 0;
}
function isBuffer(b) {
if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {
return global.Buffer.isBuffer(b);
}
return !!(b != null && b._isBuffer);
}
// based on node assert, original notice:
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var util = require('util/');
var hasOwn = Object.prototype.hasOwnProperty;
var pSlice = Array.prototype.slice;
var functionsHaveNames = (function () {
return function foo() {}.name === 'foo';
}());
function pToString (obj) {
return Object.prototype.toString.call(obj);
}
function isView(arrbuf) {
if (isBuffer(arrbuf)) {
return false;
}
if (typeof global.ArrayBuffer !== 'function') {
return false;
}
if (typeof ArrayBuffer.isView === 'function') {
return ArrayBuffer.isView(arrbuf);
}
if (!arrbuf) {
return false;
}
if (arrbuf instanceof DataView) {
return true;
}
if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {
return true;
}
return false;
}
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = module.exports = ok;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({ message: message,
// actual: actual,
// expected: expected })
var regex = /\s*function\s+([^\(\s]*)\s*/;
// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js
function getName(func) {
if (!util.isFunction(func)) {
return;
}
if (functionsHaveNames) {
return func.name;
}
var str = func.toString();
var match = str.match(regex);
return match && match[1];
}
assert.AssertionError = function AssertionError(options) {
this.name = 'AssertionError';
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
if (options.message) {
this.message = options.message;
this.generatedMessage = false;
} else {
this.message = getMessage(this);
this.generatedMessage = true;
}
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
} else {
// non v8 browsers so we can have a stacktrace
var err = new Error();
if (err.stack) {
var out = err.stack;
// try to strip useless frames
var fn_name = getName(stackStartFunction);
var idx = out.indexOf('\n' + fn_name);
if (idx >= 0) {
// once we have located the function frame
// we need to strip out everything before it (and its line)
var next_line = out.indexOf('\n', idx + 1);
out = out.substring(next_line + 1);
}
this.stack = out;
}
}
};
// assert.AssertionError instanceof Error
util.inherits(assert.AssertionError, Error);
function truncate(s, n) {
if (typeof s === 'string') {
return s.length < n ? s : s.slice(0, n);
} else {
return s;
}
}
function inspect(something) {
if (functionsHaveNames || !util.isFunction(something)) {
return util.inspect(something);
}
var rawname = getName(something);
var name = rawname ? ': ' + rawname : '';
return '[Function' + name + ']';
}
function getMessage(self) {
return truncate(inspect(self.actual), 128) + ' ' +
self.operator + ' ' +
truncate(inspect(self.expected), 128);
}
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, !!guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
function ok(value, message) {
if (!value) fail(value, true, message, '==', assert.ok);
}
assert.ok = ok;
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, '!=', assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
}
};
assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
if (!_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
}
};
function _deepEqual(actual, expected, strict, memos) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (isBuffer(actual) && isBuffer(expected)) {
return compare(actual, expected) === 0;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (util.isDate(actual) && util.isDate(expected)) {
return actual.getTime() === expected.getTime();
// 7.3 If the expected value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object with the same source and
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
} else if (util.isRegExp(actual) && util.isRegExp(expected)) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.multiline === expected.multiline &&
actual.lastIndex === expected.lastIndex &&
actual.ignoreCase === expected.ignoreCase;
// 7.4. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if ((actual === null || typeof actual !== 'object') &&
(expected === null || typeof expected !== 'object')) {
return strict ? actual === expected : actual == expected;
// If both values are instances of typed arrays, wrap their underlying
// ArrayBuffers in a Buffer each to increase performance
// This optimization requires the arrays to have the same type as checked by
// Object.prototype.toString (aka pToString). Never perform binary
// comparisons for Float*Arrays, though, since e.g. +0 === -0 but their
// bit patterns are not identical.
} else if (isView(actual) && isView(expected) &&
pToString(actual) === pToString(expected) &&
!(actual instanceof Float32Array ||
actual instanceof Float64Array)) {
return compare(new Uint8Array(actual.buffer),
new Uint8Array(expected.buffer)) === 0;
// 7.5 For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else if (isBuffer(actual) !== isBuffer(expected)) {
return false;
} else {
memos = memos || {actual: [], expected: []};
var actualIndex = memos.actual.indexOf(actual);
if (actualIndex !== -1) {
if (actualIndex === memos.expected.indexOf(expected)) {
return true;
}
}
memos.actual.push(actual);
memos.expected.push(expected);
return objEquiv(actual, expected, strict, memos);
}
}
function isArguments(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv(a, b, strict, actualVisitedObjects) {
if (a === null || a === undefined || b === null || b === undefined)
return false;
// if one is a primitive, the other must be same
if (util.isPrimitive(a) || util.isPrimitive(b))
return a === b;
if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
return false;
var aIsArgs = isArguments(a);
var bIsArgs = isArguments(b);
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
return false;
if (aIsArgs) {
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b, strict);
}
var ka = objectKeys(a);
var kb = objectKeys(b);
var key, i;
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length !== kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] !== kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected, false)) {
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
}
};
assert.notDeepStrictEqual = notDeepStrictEqual;
function notDeepStrictEqual(actual, expected, message) {
if (_deepEqual(actual, expected, true)) {
fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
}
}
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, '===', assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, '!==', assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (Object.prototype.toString.call(expected) == '[object RegExp]') {
return expected.test(actual);
}
try {
if (actual instanceof expected) {
return true;
}
} catch (e) {
// Ignore. The instanceof check doesn't work for arrow functions.
}
if (Error.isPrototypeOf(expected)) {
return false;
}
return expected.call({}, actual) === true;
}
function _tryBlock(block) {
var error;
try {
block();
} catch (e) {
error = e;
}
return error;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof block !== 'function') {
throw new TypeError('"block" argument must be a function');
}
if (typeof expected === 'string') {
message = expected;
expected = null;
}
actual = _tryBlock(block);
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail(actual, expected, 'Missing expected exception' + message);
}
var userProvidedMessage = typeof message === 'string';
var isUnwantedException = !shouldThrow && util.isError(actual);
var isUnexpectedException = !shouldThrow && actual && !expected;
if ((isUnwantedException &&
userProvidedMessage &&
expectedException(actual, expected)) ||
isUnexpectedException) {
fail(actual, expected, 'Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws(true, block, error, message);
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws(false, block, error, message);
};
assert.ifError = function(err) { if (err) throw err; };
var objectKeys = Object.keys || function (obj) {
var keys = [];
for (var key in obj) {
if (hasOwn.call(obj, key)) keys.push(key);
}
return keys;
};
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"util/":541}],44:[function(require,module,exports){
module.exports = function _atob(str) {
return atob(str)
}
},{}],45:[function(require,module,exports){
'use strict'
module.exports = barycentric
var solve = require('robust-linear-solve')
function reduce(x) {
var r = 0
for(var i=0; i 0) {
a = a.ushln(shift)
} else if(shift < 0) {
b = b.ushln(-shift)
}
return rationalize(a, b)
}
},{"./div":48,"./is-rat":50,"./lib/is-bn":54,"./lib/num-to-bn":55,"./lib/rationalize":56,"./lib/str-to-bn":57}],50:[function(require,module,exports){
'use strict'
var isBN = require('./lib/is-bn')
module.exports = isRat
function isRat(x) {
return Array.isArray(x) && x.length === 2 && isBN(x[0]) && isBN(x[1])
}
},{"./lib/is-bn":54}],51:[function(require,module,exports){
'use strict'
var BN = require('bn.js')
module.exports = sign
function sign (x) {
return x.cmp(new BN(0))
}
},{"bn.js":64}],52:[function(require,module,exports){
'use strict'
var sign = require('./bn-sign')
module.exports = bn2num
//TODO: Make this better
function bn2num(b) {
var l = b.length
var words = b.words
var out = 0
if (l === 1) {
out = words[0]
} else if (l === 2) {
out = words[0] + (words[1] * 0x4000000)
} else {
for (var i = 0; i < l; i++) {
var w = words[i]
out += w * Math.pow(0x4000000, i)
}
}
return sign(b) * out
}
},{"./bn-sign":51}],53:[function(require,module,exports){
'use strict'
var db = require('double-bits')
var ctz = require('bit-twiddle').countTrailingZeros
module.exports = ctzNumber
//Counts the number of trailing zeros
function ctzNumber(x) {
var l = ctz(db.lo(x))
if(l < 32) {
return l
}
var h = ctz(db.hi(x))
if(h > 20) {
return 52
}
return h + 32
}
},{"bit-twiddle":63,"double-bits":120}],54:[function(require,module,exports){
'use strict'
var BN = require('bn.js')
module.exports = isBN
//Test if x is a bignumber
//FIXME: obviously this is the wrong way to do it
function isBN(x) {
return x && typeof x === 'object' && Boolean(x.words)
}
},{"bn.js":64}],55:[function(require,module,exports){
'use strict'
var BN = require('bn.js')
var db = require('double-bits')
module.exports = num2bn
function num2bn(x) {
var e = db.exponent(x)
if(e < 52) {
return new BN(x)
} else {
return (new BN(x * Math.pow(2, 52-e))).ushln(e-52)
}
}
},{"bn.js":64,"double-bits":120}],56:[function(require,module,exports){
'use strict'
var num2bn = require('./num-to-bn')
var sign = require('./bn-sign')
module.exports = rationalize
function rationalize(numer, denom) {
var snumer = sign(numer)
var sdenom = sign(denom)
if(snumer === 0) {
return [num2bn(0), num2bn(1)]
}
if(sdenom === 0) {
return [num2bn(0), num2bn(0)]
}
if(sdenom < 0) {
numer = numer.neg()
denom = denom.neg()
}
var d = numer.gcd(denom)
if(d.cmpn(1)) {
return [ numer.div(d), denom.div(d) ]
}
return [ numer, denom ]
}
},{"./bn-sign":51,"./num-to-bn":55}],57:[function(require,module,exports){
'use strict'
var BN = require('bn.js')
module.exports = str2BN
function str2BN(x) {
return new BN(x)
}
},{"bn.js":64}],58:[function(require,module,exports){
'use strict'
var rationalize = require('./lib/rationalize')
module.exports = mul
function mul(a, b) {
return rationalize(a[0].mul(b[0]), a[1].mul(b[1]))
}
},{"./lib/rationalize":56}],59:[function(require,module,exports){
'use strict'
var bnsign = require('./lib/bn-sign')
module.exports = sign
function sign(x) {
return bnsign(x[0]) * bnsign(x[1])
}
},{"./lib/bn-sign":51}],60:[function(require,module,exports){
'use strict'
var rationalize = require('./lib/rationalize')
module.exports = sub
function sub(a, b) {
return rationalize(a[0].mul(b[1]).sub(a[1].mul(b[0])), a[1].mul(b[1]))
}
},{"./lib/rationalize":56}],61:[function(require,module,exports){
'use strict'
var bn2num = require('./lib/bn-to-num')
var ctz = require('./lib/ctz')
module.exports = roundRat
// Round a rational to the closest float
function roundRat (f) {
var a = f[0]
var b = f[1]
if (a.cmpn(0) === 0) {
return 0
}
var h = a.abs().divmod(b.abs())
var iv = h.div
var x = bn2num(iv)
var ir = h.mod
var sgn = (a.negative !== b.negative) ? -1 : 1
if (ir.cmpn(0) === 0) {
return sgn * x
}
if (x) {
var s = ctz(x) + 4
var y = bn2num(ir.ushln(s).divRound(b))
return sgn * (x + y * Math.pow(2, -s))
} else {
var ybits = b.bitLength() - ir.bitLength() + 53
var y = bn2num(ir.ushln(ybits).divRound(b))
if (ybits < 1023) {
return sgn * y * Math.pow(2, -ybits)
}
y *= Math.pow(2, -1023)
return sgn * y * Math.pow(2, 1023 - ybits)
}
}
},{"./lib/bn-to-num":52,"./lib/ctz":53}],62:[function(require,module,exports){
"use strict"
function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) {
var code = [
"function ", funcName, "(a,l,h,", extraArgs.join(","), "){",
earlyOut ? "" : "var i=", (reversed ? "l-1" : "h+1"),
";while(l<=h){\
var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"]
if(earlyOut) {
if(predicate.indexOf("c") < 0) {
code.push(";if(x===y){return m}else if(x<=y){")
} else {
code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){")
}
} else {
code.push(";if(", predicate, "){i=m;")
}
if(reversed) {
code.push("l=m+1}else{h=m-1}")
} else {
code.push("h=m-1}else{l=m+1}")
}
code.push("}")
if(earlyOut) {
code.push("return -1};")
} else {
code.push("return i};")
}
return code.join("")
}
function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
var result = new Function([
compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut),
compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut),
compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut),
compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut),
"function dispatchBsearch", suffix, "(a,y,c,l,h){\
if(a.shape){\
if(typeof(c)==='function'){\
return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\
}else{\
return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\
}}else{\
if(typeof(c)==='function'){\
return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\
}else{\
return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\
}}}\
return dispatchBsearch", suffix].join(""))
return result()
}
module.exports = {
ge: compileBoundsSearch(">=", false, "GE"),
gt: compileBoundsSearch(">", false, "GT"),
lt: compileBoundsSearch("<", true, "LT"),
le: compileBoundsSearch("<=", true, "LE"),
eq: compileBoundsSearch("-", true, "EQ", true)
}
},{}],63:[function(require,module,exports){
/**
* Bit twiddling hacks for JavaScript.
*
* Author: Mikola Lysenko
*
* Ported from Stanford bit twiddling hack library:
* http://graphics.stanford.edu/~seander/bithacks.html
*/
"use strict"; "use restrict";
//Number of bits in an integer
var INT_BITS = 32;
//Constants
exports.INT_BITS = INT_BITS;
exports.INT_MAX = 0x7fffffff;
exports.INT_MIN = -1<<(INT_BITS-1);
//Returns -1, 0, +1 depending on sign of x
exports.sign = function(v) {
return (v > 0) - (v < 0);
}
//Computes absolute value of integer
exports.abs = function(v) {
var mask = v >> (INT_BITS-1);
return (v ^ mask) - mask;
}
//Computes minimum of integers x and y
exports.min = function(x, y) {
return y ^ ((x ^ y) & -(x < y));
}
//Computes maximum of integers x and y
exports.max = function(x, y) {
return x ^ ((x ^ y) & -(x < y));
}
//Checks if a number is a power of two
exports.isPow2 = function(v) {
return !(v & (v-1)) && (!!v);
}
//Computes log base 2 of v
exports.log2 = function(v) {
var r, shift;
r = (v > 0xFFFF) << 4; v >>>= r;
shift = (v > 0xFF ) << 3; v >>>= shift; r |= shift;
shift = (v > 0xF ) << 2; v >>>= shift; r |= shift;
shift = (v > 0x3 ) << 1; v >>>= shift; r |= shift;
return r | (v >> 1);
}
//Computes log base 10 of v
exports.log10 = function(v) {
return (v >= 1000000000) ? 9 : (v >= 100000000) ? 8 : (v >= 10000000) ? 7 :
(v >= 1000000) ? 6 : (v >= 100000) ? 5 : (v >= 10000) ? 4 :
(v >= 1000) ? 3 : (v >= 100) ? 2 : (v >= 10) ? 1 : 0;
}
//Counts number of bits
exports.popCount = function(v) {
v = v - ((v >>> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >>> 2) & 0x33333333);
return ((v + (v >>> 4) & 0xF0F0F0F) * 0x1010101) >>> 24;
}
//Counts number of trailing zeros
function countTrailingZeros(v) {
var c = 32;
v &= -v;
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
}
exports.countTrailingZeros = countTrailingZeros;
//Rounds to next power of 2
exports.nextPow2 = function(v) {
v += v === 0;
--v;
v |= v >>> 1;
v |= v >>> 2;
v |= v >>> 4;
v |= v >>> 8;
v |= v >>> 16;
return v + 1;
}
//Rounds down to previous power of 2
exports.prevPow2 = function(v) {
v |= v >>> 1;
v |= v >>> 2;
v |= v >>> 4;
v |= v >>> 8;
v |= v >>> 16;
return v - (v>>>1);
}
//Computes parity of word
exports.parity = function(v) {
v ^= v >>> 16;
v ^= v >>> 8;
v ^= v >>> 4;
v &= 0xf;
return (0x6996 >>> v) & 1;
}
var REVERSE_TABLE = new Array(256);
(function(tab) {
for(var i=0; i<256; ++i) {
var v = i, r = i, s = 7;
for (v >>>= 1; v; v >>>= 1) {
r <<= 1;
r |= v & 1;
--s;
}
tab[i] = (r << s) & 0xff;
}
})(REVERSE_TABLE);
//Reverse bits in a 32 bit word
exports.reverse = function(v) {
return (REVERSE_TABLE[ v & 0xff] << 24) |
(REVERSE_TABLE[(v >>> 8) & 0xff] << 16) |
(REVERSE_TABLE[(v >>> 16) & 0xff] << 8) |
REVERSE_TABLE[(v >>> 24) & 0xff];
}
//Interleave bits of 2 coordinates with 16 bits. Useful for fast quadtree codes
exports.interleave2 = function(x, y) {
x &= 0xFFFF;
x = (x | (x << 8)) & 0x00FF00FF;
x = (x | (x << 4)) & 0x0F0F0F0F;
x = (x | (x << 2)) & 0x33333333;
x = (x | (x << 1)) & 0x55555555;
y &= 0xFFFF;
y = (y | (y << 8)) & 0x00FF00FF;
y = (y | (y << 4)) & 0x0F0F0F0F;
y = (y | (y << 2)) & 0x33333333;
y = (y | (y << 1)) & 0x55555555;
return x | (y << 1);
}
//Extracts the nth interleaved component
exports.deinterleave2 = function(v, n) {
v = (v >>> n) & 0x55555555;
v = (v | (v >>> 1)) & 0x33333333;
v = (v | (v >>> 2)) & 0x0F0F0F0F;
v = (v | (v >>> 4)) & 0x00FF00FF;
v = (v | (v >>> 16)) & 0x000FFFF;
return (v << 16) >> 16;
}
//Interleave bits of 3 coordinates, each with 10 bits. Useful for fast octree codes
exports.interleave3 = function(x, y, z) {
x &= 0x3FF;
x = (x | (x<<16)) & 4278190335;
x = (x | (x<<8)) & 251719695;
x = (x | (x<<4)) & 3272356035;
x = (x | (x<<2)) & 1227133513;
y &= 0x3FF;
y = (y | (y<<16)) & 4278190335;
y = (y | (y<<8)) & 251719695;
y = (y | (y<<4)) & 3272356035;
y = (y | (y<<2)) & 1227133513;
x |= (y << 1);
z &= 0x3FF;
z = (z | (z<<16)) & 4278190335;
z = (z | (z<<8)) & 251719695;
z = (z | (z<<4)) & 3272356035;
z = (z | (z<<2)) & 1227133513;
return x | (z << 2);
}
//Extracts nth interleaved component of a 3-tuple
exports.deinterleave3 = function(v, n) {
v = (v >>> n) & 1227133513;
v = (v | (v>>>2)) & 3272356035;
v = (v | (v>>>4)) & 251719695;
v = (v | (v>>>8)) & 4278190335;
v = (v | (v>>>16)) & 0x3FF;
return (v<<22)>>22;
}
//Computes next combination in colexicographic order (this is mistakenly called nextPermutation on the bit twiddling hacks page)
exports.nextCombination = function(v) {
var t = v | (v - 1);
return (t + 1) | (((~t & -~t) - 1) >>> (countTrailingZeros(v) + 1));
}
},{}],64:[function(require,module,exports){
(function (module, exports) {
'use strict';
// Utils
function assert (val, msg) {
if (!val) throw new Error(msg || 'Assertion failed');
}
// Could use `inherits` module, but don't want to move from single file
// architecture yet.
function inherits (ctor, superCtor) {
ctor.super_ = superCtor;
var TempCtor = function () {};
TempCtor.prototype = superCtor.prototype;
ctor.prototype = new TempCtor();
ctor.prototype.constructor = ctor;
}
// BN
function BN (number, base, endian) {
if (BN.isBN(number)) {
return number;
}
this.negative = 0;
this.words = null;
this.length = 0;
// Reduction context
this.red = null;
if (number !== null) {
if (base === 'le' || base === 'be') {
endian = base;
base = 10;
}
this._init(number || 0, base || 10, endian || 'be');
}
}
if (typeof module === 'object') {
module.exports = BN;
} else {
exports.BN = BN;
}
BN.BN = BN;
BN.wordSize = 26;
var Buffer;
try {
Buffer = require('buf' + 'fer').Buffer;
} catch (e) {
}
BN.isBN = function isBN (num) {
if (num instanceof BN) {
return true;
}
return num !== null && typeof num === 'object' &&
num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);
};
BN.max = function max (left, right) {
if (left.cmp(right) > 0) return left;
return right;
};
BN.min = function min (left, right) {
if (left.cmp(right) < 0) return left;
return right;
};
BN.prototype._init = function init (number, base, endian) {
if (typeof number === 'number') {
return this._initNumber(number, base, endian);
}
if (typeof number === 'object') {
return this._initArray(number, base, endian);
}
if (base === 'hex') {
base = 16;
}
assert(base === (base | 0) && base >= 2 && base <= 36);
number = number.toString().replace(/\s+/g, '');
var start = 0;
if (number[0] === '-') {
start++;
}
if (base === 16) {
this._parseHex(number, start);
} else {
this._parseBase(number, base, start);
}
if (number[0] === '-') {
this.negative = 1;
}
this.strip();
if (endian !== 'le') return;
this._initArray(this.toArray(), base, endian);
};
BN.prototype._initNumber = function _initNumber (number, base, endian) {
if (number < 0) {
this.negative = 1;
number = -number;
}
if (number < 0x4000000) {
this.words = [ number & 0x3ffffff ];
this.length = 1;
} else if (number < 0x10000000000000) {
this.words = [
number & 0x3ffffff,
(number / 0x4000000) & 0x3ffffff
];
this.length = 2;
} else {
assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)
this.words = [
number & 0x3ffffff,
(number / 0x4000000) & 0x3ffffff,
1
];
this.length = 3;
}
if (endian !== 'le') return;
// Reverse the bytes
this._initArray(this.toArray(), base, endian);
};
BN.prototype._initArray = function _initArray (number, base, endian) {
// Perhaps a Uint8Array
assert(typeof number.length === 'number');
if (number.length <= 0) {
this.words = [ 0 ];
this.length = 1;
return this;
}
this.length = Math.ceil(number.length / 3);
this.words = new Array(this.length);
for (var i = 0; i < this.length; i++) {
this.words[i] = 0;
}
var j, w;
var off = 0;
if (endian === 'be') {
for (i = number.length - 1, j = 0; i >= 0; i -= 3) {
w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);
this.words[j] |= (w << off) & 0x3ffffff;
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
off += 24;
if (off >= 26) {
off -= 26;
j++;
}
}
} else if (endian === 'le') {
for (i = 0, j = 0; i < number.length; i += 3) {
w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);
this.words[j] |= (w << off) & 0x3ffffff;
this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;
off += 24;
if (off >= 26) {
off -= 26;
j++;
}
}
}
return this.strip();
};
function parseHex (str, start, end) {
var r = 0;
var len = Math.min(str.length, end);
for (var i = start; i < len; i++) {
var c = str.charCodeAt(i) - 48;
r <<= 4;
// 'a' - 'f'
if (c >= 49 && c <= 54) {
r |= c - 49 + 0xa;
// 'A' - 'F'
} else if (c >= 17 && c <= 22) {
r |= c - 17 + 0xa;
// '0' - '9'
} else {
r |= c & 0xf;
}
}
return r;
}
BN.prototype._parseHex = function _parseHex (number, start) {
// Create possibly bigger array to ensure that it fits the number
this.length = Math.ceil((number.length - start) / 6);
this.words = new Array(this.length);
for (var i = 0; i < this.length; i++) {
this.words[i] = 0;
}
var j, w;
// Scan 24-bit chunks and add them to the number
var off = 0;
for (i = number.length - 6, j = 0; i >= start; i -= 6) {
w = parseHex(number, i, i + 6);
this.words[j] |= (w << off) & 0x3ffffff;
// NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
off += 24;
if (off >= 26) {
off -= 26;
j++;
}
}
if (i + 6 !== start) {
w = parseHex(number, start, i + 6);
this.words[j] |= (w << off) & 0x3ffffff;
this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;
}
this.strip();
};
function parseBase (str, start, end, mul) {
var r = 0;
var len = Math.min(str.length, end);
for (var i = start; i < len; i++) {
var c = str.charCodeAt(i) - 48;
r *= mul;
// 'a'
if (c >= 49) {
r += c - 49 + 0xa;
// 'A'
} else if (c >= 17) {
r += c - 17 + 0xa;
// '0' - '9'
} else {
r += c;
}
}
return r;
}
BN.prototype._parseBase = function _parseBase (number, base, start) {
// Initialize as zero
this.words = [ 0 ];
this.length = 1;
// Find length of limb in base
for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {
limbLen++;
}
limbLen--;
limbPow = (limbPow / base) | 0;
var total = number.length - start;
var mod = total % limbLen;
var end = Math.min(total, total - mod) + start;
var word = 0;
for (var i = start; i < end; i += limbLen) {
word = parseBase(number, i, i + limbLen, base);
this.imuln(limbPow);
if (this.words[0] + word < 0x4000000) {
this.words[0] += word;
} else {
this._iaddn(word);
}
}
if (mod !== 0) {
var pow = 1;
word = parseBase(number, i, number.length, base);
for (i = 0; i < mod; i++) {
pow *= base;
}
this.imuln(pow);
if (this.words[0] + word < 0x4000000) {
this.words[0] += word;
} else {
this._iaddn(word);
}
}
};
BN.prototype.copy = function copy (dest) {
dest.words = new Array(this.length);
for (var i = 0; i < this.length; i++) {
dest.words[i] = this.words[i];
}
dest.length = this.length;
dest.negative = this.negative;
dest.red = this.red;
};
BN.prototype.clone = function clone () {
var r = new BN(null);
this.copy(r);
return r;
};
BN.prototype._expand = function _expand (size) {
while (this.length < size) {
this.words[this.length++] = 0;
}
return this;
};
// Remove leading `0` from `this`
BN.prototype.strip = function strip () {
while (this.length > 1 && this.words[this.length - 1] === 0) {
this.length--;
}
return this._normSign();
};
BN.prototype._normSign = function _normSign () {
// -0 = 0
if (this.length === 1 && this.words[0] === 0) {
this.negative = 0;
}
return this;
};
BN.prototype.inspect = function inspect () {
return (this.red ? '';
};
/*
var zeros = [];
var groupSizes = [];
var groupBases = [];
var s = '';
var i = -1;
while (++i < BN.wordSize) {
zeros[i] = s;
s += '0';
}
groupSizes[0] = 0;
groupSizes[1] = 0;
groupBases[0] = 0;
groupBases[1] = 0;
var base = 2 - 1;
while (++base < 36 + 1) {
var groupSize = 0;
var groupBase = 1;
while (groupBase < (1 << BN.wordSize) / base) {
groupBase *= base;
groupSize += 1;
}
groupSizes[base] = groupSize;
groupBases[base] = groupBase;
}
*/
var zeros = [
'',
'0',
'00',
'000',
'0000',
'00000',
'000000',
'0000000',
'00000000',
'000000000',
'0000000000',
'00000000000',
'000000000000',
'0000000000000',
'00000000000000',
'000000000000000',
'0000000000000000',
'00000000000000000',
'000000000000000000',
'0000000000000000000',
'00000000000000000000',
'000000000000000000000',
'0000000000000000000000',
'00000000000000000000000',
'000000000000000000000000',
'0000000000000000000000000'
];
var groupSizes = [
0, 0,
25, 16, 12, 11, 10, 9, 8,
8, 7, 7, 7, 7, 6, 6,
6, 6, 6, 6, 6, 5, 5,
5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5
];
var groupBases = [
0, 0,
33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,
43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,
16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,
6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,
24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176
];
BN.prototype.toString = function toString (base, padding) {
base = base || 10;
padding = padding | 0 || 1;
var out;
if (base === 16 || base === 'hex') {
out = '';
var off = 0;
var carry = 0;
for (var i = 0; i < this.length; i++) {
var w = this.words[i];
var word = (((w << off) | carry) & 0xffffff).toString(16);
carry = (w >>> (24 - off)) & 0xffffff;
if (carry !== 0 || i !== this.length - 1) {
out = zeros[6 - word.length] + word + out;
} else {
out = word + out;
}
off += 2;
if (off >= 26) {
off -= 26;
i--;
}
}
if (carry !== 0) {
out = carry.toString(16) + out;
}
while (out.length % padding !== 0) {
out = '0' + out;
}
if (this.negative !== 0) {
out = '-' + out;
}
return out;
}
if (base === (base | 0) && base >= 2 && base <= 36) {
// var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));
var groupSize = groupSizes[base];
// var groupBase = Math.pow(base, groupSize);
var groupBase = groupBases[base];
out = '';
var c = this.clone();
c.negative = 0;
while (!c.isZero()) {
var r = c.modn(groupBase).toString(base);
c = c.idivn(groupBase);
if (!c.isZero()) {
out = zeros[groupSize - r.length] + r + out;
} else {
out = r + out;
}
}
if (this.isZero()) {
out = '0' + out;
}
while (out.length % padding !== 0) {
out = '0' + out;
}
if (this.negative !== 0) {
out = '-' + out;
}
return out;
}
assert(false, 'Base should be between 2 and 36');
};
BN.prototype.toNumber = function toNumber () {
var ret = this.words[0];
if (this.length === 2) {
ret += this.words[1] * 0x4000000;
} else if (this.length === 3 && this.words[2] === 0x01) {
// NOTE: at this stage it is known that the top bit is set
ret += 0x10000000000000 + (this.words[1] * 0x4000000);
} else if (this.length > 2) {
assert(false, 'Number can only safely store up to 53 bits');
}
return (this.negative !== 0) ? -ret : ret;
};
BN.prototype.toJSON = function toJSON () {
return this.toString(16);
};
BN.prototype.toBuffer = function toBuffer (endian, length) {
assert(typeof Buffer !== 'undefined');
return this.toArrayLike(Buffer, endian, length);
};
BN.prototype.toArray = function toArray (endian, length) {
return this.toArrayLike(Array, endian, length);
};
BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {
var byteLength = this.byteLength();
var reqLength = length || Math.max(1, byteLength);
assert(byteLength <= reqLength, 'byte array longer than desired length');
assert(reqLength > 0, 'Requested array length <= 0');
this.strip();
var littleEndian = endian === 'le';
var res = new ArrayType(reqLength);
var b, i;
var q = this.clone();
if (!littleEndian) {
// Assume big-endian
for (i = 0; i < reqLength - byteLength; i++) {
res[i] = 0;
}
for (i = 0; !q.isZero(); i++) {
b = q.andln(0xff);
q.iushrn(8);
res[reqLength - i - 1] = b;
}
} else {
for (i = 0; !q.isZero(); i++) {
b = q.andln(0xff);
q.iushrn(8);
res[i] = b;
}
for (; i < reqLength; i++) {
res[i] = 0;
}
}
return res;
};
if (Math.clz32) {
BN.prototype._countBits = function _countBits (w) {
return 32 - Math.clz32(w);
};
} else {
BN.prototype._countBits = function _countBits (w) {
var t = w;
var r = 0;
if (t >= 0x1000) {
r += 13;
t >>>= 13;
}
if (t >= 0x40) {
r += 7;
t >>>= 7;
}
if (t >= 0x8) {
r += 4;
t >>>= 4;
}
if (t >= 0x02) {
r += 2;
t >>>= 2;
}
return r + t;
};
}
BN.prototype._zeroBits = function _zeroBits (w) {
// Short-cut
if (w === 0) return 26;
var t = w;
var r = 0;
if ((t & 0x1fff) === 0) {
r += 13;
t >>>= 13;
}
if ((t & 0x7f) === 0) {
r += 7;
t >>>= 7;
}
if ((t & 0xf) === 0) {
r += 4;
t >>>= 4;
}
if ((t & 0x3) === 0) {
r += 2;
t >>>= 2;
}
if ((t & 0x1) === 0) {
r++;
}
return r;
};
// Return number of used bits in a BN
BN.prototype.bitLength = function bitLength () {
var w = this.words[this.length - 1];
var hi = this._countBits(w);
return (this.length - 1) * 26 + hi;
};
function toBitArray (num) {
var w = new Array(num.bitLength());
for (var bit = 0; bit < w.length; bit++) {
var off = (bit / 26) | 0;
var wbit = bit % 26;
w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;
}
return w;
}
// Number of trailing zero bits
BN.prototype.zeroBits = function zeroBits () {
if (this.isZero()) return 0;
var r = 0;
for (var i = 0; i < this.length; i++) {
var b = this._zeroBits(this.words[i]);
r += b;
if (b !== 26) break;
}
return r;
};
BN.prototype.byteLength = function byteLength () {
return Math.ceil(this.bitLength() / 8);
};
BN.prototype.toTwos = function toTwos (width) {
if (this.negative !== 0) {
return this.abs().inotn(width).iaddn(1);
}
return this.clone();
};
BN.prototype.fromTwos = function fromTwos (width) {
if (this.testn(width - 1)) {
return this.notn(width).iaddn(1).ineg();
}
return this.clone();
};
BN.prototype.isNeg = function isNeg () {
return this.negative !== 0;
};
// Return negative clone of `this`
BN.prototype.neg = function neg () {
return this.clone().ineg();
};
BN.prototype.ineg = function ineg () {
if (!this.isZero()) {
this.negative ^= 1;
}
return this;
};
// Or `num` with `this` in-place
BN.prototype.iuor = function iuor (num) {
while (this.length < num.length) {
this.words[this.length++] = 0;
}
for (var i = 0; i < num.length; i++) {
this.words[i] = this.words[i] | num.words[i];
}
return this.strip();
};
BN.prototype.ior = function ior (num) {
assert((this.negative | num.negative) === 0);
return this.iuor(num);
};
// Or `num` with `this`
BN.prototype.or = function or (num) {
if (this.length > num.length) return this.clone().ior(num);
return num.clone().ior(this);
};
BN.prototype.uor = function uor (num) {
if (this.length > num.length) return this.clone().iuor(num);
return num.clone().iuor(this);
};
// And `num` with `this` in-place
BN.prototype.iuand = function iuand (num) {
// b = min-length(num, this)
var b;
if (this.length > num.length) {
b = num;
} else {
b = this;
}
for (var i = 0; i < b.length; i++) {
this.words[i] = this.words[i] & num.words[i];
}
this.length = b.length;
return this.strip();
};
BN.prototype.iand = function iand (num) {
assert((this.negative | num.negative) === 0);
return this.iuand(num);
};
// And `num` with `this`
BN.prototype.and = function and (num) {
if (this.length > num.length) return this.clone().iand(num);
return num.clone().iand(this);
};
BN.prototype.uand = function uand (num) {
if (this.length > num.length) return this.clone().iuand(num);
return num.clone().iuand(this);
};
// Xor `num` with `this` in-place
BN.prototype.iuxor = function iuxor (num) {
// a.length > b.length
var a;
var b;
if (this.length > num.length) {
a = this;
b = num;
} else {
a = num;
b = this;
}
for (var i = 0; i < b.length; i++) {
this.words[i] = a.words[i] ^ b.words[i];
}
if (this !== a) {
for (; i < a.length; i++) {
this.words[i] = a.words[i];
}
}
this.length = a.length;
return this.strip();
};
BN.prototype.ixor = function ixor (num) {
assert((this.negative | num.negative) === 0);
return this.iuxor(num);
};
// Xor `num` with `this`
BN.prototype.xor = function xor (num) {
if (this.length > num.length) return this.clone().ixor(num);
return num.clone().ixor(this);
};
BN.prototype.uxor = function uxor (num) {
if (this.length > num.length) return this.clone().iuxor(num);
return num.clone().iuxor(this);
};
// Not ``this`` with ``width`` bitwidth
BN.prototype.inotn = function inotn (width) {
assert(typeof width === 'number' && width >= 0);
var bytesNeeded = Math.ceil(width / 26) | 0;
var bitsLeft = width % 26;
// Extend the buffer with leading zeroes
this._expand(bytesNeeded);
if (bitsLeft > 0) {
bytesNeeded--;
}
// Handle complete words
for (var i = 0; i < bytesNeeded; i++) {
this.words[i] = ~this.words[i] & 0x3ffffff;
}
// Handle the residue
if (bitsLeft > 0) {
this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));
}
// And remove leading zeroes
return this.strip();
};
BN.prototype.notn = function notn (width) {
return this.clone().inotn(width);
};
// Set `bit` of `this`
BN.prototype.setn = function setn (bit, val) {
assert(typeof bit === 'number' && bit >= 0);
var off = (bit / 26) | 0;
var wbit = bit % 26;
this._expand(off + 1);
if (val) {
this.words[off] = this.words[off] | (1 << wbit);
} else {
this.words[off] = this.words[off] & ~(1 << wbit);
}
return this.strip();
};
// Add `num` to `this` in-place
BN.prototype.iadd = function iadd (num) {
var r;
// negative + positive
if (this.negative !== 0 && num.negative === 0) {
this.negative = 0;
r = this.isub(num);
this.negative ^= 1;
return this._normSign();
// positive + negative
} else if (this.negative === 0 && num.negative !== 0) {
num.negative = 0;
r = this.isub(num);
num.negative = 1;
return r._normSign();
}
// a.length > b.length
var a, b;
if (this.length > num.length) {
a = this;
b = num;
} else {
a = num;
b = this;
}
var carry = 0;
for (var i = 0; i < b.length; i++) {
r = (a.words[i] | 0) + (b.words[i] | 0) + carry;
this.words[i] = r & 0x3ffffff;
carry = r >>> 26;
}
for (; carry !== 0 && i < a.length; i++) {
r = (a.words[i] | 0) + carry;
this.words[i] = r & 0x3ffffff;
carry = r >>> 26;
}
this.length = a.length;
if (carry !== 0) {
this.words[this.length] = carry;
this.length++;
// Copy the rest of the words
} else if (a !== this) {
for (; i < a.length; i++) {
this.words[i] = a.words[i];
}
}
return this;
};
// Add `num` to `this`
BN.prototype.add = function add (num) {
var res;
if (num.negative !== 0 && this.negative === 0) {
num.negative = 0;
res = this.sub(num);
num.negative ^= 1;
return res;
} else if (num.negative === 0 && this.negative !== 0) {
this.negative = 0;
res = num.sub(this);
this.negative = 1;
return res;
}
if (this.length > num.length) return this.clone().iadd(num);
return num.clone().iadd(this);
};
// Subtract `num` from `this` in-place
BN.prototype.isub = function isub (num) {
// this - (-num) = this + num
if (num.negative !== 0) {
num.negative = 0;
var r = this.iadd(num);
num.negative = 1;
return r._normSign();
// -this - num = -(this + num)
} else if (this.negative !== 0) {
this.negative = 0;
this.iadd(num);
this.negative = 1;
return this._normSign();
}
// At this point both numbers are positive
var cmp = this.cmp(num);
// Optimization - zeroify
if (cmp === 0) {
this.negative = 0;
this.length = 1;
this.words[0] = 0;
return this;
}
// a > b
var a, b;
if (cmp > 0) {
a = this;
b = num;
} else {
a = num;
b = this;
}
var carry = 0;
for (var i = 0; i < b.length; i++) {
r = (a.words[i] | 0) - (b.words[i] | 0) + carry;
carry = r >> 26;
this.words[i] = r & 0x3ffffff;
}
for (; carry !== 0 && i < a.length; i++) {
r = (a.words[i] | 0) + carry;
carry = r >> 26;
this.words[i] = r & 0x3ffffff;
}
// Copy rest of the words
if (carry === 0 && i < a.length && a !== this) {
for (; i < a.length; i++) {
this.words[i] = a.words[i];
}
}
this.length = Math.max(this.length, i);
if (a !== this) {
this.negative = 1;
}
return this.strip();
};
// Subtract `num` from `this`
BN.prototype.sub = function sub (num) {
return this.clone().isub(num);
};
function smallMulTo (self, num, out) {
out.negative = num.negative ^ self.negative;
var len = (self.length + num.length) | 0;
out.length = len;
len = (len - 1) | 0;
// Peel one iteration (compiler can't do it, because of code complexity)
var a = self.words[0] | 0;
var b = num.words[0] | 0;
var r = a * b;
var lo = r & 0x3ffffff;
var carry = (r / 0x4000000) | 0;
out.words[0] = lo;
for (var k = 1; k < len; k++) {
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
// note that ncarry could be >= 0x3ffffff
var ncarry = carry >>> 26;
var rword = carry & 0x3ffffff;
var maxJ = Math.min(k, num.length - 1);
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
var i = (k - j) | 0;
a = self.words[i] | 0;
b = num.words[j] | 0;
r = a * b + rword;
ncarry += (r / 0x4000000) | 0;
rword = r & 0x3ffffff;
}
out.words[k] = rword | 0;
carry = ncarry | 0;
}
if (carry !== 0) {
out.words[k] = carry | 0;
} else {
out.length--;
}
return out.strip();
}
// TODO(indutny): it may be reasonable to omit it for users who don't need
// to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit
// multiplication (like elliptic secp256k1).
var comb10MulTo = function comb10MulTo (self, num, out) {
var a = self.words;
var b = num.words;
var o = out.words;
var c = 0;
var lo;
var mid;
var hi;
var a0 = a[0] | 0;
var al0 = a0 & 0x1fff;
var ah0 = a0 >>> 13;
var a1 = a[1] | 0;
var al1 = a1 & 0x1fff;
var ah1 = a1 >>> 13;
var a2 = a[2] | 0;
var al2 = a2 & 0x1fff;
var ah2 = a2 >>> 13;
var a3 = a[3] | 0;
var al3 = a3 & 0x1fff;
var ah3 = a3 >>> 13;
var a4 = a[4] | 0;
var al4 = a4 & 0x1fff;
var ah4 = a4 >>> 13;
var a5 = a[5] | 0;
var al5 = a5 & 0x1fff;
var ah5 = a5 >>> 13;
var a6 = a[6] | 0;
var al6 = a6 & 0x1fff;
var ah6 = a6 >>> 13;
var a7 = a[7] | 0;
var al7 = a7 & 0x1fff;
var ah7 = a7 >>> 13;
var a8 = a[8] | 0;
var al8 = a8 & 0x1fff;
var ah8 = a8 >>> 13;
var a9 = a[9] | 0;
var al9 = a9 & 0x1fff;
var ah9 = a9 >>> 13;
var b0 = b[0] | 0;
var bl0 = b0 & 0x1fff;
var bh0 = b0 >>> 13;
var b1 = b[1] | 0;
var bl1 = b1 & 0x1fff;
var bh1 = b1 >>> 13;
var b2 = b[2] | 0;
var bl2 = b2 & 0x1fff;
var bh2 = b2 >>> 13;
var b3 = b[3] | 0;
var bl3 = b3 & 0x1fff;
var bh3 = b3 >>> 13;
var b4 = b[4] | 0;
var bl4 = b4 & 0x1fff;
var bh4 = b4 >>> 13;
var b5 = b[5] | 0;
var bl5 = b5 & 0x1fff;
var bh5 = b5 >>> 13;
var b6 = b[6] | 0;
var bl6 = b6 & 0x1fff;
var bh6 = b6 >>> 13;
var b7 = b[7] | 0;
var bl7 = b7 & 0x1fff;
var bh7 = b7 >>> 13;
var b8 = b[8] | 0;
var bl8 = b8 & 0x1fff;
var bh8 = b8 >>> 13;
var b9 = b[9] | 0;
var bl9 = b9 & 0x1fff;
var bh9 = b9 >>> 13;
out.negative = self.negative ^ num.negative;
out.length = 19;
/* k = 0 */
lo = Math.imul(al0, bl0);
mid = Math.imul(al0, bh0);
mid = (mid + Math.imul(ah0, bl0)) | 0;
hi = Math.imul(ah0, bh0);
var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;
w0 &= 0x3ffffff;
/* k = 1 */
lo = Math.imul(al1, bl0);
mid = Math.imul(al1, bh0);
mid = (mid + Math.imul(ah1, bl0)) | 0;
hi = Math.imul(ah1, bh0);
lo = (lo + Math.imul(al0, bl1)) | 0;
mid = (mid + Math.imul(al0, bh1)) | 0;
mid = (mid + Math.imul(ah0, bl1)) | 0;
hi = (hi + Math.imul(ah0, bh1)) | 0;
var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;
w1 &= 0x3ffffff;
/* k = 2 */
lo = Math.imul(al2, bl0);
mid = Math.imul(al2, bh0);
mid = (mid + Math.imul(ah2, bl0)) | 0;
hi = Math.imul(ah2, bh0);
lo = (lo + Math.imul(al1, bl1)) | 0;
mid = (mid + Math.imul(al1, bh1)) | 0;
mid = (mid + Math.imul(ah1, bl1)) | 0;
hi = (hi + Math.imul(ah1, bh1)) | 0;
lo = (lo + Math.imul(al0, bl2)) | 0;
mid = (mid + Math.imul(al0, bh2)) | 0;
mid = (mid + Math.imul(ah0, bl2)) | 0;
hi = (hi + Math.imul(ah0, bh2)) | 0;
var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;
w2 &= 0x3ffffff;
/* k = 3 */
lo = Math.imul(al3, bl0);
mid = Math.imul(al3, bh0);
mid = (mid + Math.imul(ah3, bl0)) | 0;
hi = Math.imul(ah3, bh0);
lo = (lo + Math.imul(al2, bl1)) | 0;
mid = (mid + Math.imul(al2, bh1)) | 0;
mid = (mid + Math.imul(ah2, bl1)) | 0;
hi = (hi + Math.imul(ah2, bh1)) | 0;
lo = (lo + Math.imul(al1, bl2)) | 0;
mid = (mid + Math.imul(al1, bh2)) | 0;
mid = (mid + Math.imul(ah1, bl2)) | 0;
hi = (hi + Math.imul(ah1, bh2)) | 0;
lo = (lo + Math.imul(al0, bl3)) | 0;
mid = (mid + Math.imul(al0, bh3)) | 0;
mid = (mid + Math.imul(ah0, bl3)) | 0;
hi = (hi + Math.imul(ah0, bh3)) | 0;
var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;
w3 &= 0x3ffffff;
/* k = 4 */
lo = Math.imul(al4, bl0);
mid = Math.imul(al4, bh0);
mid = (mid + Math.imul(ah4, bl0)) | 0;
hi = Math.imul(ah4, bh0);
lo = (lo + Math.imul(al3, bl1)) | 0;
mid = (mid + Math.imul(al3, bh1)) | 0;
mid = (mid + Math.imul(ah3, bl1)) | 0;
hi = (hi + Math.imul(ah3, bh1)) | 0;
lo = (lo + Math.imul(al2, bl2)) | 0;
mid = (mid + Math.imul(al2, bh2)) | 0;
mid = (mid + Math.imul(ah2, bl2)) | 0;
hi = (hi + Math.imul(ah2, bh2)) | 0;
lo = (lo + Math.imul(al1, bl3)) | 0;
mid = (mid + Math.imul(al1, bh3)) | 0;
mid = (mid + Math.imul(ah1, bl3)) | 0;
hi = (hi + Math.imul(ah1, bh3)) | 0;
lo = (lo + Math.imul(al0, bl4)) | 0;
mid = (mid + Math.imul(al0, bh4)) | 0;
mid = (mid + Math.imul(ah0, bl4)) | 0;
hi = (hi + Math.imul(ah0, bh4)) | 0;
var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;
w4 &= 0x3ffffff;
/* k = 5 */
lo = Math.imul(al5, bl0);
mid = Math.imul(al5, bh0);
mid = (mid + Math.imul(ah5, bl0)) | 0;
hi = Math.imul(ah5, bh0);
lo = (lo + Math.imul(al4, bl1)) | 0;
mid = (mid + Math.imul(al4, bh1)) | 0;
mid = (mid + Math.imul(ah4, bl1)) | 0;
hi = (hi + Math.imul(ah4, bh1)) | 0;
lo = (lo + Math.imul(al3, bl2)) | 0;
mid = (mid + Math.imul(al3, bh2)) | 0;
mid = (mid + Math.imul(ah3, bl2)) | 0;
hi = (hi + Math.imul(ah3, bh2)) | 0;
lo = (lo + Math.imul(al2, bl3)) | 0;
mid = (mid + Math.imul(al2, bh3)) | 0;
mid = (mid + Math.imul(ah2, bl3)) | 0;
hi = (hi + Math.imul(ah2, bh3)) | 0;
lo = (lo + Math.imul(al1, bl4)) | 0;
mid = (mid + Math.imul(al1, bh4)) | 0;
mid = (mid + Math.imul(ah1, bl4)) | 0;
hi = (hi + Math.imul(ah1, bh4)) | 0;
lo = (lo + Math.imul(al0, bl5)) | 0;
mid = (mid + Math.imul(al0, bh5)) | 0;
mid = (mid + Math.imul(ah0, bl5)) | 0;
hi = (hi + Math.imul(ah0, bh5)) | 0;
var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;
w5 &= 0x3ffffff;
/* k = 6 */
lo = Math.imul(al6, bl0);
mid = Math.imul(al6, bh0);
mid = (mid + Math.imul(ah6, bl0)) | 0;
hi = Math.imul(ah6, bh0);
lo = (lo + Math.imul(al5, bl1)) | 0;
mid = (mid + Math.imul(al5, bh1)) | 0;
mid = (mid + Math.imul(ah5, bl1)) | 0;
hi = (hi + Math.imul(ah5, bh1)) | 0;
lo = (lo + Math.imul(al4, bl2)) | 0;
mid = (mid + Math.imul(al4, bh2)) | 0;
mid = (mid + Math.imul(ah4, bl2)) | 0;
hi = (hi + Math.imul(ah4, bh2)) | 0;
lo = (lo + Math.imul(al3, bl3)) | 0;
mid = (mid + Math.imul(al3, bh3)) | 0;
mid = (mid + Math.imul(ah3, bl3)) | 0;
hi = (hi + Math.imul(ah3, bh3)) | 0;
lo = (lo + Math.imul(al2, bl4)) | 0;
mid = (mid + Math.imul(al2, bh4)) | 0;
mid = (mid + Math.imul(ah2, bl4)) | 0;
hi = (hi + Math.imul(ah2, bh4)) | 0;
lo = (lo + Math.imul(al1, bl5)) | 0;
mid = (mid + Math.imul(al1, bh5)) | 0;
mid = (mid + Math.imul(ah1, bl5)) | 0;
hi = (hi + Math.imul(ah1, bh5)) | 0;
lo = (lo + Math.imul(al0, bl6)) | 0;
mid = (mid + Math.imul(al0, bh6)) | 0;
mid = (mid + Math.imul(ah0, bl6)) | 0;
hi = (hi + Math.imul(ah0, bh6)) | 0;
var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;
w6 &= 0x3ffffff;
/* k = 7 */
lo = Math.imul(al7, bl0);
mid = Math.imul(al7, bh0);
mid = (mid + Math.imul(ah7, bl0)) | 0;
hi = Math.imul(ah7, bh0);
lo = (lo + Math.imul(al6, bl1)) | 0;
mid = (mid + Math.imul(al6, bh1)) | 0;
mid = (mid + Math.imul(ah6, bl1)) | 0;
hi = (hi + Math.imul(ah6, bh1)) | 0;
lo = (lo + Math.imul(al5, bl2)) | 0;
mid = (mid + Math.imul(al5, bh2)) | 0;
mid = (mid + Math.imul(ah5, bl2)) | 0;
hi = (hi + Math.imul(ah5, bh2)) | 0;
lo = (lo + Math.imul(al4, bl3)) | 0;
mid = (mid + Math.imul(al4, bh3)) | 0;
mid = (mid + Math.imul(ah4, bl3)) | 0;
hi = (hi + Math.imul(ah4, bh3)) | 0;
lo = (lo + Math.imul(al3, bl4)) | 0;
mid = (mid + Math.imul(al3, bh4)) | 0;
mid = (mid + Math.imul(ah3, bl4)) | 0;
hi = (hi + Math.imul(ah3, bh4)) | 0;
lo = (lo + Math.imul(al2, bl5)) | 0;
mid = (mid + Math.imul(al2, bh5)) | 0;
mid = (mid + Math.imul(ah2, bl5)) | 0;
hi = (hi + Math.imul(ah2, bh5)) | 0;
lo = (lo + Math.imul(al1, bl6)) | 0;
mid = (mid + Math.imul(al1, bh6)) | 0;
mid = (mid + Math.imul(ah1, bl6)) | 0;
hi = (hi + Math.imul(ah1, bh6)) | 0;
lo = (lo + Math.imul(al0, bl7)) | 0;
mid = (mid + Math.imul(al0, bh7)) | 0;
mid = (mid + Math.imul(ah0, bl7)) | 0;
hi = (hi + Math.imul(ah0, bh7)) | 0;
var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;
w7 &= 0x3ffffff;
/* k = 8 */
lo = Math.imul(al8, bl0);
mid = Math.imul(al8, bh0);
mid = (mid + Math.imul(ah8, bl0)) | 0;
hi = Math.imul(ah8, bh0);
lo = (lo + Math.imul(al7, bl1)) | 0;
mid = (mid + Math.imul(al7, bh1)) | 0;
mid = (mid + Math.imul(ah7, bl1)) | 0;
hi = (hi + Math.imul(ah7, bh1)) | 0;
lo = (lo + Math.imul(al6, bl2)) | 0;
mid = (mid + Math.imul(al6, bh2)) | 0;
mid = (mid + Math.imul(ah6, bl2)) | 0;
hi = (hi + Math.imul(ah6, bh2)) | 0;
lo = (lo + Math.imul(al5, bl3)) | 0;
mid = (mid + Math.imul(al5, bh3)) | 0;
mid = (mid + Math.imul(ah5, bl3)) | 0;
hi = (hi + Math.imul(ah5, bh3)) | 0;
lo = (lo + Math.imul(al4, bl4)) | 0;
mid = (mid + Math.imul(al4, bh4)) | 0;
mid = (mid + Math.imul(ah4, bl4)) | 0;
hi = (hi + Math.imul(ah4, bh4)) | 0;
lo = (lo + Math.imul(al3, bl5)) | 0;
mid = (mid + Math.imul(al3, bh5)) | 0;
mid = (mid + Math.imul(ah3, bl5)) | 0;
hi = (hi + Math.imul(ah3, bh5)) | 0;
lo = (lo + Math.imul(al2, bl6)) | 0;
mid = (mid + Math.imul(al2, bh6)) | 0;
mid = (mid + Math.imul(ah2, bl6)) | 0;
hi = (hi + Math.imul(ah2, bh6)) | 0;
lo = (lo + Math.imul(al1, bl7)) | 0;
mid = (mid + Math.imul(al1, bh7)) | 0;
mid = (mid + Math.imul(ah1, bl7)) | 0;
hi = (hi + Math.imul(ah1, bh7)) | 0;
lo = (lo + Math.imul(al0, bl8)) | 0;
mid = (mid + Math.imul(al0, bh8)) | 0;
mid = (mid + Math.imul(ah0, bl8)) | 0;
hi = (hi + Math.imul(ah0, bh8)) | 0;
var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;
w8 &= 0x3ffffff;
/* k = 9 */
lo = Math.imul(al9, bl0);
mid = Math.imul(al9, bh0);
mid = (mid + Math.imul(ah9, bl0)) | 0;
hi = Math.imul(ah9, bh0);
lo = (lo + Math.imul(al8, bl1)) | 0;
mid = (mid + Math.imul(al8, bh1)) | 0;
mid = (mid + Math.imul(ah8, bl1)) | 0;
hi = (hi + Math.imul(ah8, bh1)) | 0;
lo = (lo + Math.imul(al7, bl2)) | 0;
mid = (mid + Math.imul(al7, bh2)) | 0;
mid = (mid + Math.imul(ah7, bl2)) | 0;
hi = (hi + Math.imul(ah7, bh2)) | 0;
lo = (lo + Math.imul(al6, bl3)) | 0;
mid = (mid + Math.imul(al6, bh3)) | 0;
mid = (mid + Math.imul(ah6, bl3)) | 0;
hi = (hi + Math.imul(ah6, bh3)) | 0;
lo = (lo + Math.imul(al5, bl4)) | 0;
mid = (mid + Math.imul(al5, bh4)) | 0;
mid = (mid + Math.imul(ah5, bl4)) | 0;
hi = (hi + Math.imul(ah5, bh4)) | 0;
lo = (lo + Math.imul(al4, bl5)) | 0;
mid = (mid + Math.imul(al4, bh5)) | 0;
mid = (mid + Math.imul(ah4, bl5)) | 0;
hi = (hi + Math.imul(ah4, bh5)) | 0;
lo = (lo + Math.imul(al3, bl6)) | 0;
mid = (mid + Math.imul(al3, bh6)) | 0;
mid = (mid + Math.imul(ah3, bl6)) | 0;
hi = (hi + Math.imul(ah3, bh6)) | 0;
lo = (lo + Math.imul(al2, bl7)) | 0;
mid = (mid + Math.imul(al2, bh7)) | 0;
mid = (mid + Math.imul(ah2, bl7)) | 0;
hi = (hi + Math.imul(ah2, bh7)) | 0;
lo = (lo + Math.imul(al1, bl8)) | 0;
mid = (mid + Math.imul(al1, bh8)) | 0;
mid = (mid + Math.imul(ah1, bl8)) | 0;
hi = (hi + Math.imul(ah1, bh8)) | 0;
lo = (lo + Math.imul(al0, bl9)) | 0;
mid = (mid + Math.imul(al0, bh9)) | 0;
mid = (mid + Math.imul(ah0, bl9)) | 0;
hi = (hi + Math.imul(ah0, bh9)) | 0;
var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;
w9 &= 0x3ffffff;
/* k = 10 */
lo = Math.imul(al9, bl1);
mid = Math.imul(al9, bh1);
mid = (mid + Math.imul(ah9, bl1)) | 0;
hi = Math.imul(ah9, bh1);
lo = (lo + Math.imul(al8, bl2)) | 0;
mid = (mid + Math.imul(al8, bh2)) | 0;
mid = (mid + Math.imul(ah8, bl2)) | 0;
hi = (hi + Math.imul(ah8, bh2)) | 0;
lo = (lo + Math.imul(al7, bl3)) | 0;
mid = (mid + Math.imul(al7, bh3)) | 0;
mid = (mid + Math.imul(ah7, bl3)) | 0;
hi = (hi + Math.imul(ah7, bh3)) | 0;
lo = (lo + Math.imul(al6, bl4)) | 0;
mid = (mid + Math.imul(al6, bh4)) | 0;
mid = (mid + Math.imul(ah6, bl4)) | 0;
hi = (hi + Math.imul(ah6, bh4)) | 0;
lo = (lo + Math.imul(al5, bl5)) | 0;
mid = (mid + Math.imul(al5, bh5)) | 0;
mid = (mid + Math.imul(ah5, bl5)) | 0;
hi = (hi + Math.imul(ah5, bh5)) | 0;
lo = (lo + Math.imul(al4, bl6)) | 0;
mid = (mid + Math.imul(al4, bh6)) | 0;
mid = (mid + Math.imul(ah4, bl6)) | 0;
hi = (hi + Math.imul(ah4, bh6)) | 0;
lo = (lo + Math.imul(al3, bl7)) | 0;
mid = (mid + Math.imul(al3, bh7)) | 0;
mid = (mid + Math.imul(ah3, bl7)) | 0;
hi = (hi + Math.imul(ah3, bh7)) | 0;
lo = (lo + Math.imul(al2, bl8)) | 0;
mid = (mid + Math.imul(al2, bh8)) | 0;
mid = (mid + Math.imul(ah2, bl8)) | 0;
hi = (hi + Math.imul(ah2, bh8)) | 0;
lo = (lo + Math.imul(al1, bl9)) | 0;
mid = (mid + Math.imul(al1, bh9)) | 0;
mid = (mid + Math.imul(ah1, bl9)) | 0;
hi = (hi + Math.imul(ah1, bh9)) | 0;
var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;
w10 &= 0x3ffffff;
/* k = 11 */
lo = Math.imul(al9, bl2);
mid = Math.imul(al9, bh2);
mid = (mid + Math.imul(ah9, bl2)) | 0;
hi = Math.imul(ah9, bh2);
lo = (lo + Math.imul(al8, bl3)) | 0;
mid = (mid + Math.imul(al8, bh3)) | 0;
mid = (mid + Math.imul(ah8, bl3)) | 0;
hi = (hi + Math.imul(ah8, bh3)) | 0;
lo = (lo + Math.imul(al7, bl4)) | 0;
mid = (mid + Math.imul(al7, bh4)) | 0;
mid = (mid + Math.imul(ah7, bl4)) | 0;
hi = (hi + Math.imul(ah7, bh4)) | 0;
lo = (lo + Math.imul(al6, bl5)) | 0;
mid = (mid + Math.imul(al6, bh5)) | 0;
mid = (mid + Math.imul(ah6, bl5)) | 0;
hi = (hi + Math.imul(ah6, bh5)) | 0;
lo = (lo + Math.imul(al5, bl6)) | 0;
mid = (mid + Math.imul(al5, bh6)) | 0;
mid = (mid + Math.imul(ah5, bl6)) | 0;
hi = (hi + Math.imul(ah5, bh6)) | 0;
lo = (lo + Math.imul(al4, bl7)) | 0;
mid = (mid + Math.imul(al4, bh7)) | 0;
mid = (mid + Math.imul(ah4, bl7)) | 0;
hi = (hi + Math.imul(ah4, bh7)) | 0;
lo = (lo + Math.imul(al3, bl8)) | 0;
mid = (mid + Math.imul(al3, bh8)) | 0;
mid = (mid + Math.imul(ah3, bl8)) | 0;
hi = (hi + Math.imul(ah3, bh8)) | 0;
lo = (lo + Math.imul(al2, bl9)) | 0;
mid = (mid + Math.imul(al2, bh9)) | 0;
mid = (mid + Math.imul(ah2, bl9)) | 0;
hi = (hi + Math.imul(ah2, bh9)) | 0;
var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;
w11 &= 0x3ffffff;
/* k = 12 */
lo = Math.imul(al9, bl3);
mid = Math.imul(al9, bh3);
mid = (mid + Math.imul(ah9, bl3)) | 0;
hi = Math.imul(ah9, bh3);
lo = (lo + Math.imul(al8, bl4)) | 0;
mid = (mid + Math.imul(al8, bh4)) | 0;
mid = (mid + Math.imul(ah8, bl4)) | 0;
hi = (hi + Math.imul(ah8, bh4)) | 0;
lo = (lo + Math.imul(al7, bl5)) | 0;
mid = (mid + Math.imul(al7, bh5)) | 0;
mid = (mid + Math.imul(ah7, bl5)) | 0;
hi = (hi + Math.imul(ah7, bh5)) | 0;
lo = (lo + Math.imul(al6, bl6)) | 0;
mid = (mid + Math.imul(al6, bh6)) | 0;
mid = (mid + Math.imul(ah6, bl6)) | 0;
hi = (hi + Math.imul(ah6, bh6)) | 0;
lo = (lo + Math.imul(al5, bl7)) | 0;
mid = (mid + Math.imul(al5, bh7)) | 0;
mid = (mid + Math.imul(ah5, bl7)) | 0;
hi = (hi + Math.imul(ah5, bh7)) | 0;
lo = (lo + Math.imul(al4, bl8)) | 0;
mid = (mid + Math.imul(al4, bh8)) | 0;
mid = (mid + Math.imul(ah4, bl8)) | 0;
hi = (hi + Math.imul(ah4, bh8)) | 0;
lo = (lo + Math.imul(al3, bl9)) | 0;
mid = (mid + Math.imul(al3, bh9)) | 0;
mid = (mid + Math.imul(ah3, bl9)) | 0;
hi = (hi + Math.imul(ah3, bh9)) | 0;
var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;
w12 &= 0x3ffffff;
/* k = 13 */
lo = Math.imul(al9, bl4);
mid = Math.imul(al9, bh4);
mid = (mid + Math.imul(ah9, bl4)) | 0;
hi = Math.imul(ah9, bh4);
lo = (lo + Math.imul(al8, bl5)) | 0;
mid = (mid + Math.imul(al8, bh5)) | 0;
mid = (mid + Math.imul(ah8, bl5)) | 0;
hi = (hi + Math.imul(ah8, bh5)) | 0;
lo = (lo + Math.imul(al7, bl6)) | 0;
mid = (mid + Math.imul(al7, bh6)) | 0;
mid = (mid + Math.imul(ah7, bl6)) | 0;
hi = (hi + Math.imul(ah7, bh6)) | 0;
lo = (lo + Math.imul(al6, bl7)) | 0;
mid = (mid + Math.imul(al6, bh7)) | 0;
mid = (mid + Math.imul(ah6, bl7)) | 0;
hi = (hi + Math.imul(ah6, bh7)) | 0;
lo = (lo + Math.imul(al5, bl8)) | 0;
mid = (mid + Math.imul(al5, bh8)) | 0;
mid = (mid + Math.imul(ah5, bl8)) | 0;
hi = (hi + Math.imul(ah5, bh8)) | 0;
lo = (lo + Math.imul(al4, bl9)) | 0;
mid = (mid + Math.imul(al4, bh9)) | 0;
mid = (mid + Math.imul(ah4, bl9)) | 0;
hi = (hi + Math.imul(ah4, bh9)) | 0;
var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;
w13 &= 0x3ffffff;
/* k = 14 */
lo = Math.imul(al9, bl5);
mid = Math.imul(al9, bh5);
mid = (mid + Math.imul(ah9, bl5)) | 0;
hi = Math.imul(ah9, bh5);
lo = (lo + Math.imul(al8, bl6)) | 0;
mid = (mid + Math.imul(al8, bh6)) | 0;
mid = (mid + Math.imul(ah8, bl6)) | 0;
hi = (hi + Math.imul(ah8, bh6)) | 0;
lo = (lo + Math.imul(al7, bl7)) | 0;
mid = (mid + Math.imul(al7, bh7)) | 0;
mid = (mid + Math.imul(ah7, bl7)) | 0;
hi = (hi + Math.imul(ah7, bh7)) | 0;
lo = (lo + Math.imul(al6, bl8)) | 0;
mid = (mid + Math.imul(al6, bh8)) | 0;
mid = (mid + Math.imul(ah6, bl8)) | 0;
hi = (hi + Math.imul(ah6, bh8)) | 0;
lo = (lo + Math.imul(al5, bl9)) | 0;
mid = (mid + Math.imul(al5, bh9)) | 0;
mid = (mid + Math.imul(ah5, bl9)) | 0;
hi = (hi + Math.imul(ah5, bh9)) | 0;
var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;
w14 &= 0x3ffffff;
/* k = 15 */
lo = Math.imul(al9, bl6);
mid = Math.imul(al9, bh6);
mid = (mid + Math.imul(ah9, bl6)) | 0;
hi = Math.imul(ah9, bh6);
lo = (lo + Math.imul(al8, bl7)) | 0;
mid = (mid + Math.imul(al8, bh7)) | 0;
mid = (mid + Math.imul(ah8, bl7)) | 0;
hi = (hi + Math.imul(ah8, bh7)) | 0;
lo = (lo + Math.imul(al7, bl8)) | 0;
mid = (mid + Math.imul(al7, bh8)) | 0;
mid = (mid + Math.imul(ah7, bl8)) | 0;
hi = (hi + Math.imul(ah7, bh8)) | 0;
lo = (lo + Math.imul(al6, bl9)) | 0;
mid = (mid + Math.imul(al6, bh9)) | 0;
mid = (mid + Math.imul(ah6, bl9)) | 0;
hi = (hi + Math.imul(ah6, bh9)) | 0;
var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;
w15 &= 0x3ffffff;
/* k = 16 */
lo = Math.imul(al9, bl7);
mid = Math.imul(al9, bh7);
mid = (mid + Math.imul(ah9, bl7)) | 0;
hi = Math.imul(ah9, bh7);
lo = (lo + Math.imul(al8, bl8)) | 0;
mid = (mid + Math.imul(al8, bh8)) | 0;
mid = (mid + Math.imul(ah8, bl8)) | 0;
hi = (hi + Math.imul(ah8, bh8)) | 0;
lo = (lo + Math.imul(al7, bl9)) | 0;
mid = (mid + Math.imul(al7, bh9)) | 0;
mid = (mid + Math.imul(ah7, bl9)) | 0;
hi = (hi + Math.imul(ah7, bh9)) | 0;
var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;
w16 &= 0x3ffffff;
/* k = 17 */
lo = Math.imul(al9, bl8);
mid = Math.imul(al9, bh8);
mid = (mid + Math.imul(ah9, bl8)) | 0;
hi = Math.imul(ah9, bh8);
lo = (lo + Math.imul(al8, bl9)) | 0;
mid = (mid + Math.imul(al8, bh9)) | 0;
mid = (mid + Math.imul(ah8, bl9)) | 0;
hi = (hi + Math.imul(ah8, bh9)) | 0;
var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;
w17 &= 0x3ffffff;
/* k = 18 */
lo = Math.imul(al9, bl9);
mid = Math.imul(al9, bh9);
mid = (mid + Math.imul(ah9, bl9)) | 0;
hi = Math.imul(ah9, bh9);
var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;
c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;
w18 &= 0x3ffffff;
o[0] = w0;
o[1] = w1;
o[2] = w2;
o[3] = w3;
o[4] = w4;
o[5] = w5;
o[6] = w6;
o[7] = w7;
o[8] = w8;
o[9] = w9;
o[10] = w10;
o[11] = w11;
o[12] = w12;
o[13] = w13;
o[14] = w14;
o[15] = w15;
o[16] = w16;
o[17] = w17;
o[18] = w18;
if (c !== 0) {
o[19] = c;
out.length++;
}
return out;
};
// Polyfill comb
if (!Math.imul) {
comb10MulTo = smallMulTo;
}
function bigMulTo (self, num, out) {
out.negative = num.negative ^ self.negative;
out.length = self.length + num.length;
var carry = 0;
var hncarry = 0;
for (var k = 0; k < out.length - 1; k++) {
// Sum all words with the same `i + j = k` and accumulate `ncarry`,
// note that ncarry could be >= 0x3ffffff
var ncarry = hncarry;
hncarry = 0;
var rword = carry & 0x3ffffff;
var maxJ = Math.min(k, num.length - 1);
for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {
var i = k - j;
var a = self.words[i] | 0;
var b = num.words[j] | 0;
var r = a * b;
var lo = r & 0x3ffffff;
ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;
lo = (lo + rword) | 0;
rword = lo & 0x3ffffff;
ncarry = (ncarry + (lo >>> 26)) | 0;
hncarry += ncarry >>> 26;
ncarry &= 0x3ffffff;
}
out.words[k] = rword;
carry = ncarry;
ncarry = hncarry;
}
if (carry !== 0) {
out.words[k] = carry;
} else {
out.length--;
}
return out.strip();
}
function jumboMulTo (self, num, out) {
var fftm = new FFTM();
return fftm.mulp(self, num, out);
}
BN.prototype.mulTo = function mulTo (num, out) {
var res;
var len = this.length + num.length;
if (this.length === 10 && num.length === 10) {
res = comb10MulTo(this, num, out);
} else if (len < 63) {
res = smallMulTo(this, num, out);
} else if (len < 1024) {
res = bigMulTo(this, num, out);
} else {
res = jumboMulTo(this, num, out);
}
return res;
};
// Cooley-Tukey algorithm for FFT
// slightly revisited to rely on looping instead of recursion
function FFTM (x, y) {
this.x = x;
this.y = y;
}
FFTM.prototype.makeRBT = function makeRBT (N) {
var t = new Array(N);
var l = BN.prototype._countBits(N) - 1;
for (var i = 0; i < N; i++) {
t[i] = this.revBin(i, l, N);
}
return t;
};
// Returns binary-reversed representation of `x`
FFTM.prototype.revBin = function revBin (x, l, N) {
if (x === 0 || x === N - 1) return x;
var rb = 0;
for (var i = 0; i < l; i++) {
rb |= (x & 1) << (l - i - 1);
x >>= 1;
}
return rb;
};
// Performs "tweedling" phase, therefore 'emulating'
// behaviour of the recursive algorithm
FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {
for (var i = 0; i < N; i++) {
rtws[i] = rws[rbt[i]];
itws[i] = iws[rbt[i]];
}
};
FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {
this.permute(rbt, rws, iws, rtws, itws, N);
for (var s = 1; s < N; s <<= 1) {
var l = s << 1;
var rtwdf = Math.cos(2 * Math.PI / l);
var itwdf = Math.sin(2 * Math.PI / l);
for (var p = 0; p < N; p += l) {
var rtwdf_ = rtwdf;
var itwdf_ = itwdf;
for (var j = 0; j < s; j++) {
var re = rtws[p + j];
var ie = itws[p + j];
var ro = rtws[p + j + s];
var io = itws[p + j + s];
var rx = rtwdf_ * ro - itwdf_ * io;
io = rtwdf_ * io + itwdf_ * ro;
ro = rx;
rtws[p + j] = re + ro;
itws[p + j] = ie + io;
rtws[p + j + s] = re - ro;
itws[p + j + s] = ie - io;
/* jshint maxdepth : false */
if (j !== l) {
rx = rtwdf * rtwdf_ - itwdf * itwdf_;
itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;
rtwdf_ = rx;
}
}
}
}
};
FFTM.prototype.guessLen13b = function guessLen13b (n, m) {
var N = Math.max(m, n) | 1;
var odd = N & 1;
var i = 0;
for (N = N / 2 | 0; N; N = N >>> 1) {
i++;
}
return 1 << i + 1 + odd;
};
FFTM.prototype.conjugate = function conjugate (rws, iws, N) {
if (N <= 1) return;
for (var i = 0; i < N / 2; i++) {
var t = rws[i];
rws[i] = rws[N - i - 1];
rws[N - i - 1] = t;
t = iws[i];
iws[i] = -iws[N - i - 1];
iws[N - i - 1] = -t;
}
};
FFTM.prototype.normalize13b = function normalize13b (ws, N) {
var carry = 0;
for (var i = 0; i < N / 2; i++) {
var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +
Math.round(ws[2 * i] / N) +
carry;
ws[i] = w & 0x3ffffff;
if (w < 0x4000000) {
carry = 0;
} else {
carry = w / 0x4000000 | 0;
}
}
return ws;
};
FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {
var carry = 0;
for (var i = 0; i < len; i++) {
carry = carry + (ws[i] | 0);
rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;
rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;
}
// Pad with zeroes
for (i = 2 * len; i < N; ++i) {
rws[i] = 0;
}
assert(carry === 0);
assert((carry & ~0x1fff) === 0);
};
FFTM.prototype.stub = function stub (N) {
var ph = new Array(N);
for (var i = 0; i < N; i++) {
ph[i] = 0;
}
return ph;
};
FFTM.prototype.mulp = function mulp (x, y, out) {
var N = 2 * this.guessLen13b(x.length, y.length);
var rbt = this.makeRBT(N);
var _ = this.stub(N);
var rws = new Array(N);
var rwst = new Array(N);
var iwst = new Array(N);
var nrws = new Array(N);
var nrwst = new Array(N);
var niwst = new Array(N);
var rmws = out.words;
rmws.length = N;
this.convert13b(x.words, x.length, rws, N);
this.convert13b(y.words, y.length, nrws, N);
this.transform(rws, _, rwst, iwst, N, rbt);
this.transform(nrws, _, nrwst, niwst, N, rbt);
for (var i = 0; i < N; i++) {
var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];
iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];
rwst[i] = rx;
}
this.conjugate(rwst, iwst, N);
this.transform(rwst, iwst, rmws, _, N, rbt);
this.conjugate(rmws, _, N);
this.normalize13b(rmws, N);
out.negative = x.negative ^ y.negative;
out.length = x.length + y.length;
return out.strip();
};
// Multiply `this` by `num`
BN.prototype.mul = function mul (num) {
var out = new BN(null);
out.words = new Array(this.length + num.length);
return this.mulTo(num, out);
};
// Multiply employing FFT
BN.prototype.mulf = function mulf (num) {
var out = new BN(null);
out.words = new Array(this.length + num.length);
return jumboMulTo(this, num, out);
};
// In-place Multiplication
BN.prototype.imul = function imul (num) {
return this.clone().mulTo(num, this);
};
BN.prototype.imuln = function imuln (num) {
assert(typeof num === 'number');
assert(num < 0x4000000);
// Carry
var carry = 0;
for (var i = 0; i < this.length; i++) {
var w = (this.words[i] | 0) * num;
var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);
carry >>= 26;
carry += (w / 0x4000000) | 0;
// NOTE: lo is 27bit maximum
carry += lo >>> 26;
this.words[i] = lo & 0x3ffffff;
}
if (carry !== 0) {
this.words[i] = carry;
this.length++;
}
return this;
};
BN.prototype.muln = function muln (num) {
return this.clone().imuln(num);
};
// `this` * `this`
BN.prototype.sqr = function sqr () {
return this.mul(this);
};
// `this` * `this` in-place
BN.prototype.isqr = function isqr () {
return this.imul(this.clone());
};
// Math.pow(`this`, `num`)
BN.prototype.pow = function pow (num) {
var w = toBitArray(num);
if (w.length === 0) return new BN(1);
// Skip leading zeroes
var res = this;
for (var i = 0; i < w.length; i++, res = res.sqr()) {
if (w[i] !== 0) break;
}
if (++i < w.length) {
for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {
if (w[i] === 0) continue;
res = res.mul(q);
}
}
return res;
};
// Shift-left in-place
BN.prototype.iushln = function iushln (bits) {
assert(typeof bits === 'number' && bits >= 0);
var r = bits % 26;
var s = (bits - r) / 26;
var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);
var i;
if (r !== 0) {
var carry = 0;
for (i = 0; i < this.length; i++) {
var newCarry = this.words[i] & carryMask;
var c = ((this.words[i] | 0) - newCarry) << r;
this.words[i] = c | carry;
carry = newCarry >>> (26 - r);
}
if (carry) {
this.words[i] = carry;
this.length++;
}
}
if (s !== 0) {
for (i = this.length - 1; i >= 0; i--) {
this.words[i + s] = this.words[i];
}
for (i = 0; i < s; i++) {
this.words[i] = 0;
}
this.length += s;
}
return this.strip();
};
BN.prototype.ishln = function ishln (bits) {
// TODO(indutny): implement me
assert(this.negative === 0);
return this.iushln(bits);
};
// Shift-right in-place
// NOTE: `hint` is a lowest bit before trailing zeroes
// NOTE: if `extended` is present - it will be filled with destroyed bits
BN.prototype.iushrn = function iushrn (bits, hint, extended) {
assert(typeof bits === 'number' && bits >= 0);
var h;
if (hint) {
h = (hint - (hint % 26)) / 26;
} else {
h = 0;
}
var r = bits % 26;
var s = Math.min((bits - r) / 26, this.length);
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
var maskedWords = extended;
h -= s;
h = Math.max(0, h);
// Extended mode, copy masked part
if (maskedWords) {
for (var i = 0; i < s; i++) {
maskedWords.words[i] = this.words[i];
}
maskedWords.length = s;
}
if (s === 0) {
// No-op, we should not move anything at all
} else if (this.length > s) {
this.length -= s;
for (i = 0; i < this.length; i++) {
this.words[i] = this.words[i + s];
}
} else {
this.words[0] = 0;
this.length = 1;
}
var carry = 0;
for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {
var word = this.words[i] | 0;
this.words[i] = (carry << (26 - r)) | (word >>> r);
carry = word & mask;
}
// Push carried bits as a mask
if (maskedWords && carry !== 0) {
maskedWords.words[maskedWords.length++] = carry;
}
if (this.length === 0) {
this.words[0] = 0;
this.length = 1;
}
return this.strip();
};
BN.prototype.ishrn = function ishrn (bits, hint, extended) {
// TODO(indutny): implement me
assert(this.negative === 0);
return this.iushrn(bits, hint, extended);
};
// Shift-left
BN.prototype.shln = function shln (bits) {
return this.clone().ishln(bits);
};
BN.prototype.ushln = function ushln (bits) {
return this.clone().iushln(bits);
};
// Shift-right
BN.prototype.shrn = function shrn (bits) {
return this.clone().ishrn(bits);
};
BN.prototype.ushrn = function ushrn (bits) {
return this.clone().iushrn(bits);
};
// Test if n bit is set
BN.prototype.testn = function testn (bit) {
assert(typeof bit === 'number' && bit >= 0);
var r = bit % 26;
var s = (bit - r) / 26;
var q = 1 << r;
// Fast case: bit is much higher than all existing words
if (this.length <= s) return false;
// Check bit and return
var w = this.words[s];
return !!(w & q);
};
// Return only lowers bits of number (in-place)
BN.prototype.imaskn = function imaskn (bits) {
assert(typeof bits === 'number' && bits >= 0);
var r = bits % 26;
var s = (bits - r) / 26;
assert(this.negative === 0, 'imaskn works only with positive numbers');
if (this.length <= s) {
return this;
}
if (r !== 0) {
s++;
}
this.length = Math.min(s, this.length);
if (r !== 0) {
var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);
this.words[this.length - 1] &= mask;
}
return this.strip();
};
// Return only lowers bits of number
BN.prototype.maskn = function maskn (bits) {
return this.clone().imaskn(bits);
};
// Add plain number `num` to `this`
BN.prototype.iaddn = function iaddn (num) {
assert(typeof num === 'number');
assert(num < 0x4000000);
if (num < 0) return this.isubn(-num);
// Possible sign change
if (this.negative !== 0) {
if (this.length === 1 && (this.words[0] | 0) < num) {
this.words[0] = num - (this.words[0] | 0);
this.negative = 0;
return this;
}
this.negative = 0;
this.isubn(num);
this.negative = 1;
return this;
}
// Add without checks
return this._iaddn(num);
};
BN.prototype._iaddn = function _iaddn (num) {
this.words[0] += num;
// Carry
for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {
this.words[i] -= 0x4000000;
if (i === this.length - 1) {
this.words[i + 1] = 1;
} else {
this.words[i + 1]++;
}
}
this.length = Math.max(this.length, i + 1);
return this;
};
// Subtract plain number `num` from `this`
BN.prototype.isubn = function isubn (num) {
assert(typeof num === 'number');
assert(num < 0x4000000);
if (num < 0) return this.iaddn(-num);
if (this.negative !== 0) {
this.negative = 0;
this.iaddn(num);
this.negative = 1;
return this;
}
this.words[0] -= num;
if (this.length === 1 && this.words[0] < 0) {
this.words[0] = -this.words[0];
this.negative = 1;
} else {
// Carry
for (var i = 0; i < this.length && this.words[i] < 0; i++) {
this.words[i] += 0x4000000;
this.words[i + 1] -= 1;
}
}
return this.strip();
};
BN.prototype.addn = function addn (num) {
return this.clone().iaddn(num);
};
BN.prototype.subn = function subn (num) {
return this.clone().isubn(num);
};
BN.prototype.iabs = function iabs () {
this.negative = 0;
return this;
};
BN.prototype.abs = function abs () {
return this.clone().iabs();
};
BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {
var len = num.length + shift;
var i;
this._expand(len);
var w;
var carry = 0;
for (i = 0; i < num.length; i++) {
w = (this.words[i + shift] | 0) + carry;
var right = (num.words[i] | 0) * mul;
w -= right & 0x3ffffff;
carry = (w >> 26) - ((right / 0x4000000) | 0);
this.words[i + shift] = w & 0x3ffffff;
}
for (; i < this.length - shift; i++) {
w = (this.words[i + shift] | 0) + carry;
carry = w >> 26;
this.words[i + shift] = w & 0x3ffffff;
}
if (carry === 0) return this.strip();
// Subtraction overflow
assert(carry === -1);
carry = 0;
for (i = 0; i < this.length; i++) {
w = -(this.words[i] | 0) + carry;
carry = w >> 26;
this.words[i] = w & 0x3ffffff;
}
this.negative = 1;
return this.strip();
};
BN.prototype._wordDiv = function _wordDiv (num, mode) {
var shift = this.length - num.length;
var a = this.clone();
var b = num;
// Normalize
var bhi = b.words[b.length - 1] | 0;
var bhiBits = this._countBits(bhi);
shift = 26 - bhiBits;
if (shift !== 0) {
b = b.ushln(shift);
a.iushln(shift);
bhi = b.words[b.length - 1] | 0;
}
// Initialize quotient
var m = a.length - b.length;
var q;
if (mode !== 'mod') {
q = new BN(null);
q.length = m + 1;
q.words = new Array(q.length);
for (var i = 0; i < q.length; i++) {
q.words[i] = 0;
}
}
var diff = a.clone()._ishlnsubmul(b, 1, m);
if (diff.negative === 0) {
a = diff;
if (q) {
q.words[m] = 1;
}
}
for (var j = m - 1; j >= 0; j--) {
var qj = (a.words[b.length + j] | 0) * 0x4000000 +
(a.words[b.length + j - 1] | 0);
// NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max
// (0x7ffffff)
qj = Math.min((qj / bhi) | 0, 0x3ffffff);
a._ishlnsubmul(b, qj, j);
while (a.negative !== 0) {
qj--;
a.negative = 0;
a._ishlnsubmul(b, 1, j);
if (!a.isZero()) {
a.negative ^= 1;
}
}
if (q) {
q.words[j] = qj;
}
}
if (q) {
q.strip();
}
a.strip();
// Denormalize
if (mode !== 'div' && shift !== 0) {
a.iushrn(shift);
}
return {
div: q || null,
mod: a
};
};
// NOTE: 1) `mode` can be set to `mod` to request mod only,
// to `div` to request div only, or be absent to
// request both div & mod
// 2) `positive` is true if unsigned mod is requested
BN.prototype.divmod = function divmod (num, mode, positive) {
assert(!num.isZero());
if (this.isZero()) {
return {
div: new BN(0),
mod: new BN(0)
};
}
var div, mod, res;
if (this.negative !== 0 && num.negative === 0) {
res = this.neg().divmod(num, mode);
if (mode !== 'mod') {
div = res.div.neg();
}
if (mode !== 'div') {
mod = res.mod.neg();
if (positive && mod.negative !== 0) {
mod.iadd(num);
}
}
return {
div: div,
mod: mod
};
}
if (this.negative === 0 && num.negative !== 0) {
res = this.divmod(num.neg(), mode);
if (mode !== 'mod') {
div = res.div.neg();
}
return {
div: div,
mod: res.mod
};
}
if ((this.negative & num.negative) !== 0) {
res = this.neg().divmod(num.neg(), mode);
if (mode !== 'div') {
mod = res.mod.neg();
if (positive && mod.negative !== 0) {
mod.isub(num);
}
}
return {
div: res.div,
mod: mod
};
}
// Both numbers are positive at this point
// Strip both numbers to approximate shift value
if (num.length > this.length || this.cmp(num) < 0) {
return {
div: new BN(0),
mod: this
};
}
// Very short reduction
if (num.length === 1) {
if (mode === 'div') {
return {
div: this.divn(num.words[0]),
mod: null
};
}
if (mode === 'mod') {
return {
div: null,
mod: new BN(this.modn(num.words[0]))
};
}
return {
div: this.divn(num.words[0]),
mod: new BN(this.modn(num.words[0]))
};
}
return this._wordDiv(num, mode);
};
// Find `this` / `num`
BN.prototype.div = function div (num) {
return this.divmod(num, 'div', false).div;
};
// Find `this` % `num`
BN.prototype.mod = function mod (num) {
return this.divmod(num, 'mod', false).mod;
};
BN.prototype.umod = function umod (num) {
return this.divmod(num, 'mod', true).mod;
};
// Find Round(`this` / `num`)
BN.prototype.divRound = function divRound (num) {
var dm = this.divmod(num);
// Fast case - exact division
if (dm.mod.isZero()) return dm.div;
var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;
var half = num.ushrn(1);
var r2 = num.andln(1);
var cmp = mod.cmp(half);
// Round down
if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;
// Round up
return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);
};
BN.prototype.modn = function modn (num) {
assert(num <= 0x3ffffff);
var p = (1 << 26) % num;
var acc = 0;
for (var i = this.length - 1; i >= 0; i--) {
acc = (p * acc + (this.words[i] | 0)) % num;
}
return acc;
};
// In-place division by number
BN.prototype.idivn = function idivn (num) {
assert(num <= 0x3ffffff);
var carry = 0;
for (var i = this.length - 1; i >= 0; i--) {
var w = (this.words[i] | 0) + carry * 0x4000000;
this.words[i] = (w / num) | 0;
carry = w % num;
}
return this.strip();
};
BN.prototype.divn = function divn (num) {
return this.clone().idivn(num);
};
BN.prototype.egcd = function egcd (p) {
assert(p.negative === 0);
assert(!p.isZero());
var x = this;
var y = p.clone();
if (x.negative !== 0) {
x = x.umod(p);
} else {
x = x.clone();
}
// A * x + B * y = x
var A = new BN(1);
var B = new BN(0);
// C * x + D * y = y
var C = new BN(0);
var D = new BN(1);
var g = 0;
while (x.isEven() && y.isEven()) {
x.iushrn(1);
y.iushrn(1);
++g;
}
var yp = y.clone();
var xp = x.clone();
while (!x.isZero()) {
for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
if (i > 0) {
x.iushrn(i);
while (i-- > 0) {
if (A.isOdd() || B.isOdd()) {
A.iadd(yp);
B.isub(xp);
}
A.iushrn(1);
B.iushrn(1);
}
}
for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
if (j > 0) {
y.iushrn(j);
while (j-- > 0) {
if (C.isOdd() || D.isOdd()) {
C.iadd(yp);
D.isub(xp);
}
C.iushrn(1);
D.iushrn(1);
}
}
if (x.cmp(y) >= 0) {
x.isub(y);
A.isub(C);
B.isub(D);
} else {
y.isub(x);
C.isub(A);
D.isub(B);
}
}
return {
a: C,
b: D,
gcd: y.iushln(g)
};
};
// This is reduced incarnation of the binary EEA
// above, designated to invert members of the
// _prime_ fields F(p) at a maximal speed
BN.prototype._invmp = function _invmp (p) {
assert(p.negative === 0);
assert(!p.isZero());
var a = this;
var b = p.clone();
if (a.negative !== 0) {
a = a.umod(p);
} else {
a = a.clone();
}
var x1 = new BN(1);
var x2 = new BN(0);
var delta = b.clone();
while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {
for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);
if (i > 0) {
a.iushrn(i);
while (i-- > 0) {
if (x1.isOdd()) {
x1.iadd(delta);
}
x1.iushrn(1);
}
}
for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);
if (j > 0) {
b.iushrn(j);
while (j-- > 0) {
if (x2.isOdd()) {
x2.iadd(delta);
}
x2.iushrn(1);
}
}
if (a.cmp(b) >= 0) {
a.isub(b);
x1.isub(x2);
} else {
b.isub(a);
x2.isub(x1);
}
}
var res;
if (a.cmpn(1) === 0) {
res = x1;
} else {
res = x2;
}
if (res.cmpn(0) < 0) {
res.iadd(p);
}
return res;
};
BN.prototype.gcd = function gcd (num) {
if (this.isZero()) return num.abs();
if (num.isZero()) return this.abs();
var a = this.clone();
var b = num.clone();
a.negative = 0;
b.negative = 0;
// Remove common factor of two
for (var shift = 0; a.isEven() && b.isEven(); shift++) {
a.iushrn(1);
b.iushrn(1);
}
do {
while (a.isEven()) {
a.iushrn(1);
}
while (b.isEven()) {
b.iushrn(1);
}
var r = a.cmp(b);
if (r < 0) {
// Swap `a` and `b` to make `a` always bigger than `b`
var t = a;
a = b;
b = t;
} else if (r === 0 || b.cmpn(1) === 0) {
break;
}
a.isub(b);
} while (true);
return b.iushln(shift);
};
// Invert number in the field F(num)
BN.prototype.invm = function invm (num) {
return this.egcd(num).a.umod(num);
};
BN.prototype.isEven = function isEven () {
return (this.words[0] & 1) === 0;
};
BN.prototype.isOdd = function isOdd () {
return (this.words[0] & 1) === 1;
};
// And first word and num
BN.prototype.andln = function andln (num) {
return this.words[0] & num;
};
// Increment at the bit position in-line
BN.prototype.bincn = function bincn (bit) {
assert(typeof bit === 'number');
var r = bit % 26;
var s = (bit - r) / 26;
var q = 1 << r;
// Fast case: bit is much higher than all existing words
if (this.length <= s) {
this._expand(s + 1);
this.words[s] |= q;
return this;
}
// Add bit and propagate, if needed
var carry = q;
for (var i = s; carry !== 0 && i < this.length; i++) {
var w = this.words[i] | 0;
w += carry;
carry = w >>> 26;
w &= 0x3ffffff;
this.words[i] = w;
}
if (carry !== 0) {
this.words[i] = carry;
this.length++;
}
return this;
};
BN.prototype.isZero = function isZero () {
return this.length === 1 && this.words[0] === 0;
};
BN.prototype.cmpn = function cmpn (num) {
var negative = num < 0;
if (this.negative !== 0 && !negative) return -1;
if (this.negative === 0 && negative) return 1;
this.strip();
var res;
if (this.length > 1) {
res = 1;
} else {
if (negative) {
num = -num;
}
assert(num <= 0x3ffffff, 'Number is too big');
var w = this.words[0] | 0;
res = w === num ? 0 : w < num ? -1 : 1;
}
if (this.negative !== 0) return -res | 0;
return res;
};
// Compare two numbers and return:
// 1 - if `this` > `num`
// 0 - if `this` == `num`
// -1 - if `this` < `num`
BN.prototype.cmp = function cmp (num) {
if (this.negative !== 0 && num.negative === 0) return -1;
if (this.negative === 0 && num.negative !== 0) return 1;
var res = this.ucmp(num);
if (this.negative !== 0) return -res | 0;
return res;
};
// Unsigned comparison
BN.prototype.ucmp = function ucmp (num) {
// At this point both numbers have the same sign
if (this.length > num.length) return 1;
if (this.length < num.length) return -1;
var res = 0;
for (var i = this.length - 1; i >= 0; i--) {
var a = this.words[i] | 0;
var b = num.words[i] | 0;
if (a === b) continue;
if (a < b) {
res = -1;
} else if (a > b) {
res = 1;
}
break;
}
return res;
};
BN.prototype.gtn = function gtn (num) {
return this.cmpn(num) === 1;
};
BN.prototype.gt = function gt (num) {
return this.cmp(num) === 1;
};
BN.prototype.gten = function gten (num) {
return this.cmpn(num) >= 0;
};
BN.prototype.gte = function gte (num) {
return this.cmp(num) >= 0;
};
BN.prototype.ltn = function ltn (num) {
return this.cmpn(num) === -1;
};
BN.prototype.lt = function lt (num) {
return this.cmp(num) === -1;
};
BN.prototype.lten = function lten (num) {
return this.cmpn(num) <= 0;
};
BN.prototype.lte = function lte (num) {
return this.cmp(num) <= 0;
};
BN.prototype.eqn = function eqn (num) {
return this.cmpn(num) === 0;
};
BN.prototype.eq = function eq (num) {
return this.cmp(num) === 0;
};
//
// A reduce context, could be using montgomery or something better, depending
// on the `m` itself.
//
BN.red = function red (num) {
return new Red(num);
};
BN.prototype.toRed = function toRed (ctx) {
assert(!this.red, 'Already a number in reduction context');
assert(this.negative === 0, 'red works only with positives');
return ctx.convertTo(this)._forceRed(ctx);
};
BN.prototype.fromRed = function fromRed () {
assert(this.red, 'fromRed works only with numbers in reduction context');
return this.red.convertFrom(this);
};
BN.prototype._forceRed = function _forceRed (ctx) {
this.red = ctx;
return this;
};
BN.prototype.forceRed = function forceRed (ctx) {
assert(!this.red, 'Already a number in reduction context');
return this._forceRed(ctx);
};
BN.prototype.redAdd = function redAdd (num) {
assert(this.red, 'redAdd works only with red numbers');
return this.red.add(this, num);
};
BN.prototype.redIAdd = function redIAdd (num) {
assert(this.red, 'redIAdd works only with red numbers');
return this.red.iadd(this, num);
};
BN.prototype.redSub = function redSub (num) {
assert(this.red, 'redSub works only with red numbers');
return this.red.sub(this, num);
};
BN.prototype.redISub = function redISub (num) {
assert(this.red, 'redISub works only with red numbers');
return this.red.isub(this, num);
};
BN.prototype.redShl = function redShl (num) {
assert(this.red, 'redShl works only with red numbers');
return this.red.shl(this, num);
};
BN.prototype.redMul = function redMul (num) {
assert(this.red, 'redMul works only with red numbers');
this.red._verify2(this, num);
return this.red.mul(this, num);
};
BN.prototype.redIMul = function redIMul (num) {
assert(this.red, 'redMul works only with red numbers');
this.red._verify2(this, num);
return this.red.imul(this, num);
};
BN.prototype.redSqr = function redSqr () {
assert(this.red, 'redSqr works only with red numbers');
this.red._verify1(this);
return this.red.sqr(this);
};
BN.prototype.redISqr = function redISqr () {
assert(this.red, 'redISqr works only with red numbers');
this.red._verify1(this);
return this.red.isqr(this);
};
// Square root over p
BN.prototype.redSqrt = function redSqrt () {
assert(this.red, 'redSqrt works only with red numbers');
this.red._verify1(this);
return this.red.sqrt(this);
};
BN.prototype.redInvm = function redInvm () {
assert(this.red, 'redInvm works only with red numbers');
this.red._verify1(this);
return this.red.invm(this);
};
// Return negative clone of `this` % `red modulo`
BN.prototype.redNeg = function redNeg () {
assert(this.red, 'redNeg works only with red numbers');
this.red._verify1(this);
return this.red.neg(this);
};
BN.prototype.redPow = function redPow (num) {
assert(this.red && !num.red, 'redPow(normalNum)');
this.red._verify1(this);
return this.red.pow(this, num);
};
// Prime numbers with efficient reduction
var primes = {
k256: null,
p224: null,
p192: null,
p25519: null
};
// Pseudo-Mersenne prime
function MPrime (name, p) {
// P = 2 ^ N - K
this.name = name;
this.p = new BN(p, 16);
this.n = this.p.bitLength();
this.k = new BN(1).iushln(this.n).isub(this.p);
this.tmp = this._tmp();
}
MPrime.prototype._tmp = function _tmp () {
var tmp = new BN(null);
tmp.words = new Array(Math.ceil(this.n / 13));
return tmp;
};
MPrime.prototype.ireduce = function ireduce (num) {
// Assumes that `num` is less than `P^2`
// num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)
var r = num;
var rlen;
do {
this.split(r, this.tmp);
r = this.imulK(r);
r = r.iadd(this.tmp);
rlen = r.bitLength();
} while (rlen > this.n);
var cmp = rlen < this.n ? -1 : r.ucmp(this.p);
if (cmp === 0) {
r.words[0] = 0;
r.length = 1;
} else if (cmp > 0) {
r.isub(this.p);
} else {
r.strip();
}
return r;
};
MPrime.prototype.split = function split (input, out) {
input.iushrn(this.n, 0, out);
};
MPrime.prototype.imulK = function imulK (num) {
return num.imul(this.k);
};
function K256 () {
MPrime.call(
this,
'k256',
'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');
}
inherits(K256, MPrime);
K256.prototype.split = function split (input, output) {
// 256 = 9 * 26 + 22
var mask = 0x3fffff;
var outLen = Math.min(input.length, 9);
for (var i = 0; i < outLen; i++) {
output.words[i] = input.words[i];
}
output.length = outLen;
if (input.length <= 9) {
input.words[0] = 0;
input.length = 1;
return;
}
// Shift by 9 limbs
var prev = input.words[9];
output.words[output.length++] = prev & mask;
for (i = 10; i < input.length; i++) {
var next = input.words[i] | 0;
input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);
prev = next;
}
prev >>>= 22;
input.words[i - 10] = prev;
if (prev === 0 && input.length > 10) {
input.length -= 10;
} else {
input.length -= 9;
}
};
K256.prototype.imulK = function imulK (num) {
// K = 0x1000003d1 = [ 0x40, 0x3d1 ]
num.words[num.length] = 0;
num.words[num.length + 1] = 0;
num.length += 2;
// bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390
var lo = 0;
for (var i = 0; i < num.length; i++) {
var w = num.words[i] | 0;
lo += w * 0x3d1;
num.words[i] = lo & 0x3ffffff;
lo = w * 0x40 + ((lo / 0x4000000) | 0);
}
// Fast length reduction
if (num.words[num.length - 1] === 0) {
num.length--;
if (num.words[num.length - 1] === 0) {
num.length--;
}
}
return num;
};
function P224 () {
MPrime.call(
this,
'p224',
'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');
}
inherits(P224, MPrime);
function P192 () {
MPrime.call(
this,
'p192',
'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');
}
inherits(P192, MPrime);
function P25519 () {
// 2 ^ 255 - 19
MPrime.call(
this,
'25519',
'7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');
}
inherits(P25519, MPrime);
P25519.prototype.imulK = function imulK (num) {
// K = 0x13
var carry = 0;
for (var i = 0; i < num.length; i++) {
var hi = (num.words[i] | 0) * 0x13 + carry;
var lo = hi & 0x3ffffff;
hi >>>= 26;
num.words[i] = lo;
carry = hi;
}
if (carry !== 0) {
num.words[num.length++] = carry;
}
return num;
};
// Exported mostly for testing purposes, use plain name instead
BN._prime = function prime (name) {
// Cached version of prime
if (primes[name]) return primes[name];
var prime;
if (name === 'k256') {
prime = new K256();
} else if (name === 'p224') {
prime = new P224();
} else if (name === 'p192') {
prime = new P192();
} else if (name === 'p25519') {
prime = new P25519();
} else {
throw new Error('Unknown prime ' + name);
}
primes[name] = prime;
return prime;
};
//
// Base reduction engine
//
function Red (m) {
if (typeof m === 'string') {
var prime = BN._prime(m);
this.m = prime.p;
this.prime = prime;
} else {
assert(m.gtn(1), 'modulus must be greater than 1');
this.m = m;
this.prime = null;
}
}
Red.prototype._verify1 = function _verify1 (a) {
assert(a.negative === 0, 'red works only with positives');
assert(a.red, 'red works only with red numbers');
};
Red.prototype._verify2 = function _verify2 (a, b) {
assert((a.negative | b.negative) === 0, 'red works only with positives');
assert(a.red && a.red === b.red,
'red works only with red numbers');
};
Red.prototype.imod = function imod (a) {
if (this.prime) return this.prime.ireduce(a)._forceRed(this);
return a.umod(this.m)._forceRed(this);
};
Red.prototype.neg = function neg (a) {
if (a.isZero()) {
return a.clone();
}
return this.m.sub(a)._forceRed(this);
};
Red.prototype.add = function add (a, b) {
this._verify2(a, b);
var res = a.add(b);
if (res.cmp(this.m) >= 0) {
res.isub(this.m);
}
return res._forceRed(this);
};
Red.prototype.iadd = function iadd (a, b) {
this._verify2(a, b);
var res = a.iadd(b);
if (res.cmp(this.m) >= 0) {
res.isub(this.m);
}
return res;
};
Red.prototype.sub = function sub (a, b) {
this._verify2(a, b);
var res = a.sub(b);
if (res.cmpn(0) < 0) {
res.iadd(this.m);
}
return res._forceRed(this);
};
Red.prototype.isub = function isub (a, b) {
this._verify2(a, b);
var res = a.isub(b);
if (res.cmpn(0) < 0) {
res.iadd(this.m);
}
return res;
};
Red.prototype.shl = function shl (a, num) {
this._verify1(a);
return this.imod(a.ushln(num));
};
Red.prototype.imul = function imul (a, b) {
this._verify2(a, b);
return this.imod(a.imul(b));
};
Red.prototype.mul = function mul (a, b) {
this._verify2(a, b);
return this.imod(a.mul(b));
};
Red.prototype.isqr = function isqr (a) {
return this.imul(a, a.clone());
};
Red.prototype.sqr = function sqr (a) {
return this.mul(a, a);
};
Red.prototype.sqrt = function sqrt (a) {
if (a.isZero()) return a.clone();
var mod3 = this.m.andln(3);
assert(mod3 % 2 === 1);
// Fast case
if (mod3 === 3) {
var pow = this.m.add(new BN(1)).iushrn(2);
return this.pow(a, pow);
}
// Tonelli-Shanks algorithm (Totally unoptimized and slow)
//
// Find Q and S, that Q * 2 ^ S = (P - 1)
var q = this.m.subn(1);
var s = 0;
while (!q.isZero() && q.andln(1) === 0) {
s++;
q.iushrn(1);
}
assert(!q.isZero());
var one = new BN(1).toRed(this);
var nOne = one.redNeg();
// Find quadratic non-residue
// NOTE: Max is such because of generalized Riemann hypothesis.
var lpow = this.m.subn(1).iushrn(1);
var z = this.m.bitLength();
z = new BN(2 * z * z).toRed(this);
while (this.pow(z, lpow).cmp(nOne) !== 0) {
z.redIAdd(nOne);
}
var c = this.pow(z, q);
var r = this.pow(a, q.addn(1).iushrn(1));
var t = this.pow(a, q);
var m = s;
while (t.cmp(one) !== 0) {
var tmp = t;
for (var i = 0; tmp.cmp(one) !== 0; i++) {
tmp = tmp.redSqr();
}
assert(i < m);
var b = this.pow(c, new BN(1).iushln(m - i - 1));
r = r.redMul(b);
c = b.redSqr();
t = t.redMul(c);
m = i;
}
return r;
};
Red.prototype.invm = function invm (a) {
var inv = a._invmp(this.m);
if (inv.negative !== 0) {
inv.negative = 0;
return this.imod(inv).redNeg();
} else {
return this.imod(inv);
}
};
Red.prototype.pow = function pow (a, num) {
if (num.isZero()) return new BN(1);
if (num.cmpn(1) === 0) return a.clone();
var windowSize = 4;
var wnd = new Array(1 << windowSize);
wnd[0] = new BN(1).toRed(this);
wnd[1] = a;
for (var i = 2; i < wnd.length; i++) {
wnd[i] = this.mul(wnd[i - 1], a);
}
var res = wnd[0];
var current = 0;
var currentLen = 0;
var start = num.bitLength() % 26;
if (start === 0) {
start = 26;
}
for (i = num.length - 1; i >= 0; i--) {
var word = num.words[i];
for (var j = start - 1; j >= 0; j--) {
var bit = (word >> j) & 1;
if (res !== wnd[0]) {
res = this.sqr(res);
}
if (bit === 0 && current === 0) {
currentLen = 0;
continue;
}
current <<= 1;
current |= bit;
currentLen++;
if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;
res = this.mul(res, wnd[current]);
currentLen = 0;
current = 0;
}
start = 26;
}
return res;
};
Red.prototype.convertTo = function convertTo (num) {
var r = num.umod(this.m);
return r === num ? r.clone() : r;
};
Red.prototype.convertFrom = function convertFrom (num) {
var res = num.clone();
res.red = null;
return res;
};
//
// Montgomery method engine
//
BN.mont = function mont (num) {
return new Mont(num);
};
function Mont (m) {
Red.call(this, m);
this.shift = this.m.bitLength();
if (this.shift % 26 !== 0) {
this.shift += 26 - (this.shift % 26);
}
this.r = new BN(1).iushln(this.shift);
this.r2 = this.imod(this.r.sqr());
this.rinv = this.r._invmp(this.m);
this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);
this.minv = this.minv.umod(this.r);
this.minv = this.r.sub(this.minv);
}
inherits(Mont, Red);
Mont.prototype.convertTo = function convertTo (num) {
return this.imod(num.ushln(this.shift));
};
Mont.prototype.convertFrom = function convertFrom (num) {
var r = this.imod(num.mul(this.rinv));
r.red = null;
return r;
};
Mont.prototype.imul = function imul (a, b) {
if (a.isZero() || b.isZero()) {
a.words[0] = 0;
a.length = 1;
return a;
}
var t = a.imul(b);
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
var u = t.isub(c).iushrn(this.shift);
var res = u;
if (u.cmp(this.m) >= 0) {
res = u.isub(this.m);
} else if (u.cmpn(0) < 0) {
res = u.iadd(this.m);
}
return res._forceRed(this);
};
Mont.prototype.mul = function mul (a, b) {
if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);
var t = a.mul(b);
var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);
var u = t.isub(c).iushrn(this.shift);
var res = u;
if (u.cmp(this.m) >= 0) {
res = u.isub(this.m);
} else if (u.cmpn(0) < 0) {
res = u.iadd(this.m);
}
return res._forceRed(this);
};
Mont.prototype.invm = function invm (a) {
// (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R
var res = this.imod(a._invmp(this.m).mul(this.r2));
return res._forceRed(this);
};
})(typeof module === 'undefined' || module, this);
},{}],65:[function(require,module,exports){
'use strict'
module.exports = boundary
function boundary (cells) {
var i, j, k
var n = cells.length
var sz = 0
for (i = 0; i < n; ++i) {
sz += cells[i].length
}
var result = new Array(sz)
var ptr = 0
for (i = 0; i < n; ++i) {
var c = cells[i]
var d = c.length
for (j = 0; j < d; ++j) {
var b = result[ptr++] = new Array(d - 1)
var p = 0
for (k = 0; k < d; ++k) {
if (k === j) {
continue
}
b[p++] = c[k]
}
if (j & 1) {
var tmp = b[1]
b[1] = b[0]
b[0] = tmp
}
}
}
return result
}
},{}],66:[function(require,module,exports){
'use strict'
module.exports = boxIntersectWrapper
var pool = require('typedarray-pool')
var sweep = require('./lib/sweep')
var boxIntersectIter = require('./lib/intersect')
function boxEmpty(d, box) {
for(var j=0; j>>1
if(d <= 0) {
return
}
var retval
//Convert red boxes
var redList = pool.mallocDouble(2*d*n)
var redIds = pool.mallocInt32(n)
n = convertBoxes(red, d, redList, redIds)
if(n > 0) {
if(d === 1 && full) {
//Special case: 1d complete
sweep.init(n)
retval = sweep.sweepComplete(
d, visit,
0, n, redList, redIds,
0, n, redList, redIds)
} else {
//Convert blue boxes
var blueList = pool.mallocDouble(2*d*m)
var blueIds = pool.mallocInt32(m)
m = convertBoxes(blue, d, blueList, blueIds)
if(m > 0) {
sweep.init(n+m)
if(d === 1) {
//Special case: 1d bipartite
retval = sweep.sweepBipartite(
d, visit,
0, n, redList, redIds,
0, m, blueList, blueIds)
} else {
//General case: d>1
retval = boxIntersectIter(
d, visit, full,
n, redList, redIds,
m, blueList, blueIds)
}
pool.free(blueList)
pool.free(blueIds)
}
}
pool.free(redList)
pool.free(redIds)
}
return retval
}
var RESULT
function appendItem(i,j) {
RESULT.push([i,j])
}
function intersectFullArray(x) {
RESULT = []
boxIntersect(x, x, appendItem, true)
return RESULT
}
function intersectBipartiteArray(x, y) {
RESULT = []
boxIntersect(x, y, appendItem, false)
return RESULT
}
//User-friendly wrapper, handle full input and no-visitor cases
function boxIntersectWrapper(arg0, arg1, arg2) {
var result
switch(arguments.length) {
case 1:
return intersectFullArray(arg0)
case 2:
if(typeof arg1 === 'function') {
return boxIntersect(arg0, arg0, arg1, true)
} else {
return intersectBipartiteArray(arg0, arg1)
}
case 3:
return boxIntersect(arg0, arg1, arg2, false)
default:
throw new Error('box-intersect: Invalid arguments')
}
}
},{"./lib/intersect":68,"./lib/sweep":72,"typedarray-pool":533}],67:[function(require,module,exports){
'use strict'
var DIMENSION = 'd'
var AXIS = 'ax'
var VISIT = 'vv'
var FLIP = 'fp'
var ELEM_SIZE = 'es'
var RED_START = 'rs'
var RED_END = 're'
var RED_BOXES = 'rb'
var RED_INDEX = 'ri'
var RED_PTR = 'rp'
var BLUE_START = 'bs'
var BLUE_END = 'be'
var BLUE_BOXES = 'bb'
var BLUE_INDEX = 'bi'
var BLUE_PTR = 'bp'
var RETVAL = 'rv'
var INNER_LABEL = 'Q'
var ARGS = [
DIMENSION,
AXIS,
VISIT,
RED_START,
RED_END,
RED_BOXES,
RED_INDEX,
BLUE_START,
BLUE_END,
BLUE_BOXES,
BLUE_INDEX
]
function generateBruteForce(redMajor, flip, full) {
var funcName = 'bruteForce' +
(redMajor ? 'Red' : 'Blue') +
(flip ? 'Flip' : '') +
(full ? 'Full' : '')
var code = ['function ', funcName, '(', ARGS.join(), '){',
'var ', ELEM_SIZE, '=2*', DIMENSION, ';']
var redLoop =
'for(var i=' + RED_START + ',' + RED_PTR + '=' + ELEM_SIZE + '*' + RED_START + ';' +
'i<' + RED_END +';' +
'++i,' + RED_PTR + '+=' + ELEM_SIZE + '){' +
'var x0=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '],' +
'x1=' + RED_BOXES + '[' + AXIS + '+' + RED_PTR + '+' + DIMENSION + '],' +
'xi=' + RED_INDEX + '[i];'
var blueLoop =
'for(var j=' + BLUE_START + ',' + BLUE_PTR + '=' + ELEM_SIZE + '*' + BLUE_START + ';' +
'j<' + BLUE_END + ';' +
'++j,' + BLUE_PTR + '+=' + ELEM_SIZE + '){' +
'var y0=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '],' +
(full ? 'y1=' + BLUE_BOXES + '[' + AXIS + '+' + BLUE_PTR + '+' + DIMENSION + '],' : '') +
'yi=' + BLUE_INDEX + '[j];'
if(redMajor) {
code.push(redLoop, INNER_LABEL, ':', blueLoop)
} else {
code.push(blueLoop, INNER_LABEL, ':', redLoop)
}
if(full) {
code.push('if(y1' +
BLUE_END + '-' + BLUE_START + '){')
if(full) {
invoke(true, false)
code.push('}else{')
invoke(false, false)
} else {
code.push('if(' + FLIP + '){')
invoke(true, true)
code.push('}else{')
invoke(true, false)
code.push('}}else{if(' + FLIP + '){')
invoke(false, true)
code.push('}else{')
invoke(false, false)
code.push('}')
}
code.push('}}return ' + funcName)
var codeStr = prefix.join('') + code.join('')
var proc = new Function(codeStr)
return proc()
}
exports.partial = bruteForcePlanner(false)
exports.full = bruteForcePlanner(true)
},{}],68:[function(require,module,exports){
'use strict'
module.exports = boxIntersectIter
var pool = require('typedarray-pool')
var bits = require('bit-twiddle')
var bruteForce = require('./brute')
var bruteForcePartial = bruteForce.partial
var bruteForceFull = bruteForce.full
var sweep = require('./sweep')
var findMedian = require('./median')
var genPartition = require('./partition')
//Twiddle parameters
var BRUTE_FORCE_CUTOFF = 128 //Cut off for brute force search
var SCAN_CUTOFF = (1<<22) //Cut off for two way scan
var SCAN_COMPLETE_CUTOFF = (1<<22)
//Partition functions
var partitionInteriorContainsInterval = genPartition(
'!(lo>=p0)&&!(p1>=hi)',
['p0', 'p1'])
var partitionStartEqual = genPartition(
'lo===p0',
['p0'])
var partitionStartLessThan = genPartition(
'lo 0) {
top -= 1
var iptr = top * IFRAME_SIZE
var axis = BOX_ISTACK[iptr]
var redStart = BOX_ISTACK[iptr+1]
var redEnd = BOX_ISTACK[iptr+2]
var blueStart = BOX_ISTACK[iptr+3]
var blueEnd = BOX_ISTACK[iptr+4]
var state = BOX_ISTACK[iptr+5]
var dptr = top * DFRAME_SIZE
var lo = BOX_DSTACK[dptr]
var hi = BOX_DSTACK[dptr+1]
//Unpack state info
var flip = (state & 1)
var full = !!(state & 16)
//Unpack indices
var red = xBoxes
var redIndex = xIndex
var blue = yBoxes
var blueIndex = yIndex
if(flip) {
red = yBoxes
redIndex = yIndex
blue = xBoxes
blueIndex = xIndex
}
if(state & 2) {
redEnd = partitionStartLessThan(
d, axis,
redStart, redEnd, red, redIndex,
hi)
if(redStart >= redEnd) {
continue
}
}
if(state & 4) {
redStart = partitionEndLessThanEqual(
d, axis,
redStart, redEnd, red, redIndex,
lo)
if(redStart >= redEnd) {
continue
}
}
var redCount = redEnd - redStart
var blueCount = blueEnd - blueStart
if(full) {
if(d * redCount * (redCount + blueCount) < SCAN_COMPLETE_CUTOFF) {
retval = sweep.scanComplete(
d, axis, visit,
redStart, redEnd, red, redIndex,
blueStart, blueEnd, blue, blueIndex)
if(retval !== void 0) {
return retval
}
continue
}
} else {
if(d * Math.min(redCount, blueCount) < BRUTE_FORCE_CUTOFF) {
//If input small, then use brute force
retval = bruteForcePartial(
d, axis, visit, flip,
redStart, redEnd, red, redIndex,
blueStart, blueEnd, blue, blueIndex)
if(retval !== void 0) {
return retval
}
continue
} else if(d * redCount * blueCount < SCAN_CUTOFF) {
//If input medium sized, then use sweep and prune
retval = sweep.scanBipartite(
d, axis, visit, flip,
redStart, redEnd, red, redIndex,
blueStart, blueEnd, blue, blueIndex)
if(retval !== void 0) {
return retval
}
continue
}
}
//First, find all red intervals whose interior contains (lo,hi)
var red0 = partitionInteriorContainsInterval(
d, axis,
redStart, redEnd, red, redIndex,
lo, hi)
//Lower dimensional case
if(redStart < red0) {
if(d * (red0 - redStart) < BRUTE_FORCE_CUTOFF) {
//Special case for small inputs: use brute force
retval = bruteForceFull(
d, axis+1, visit,
redStart, red0, red, redIndex,
blueStart, blueEnd, blue, blueIndex)
if(retval !== void 0) {
return retval
}
} else if(axis === d-2) {
if(flip) {
retval = sweep.sweepBipartite(
d, visit,
blueStart, blueEnd, blue, blueIndex,
redStart, red0, red, redIndex)
} else {
retval = sweep.sweepBipartite(
d, visit,
redStart, red0, red, redIndex,
blueStart, blueEnd, blue, blueIndex)
}
if(retval !== void 0) {
return retval
}
} else {
iterPush(top++,
axis+1,
redStart, red0,
blueStart, blueEnd,
flip,
-Infinity, Infinity)
iterPush(top++,
axis+1,
blueStart, blueEnd,
redStart, red0,
flip^1,
-Infinity, Infinity)
}
}
//Divide and conquer phase
if(red0 < redEnd) {
//Cut blue into 3 parts:
//
// Points < mid point
// Points = mid point
// Points > mid point
//
var blue0 = findMedian(
d, axis,
blueStart, blueEnd, blue, blueIndex)
var mid = blue[elemSize * blue0 + axis]
var blue1 = partitionStartEqual(
d, axis,
blue0, blueEnd, blue, blueIndex,
mid)
//Right case
if(blue1 < blueEnd) {
iterPush(top++,
axis,
red0, redEnd,
blue1, blueEnd,
(flip|4) + (full ? 16 : 0),
mid, hi)
}
//Left case
if(blueStart < blue0) {
iterPush(top++,
axis,
red0, redEnd,
blueStart, blue0,
(flip|2) + (full ? 16 : 0),
lo, mid)
}
//Center case (the hard part)
if(blue0 + 1 === blue1) {
//Optimization: Range with exactly 1 point, use a brute force scan
if(full) {
retval = onePointFull(
d, axis, visit,
red0, redEnd, red, redIndex,
blue0, blue, blueIndex[blue0])
} else {
retval = onePointPartial(
d, axis, visit, flip,
red0, redEnd, red, redIndex,
blue0, blue, blueIndex[blue0])
}
if(retval !== void 0) {
return retval
}
} else if(blue0 < blue1) {
var red1
if(full) {
//If full intersection, need to handle special case
red1 = partitionContainsPoint(
d, axis,
red0, redEnd, red, redIndex,
mid)
if(red0 < red1) {
var redX = partitionStartEqual(
d, axis,
red0, red1, red, redIndex,
mid)
if(axis === d-2) {
//Degenerate sweep intersection:
// [red0, redX] with [blue0, blue1]
if(red0 < redX) {
retval = sweep.sweepComplete(
d, visit,
red0, redX, red, redIndex,
blue0, blue1, blue, blueIndex)
if(retval !== void 0) {
return retval
}
}
//Normal sweep intersection:
// [redX, red1] with [blue0, blue1]
if(redX < red1) {
retval = sweep.sweepBipartite(
d, visit,
redX, red1, red, redIndex,
blue0, blue1, blue, blueIndex)
if(retval !== void 0) {
return retval
}
}
} else {
if(red0 < redX) {
iterPush(top++,
axis+1,
red0, redX,
blue0, blue1,
16,
-Infinity, Infinity)
}
if(redX < red1) {
iterPush(top++,
axis+1,
redX, red1,
blue0, blue1,
0,
-Infinity, Infinity)
iterPush(top++,
axis+1,
blue0, blue1,
redX, red1,
1,
-Infinity, Infinity)
}
}
}
} else {
if(flip) {
red1 = partitionContainsPointProper(
d, axis,
red0, redEnd, red, redIndex,
mid)
} else {
red1 = partitionContainsPoint(
d, axis,
red0, redEnd, red, redIndex,
mid)
}
if(red0 < red1) {
if(axis === d-2) {
if(flip) {
retval = sweep.sweepBipartite(
d, visit,
blue0, blue1, blue, blueIndex,
red0, red1, red, redIndex)
} else {
retval = sweep.sweepBipartite(
d, visit,
red0, red1, red, redIndex,
blue0, blue1, blue, blueIndex)
}
} else {
iterPush(top++,
axis+1,
red0, red1,
blue0, blue1,
flip,
-Infinity, Infinity)
iterPush(top++,
axis+1,
blue0, blue1,
red0, red1,
flip^1,
-Infinity, Infinity)
}
}
}
}
}
}
}
},{"./brute":67,"./median":69,"./partition":70,"./sweep":72,"bit-twiddle":63,"typedarray-pool":533}],69:[function(require,module,exports){
'use strict'
module.exports = findMedian
var genPartition = require('./partition')
var partitionStartLessThan = genPartition('lostart && boxes[ptr+axis] > x;
--j, ptr-=elemSize) {
//Swap
var aPtr = ptr
var bPtr = ptr+elemSize
for(var k=0; k>> 1)
var elemSize = 2*d
var pivot = mid
var value = boxes[elemSize*mid+axis]
while(lo < hi) {
if(hi - lo < PARTITION_THRESHOLD) {
insertionSort(d, axis, lo, hi, boxes, ids)
value = boxes[elemSize*mid+axis]
break
}
//Select pivot using median-of-3
var count = hi - lo
var pivot0 = (Math.random()*count+lo)|0
var value0 = boxes[elemSize*pivot0 + axis]
var pivot1 = (Math.random()*count+lo)|0
var value1 = boxes[elemSize*pivot1 + axis]
var pivot2 = (Math.random()*count+lo)|0
var value2 = boxes[elemSize*pivot2 + axis]
if(value0 <= value1) {
if(value2 >= value1) {
pivot = pivot1
value = value1
} else if(value0 >= value2) {
pivot = pivot0
value = value0
} else {
pivot = pivot2
value = value2
}
} else {
if(value1 >= value2) {
pivot = pivot1
value = value1
} else if(value2 >= value0) {
pivot = pivot0
value = value0
} else {
pivot = pivot2
value = value2
}
}
//Swap pivot to end of array
var aPtr = elemSize * (hi-1)
var bPtr = elemSize * pivot
for(var i=0; i= 0) {
reads.push('lo=e[k+n]')
}
if(predicate.indexOf('hi') >= 0) {
reads.push('hi=e[k+o]')
}
fargs.push(
code.replace('_', reads.join())
.replace('$', predicate))
return Function.apply(void 0, fargs)
}
},{}],71:[function(require,module,exports){
'use strict';
//This code is extracted from ndarray-sort
//It is inlined here as a temporary workaround
module.exports = wrapper;
var INSERT_SORT_CUTOFF = 32
function wrapper(data, n0) {
if (n0 <= 4*INSERT_SORT_CUTOFF) {
insertionSort(0, n0 - 1, data);
} else {
quickSort(0, n0 - 1, data);
}
}
function insertionSort(left, right, data) {
var ptr = 2*(left+1)
for(var i=left+1; i<=right; ++i) {
var a = data[ptr++]
var b = data[ptr++]
var j = i
var jptr = ptr-2
while(j-- > left) {
var x = data[jptr-2]
var y = data[jptr-1]
if(x < a) {
break
} else if(x === a && y < b) {
break
}
data[jptr] = x
data[jptr+1] = y
jptr -= 2
}
data[jptr] = a
data[jptr+1] = b
}
}
function swap(i, j, data) {
i *= 2
j *= 2
var x = data[i]
var y = data[i+1]
data[i] = data[j]
data[i+1] = data[j+1]
data[j] = x
data[j+1] = y
}
function move(i, j, data) {
i *= 2
j *= 2
data[i] = data[j]
data[i+1] = data[j+1]
}
function rotate(i, j, k, data) {
i *= 2
j *= 2
k *= 2
var x = data[i]
var y = data[i+1]
data[i] = data[j]
data[i+1] = data[j+1]
data[j] = data[k]
data[j+1] = data[k+1]
data[k] = x
data[k+1] = y
}
function shufflePivot(i, j, px, py, data) {
i *= 2
j *= 2
data[i] = data[j]
data[j] = px
data[i+1] = data[j+1]
data[j+1] = py
}
function compare(i, j, data) {
i *= 2
j *= 2
var x = data[i],
y = data[j]
if(x < y) {
return false
} else if(x === y) {
return data[i+1] > data[j+1]
}
return true
}
function comparePivot(i, y, b, data) {
i *= 2
var x = data[i]
if(x < y) {
return true
} else if(x === y) {
return data[i+1] < b
}
return false
}
function quickSort(left, right, data) {
var sixth = (right - left + 1) / 6 | 0,
index1 = left + sixth,
index5 = right - sixth,
index3 = left + right >> 1,
index2 = index3 - sixth,
index4 = index3 + sixth,
el1 = index1,
el2 = index2,
el3 = index3,
el4 = index4,
el5 = index5,
less = left + 1,
great = right - 1,
tmp = 0
if(compare(el1, el2, data)) {
tmp = el1
el1 = el2
el2 = tmp
}
if(compare(el4, el5, data)) {
tmp = el4
el4 = el5
el5 = tmp
}
if(compare(el1, el3, data)) {
tmp = el1
el1 = el3
el3 = tmp
}
if(compare(el2, el3, data)) {
tmp = el2
el2 = el3
el3 = tmp
}
if(compare(el1, el4, data)) {
tmp = el1
el1 = el4
el4 = tmp
}
if(compare(el3, el4, data)) {
tmp = el3
el3 = el4
el4 = tmp
}
if(compare(el2, el5, data)) {
tmp = el2
el2 = el5
el5 = tmp
}
if(compare(el2, el3, data)) {
tmp = el2
el2 = el3
el3 = tmp
}
if(compare(el4, el5, data)) {
tmp = el4
el4 = el5
el5 = tmp
}
var pivot1X = data[2*el2]
var pivot1Y = data[2*el2+1]
var pivot2X = data[2*el4]
var pivot2Y = data[2*el4+1]
var ptr0 = 2 * el1;
var ptr2 = 2 * el3;
var ptr4 = 2 * el5;
var ptr5 = 2 * index1;
var ptr6 = 2 * index3;
var ptr7 = 2 * index5;
for (var i1 = 0; i1 < 2; ++i1) {
var x = data[ptr0+i1];
var y = data[ptr2+i1];
var z = data[ptr4+i1];
data[ptr5+i1] = x;
data[ptr6+i1] = y;
data[ptr7+i1] = z;
}
move(index2, left, data)
move(index4, right, data)
for (var k = less; k <= great; ++k) {
if (comparePivot(k, pivot1X, pivot1Y, data)) {
if (k !== less) {
swap(k, less, data)
}
++less;
} else {
if (!comparePivot(k, pivot2X, pivot2Y, data)) {
while (true) {
if (!comparePivot(great, pivot2X, pivot2Y, data)) {
if (--great < k) {
break;
}
continue;
} else {
if (comparePivot(great, pivot1X, pivot1Y, data)) {
rotate(k, less, great, data)
++less;
--great;
} else {
swap(k, great, data)
--great;
}
break;
}
}
}
}
}
shufflePivot(left, less-1, pivot1X, pivot1Y, data)
shufflePivot(right, great+1, pivot2X, pivot2Y, data)
if (less - 2 - left <= INSERT_SORT_CUTOFF) {
insertionSort(left, less - 2, data);
} else {
quickSort(left, less - 2, data);
}
if (right - (great + 2) <= INSERT_SORT_CUTOFF) {
insertionSort(great + 2, right, data);
} else {
quickSort(great + 2, right, data);
}
if (great - less <= INSERT_SORT_CUTOFF) {
insertionSort(less, great, data);
} else {
quickSort(less, great, data);
}
}
},{}],72:[function(require,module,exports){
'use strict'
module.exports = {
init: sqInit,
sweepBipartite: sweepBipartite,
sweepComplete: sweepComplete,
scanBipartite: scanBipartite,
scanComplete: scanComplete
}
var pool = require('typedarray-pool')
var bits = require('bit-twiddle')
var isort = require('./sort')
//Flag for blue
var BLUE_FLAG = (1<<28)
//1D sweep event queue stuff (use pool to save space)
var INIT_CAPACITY = 1024
var RED_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY)
var RED_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY)
var BLUE_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY)
var BLUE_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY)
var COMMON_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY)
var COMMON_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY)
var SWEEP_EVENTS = pool.mallocDouble(INIT_CAPACITY * 8)
//Reserves memory for the 1D sweep data structures
function sqInit(count) {
var rcount = bits.nextPow2(count)
if(RED_SWEEP_QUEUE.length < rcount) {
pool.free(RED_SWEEP_QUEUE)
RED_SWEEP_QUEUE = pool.mallocInt32(rcount)
}
if(RED_SWEEP_INDEX.length < rcount) {
pool.free(RED_SWEEP_INDEX)
RED_SWEEP_INDEX = pool.mallocInt32(rcount)
}
if(BLUE_SWEEP_QUEUE.length < rcount) {
pool.free(BLUE_SWEEP_QUEUE)
BLUE_SWEEP_QUEUE = pool.mallocInt32(rcount)
}
if(BLUE_SWEEP_INDEX.length < rcount) {
pool.free(BLUE_SWEEP_INDEX)
BLUE_SWEEP_INDEX = pool.mallocInt32(rcount)
}
if(COMMON_SWEEP_QUEUE.length < rcount) {
pool.free(COMMON_SWEEP_QUEUE)
COMMON_SWEEP_QUEUE = pool.mallocInt32(rcount)
}
if(COMMON_SWEEP_INDEX.length < rcount) {
pool.free(COMMON_SWEEP_INDEX)
COMMON_SWEEP_INDEX = pool.mallocInt32(rcount)
}
var eventLength = 8 * rcount
if(SWEEP_EVENTS.length < eventLength) {
pool.free(SWEEP_EVENTS)
SWEEP_EVENTS = pool.mallocDouble(eventLength)
}
}
//Remove an item from the active queue in O(1)
function sqPop(queue, index, count, item) {
var idx = index[item]
var top = queue[count-1]
queue[idx] = top
index[top] = idx
}
//Insert an item into the active queue in O(1)
function sqPush(queue, index, count, item) {
queue[count] = item
index[item] = count
}
//Recursion base case: use 1D sweep algorithm
function sweepBipartite(
d, visit,
redStart, redEnd, red, redIndex,
blueStart, blueEnd, blue, blueIndex) {
//store events as pairs [coordinate, idx]
//
// red create: -(idx+1)
// red destroy: idx
// blue create: -(idx+BLUE_FLAG)
// blue destroy: idx+BLUE_FLAG
//
var ptr = 0
var elemSize = 2*d
var istart = d-1
var iend = elemSize-1
for(var i=redStart; iright
var n = ptr >>> 1
isort(SWEEP_EVENTS, n)
var redActive = 0
var blueActive = 0
for(var i=0; i= BLUE_FLAG) {
//blue destroy event
e = (e-BLUE_FLAG)|0
sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, e)
} else if(e >= 0) {
//red destroy event
sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e)
} else if(e <= -BLUE_FLAG) {
//blue create event
e = (-e-BLUE_FLAG)|0
for(var j=0; jright
var n = ptr >>> 1
isort(SWEEP_EVENTS, n)
var redActive = 0
var blueActive = 0
var commonActive = 0
for(var i=0; i>1) === (SWEEP_EVENTS[2*i+3]>>1)) {
color = 2
i += 1
}
if(e < 0) {
//Create event
var id = -(e>>1) - 1
//Intersect with common
for(var j=0; j>1) - 1
if(color === 0) {
//Red
sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, id)
} else if(color === 1) {
//Blue
sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, id)
} else if(color === 2) {
//Both
sqPop(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive--, id)
}
}
}
}
//Sweep and prune/scanline algorithm:
// Scan along axis, detect intersections
// Brute force all boxes along axis
function scanBipartite(
d, axis, visit, flip,
redStart, redEnd, red, redIndex,
blueStart, blueEnd, blue, blueIndex) {
var ptr = 0
var elemSize = 2*d
var istart = axis
var iend = axis+d
var redShift = 1
var blueShift = 1
if(flip) {
blueShift = BLUE_FLAG
} else {
redShift = BLUE_FLAG
}
for(var i=redStart; iright
var n = ptr >>> 1
isort(SWEEP_EVENTS, n)
var redActive = 0
for(var i=0; i= BLUE_FLAG) {
isRed = !flip
idx -= BLUE_FLAG
} else {
isRed = !!flip
idx -= 1
}
if(isRed) {
sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, idx)
} else {
var blueId = blueIndex[idx]
var bluePtr = elemSize * idx
var b0 = blue[bluePtr+axis+1]
var b1 = blue[bluePtr+axis+1+d]
red_loop:
for(var j=0; jright
var n = ptr >>> 1
isort(SWEEP_EVENTS, n)
var redActive = 0
for(var i=0; i= BLUE_FLAG) {
RED_SWEEP_QUEUE[redActive++] = idx - BLUE_FLAG
} else {
idx -= 1
var blueId = blueIndex[idx]
var bluePtr = elemSize * idx
var b0 = blue[bluePtr+axis+1]
var b1 = blue[bluePtr+axis+1+d]
red_loop:
for(var j=0; j=0; --j) {
if(RED_SWEEP_QUEUE[j] === idx) {
for(var k=j+1; k
* @license MIT
*/
/* eslint-disable no-proto */
'use strict'
var base64 = require('base64-js')
var ieee754 = require('ieee754')
exports.Buffer = Buffer
exports.SlowBuffer = SlowBuffer
exports.INSPECT_MAX_BYTES = 50
var K_MAX_LENGTH = 0x7fffffff
exports.kMaxLength = K_MAX_LENGTH
/**
* If `Buffer.TYPED_ARRAY_SUPPORT`:
* === true Use Uint8Array implementation (fastest)
* === false Print warning and recommend using `buffer` v4.x which has an Object
* implementation (most compatible, even IE6)
*
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
* Opera 11.6+, iOS 4.2+.
*
* We report that the browser does not support typed arrays if the are not subclassable
* using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array`
* (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support
* for __proto__ and has a buggy typed array implementation.
*/
Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport()
if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' &&
typeof console.error === 'function') {
console.error(
'This browser lacks typed array (Uint8Array) support which is required by ' +
'`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'
)
}
function typedArraySupport () {
// Can typed array instances can be augmented?
try {
var arr = new Uint8Array(1)
arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
return arr.foo() === 42
} catch (e) {
return false
}
}
function createBuffer (length) {
if (length > K_MAX_LENGTH) {
throw new RangeError('Invalid typed array length')
}
// Return an augmented `Uint8Array` instance
var buf = new Uint8Array(length)
buf.__proto__ = Buffer.prototype
return buf
}
/**
* The Buffer constructor returns instances of `Uint8Array` that have their
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
* returns a single octet.
*
* The `Uint8Array` prototype remains unmodified.
*/
function Buffer (arg, encodingOrOffset, length) {
// Common case.
if (typeof arg === 'number') {
if (typeof encodingOrOffset === 'string') {
throw new Error(
'If encoding is specified then the first argument must be a string'
)
}
return allocUnsafe(arg)
}
return from(arg, encodingOrOffset, length)
}
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
if (typeof Symbol !== 'undefined' && Symbol.species &&
Buffer[Symbol.species] === Buffer) {
Object.defineProperty(Buffer, Symbol.species, {
value: null,
configurable: true,
enumerable: false,
writable: false
})
}
Buffer.poolSize = 8192 // not used by this implementation
function from (value, encodingOrOffset, length) {
if (typeof value === 'number') {
throw new TypeError('"value" argument must not be a number')
}
if (value instanceof ArrayBuffer) {
return fromArrayBuffer(value, encodingOrOffset, length)
}
if (typeof value === 'string') {
return fromString(value, encodingOrOffset)
}
return fromObject(value)
}
/**
* Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
* if value is a number.
* Buffer.from(str[, encoding])
* Buffer.from(array)
* Buffer.from(buffer)
* Buffer.from(arrayBuffer[, byteOffset[, length]])
**/
Buffer.from = function (value, encodingOrOffset, length) {
return from(value, encodingOrOffset, length)
}
// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug:
// https://github.com/feross/buffer/pull/148
Buffer.prototype.__proto__ = Uint8Array.prototype
Buffer.__proto__ = Uint8Array
function assertSize (size) {
if (typeof size !== 'number') {
throw new TypeError('"size" argument must be a number')
} else if (size < 0) {
throw new RangeError('"size" argument must not be negative')
}
}
function alloc (size, fill, encoding) {
assertSize(size)
if (size <= 0) {
return createBuffer(size)
}
if (fill !== undefined) {
// Only pay attention to encoding if it's a string. This
// prevents accidentally sending in a number that would
// be interpretted as a start offset.
return typeof encoding === 'string'
? createBuffer(size).fill(fill, encoding)
: createBuffer(size).fill(fill)
}
return createBuffer(size)
}
/**
* Creates a new filled Buffer instance.
* alloc(size[, fill[, encoding]])
**/
Buffer.alloc = function (size, fill, encoding) {
return alloc(size, fill, encoding)
}
function allocUnsafe (size) {
assertSize(size)
return createBuffer(size < 0 ? 0 : checked(size) | 0)
}
/**
* Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
* */
Buffer.allocUnsafe = function (size) {
return allocUnsafe(size)
}
/**
* Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
*/
Buffer.allocUnsafeSlow = function (size) {
return allocUnsafe(size)
}
function fromString (string, encoding) {
if (typeof encoding !== 'string' || encoding === '') {
encoding = 'utf8'
}
if (!Buffer.isEncoding(encoding)) {
throw new TypeError('"encoding" must be a valid string encoding')
}
var length = byteLength(string, encoding) | 0
var buf = createBuffer(length)
var actual = buf.write(string, encoding)
if (actual !== length) {
// Writing a hex string, for example, that contains invalid characters will
// cause everything after the first invalid character to be ignored. (e.g.
// 'abxxcd' will be treated as 'ab')
buf = buf.slice(0, actual)
}
return buf
}
function fromArrayLike (array) {
var length = array.length < 0 ? 0 : checked(array.length) | 0
var buf = createBuffer(length)
for (var i = 0; i < length; i += 1) {
buf[i] = array[i] & 255
}
return buf
}
function fromArrayBuffer (array, byteOffset, length) {
if (byteOffset < 0 || array.byteLength < byteOffset) {
throw new RangeError('\'offset\' is out of bounds')
}
if (array.byteLength < byteOffset + (length || 0)) {
throw new RangeError('\'length\' is out of bounds')
}
var buf
if (byteOffset === undefined && length === undefined) {
buf = new Uint8Array(array)
} else if (length === undefined) {
buf = new Uint8Array(array, byteOffset)
} else {
buf = new Uint8Array(array, byteOffset, length)
}
// Return an augmented `Uint8Array` instance
buf.__proto__ = Buffer.prototype
return buf
}
function fromObject (obj) {
if (Buffer.isBuffer(obj)) {
var len = checked(obj.length) | 0
var buf = createBuffer(len)
if (buf.length === 0) {
return buf
}
obj.copy(buf, 0, 0, len)
return buf
}
if (obj) {
if (isArrayBufferView(obj) || 'length' in obj) {
if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) {
return createBuffer(0)
}
return fromArrayLike(obj)
}
if (obj.type === 'Buffer' && Array.isArray(obj.data)) {
return fromArrayLike(obj.data)
}
}
throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
}
function checked (length) {
// Note: cannot use `length < K_MAX_LENGTH` here because that fails when
// length is NaN (which is otherwise coerced to zero.)
if (length >= K_MAX_LENGTH) {
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes')
}
return length | 0
}
function SlowBuffer (length) {
if (+length != length) { // eslint-disable-line eqeqeq
length = 0
}
return Buffer.alloc(+length)
}
Buffer.isBuffer = function isBuffer (b) {
return b != null && b._isBuffer === true
}
Buffer.compare = function compare (a, b) {
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
throw new TypeError('Arguments must be Buffers')
}
if (a === b) return 0
var x = a.length
var y = b.length
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
if (a[i] !== b[i]) {
x = a[i]
y = b[i]
break
}
}
if (x < y) return -1
if (y < x) return 1
return 0
}
Buffer.isEncoding = function isEncoding (encoding) {
switch (String(encoding).toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'latin1':
case 'binary':
case 'base64':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return true
default:
return false
}
}
Buffer.concat = function concat (list, length) {
if (!Array.isArray(list)) {
throw new TypeError('"list" argument must be an Array of Buffers')
}
if (list.length === 0) {
return Buffer.alloc(0)
}
var i
if (length === undefined) {
length = 0
for (i = 0; i < list.length; ++i) {
length += list[i].length
}
}
var buffer = Buffer.allocUnsafe(length)
var pos = 0
for (i = 0; i < list.length; ++i) {
var buf = list[i]
if (!Buffer.isBuffer(buf)) {
throw new TypeError('"list" argument must be an Array of Buffers')
}
buf.copy(buffer, pos)
pos += buf.length
}
return buffer
}
function byteLength (string, encoding) {
if (Buffer.isBuffer(string)) {
return string.length
}
if (isArrayBufferView(string) || string instanceof ArrayBuffer) {
return string.byteLength
}
if (typeof string !== 'string') {
string = '' + string
}
var len = string.length
if (len === 0) return 0
// Use a for loop to avoid recursion
var loweredCase = false
for (;;) {
switch (encoding) {
case 'ascii':
case 'latin1':
case 'binary':
return len
case 'utf8':
case 'utf-8':
case undefined:
return utf8ToBytes(string).length
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return len * 2
case 'hex':
return len >>> 1
case 'base64':
return base64ToBytes(string).length
default:
if (loweredCase) return utf8ToBytes(string).length // assume utf8
encoding = ('' + encoding).toLowerCase()
loweredCase = true
}
}
}
Buffer.byteLength = byteLength
function slowToString (encoding, start, end) {
var loweredCase = false
// No need to verify that "this.length <= MAX_UINT32" since it's a read-only
// property of a typed array.
// This behaves neither like String nor Uint8Array in that we set start/end
// to their upper/lower bounds if the value passed is out of range.
// undefined is handled specially as per ECMA-262 6th Edition,
// Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
if (start === undefined || start < 0) {
start = 0
}
// Return early if start > this.length. Done here to prevent potential uint32
// coercion fail below.
if (start > this.length) {
return ''
}
if (end === undefined || end > this.length) {
end = this.length
}
if (end <= 0) {
return ''
}
// Force coersion to uint32. This will also coerce falsey/NaN values to 0.
end >>>= 0
start >>>= 0
if (end <= start) {
return ''
}
if (!encoding) encoding = 'utf8'
while (true) {
switch (encoding) {
case 'hex':
return hexSlice(this, start, end)
case 'utf8':
case 'utf-8':
return utf8Slice(this, start, end)
case 'ascii':
return asciiSlice(this, start, end)
case 'latin1':
case 'binary':
return latin1Slice(this, start, end)
case 'base64':
return base64Slice(this, start, end)
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return utf16leSlice(this, start, end)
default:
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
encoding = (encoding + '').toLowerCase()
loweredCase = true
}
}
}
// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package)
// to detect a Buffer instance. It's not possible to use `instanceof Buffer`
// reliably in a browserify context because there could be multiple different
// copies of the 'buffer' package in use. This method works even for Buffer
// instances that were created from another copy of the `buffer` package.
// See: https://github.com/feross/buffer/issues/154
Buffer.prototype._isBuffer = true
function swap (b, n, m) {
var i = b[n]
b[n] = b[m]
b[m] = i
}
Buffer.prototype.swap16 = function swap16 () {
var len = this.length
if (len % 2 !== 0) {
throw new RangeError('Buffer size must be a multiple of 16-bits')
}
for (var i = 0; i < len; i += 2) {
swap(this, i, i + 1)
}
return this
}
Buffer.prototype.swap32 = function swap32 () {
var len = this.length
if (len % 4 !== 0) {
throw new RangeError('Buffer size must be a multiple of 32-bits')
}
for (var i = 0; i < len; i += 4) {
swap(this, i, i + 3)
swap(this, i + 1, i + 2)
}
return this
}
Buffer.prototype.swap64 = function swap64 () {
var len = this.length
if (len % 8 !== 0) {
throw new RangeError('Buffer size must be a multiple of 64-bits')
}
for (var i = 0; i < len; i += 8) {
swap(this, i, i + 7)
swap(this, i + 1, i + 6)
swap(this, i + 2, i + 5)
swap(this, i + 3, i + 4)
}
return this
}
Buffer.prototype.toString = function toString () {
var length = this.length
if (length === 0) return ''
if (arguments.length === 0) return utf8Slice(this, 0, length)
return slowToString.apply(this, arguments)
}
Buffer.prototype.equals = function equals (b) {
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
if (this === b) return true
return Buffer.compare(this, b) === 0
}
Buffer.prototype.inspect = function inspect () {
var str = ''
var max = exports.INSPECT_MAX_BYTES
if (this.length > 0) {
str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
if (this.length > max) str += ' ... '
}
return ''
}
Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
if (!Buffer.isBuffer(target)) {
throw new TypeError('Argument must be a Buffer')
}
if (start === undefined) {
start = 0
}
if (end === undefined) {
end = target ? target.length : 0
}
if (thisStart === undefined) {
thisStart = 0
}
if (thisEnd === undefined) {
thisEnd = this.length
}
if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
throw new RangeError('out of range index')
}
if (thisStart >= thisEnd && start >= end) {
return 0
}
if (thisStart >= thisEnd) {
return -1
}
if (start >= end) {
return 1
}
start >>>= 0
end >>>= 0
thisStart >>>= 0
thisEnd >>>= 0
if (this === target) return 0
var x = thisEnd - thisStart
var y = end - start
var len = Math.min(x, y)
var thisCopy = this.slice(thisStart, thisEnd)
var targetCopy = target.slice(start, end)
for (var i = 0; i < len; ++i) {
if (thisCopy[i] !== targetCopy[i]) {
x = thisCopy[i]
y = targetCopy[i]
break
}
}
if (x < y) return -1
if (y < x) return 1
return 0
}
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
// Empty buffer means no match
if (buffer.length === 0) return -1
// Normalize byteOffset
if (typeof byteOffset === 'string') {
encoding = byteOffset
byteOffset = 0
} else if (byteOffset > 0x7fffffff) {
byteOffset = 0x7fffffff
} else if (byteOffset < -0x80000000) {
byteOffset = -0x80000000
}
byteOffset = +byteOffset // Coerce to Number.
if (numberIsNaN(byteOffset)) {
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
byteOffset = dir ? 0 : (buffer.length - 1)
}
// Normalize byteOffset: negative offsets start from the end of the buffer
if (byteOffset < 0) byteOffset = buffer.length + byteOffset
if (byteOffset >= buffer.length) {
if (dir) return -1
else byteOffset = buffer.length - 1
} else if (byteOffset < 0) {
if (dir) byteOffset = 0
else return -1
}
// Normalize val
if (typeof val === 'string') {
val = Buffer.from(val, encoding)
}
// Finally, search either indexOf (if dir is true) or lastIndexOf
if (Buffer.isBuffer(val)) {
// Special case: looking for empty string/buffer always fails
if (val.length === 0) {
return -1
}
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
} else if (typeof val === 'number') {
val = val & 0xFF // Search for a byte value [0-255]
if (typeof Uint8Array.prototype.indexOf === 'function') {
if (dir) {
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
} else {
return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
}
}
return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
}
throw new TypeError('val must be string, number or Buffer')
}
function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
var indexSize = 1
var arrLength = arr.length
var valLength = val.length
if (encoding !== undefined) {
encoding = String(encoding).toLowerCase()
if (encoding === 'ucs2' || encoding === 'ucs-2' ||
encoding === 'utf16le' || encoding === 'utf-16le') {
if (arr.length < 2 || val.length < 2) {
return -1
}
indexSize = 2
arrLength /= 2
valLength /= 2
byteOffset /= 2
}
}
function read (buf, i) {
if (indexSize === 1) {
return buf[i]
} else {
return buf.readUInt16BE(i * indexSize)
}
}
var i
if (dir) {
var foundIndex = -1
for (i = byteOffset; i < arrLength; i++) {
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
if (foundIndex === -1) foundIndex = i
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
} else {
if (foundIndex !== -1) i -= i - foundIndex
foundIndex = -1
}
}
} else {
if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
for (i = byteOffset; i >= 0; i--) {
var found = true
for (var j = 0; j < valLength; j++) {
if (read(arr, i + j) !== read(val, j)) {
found = false
break
}
}
if (found) return i
}
}
return -1
}
Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
return this.indexOf(val, byteOffset, encoding) !== -1
}
Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
}
Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}
function hexWrite (buf, string, offset, length) {
offset = Number(offset) || 0
var remaining = buf.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
// must be an even number of digits
var strLen = string.length
if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
if (length > strLen / 2) {
length = strLen / 2
}
for (var i = 0; i < length; ++i) {
var parsed = parseInt(string.substr(i * 2, 2), 16)
if (numberIsNaN(parsed)) return i
buf[offset + i] = parsed
}
return i
}
function utf8Write (buf, string, offset, length) {
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
}
function asciiWrite (buf, string, offset, length) {
return blitBuffer(asciiToBytes(string), buf, offset, length)
}
function latin1Write (buf, string, offset, length) {
return asciiWrite(buf, string, offset, length)
}
function base64Write (buf, string, offset, length) {
return blitBuffer(base64ToBytes(string), buf, offset, length)
}
function ucs2Write (buf, string, offset, length) {
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
}
Buffer.prototype.write = function write (string, offset, length, encoding) {
// Buffer#write(string)
if (offset === undefined) {
encoding = 'utf8'
length = this.length
offset = 0
// Buffer#write(string, encoding)
} else if (length === undefined && typeof offset === 'string') {
encoding = offset
length = this.length
offset = 0
// Buffer#write(string, offset[, length][, encoding])
} else if (isFinite(offset)) {
offset = offset >>> 0
if (isFinite(length)) {
length = length >>> 0
if (encoding === undefined) encoding = 'utf8'
} else {
encoding = length
length = undefined
}
} else {
throw new Error(
'Buffer.write(string, encoding, offset[, length]) is no longer supported'
)
}
var remaining = this.length - offset
if (length === undefined || length > remaining) length = remaining
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
throw new RangeError('Attempt to write outside buffer bounds')
}
if (!encoding) encoding = 'utf8'
var loweredCase = false
for (;;) {
switch (encoding) {
case 'hex':
return hexWrite(this, string, offset, length)
case 'utf8':
case 'utf-8':
return utf8Write(this, string, offset, length)
case 'ascii':
return asciiWrite(this, string, offset, length)
case 'latin1':
case 'binary':
return latin1Write(this, string, offset, length)
case 'base64':
// Warning: maxLength not taken into account in base64Write
return base64Write(this, string, offset, length)
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return ucs2Write(this, string, offset, length)
default:
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
encoding = ('' + encoding).toLowerCase()
loweredCase = true
}
}
}
Buffer.prototype.toJSON = function toJSON () {
return {
type: 'Buffer',
data: Array.prototype.slice.call(this._arr || this, 0)
}
}
function base64Slice (buf, start, end) {
if (start === 0 && end === buf.length) {
return base64.fromByteArray(buf)
} else {
return base64.fromByteArray(buf.slice(start, end))
}
}
function utf8Slice (buf, start, end) {
end = Math.min(buf.length, end)
var res = []
var i = start
while (i < end) {
var firstByte = buf[i]
var codePoint = null
var bytesPerSequence = (firstByte > 0xEF) ? 4
: (firstByte > 0xDF) ? 3
: (firstByte > 0xBF) ? 2
: 1
if (i + bytesPerSequence <= end) {
var secondByte, thirdByte, fourthByte, tempCodePoint
switch (bytesPerSequence) {
case 1:
if (firstByte < 0x80) {
codePoint = firstByte
}
break
case 2:
secondByte = buf[i + 1]
if ((secondByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
if (tempCodePoint > 0x7F) {
codePoint = tempCodePoint
}
}
break
case 3:
secondByte = buf[i + 1]
thirdByte = buf[i + 2]
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
codePoint = tempCodePoint
}
}
break
case 4:
secondByte = buf[i + 1]
thirdByte = buf[i + 2]
fourthByte = buf[i + 3]
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
codePoint = tempCodePoint
}
}
}
}
if (codePoint === null) {
// we did not generate a valid codePoint so insert a
// replacement char (U+FFFD) and advance only 1 byte
codePoint = 0xFFFD
bytesPerSequence = 1
} else if (codePoint > 0xFFFF) {
// encode to utf16 (surrogate pair dance)
codePoint -= 0x10000
res.push(codePoint >>> 10 & 0x3FF | 0xD800)
codePoint = 0xDC00 | codePoint & 0x3FF
}
res.push(codePoint)
i += bytesPerSequence
}
return decodeCodePointsArray(res)
}
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
var MAX_ARGUMENTS_LENGTH = 0x1000
function decodeCodePointsArray (codePoints) {
var len = codePoints.length
if (len <= MAX_ARGUMENTS_LENGTH) {
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
}
// Decode in chunks to avoid "call stack size exceeded".
var res = ''
var i = 0
while (i < len) {
res += String.fromCharCode.apply(
String,
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
)
}
return res
}
function asciiSlice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i] & 0x7F)
}
return ret
}
function latin1Slice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; ++i) {
ret += String.fromCharCode(buf[i])
}
return ret
}
function hexSlice (buf, start, end) {
var len = buf.length
if (!start || start < 0) start = 0
if (!end || end < 0 || end > len) end = len
var out = ''
for (var i = start; i < end; ++i) {
out += toHex(buf[i])
}
return out
}
function utf16leSlice (buf, start, end) {
var bytes = buf.slice(start, end)
var res = ''
for (var i = 0; i < bytes.length; i += 2) {
res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256))
}
return res
}
Buffer.prototype.slice = function slice (start, end) {
var len = this.length
start = ~~start
end = end === undefined ? len : ~~end
if (start < 0) {
start += len
if (start < 0) start = 0
} else if (start > len) {
start = len
}
if (end < 0) {
end += len
if (end < 0) end = 0
} else if (end > len) {
end = len
}
if (end < start) end = start
var newBuf = this.subarray(start, end)
// Return an augmented `Uint8Array` instance
newBuf.__proto__ = Buffer.prototype
return newBuf
}
/*
* Need to make sure that buffer isn't trying to write out of bounds.
*/
function checkOffset (offset, ext, length) {
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
}
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var val = this[offset]
var mul = 1
var i = 0
while (++i < byteLength && (mul *= 0x100)) {
val += this[offset + i] * mul
}
return val
}
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
checkOffset(offset, byteLength, this.length)
}
var val = this[offset + --byteLength]
var mul = 1
while (byteLength > 0 && (mul *= 0x100)) {
val += this[offset + --byteLength] * mul
}
return val
}
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 1, this.length)
return this[offset]
}
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
return this[offset] | (this[offset + 1] << 8)
}
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
return (this[offset] << 8) | this[offset + 1]
}
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ((this[offset]) |
(this[offset + 1] << 8) |
(this[offset + 2] << 16)) +
(this[offset + 3] * 0x1000000)
}
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset] * 0x1000000) +
((this[offset + 1] << 16) |
(this[offset + 2] << 8) |
this[offset + 3])
}
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var val = this[offset]
var mul = 1
var i = 0
while (++i < byteLength && (mul *= 0x100)) {
val += this[offset + i] * mul
}
mul *= 0x80
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
return val
}
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) checkOffset(offset, byteLength, this.length)
var i = byteLength
var mul = 1
var val = this[offset + --i]
while (i > 0 && (mul *= 0x100)) {
val += this[offset + --i] * mul
}
mul *= 0x80
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
return val
}
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 1, this.length)
if (!(this[offset] & 0x80)) return (this[offset])
return ((0xff - this[offset] + 1) * -1)
}
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
var val = this[offset] | (this[offset + 1] << 8)
return (val & 0x8000) ? val | 0xFFFF0000 : val
}
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 2, this.length)
var val = this[offset + 1] | (this[offset] << 8)
return (val & 0x8000) ? val | 0xFFFF0000 : val
}
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset]) |
(this[offset + 1] << 8) |
(this[offset + 2] << 16) |
(this[offset + 3] << 24)
}
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return (this[offset] << 24) |
(this[offset + 1] << 16) |
(this[offset + 2] << 8) |
(this[offset + 3])
}
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ieee754.read(this, offset, true, 23, 4)
}
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 4, this.length)
return ieee754.read(this, offset, false, 23, 4)
}
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 8, this.length)
return ieee754.read(this, offset, true, 52, 8)
}
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
offset = offset >>> 0
if (!noAssert) checkOffset(offset, 8, this.length)
return ieee754.read(this, offset, false, 52, 8)
}
function checkInt (buf, value, offset, ext, max, min) {
if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
if (offset + ext > buf.length) throw new RangeError('Index out of range')
}
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
var maxBytes = Math.pow(2, 8 * byteLength) - 1
checkInt(this, value, offset, byteLength, maxBytes, 0)
}
var mul = 1
var i = 0
this[offset] = value & 0xFF
while (++i < byteLength && (mul *= 0x100)) {
this[offset + i] = (value / mul) & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
byteLength = byteLength >>> 0
if (!noAssert) {
var maxBytes = Math.pow(2, 8 * byteLength) - 1
checkInt(this, value, offset, byteLength, maxBytes, 0)
}
var i = byteLength - 1
var mul = 1
this[offset + i] = value & 0xFF
while (--i >= 0 && (mul *= 0x100)) {
this[offset + i] = (value / mul) & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
this[offset] = (value & 0xff)
return offset + 1
}
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
return offset + 2
}
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
this[offset] = (value >>> 8)
this[offset + 1] = (value & 0xff)
return offset + 2
}
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
this[offset + 3] = (value >>> 24)
this[offset + 2] = (value >>> 16)
this[offset + 1] = (value >>> 8)
this[offset] = (value & 0xff)
return offset + 4
}
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
this[offset] = (value >>> 24)
this[offset + 1] = (value >>> 16)
this[offset + 2] = (value >>> 8)
this[offset + 3] = (value & 0xff)
return offset + 4
}
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
var limit = Math.pow(2, (8 * byteLength) - 1)
checkInt(this, value, offset, byteLength, limit - 1, -limit)
}
var i = 0
var mul = 1
var sub = 0
this[offset] = value & 0xFF
while (++i < byteLength && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
sub = 1
}
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
var limit = Math.pow(2, (8 * byteLength) - 1)
checkInt(this, value, offset, byteLength, limit - 1, -limit)
}
var i = byteLength - 1
var mul = 1
var sub = 0
this[offset + i] = value & 0xFF
while (--i >= 0 && (mul *= 0x100)) {
if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
sub = 1
}
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
}
return offset + byteLength
}
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
if (value < 0) value = 0xff + value + 1
this[offset] = (value & 0xff)
return offset + 1
}
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
return offset + 2
}
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
this[offset] = (value >>> 8)
this[offset + 1] = (value & 0xff)
return offset + 2
}
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
this[offset] = (value & 0xff)
this[offset + 1] = (value >>> 8)
this[offset + 2] = (value >>> 16)
this[offset + 3] = (value >>> 24)
return offset + 4
}
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
if (value < 0) value = 0xffffffff + value + 1
this[offset] = (value >>> 24)
this[offset + 1] = (value >>> 16)
this[offset + 2] = (value >>> 8)
this[offset + 3] = (value & 0xff)
return offset + 4
}
function checkIEEE754 (buf, value, offset, ext, max, min) {
if (offset + ext > buf.length) throw new RangeError('Index out of range')
if (offset < 0) throw new RangeError('Index out of range')
}
function writeFloat (buf, value, offset, littleEndian, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
}
ieee754.write(buf, value, offset, littleEndian, 23, 4)
return offset + 4
}
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
return writeFloat(this, value, offset, true, noAssert)
}
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
return writeFloat(this, value, offset, false, noAssert)
}
function writeDouble (buf, value, offset, littleEndian, noAssert) {
value = +value
offset = offset >>> 0
if (!noAssert) {
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
}
ieee754.write(buf, value, offset, littleEndian, 52, 8)
return offset + 8
}
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
return writeDouble(this, value, offset, true, noAssert)
}
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
return writeDouble(this, value, offset, false, noAssert)
}
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
if (!start) start = 0
if (!end && end !== 0) end = this.length
if (targetStart >= target.length) targetStart = target.length
if (!targetStart) targetStart = 0
if (end > 0 && end < start) end = start
// Copy 0 bytes; we're done
if (end === start) return 0
if (target.length === 0 || this.length === 0) return 0
// Fatal error conditions
if (targetStart < 0) {
throw new RangeError('targetStart out of bounds')
}
if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
if (end < 0) throw new RangeError('sourceEnd out of bounds')
// Are we oob?
if (end > this.length) end = this.length
if (target.length - targetStart < end - start) {
end = target.length - targetStart + start
}
var len = end - start
var i
if (this === target && start < targetStart && targetStart < end) {
// descending copy from end
for (i = len - 1; i >= 0; --i) {
target[i + targetStart] = this[i + start]
}
} else if (len < 1000) {
// ascending copy from start
for (i = 0; i < len; ++i) {
target[i + targetStart] = this[i + start]
}
} else {
Uint8Array.prototype.set.call(
target,
this.subarray(start, start + len),
targetStart
)
}
return len
}
// Usage:
// buffer.fill(number[, offset[, end]])
// buffer.fill(buffer[, offset[, end]])
// buffer.fill(string[, offset[, end]][, encoding])
Buffer.prototype.fill = function fill (val, start, end, encoding) {
// Handle string cases:
if (typeof val === 'string') {
if (typeof start === 'string') {
encoding = start
start = 0
end = this.length
} else if (typeof end === 'string') {
encoding = end
end = this.length
}
if (val.length === 1) {
var code = val.charCodeAt(0)
if (code < 256) {
val = code
}
}
if (encoding !== undefined && typeof encoding !== 'string') {
throw new TypeError('encoding must be a string')
}
if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
throw new TypeError('Unknown encoding: ' + encoding)
}
} else if (typeof val === 'number') {
val = val & 255
}
// Invalid ranges are not set to a default, so can range check early.
if (start < 0 || this.length < start || this.length < end) {
throw new RangeError('Out of range index')
}
if (end <= start) {
return this
}
start = start >>> 0
end = end === undefined ? this.length : end >>> 0
if (!val) val = 0
var i
if (typeof val === 'number') {
for (i = start; i < end; ++i) {
this[i] = val
}
} else {
var bytes = Buffer.isBuffer(val)
? val
: new Buffer(val, encoding)
var len = bytes.length
for (i = 0; i < end - start; ++i) {
this[i + start] = bytes[i % len]
}
}
return this
}
// HELPER FUNCTIONS
// ================
var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g
function base64clean (str) {
// Node strips out invalid characters like \n and \t from the string, base64-js does not
str = str.trim().replace(INVALID_BASE64_RE, '')
// Node converts strings with length < 2 to ''
if (str.length < 2) return ''
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
while (str.length % 4 !== 0) {
str = str + '='
}
return str
}
function toHex (n) {
if (n < 16) return '0' + n.toString(16)
return n.toString(16)
}
function utf8ToBytes (string, units) {
units = units || Infinity
var codePoint
var length = string.length
var leadSurrogate = null
var bytes = []
for (var i = 0; i < length; ++i) {
codePoint = string.charCodeAt(i)
// is surrogate component
if (codePoint > 0xD7FF && codePoint < 0xE000) {
// last char was a lead
if (!leadSurrogate) {
// no lead yet
if (codePoint > 0xDBFF) {
// unexpected trail
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
continue
} else if (i + 1 === length) {
// unpaired lead
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
continue
}
// valid lead
leadSurrogate = codePoint
continue
}
// 2 leads in a row
if (codePoint < 0xDC00) {
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
leadSurrogate = codePoint
continue
}
// valid surrogate pair
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
} else if (leadSurrogate) {
// valid bmp char, but last char was a lead
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
}
leadSurrogate = null
// encode utf8
if (codePoint < 0x80) {
if ((units -= 1) < 0) break
bytes.push(codePoint)
} else if (codePoint < 0x800) {
if ((units -= 2) < 0) break
bytes.push(
codePoint >> 0x6 | 0xC0,
codePoint & 0x3F | 0x80
)
} else if (codePoint < 0x10000) {
if ((units -= 3) < 0) break
bytes.push(
codePoint >> 0xC | 0xE0,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
)
} else if (codePoint < 0x110000) {
if ((units -= 4) < 0) break
bytes.push(
codePoint >> 0x12 | 0xF0,
codePoint >> 0xC & 0x3F | 0x80,
codePoint >> 0x6 & 0x3F | 0x80,
codePoint & 0x3F | 0x80
)
} else {
throw new Error('Invalid code point')
}
}
return bytes
}
function asciiToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; ++i) {
// Node's code seems to be doing this and not & 0x7F..
byteArray.push(str.charCodeAt(i) & 0xFF)
}
return byteArray
}
function utf16leToBytes (str, units) {
var c, hi, lo
var byteArray = []
for (var i = 0; i < str.length; ++i) {
if ((units -= 2) < 0) break
c = str.charCodeAt(i)
hi = c >> 8
lo = c % 256
byteArray.push(lo)
byteArray.push(hi)
}
return byteArray
}
function base64ToBytes (str) {
return base64.toByteArray(base64clean(str))
}
function blitBuffer (src, dst, offset, length) {
for (var i = 0; i < length; ++i) {
if ((i + offset >= dst.length) || (i >= src.length)) break
dst[i + offset] = src[i]
}
return i
}
// Node 0.10 supports `ArrayBuffer` but lacks `ArrayBuffer.isView`
function isArrayBufferView (obj) {
return (typeof ArrayBuffer.isView === 'function') && ArrayBuffer.isView(obj)
}
function numberIsNaN (obj) {
return obj !== obj // eslint-disable-line no-self-compare
}
},{"base64-js":74,"ieee754":283}],74:[function(require,module,exports){
'use strict'
exports.byteLength = byteLength
exports.toByteArray = toByteArray
exports.fromByteArray = fromByteArray
var lookup = []
var revLookup = []
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
for (var i = 0, len = code.length; i < len; ++i) {
lookup[i] = code[i]
revLookup[code.charCodeAt(i)] = i
}
revLookup['-'.charCodeAt(0)] = 62
revLookup['_'.charCodeAt(0)] = 63
function placeHoldersCount (b64) {
var len = b64.length
if (len % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
}
function byteLength (b64) {
// base64 is 4/3 + up to two characters of the original data
return b64.length * 3 / 4 - placeHoldersCount(b64)
}
function toByteArray (b64) {
var i, j, l, tmp, placeHolders, arr
var len = b64.length
placeHolders = placeHoldersCount(b64)
arr = new Arr(len * 3 / 4 - placeHolders)
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? len - 4 : len
var L = 0
for (i = 0, j = 0; i < l; i += 4, j += 3) {
tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
arr[L++] = (tmp >> 16) & 0xFF
arr[L++] = (tmp >> 8) & 0xFF
arr[L++] = tmp & 0xFF
}
if (placeHolders === 2) {
tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
arr[L++] = tmp & 0xFF
} else if (placeHolders === 1) {
tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
arr[L++] = (tmp >> 8) & 0xFF
arr[L++] = tmp & 0xFF
}
return arr
}
function tripletToBase64 (num) {
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
}
function encodeChunk (uint8, start, end) {
var tmp
var output = []
for (var i = start; i < end; i += 3) {
tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
output.push(tripletToBase64(tmp))
}
return output.join('')
}
function fromByteArray (uint8) {
var tmp
var len = uint8.length
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
var output = ''
var parts = []
var maxChunkLength = 16383 // must be multiple of 3
// go through the array every three bytes, we'll deal with trailing stuff later
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
}
// pad the end with zeros, but make sure to not forget the extra bytes
if (extraBytes === 1) {
tmp = uint8[len - 1]
output += lookup[tmp >> 2]
output += lookup[(tmp << 4) & 0x3F]
output += '=='
} else if (extraBytes === 2) {
tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
output += lookup[tmp >> 10]
output += lookup[(tmp >> 4) & 0x3F]
output += lookup[(tmp << 2) & 0x3F]
output += '='
}
parts.push(output)
return parts.join('')
}
},{}],75:[function(require,module,exports){
'use strict'
var monotoneTriangulate = require('./lib/monotone')
var makeIndex = require('./lib/triangulation')
var delaunayFlip = require('./lib/delaunay')
var filterTriangulation = require('./lib/filter')
module.exports = cdt2d
function canonicalizeEdge(e) {
return [Math.min(e[0], e[1]), Math.max(e[0], e[1])]
}
function compareEdge(a, b) {
return a[0]-b[0] || a[1]-b[1]
}
function canonicalizeEdges(edges) {
return edges.map(canonicalizeEdge).sort(compareEdge)
}
function getDefault(options, property, dflt) {
if(property in options) {
return options[property]
}
return dflt
}
function cdt2d(points, edges, options) {
if(!Array.isArray(edges)) {
options = edges || {}
edges = []
} else {
options = options || {}
edges = edges || []
}
//Parse out options
var delaunay = !!getDefault(options, 'delaunay', true)
var interior = !!getDefault(options, 'interior', true)
var exterior = !!getDefault(options, 'exterior', true)
var infinity = !!getDefault(options, 'infinity', false)
//Handle trivial case
if((!interior && !exterior) || points.length === 0) {
return []
}
//Construct initial triangulation
var cells = monotoneTriangulate(points, edges)
//If delaunay refinement needed, then improve quality by edge flipping
if(delaunay || interior !== exterior || infinity) {
//Index all of the cells to support fast neighborhood queries
var triangulation = makeIndex(points.length, canonicalizeEdges(edges))
for(var i=0; i 0) {
var b = stack.pop()
var a = stack.pop()
//Find opposite pairs
var x = -1, y = -1
var star = stars[a]
for(var i=1; i= 0) {
continue
}
//Flip the edge
triangulation.flip(a, b)
//Test flipping neighboring edges
testFlip(points, triangulation, stack, x, a, y)
testFlip(points, triangulation, stack, a, y, x)
testFlip(points, triangulation, stack, y, b, x)
testFlip(points, triangulation, stack, b, x, y)
}
}
},{"binary-search-bounds":80,"robust-in-sphere":498}],77:[function(require,module,exports){
'use strict'
var bsearch = require('binary-search-bounds')
module.exports = classifyFaces
function FaceIndex(cells, neighbor, constraint, flags, active, next, boundary) {
this.cells = cells
this.neighbor = neighbor
this.flags = flags
this.constraint = constraint
this.active = active
this.next = next
this.boundary = boundary
}
var proto = FaceIndex.prototype
function compareCell(a, b) {
return a[0] - b[0] ||
a[1] - b[1] ||
a[2] - b[2]
}
proto.locate = (function() {
var key = [0,0,0]
return function(a, b, c) {
var x = a, y = b, z = c
if(b < c) {
if(b < a) {
x = b
y = c
z = a
}
} else if(c < a) {
x = c
y = a
z = b
}
if(x < 0) {
return -1
}
key[0] = x
key[1] = y
key[2] = z
return bsearch.eq(this.cells, key, compareCell)
}
})()
function indexCells(triangulation, infinity) {
//First get cells and canonicalize
var cells = triangulation.cells()
var nc = cells.length
for(var i=0; i 0 || next.length > 0) {
while(active.length > 0) {
var t = active.pop()
if(flags[t] === -side) {
continue
}
flags[t] = side
var c = cells[t]
for(var j=0; j<3; ++j) {
var f = neighbor[3*t+j]
if(f >= 0 && flags[f] === 0) {
if(constraint[3*t+j]) {
next.push(f)
} else {
active.push(f)
flags[f] = side
}
}
}
}
//Swap arrays and loop
var tmp = next
next = active
active = tmp
next.length = 0
side = -side
}
var result = filterCells(cells, flags, target)
if(infinity) {
return result.concat(index.boundary)
}
return result
}
},{"binary-search-bounds":80}],78:[function(require,module,exports){
'use strict'
var bsearch = require('binary-search-bounds')
var orient = require('robust-orientation')[3]
var EVENT_POINT = 0
var EVENT_END = 1
var EVENT_START = 2
module.exports = monotoneTriangulate
//A partial convex hull fragment, made of two unimonotone polygons
function PartialHull(a, b, idx, lowerIds, upperIds) {
this.a = a
this.b = b
this.idx = idx
this.lowerIds = lowerIds
this.upperIds = upperIds
}
//An event in the sweep line procedure
function Event(a, b, type, idx) {
this.a = a
this.b = b
this.type = type
this.idx = idx
}
//This is used to compare events for the sweep line procedure
// Points are:
// 1. sorted lexicographically
// 2. sorted by type (point < end < start)
// 3. segments sorted by winding order
// 4. sorted by index
function compareEvent(a, b) {
var d =
(a.a[0] - b.a[0]) ||
(a.a[1] - b.a[1]) ||
(a.type - b.type)
if(d) { return d }
if(a.type !== EVENT_POINT) {
d = orient(a.a, a.b, b.b)
if(d) { return d }
}
return a.idx - b.idx
}
function testPoint(hull, p) {
return orient(hull.a, hull.b, p)
}
function addPoint(cells, hulls, points, p, idx) {
var lo = bsearch.lt(hulls, p, testPoint)
var hi = bsearch.gt(hulls, p, testPoint)
for(var i=lo; i 1 && orient(
points[lowerIds[m-2]],
points[lowerIds[m-1]],
p) > 0) {
cells.push(
[lowerIds[m-1],
lowerIds[m-2],
idx])
m -= 1
}
lowerIds.length = m
lowerIds.push(idx)
//Insert p into upper hull
var upperIds = hull.upperIds
var m = upperIds.length
while(m > 1 && orient(
points[upperIds[m-2]],
points[upperIds[m-1]],
p) < 0) {
cells.push(
[upperIds[m-2],
upperIds[m-1],
idx])
m -= 1
}
upperIds.length = m
upperIds.push(idx)
}
}
function findSplit(hull, edge) {
var d
if(hull.a[0] < edge.a[0]) {
d = orient(hull.a, hull.b, edge.a)
} else {
d = orient(edge.b, edge.a, hull.a)
}
if(d) { return d }
if(edge.b[0] < hull.b[0]) {
d = orient(hull.a, hull.b, edge.b)
} else {
d = orient(edge.b, edge.a, hull.b)
}
return d || hull.idx - edge.idx
}
function splitHulls(hulls, points, event) {
var splitIdx = bsearch.le(hulls, event, findSplit)
var hull = hulls[splitIdx]
var upperIds = hull.upperIds
var x = upperIds[upperIds.length-1]
hull.upperIds = [x]
hulls.splice(splitIdx+1, 0,
new PartialHull(event.a, event.b, event.idx, [x], upperIds))
}
function mergeHulls(hulls, points, event) {
//Swap pointers for merge search
var tmp = event.a
event.a = event.b
event.b = tmp
var mergeIdx = bsearch.eq(hulls, event, findSplit)
var upper = hulls[mergeIdx]
var lower = hulls[mergeIdx-1]
lower.upperIds = upper.upperIds
hulls.splice(mergeIdx, 1)
}
function monotoneTriangulate(points, edges) {
var numPoints = points.length
var numEdges = edges.length
var events = []
//Create point events
for(var i=0; i b[0]) {
events.push(
new Event(b, a, EVENT_START, i),
new Event(a, b, EVENT_END, i))
}
}
//Sort events
events.sort(compareEvent)
//Initialize hull
var minX = events[0].a[0] - (1 + Math.abs(events[0].a[0])) * Math.pow(2, -52)
var hull = [ new PartialHull([minX, 1], [minX, 0], -1, [], [], [], []) ]
//Process events in order
var cells = []
for(var i=0, numEvents=events.length; i= 0
}
})()
proto.removeTriangle = function(i, j, k) {
var stars = this.stars
removePair(stars[i], j, k)
removePair(stars[j], k, i)
removePair(stars[k], i, j)
}
proto.addTriangle = function(i, j, k) {
var stars = this.stars
stars[i].push(j, k)
stars[j].push(k, i)
stars[k].push(i, j)
}
proto.opposite = function(j, i) {
var list = this.stars[i]
for(var k=1, n=list.length; k>>1,x=a[m]"]
if(earlyOut) {
if(predicate.indexOf("c") < 0) {
code.push(";if(x===y){return m}else if(x<=y){")
} else {
code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){")
}
} else {
code.push(";if(", predicate, "){i=m;")
}
if(reversed) {
code.push("l=m+1}else{h=m-1}")
} else {
code.push("h=m-1}else{l=m+1}")
}
code.push("}")
if(earlyOut) {
code.push("return -1};")
} else {
code.push("return i};")
}
return code.join("")
}
function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
var result = new Function([
compileSearch("A", "x" + predicate + "y", reversed, ["y"], earlyOut),
compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], earlyOut),
"function dispatchBsearch", suffix, "(a,y,c,l,h){\
if(typeof(c)==='function'){\
return P(a,(l===void 0)?0:l|0,(h===void 0)?a.length-1:h|0,y,c)\
}else{\
return A(a,(c===void 0)?0:c|0,(l===void 0)?a.length-1:l|0,y)\
}}\
return dispatchBsearch", suffix].join(""))
return result()
}
module.exports = {
ge: compileBoundsSearch(">=", false, "GE"),
gt: compileBoundsSearch(">", false, "GT"),
lt: compileBoundsSearch("<", true, "LT"),
le: compileBoundsSearch("<=", true, "LE"),
eq: compileBoundsSearch("-", true, "EQ", true)
}
},{}],81:[function(require,module,exports){
'use strict'
module.exports = orientation
function orientation(s) {
var p = 1
for(var i=1; i max ? max : value)
: (value < max ? max : value > min ? min : value)
}
},{}],85:[function(require,module,exports){
'use strict'
module.exports = cleanPSLG
var UnionFind = require('union-find')
var boxIntersect = require('box-intersect')
var segseg = require('robust-segment-intersect')
var rat = require('big-rat')
var ratCmp = require('big-rat/cmp')
var ratToFloat = require('big-rat/to-float')
var ratVec = require('rat-vec')
var nextafter = require('nextafter')
var solveIntersection = require('./lib/rat-seg-intersect')
// Bounds on a rational number when rounded to a float
function boundRat (r) {
var f = ratToFloat(r)
return [
nextafter(f, -Infinity),
nextafter(f, Infinity)
]
}
// Convert a list of edges in a pslg to bounding boxes
function boundEdges (points, edges) {
var bounds = new Array(edges.length)
for (var i = 0; i < edges.length; ++i) {
var e = edges[i]
var a = points[e[0]]
var b = points[e[1]]
bounds[i] = [
nextafter(Math.min(a[0], b[0]), -Infinity),
nextafter(Math.min(a[1], b[1]), -Infinity),
nextafter(Math.max(a[0], b[0]), Infinity),
nextafter(Math.max(a[1], b[1]), Infinity)
]
}
return bounds
}
// Convert a list of points into bounding boxes by duplicating coords
function boundPoints (points) {
var bounds = new Array(points.length)
for (var i = 0; i < points.length; ++i) {
var p = points[i]
bounds[i] = [
nextafter(p[0], -Infinity),
nextafter(p[1], -Infinity),
nextafter(p[0], Infinity),
nextafter(p[1], Infinity)
]
}
return bounds
}
// Find all pairs of crossing edges in a pslg (given edge bounds)
function getCrossings (points, edges, edgeBounds) {
var result = []
boxIntersect(edgeBounds, function (i, j) {
var e = edges[i]
var f = edges[j]
if (e[0] === f[0] || e[0] === f[1] ||
e[1] === f[0] || e[1] === f[1]) {
return
}
var a = points[e[0]]
var b = points[e[1]]
var c = points[f[0]]
var d = points[f[1]]
if (segseg(a, b, c, d)) {
result.push([i, j])
}
})
return result
}
// Find all pairs of crossing vertices in a pslg (given edge/vert bounds)
function getTJunctions (points, edges, edgeBounds, vertBounds) {
var result = []
boxIntersect(edgeBounds, vertBounds, function (i, v) {
var e = edges[i]
if (e[0] === v || e[1] === v) {
return
}
var p = points[v]
var a = points[e[0]]
var b = points[e[1]]
if (segseg(a, b, p, p)) {
result.push([i, v])
}
})
return result
}
// Cut edges along crossings/tjunctions
function cutEdges (floatPoints, edges, crossings, junctions, useColor) {
var i, e
// Convert crossings into tjunctions by constructing rational points
var ratPoints = floatPoints.map(function(p) {
return [
rat(p[0]),
rat(p[1])
]
})
for (i = 0; i < crossings.length; ++i) {
var crossing = crossings[i]
e = crossing[0]
var f = crossing[1]
var ee = edges[e]
var ef = edges[f]
var x = solveIntersection(
ratVec(floatPoints[ee[0]]),
ratVec(floatPoints[ee[1]]),
ratVec(floatPoints[ef[0]]),
ratVec(floatPoints[ef[1]]))
if (!x) {
// Segments are parallel, should already be handled by t-junctions
continue
}
var idx = floatPoints.length
floatPoints.push([ratToFloat(x[0]), ratToFloat(x[1])])
ratPoints.push(x)
junctions.push([e, idx], [f, idx])
}
// Sort tjunctions
junctions.sort(function (a, b) {
if (a[0] !== b[0]) {
return a[0] - b[0]
}
var u = ratPoints[a[1]]
var v = ratPoints[b[1]]
return ratCmp(u[0], v[0]) || ratCmp(u[1], v[1])
})
// Split edges along junctions
for (i = junctions.length - 1; i >= 0; --i) {
var junction = junctions[i]
e = junction[0]
var edge = edges[e]
var s = edge[0]
var t = edge[1]
// Check if edge is not lexicographically sorted
var a = floatPoints[s]
var b = floatPoints[t]
if (((a[0] - b[0]) || (a[1] - b[1])) < 0) {
var tmp = s
s = t
t = tmp
}
// Split leading edge
edge[0] = s
var last = edge[1] = junction[1]
// If we are grouping edges by color, remember to track data
var color
if (useColor) {
color = edge[2]
}
// Split other edges
while (i > 0 && junctions[i - 1][0] === e) {
var junction = junctions[--i]
var next = junction[1]
if (useColor) {
edges.push([last, next, color])
} else {
edges.push([last, next])
}
last = next
}
// Add final edge
if (useColor) {
edges.push([last, t, color])
} else {
edges.push([last, t])
}
}
// Return constructed rational points
return ratPoints
}
// Merge overlapping points
function dedupPoints (floatPoints, ratPoints, floatBounds) {
var numPoints = ratPoints.length
var uf = new UnionFind(numPoints)
// Compute rational bounds
var bounds = []
for (var i = 0; i < ratPoints.length; ++i) {
var p = ratPoints[i]
var xb = boundRat(p[0])
var yb = boundRat(p[1])
bounds.push([
nextafter(xb[0], -Infinity),
nextafter(yb[0], -Infinity),
nextafter(xb[1], Infinity),
nextafter(yb[1], Infinity)
])
}
// Link all points with over lapping boxes
boxIntersect(bounds, function (i, j) {
uf.link(i, j)
})
// Do 1 pass over points to combine points in label sets
var noDupes = true
var labels = new Array(numPoints)
for (var i = 0; i < numPoints; ++i) {
var j = uf.find(i)
if (j !== i) {
// Clear no-dupes flag, zero out label
noDupes = false
// Make each point the top-left point from its cell
floatPoints[j] = [
Math.min(floatPoints[i][0], floatPoints[j][0]),
Math.min(floatPoints[i][1], floatPoints[j][1])
]
}
}
// If no duplicates, return null to signal termination
if (noDupes) {
return null
}
var ptr = 0
for (var i = 0; i < numPoints; ++i) {
var j = uf.find(i)
if (j === i) {
labels[i] = ptr
floatPoints[ptr++] = floatPoints[i]
} else {
labels[i] = -1
}
}
floatPoints.length = ptr
// Do a second pass to fix up missing labels
for (var i = 0; i < numPoints; ++i) {
if (labels[i] < 0) {
labels[i] = labels[uf.find(i)]
}
}
// Return resulting union-find data structure
return labels
}
function compareLex2 (a, b) { return (a[0] - b[0]) || (a[1] - b[1]) }
function compareLex3 (a, b) {
var d = (a[0] - b[0]) || (a[1] - b[1])
if (d) {
return d
}
if (a[2] < b[2]) {
return -1
} else if (a[2] > b[2]) {
return 1
}
return 0
}
// Remove duplicate edge labels
function dedupEdges (edges, labels, useColor) {
if (edges.length === 0) {
return
}
if (labels) {
for (var i = 0; i < edges.length; ++i) {
var e = edges[i]
var a = labels[e[0]]
var b = labels[e[1]]
e[0] = Math.min(a, b)
e[1] = Math.max(a, b)
}
} else {
for (var i = 0; i < edges.length; ++i) {
var e = edges[i]
var a = e[0]
var b = e[1]
e[0] = Math.min(a, b)
e[1] = Math.max(a, b)
}
}
if (useColor) {
edges.sort(compareLex3)
} else {
edges.sort(compareLex2)
}
var ptr = 1
for (var i = 1; i < edges.length; ++i) {
var prev = edges[i - 1]
var next = edges[i]
if (next[0] === prev[0] && next[1] === prev[1] &&
(!useColor || next[2] === prev[2])) {
continue
}
edges[ptr++] = next
}
edges.length = ptr
}
function preRound (points, edges, useColor) {
var labels = dedupPoints(points, [], boundPoints(points))
dedupEdges(edges, labels, useColor)
return !!labels
}
// Repeat until convergence
function snapRound (points, edges, useColor) {
// 1. find edge crossings
var edgeBounds = boundEdges(points, edges)
var crossings = getCrossings(points, edges, edgeBounds)
// 2. find t-junctions
var vertBounds = boundPoints(points)
var tjunctions = getTJunctions(points, edges, edgeBounds, vertBounds)
// 3. cut edges, construct rational points
var ratPoints = cutEdges(points, edges, crossings, tjunctions, useColor)
// 4. dedupe verts
var labels = dedupPoints(points, ratPoints, vertBounds)
// 5. dedupe edges
dedupEdges(edges, labels, useColor)
// 6. check termination
if (!labels) {
return (crossings.length > 0 || tjunctions.length > 0)
}
// More iterations necessary
return true
}
// Main loop, runs PSLG clean up until completion
function cleanPSLG (points, edges, colors) {
// If using colors, augment edges with color data
var prevEdges
if (colors) {
prevEdges = edges
var augEdges = new Array(edges.length)
for (var i = 0; i < edges.length; ++i) {
var e = edges[i]
augEdges[i] = [e[0], e[1], colors[i]]
}
edges = augEdges
}
// First round: remove duplicate edges and points
var modified = preRound(points, edges, !!colors)
// Run snap rounding until convergence
while (snapRound(points, edges, !!colors)) {
modified = true
}
// Strip color tags
if (!!colors && modified) {
prevEdges.length = 0
colors.length = 0
for (var i = 0; i < edges.length; ++i) {
var e = edges[i]
prevEdges.push([e[0], e[1]])
colors.push(e[2])
}
}
return modified
}
},{"./lib/rat-seg-intersect":86,"big-rat":49,"big-rat/cmp":47,"big-rat/to-float":61,"box-intersect":66,"nextafter":461,"rat-vec":487,"robust-segment-intersect":503,"union-find":534}],86:[function(require,module,exports){
'use strict'
module.exports = solveIntersection
var ratMul = require('big-rat/mul')
var ratDiv = require('big-rat/div')
var ratSub = require('big-rat/sub')
var ratSign = require('big-rat/sign')
var rvSub = require('rat-vec/sub')
var rvAdd = require('rat-vec/add')
var rvMuls = require('rat-vec/muls')
function ratPerp (a, b) {
return ratSub(ratMul(a[0], b[1]), ratMul(a[1], b[0]))
}
// Solve for intersection
// x = a + t (b-a)
// (x - c) ^ (d-c) = 0
// (t * (b-a) + (a-c) ) ^ (d-c) = 0
// t * (b-a)^(d-c) = (d-c)^(a-c)
// t = (d-c)^(a-c) / (b-a)^(d-c)
function solveIntersection (a, b, c, d) {
var ba = rvSub(b, a)
var dc = rvSub(d, c)
var baXdc = ratPerp(ba, dc)
if (ratSign(baXdc) === 0) {
return null
}
var ac = rvSub(a, c)
var dcXac = ratPerp(dc, ac)
var t = ratDiv(dcXac, baXdc)
var s = rvMuls(ba, t)
var r = rvAdd(a, s)
return r
}
},{"big-rat/div":48,"big-rat/mul":58,"big-rat/sign":59,"big-rat/sub":60,"rat-vec/add":486,"rat-vec/muls":488,"rat-vec/sub":489}],87:[function(require,module,exports){
(function (Buffer){
var clone = (function() {
'use strict';
/**
* Clones (copies) an Object using deep copying.
*
* This function supports circular references by default, but if you are certain
* there are no circular references in your object, you can save some CPU time
* by calling clone(obj, false).
*
* Caution: if `circular` is false and `parent` contains circular references,
* your program may enter an infinite loop and crash.
*
* @param `parent` - the object to be cloned
* @param `circular` - set to true if the object to be cloned may contain
* circular references. (optional - true by default)
* @param `depth` - set to a number if the object is only to be cloned to
* a particular depth. (optional - defaults to Infinity)
* @param `prototype` - sets the prototype to be used when cloning an object.
* (optional - defaults to parent prototype).
*/
function clone(parent, circular, depth, prototype) {
var filter;
if (typeof circular === 'object') {
depth = circular.depth;
prototype = circular.prototype;
filter = circular.filter;
circular = circular.circular
}
// maintain two arrays for circular references, where corresponding parents
// and children have the same index
var allParents = [];
var allChildren = [];
var useBuffer = typeof Buffer != 'undefined';
if (typeof circular == 'undefined')
circular = true;
if (typeof depth == 'undefined')
depth = Infinity;
// recurse this function so we don't reset allParents and allChildren
function _clone(parent, depth) {
// cloning null always returns null
if (parent === null)
return null;
if (depth == 0)
return parent;
var child;
var proto;
if (typeof parent != 'object') {
return parent;
}
if (clone.__isArray(parent)) {
child = [];
} else if (clone.__isRegExp(parent)) {
child = new RegExp(parent.source, __getRegExpFlags(parent));
if (parent.lastIndex) child.lastIndex = parent.lastIndex;
} else if (clone.__isDate(parent)) {
child = new Date(parent.getTime());
} else if (useBuffer && Buffer.isBuffer(parent)) {
child = new Buffer(parent.length);
parent.copy(child);
return child;
} else {
if (typeof prototype == 'undefined') {
proto = Object.getPrototypeOf(parent);
child = Object.create(proto);
}
else {
child = Object.create(prototype);
proto = prototype;
}
}
if (circular) {
var index = allParents.indexOf(parent);
if (index != -1) {
return allChildren[index];
}
allParents.push(parent);
allChildren.push(child);
}
for (var i in parent) {
var attrs;
if (proto) {
attrs = Object.getOwnPropertyDescriptor(proto, i);
}
if (attrs && attrs.set == null) {
continue;
}
child[i] = _clone(parent[i], depth - 1);
}
return child;
}
return _clone(parent, depth);
}
/**
* Simple flat clone using prototype, accepts only objects, usefull for property
* override on FLAT configuration object (no nested props).
*
* USE WITH CAUTION! This may not behave as you wish if you do not know how this
* works.
*/
clone.clonePrototype = function clonePrototype(parent) {
if (parent === null)
return null;
var c = function () {};
c.prototype = parent;
return new c();
};
// private utility functions
function __objToStr(o) {
return Object.prototype.toString.call(o);
};
clone.__objToStr = __objToStr;
function __isDate(o) {
return typeof o === 'object' && __objToStr(o) === '[object Date]';
};
clone.__isDate = __isDate;
function __isArray(o) {
return typeof o === 'object' && __objToStr(o) === '[object Array]';
};
clone.__isArray = __isArray;
function __isRegExp(o) {
return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
};
clone.__isRegExp = __isRegExp;
function __getRegExpFlags(re) {
var flags = '';
if (re.global) flags += 'g';
if (re.ignoreCase) flags += 'i';
if (re.multiline) flags += 'm';
return flags;
};
clone.__getRegExpFlags = __getRegExpFlags;
return clone;
})();
if (typeof module === 'object' && module.exports) {
module.exports = clone;
}
}).call(this,require("buffer").Buffer)
},{"buffer":73}],88:[function(require,module,exports){
/** @module color-number */
'use strict'
var clamp = require('clamp')
module.exports = toNumber
function toNumber (rgba, normalized) {
if(normalized == null) normalized = true
var r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3]
if (a == null) a = normalized ? 1 : 255
if (normalized) {
r *= 255
g *= 255
b *= 255
a *= 255
}
r = clamp(r, 0, 255) & 0xFF
g = clamp(g, 0, 255) & 0xFF
b = clamp(b, 0, 255) & 0xFF
a = clamp(a, 0, 255) & 0xFF
//hi-order shift converts to -1, so we can't use <<24
var n = (r * 0x01000000) + (g << 16) + (b << 8) + (a)
return n
}
},{"clamp":84}],89:[function(require,module,exports){
module.exports = {
"aliceblue": [240, 248, 255],
"antiquewhite": [250, 235, 215],
"aqua": [0, 255, 255],
"aquamarine": [127, 255, 212],
"azure": [240, 255, 255],
"beige": [245, 245, 220],
"bisque": [255, 228, 196],
"black": [0, 0, 0],
"blanchedalmond": [255, 235, 205],
"blue": [0, 0, 255],
"blueviolet": [138, 43, 226],
"brown": [165, 42, 42],
"burlywood": [222, 184, 135],
"cadetblue": [95, 158, 160],
"chartreuse": [127, 255, 0],
"chocolate": [210, 105, 30],
"coral": [255, 127, 80],
"cornflowerblue": [100, 149, 237],
"cornsilk": [255, 248, 220],
"crimson": [220, 20, 60],
"cyan": [0, 255, 255],
"darkblue": [0, 0, 139],
"darkcyan": [0, 139, 139],
"darkgoldenrod": [184, 134, 11],
"darkgray": [169, 169, 169],
"darkgreen": [0, 100, 0],
"darkgrey": [169, 169, 169],
"darkkhaki": [189, 183, 107],
"darkmagenta": [139, 0, 139],
"darkolivegreen": [85, 107, 47],
"darkorange": [255, 140, 0],
"darkorchid": [153, 50, 204],
"darkred": [139, 0, 0],
"darksalmon": [233, 150, 122],
"darkseagreen": [143, 188, 143],
"darkslateblue": [72, 61, 139],
"darkslategray": [47, 79, 79],
"darkslategrey": [47, 79, 79],
"darkturquoise": [0, 206, 209],
"darkviolet": [148, 0, 211],
"deeppink": [255, 20, 147],
"deepskyblue": [0, 191, 255],
"dimgray": [105, 105, 105],
"dimgrey": [105, 105, 105],
"dodgerblue": [30, 144, 255],
"firebrick": [178, 34, 34],
"floralwhite": [255, 250, 240],
"forestgreen": [34, 139, 34],
"fuchsia": [255, 0, 255],
"gainsboro": [220, 220, 220],
"ghostwhite": [248, 248, 255],
"gold": [255, 215, 0],
"goldenrod": [218, 165, 32],
"gray": [128, 128, 128],
"green": [0, 128, 0],
"greenyellow": [173, 255, 47],
"grey": [128, 128, 128],
"honeydew": [240, 255, 240],
"hotpink": [255, 105, 180],
"indianred": [205, 92, 92],
"indigo": [75, 0, 130],
"ivory": [255, 255, 240],
"khaki": [240, 230, 140],
"lavender": [230, 230, 250],
"lavenderblush": [255, 240, 245],
"lawngreen": [124, 252, 0],
"lemonchiffon": [255, 250, 205],
"lightblue": [173, 216, 230],
"lightcoral": [240, 128, 128],
"lightcyan": [224, 255, 255],
"lightgoldenrodyellow": [250, 250, 210],
"lightgray": [211, 211, 211],
"lightgreen": [144, 238, 144],
"lightgrey": [211, 211, 211],
"lightpink": [255, 182, 193],
"lightsalmon": [255, 160, 122],
"lightseagreen": [32, 178, 170],
"lightskyblue": [135, 206, 250],
"lightslategray": [119, 136, 153],
"lightslategrey": [119, 136, 153],
"lightsteelblue": [176, 196, 222],
"lightyellow": [255, 255, 224],
"lime": [0, 255, 0],
"limegreen": [50, 205, 50],
"linen": [250, 240, 230],
"magenta": [255, 0, 255],
"maroon": [128, 0, 0],
"mediumaquamarine": [102, 205, 170],
"mediumblue": [0, 0, 205],
"mediumorchid": [186, 85, 211],
"mediumpurple": [147, 112, 219],
"mediumseagreen": [60, 179, 113],
"mediumslateblue": [123, 104, 238],
"mediumspringgreen": [0, 250, 154],
"mediumturquoise": [72, 209, 204],
"mediumvioletred": [199, 21, 133],
"midnightblue": [25, 25, 112],
"mintcream": [245, 255, 250],
"mistyrose": [255, 228, 225],
"moccasin": [255, 228, 181],
"navajowhite": [255, 222, 173],
"navy": [0, 0, 128],
"oldlace": [253, 245, 230],
"olive": [128, 128, 0],
"olivedrab": [107, 142, 35],
"orange": [255, 165, 0],
"orangered": [255, 69, 0],
"orchid": [218, 112, 214],
"palegoldenrod": [238, 232, 170],
"palegreen": [152, 251, 152],
"paleturquoise": [175, 238, 238],
"palevioletred": [219, 112, 147],
"papayawhip": [255, 239, 213],
"peachpuff": [255, 218, 185],
"peru": [205, 133, 63],
"pink": [255, 192, 203],
"plum": [221, 160, 221],
"powderblue": [176, 224, 230],
"purple": [128, 0, 128],
"rebeccapurple": [102, 51, 153],
"red": [255, 0, 0],
"rosybrown": [188, 143, 143],
"royalblue": [65, 105, 225],
"saddlebrown": [139, 69, 19],
"salmon": [250, 128, 114],
"sandybrown": [244, 164, 96],
"seagreen": [46, 139, 87],
"seashell": [255, 245, 238],
"sienna": [160, 82, 45],
"silver": [192, 192, 192],
"skyblue": [135, 206, 235],
"slateblue": [106, 90, 205],
"slategray": [112, 128, 144],
"slategrey": [112, 128, 144],
"snow": [255, 250, 250],
"springgreen": [0, 255, 127],
"steelblue": [70, 130, 180],
"tan": [210, 180, 140],
"teal": [0, 128, 128],
"thistle": [216, 191, 216],
"tomato": [255, 99, 71],
"turquoise": [64, 224, 208],
"violet": [238, 130, 238],
"wheat": [245, 222, 179],
"white": [255, 255, 255],
"whitesmoke": [245, 245, 245],
"yellow": [255, 255, 0],
"yellowgreen": [154, 205, 50]
};
},{}],90:[function(require,module,exports){
/**
* @module color-parse
*/
'use strict'
module.exports = parse;
var names = require('color-name');
var isObject = require('is-plain-obj');
/**
* Base hues
* http://dev.w3.org/csswg/css-color/#typedef-named-hue
*/
//FIXME: use external hue detector
var baseHues = {
red: 0,
orange: 60,
yellow: 120,
green: 180,
blue: 240,
purple: 300
};
/**
* Parse color from the string passed
*
* @return {Object} A space indicator `space`, an array `values` and `alpha`
*/
function parse (cstr) {
var m, parts = [], alpha = 1, space;
if (typeof cstr === 'string') {
//keyword
if (names[cstr]) {
parts = names[cstr].slice();
space = 'rgb'
}
//reserved words
else if (cstr === 'transparent') {
alpha = 0;
space = 'rgb'
parts = [0,0,0]
}
//hex
else if (/^#[A-Fa-f0-9]+$/.test(cstr)) {
var base = cstr.slice(1);
var size = base.length;
var isShort = size <= 4;
alpha = 1;
if (isShort) {
parts = [
parseInt(base[0] + base[0], 16),
parseInt(base[1] + base[1], 16),
parseInt(base[2] + base[2], 16)
]
if (size === 4) {
alpha = parseInt(base[3] + base[3], 16) / 255
}
}
else {
parts = [
parseInt(base[0] + base[1], 16),
parseInt(base[2] + base[3], 16),
parseInt(base[4] + base[5], 16)
]
if (size === 8) {
alpha = parseInt(base[6] + base[7], 16) / 255
}
}
if (!parts[0]) parts[0] = 0;
if (!parts[1]) parts[1] = 0;
if (!parts[2]) parts[2] = 0;
space = 'rgb'
}
//color space
else if (m = /^((?:rgb|hs[lvb]|hwb|cmyk?|xy[zy]|gray|lab|lchu?v?|[ly]uv|lms)a?)\s*\(([^\)]*)\)/.exec(cstr)) {
var name = m[1];
var base = name.replace(/a$/, '');
space = base;
var size = base === 'cmyk' ? 4 : base === 'gray' ? 1 : 3;
parts = m[2].trim()
.split(/\s*,\s*/)
.map(function (x, i) {
//
if (/%$/.test(x)) {
//alpha
if (i === size) return parseFloat(x) / 100;
//rgb
if (base === 'rgb') return parseFloat(x) * 255 / 100;
return parseFloat(x);
}
//hue
else if (base[i] === 'h') {
//
if (/deg$/.test(x)) {
return parseFloat(x);
}
//
else if (baseHues[x] !== undefined) {
return baseHues[x];
}
}
return parseFloat(x);
});
if (name === base) parts.push(1);
alpha = parts[size] === undefined ? 1 : parts[size];
parts = parts.slice(0, size);
}
//named channels case
else if (cstr.length > 10 && /[0-9](?:\s|\/)/.test(cstr)) {
parts = cstr.match(/([0-9]+)/g).map(function (value) {
return parseFloat(value);
});
space = cstr.match(/([a-z])/ig).join('').toLowerCase();
}
}
//numeric case
else if (typeof cstr === 'number') {
space = 'rgb'
parts = [cstr >>> 16, (cstr & 0x00ff00) >>> 8, cstr & 0x0000ff];
}
//object case - detects css cases of rgb and hsl
else if (isObject(cstr)) {
if (cstr.r != null) {
parts = [cstr.r, cstr.g, cstr.b];
space = 'rgb'
}
else if (cstr.red != null) {
parts = [cstr.red, cstr.green, cstr.blue];
space = 'rgb'
}
else if (cstr.h != null) {
parts = [cstr.h, cstr.s, cstr.l];
space = 'hsl';
}
else if (cstr.hue != null) {
parts = [cstr.hue, cstr.saturation, cstr.lightness];
space = 'hsl';
}
if (cstr.a != null) alpha = cstr.a;
else if (cstr.alpha != null) alpha = cstr.alpha;
else if (cstr.opacity != null) alpha = cstr.opacity / 100;
}
//array
else if (Array.isArray(cstr) || ArrayBuffer.isView(cstr)) {
parts = [cstr[0], cstr[1], cstr[2]];
space = 'rgb'
alpha = cstr.length === 4 ? cstr[3] : 1;
}
return {
space: space,
values: parts,
alpha: alpha
};
}
},{"color-name":89,"is-plain-obj":290}],91:[function(require,module,exports){
/** @module color-rgba */
'use strict'
var parse = require('color-parse')
var hsl = require('color-space/hsl')
var clamp = require('clamp')
module.exports = function rgba (color, normalize) {
if (normalize == null) normalize = true
var parsed = parse(color);
if (!parsed.space) return [];
if (Array.isArray(color)) return color;
var values = parsed.values, i, l = values.length;
for (i = 0; i < l; i++) {
values[i] = clamp(values[i], 0, 255)
}
if (parsed.space[0] === 'h') {
values = hsl.rgb(values)
}
if (normalize) {
for (i = 0; i < l; i++) {
values[i] /= 255
}
}
values.push(clamp(parsed.alpha, 0, 1))
return values
}
},{"clamp":84,"color-parse":90,"color-space/hsl":92}],92:[function(require,module,exports){
/**
* @module color-space/hsl
*/
'use strict'
var rgb = require('./rgb');
module.exports = {
name: 'hsl',
min: [0,0,0],
max: [360,100,100],
channel: ['hue', 'saturation', 'lightness'],
alias: ['HSL'],
rgb: function(hsl) {
var h = hsl[0] / 360,
s = hsl[1] / 100,
l = hsl[2] / 100,
t1, t2, t3, rgb, val;
if (s === 0) {
val = l * 255;
return [val, val, val];
}
if (l < 0.5) {
t2 = l * (1 + s);
}
else {
t2 = l + s - l * s;
}
t1 = 2 * l - t2;
rgb = [0, 0, 0];
for (var i = 0; i < 3; i++) {
t3 = h + 1 / 3 * - (i - 1);
if (t3 < 0) {
t3++;
}
else if (t3 > 1) {
t3--;
}
if (6 * t3 < 1) {
val = t1 + (t2 - t1) * 6 * t3;
}
else if (2 * t3 < 1) {
val = t2;
}
else if (3 * t3 < 2) {
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
}
else {
val = t1;
}
rgb[i] = val * 255;
}
return rgb;
}
};
//extend rgb
rgb.hsl = function(rgb) {
var r = rgb[0]/255,
g = rgb[1]/255,
b = rgb[2]/255,
min = Math.min(r, g, b),
max = Math.max(r, g, b),
delta = max - min,
h, s, l;
if (max === min) {
h = 0;
}
else if (r === max) {
h = (g - b) / delta;
}
else if (g === max) {
h = 2 + (b - r) / delta;
}
else if (b === max) {
h = 4 + (r - g)/ delta;
}
h = Math.min(h * 60, 360);
if (h < 0) {
h += 360;
}
l = (min + max) / 2;
if (max === min) {
s = 0;
}
else if (l <= 0.5) {
s = delta / (max + min);
}
else {
s = delta / (2 - max - min);
}
return [h, s * 100, l * 100];
};
},{"./rgb":93}],93:[function(require,module,exports){
/**
* RGB space.
*
* @module color-space/rgb
*/
'use strict'
module.exports = {
name: 'rgb',
min: [0,0,0],
max: [255,255,255],
channel: ['red', 'green', 'blue'],
alias: ['RGB']
};
},{}],94:[function(require,module,exports){
module.exports={
"jet":[{"index":0,"rgb":[0,0,131]},{"index":0.125,"rgb":[0,60,170]},{"index":0.375,"rgb":[5,255,255]},{"index":0.625,"rgb":[255,255,0]},{"index":0.875,"rgb":[250,0,0]},{"index":1,"rgb":[128,0,0]}],
"hsv":[{"index":0,"rgb":[255,0,0]},{"index":0.169,"rgb":[253,255,2]},{"index":0.173,"rgb":[247,255,2]},{"index":0.337,"rgb":[0,252,4]},{"index":0.341,"rgb":[0,252,10]},{"index":0.506,"rgb":[1,249,255]},{"index":0.671,"rgb":[2,0,253]},{"index":0.675,"rgb":[8,0,253]},{"index":0.839,"rgb":[255,0,251]},{"index":0.843,"rgb":[255,0,245]},{"index":1,"rgb":[255,0,6]}],
"hot":[{"index":0,"rgb":[0,0,0]},{"index":0.3,"rgb":[230,0,0]},{"index":0.6,"rgb":[255,210,0]},{"index":1,"rgb":[255,255,255]}],
"cool":[{"index":0,"rgb":[0,255,255]},{"index":1,"rgb":[255,0,255]}],
"spring":[{"index":0,"rgb":[255,0,255]},{"index":1,"rgb":[255,255,0]}],
"summer":[{"index":0,"rgb":[0,128,102]},{"index":1,"rgb":[255,255,102]}],
"autumn":[{"index":0,"rgb":[255,0,0]},{"index":1,"rgb":[255,255,0]}],
"winter":[{"index":0,"rgb":[0,0,255]},{"index":1,"rgb":[0,255,128]}],
"bone":[{"index":0,"rgb":[0,0,0]},{"index":0.376,"rgb":[84,84,116]},{"index":0.753,"rgb":[169,200,200]},{"index":1,"rgb":[255,255,255]}],
"copper":[{"index":0,"rgb":[0,0,0]},{"index":0.804,"rgb":[255,160,102]},{"index":1,"rgb":[255,199,127]}],
"greys":[{"index":0,"rgb":[0,0,0]},{"index":1,"rgb":[255,255,255]}],
"yignbu":[{"index":0,"rgb":[8,29,88]},{"index":0.125,"rgb":[37,52,148]},{"index":0.25,"rgb":[34,94,168]},{"index":0.375,"rgb":[29,145,192]},{"index":0.5,"rgb":[65,182,196]},{"index":0.625,"rgb":[127,205,187]},{"index":0.75,"rgb":[199,233,180]},{"index":0.875,"rgb":[237,248,217]},{"index":1,"rgb":[255,255,217]}],
"greens":[{"index":0,"rgb":[0,68,27]},{"index":0.125,"rgb":[0,109,44]},{"index":0.25,"rgb":[35,139,69]},{"index":0.375,"rgb":[65,171,93]},{"index":0.5,"rgb":[116,196,118]},{"index":0.625,"rgb":[161,217,155]},{"index":0.75,"rgb":[199,233,192]},{"index":0.875,"rgb":[229,245,224]},{"index":1,"rgb":[247,252,245]}],
"yiorrd":[{"index":0,"rgb":[128,0,38]},{"index":0.125,"rgb":[189,0,38]},{"index":0.25,"rgb":[227,26,28]},{"index":0.375,"rgb":[252,78,42]},{"index":0.5,"rgb":[253,141,60]},{"index":0.625,"rgb":[254,178,76]},{"index":0.75,"rgb":[254,217,118]},{"index":0.875,"rgb":[255,237,160]},{"index":1,"rgb":[255,255,204]}],
"bluered":[{"index":0,"rgb":[0,0,255]},{"index":1,"rgb":[255,0,0]}],
"rdbu":[{"index":0,"rgb":[5,10,172]},{"index":0.35,"rgb":[106,137,247]},{"index":0.5,"rgb":[190,190,190]},{"index":0.6,"rgb":[220,170,132]},{"index":0.7,"rgb":[230,145,90]},{"index":1,"rgb":[178,10,28]}],
"picnic":[{"index":0,"rgb":[0,0,255]},{"index":0.1,"rgb":[51,153,255]},{"index":0.2,"rgb":[102,204,255]},{"index":0.3,"rgb":[153,204,255]},{"index":0.4,"rgb":[204,204,255]},{"index":0.5,"rgb":[255,255,255]},{"index":0.6,"rgb":[255,204,255]},{"index":0.7,"rgb":[255,153,255]},{"index":0.8,"rgb":[255,102,204]},{"index":0.9,"rgb":[255,102,102]},{"index":1,"rgb":[255,0,0]}],
"rainbow":[{"index":0,"rgb":[150,0,90]},{"index":0.125,"rgb":[0,0,200]},{"index":0.25,"rgb":[0,25,255]},{"index":0.375,"rgb":[0,152,255]},{"index":0.5,"rgb":[44,255,150]},{"index":0.625,"rgb":[151,255,0]},{"index":0.75,"rgb":[255,234,0]},{"index":0.875,"rgb":[255,111,0]},{"index":1,"rgb":[255,0,0]}],
"portland":[{"index":0,"rgb":[12,51,131]},{"index":0.25,"rgb":[10,136,186]},{"index":0.5,"rgb":[242,211,56]},{"index":0.75,"rgb":[242,143,56]},{"index":1,"rgb":[217,30,30]}],
"blackbody":[{"index":0,"rgb":[0,0,0]},{"index":0.2,"rgb":[230,0,0]},{"index":0.4,"rgb":[230,210,0]},{"index":0.7,"rgb":[255,255,255]},{"index":1,"rgb":[160,200,255]}],
"earth":[{"index":0,"rgb":[0,0,130]},{"index":0.1,"rgb":[0,180,180]},{"index":0.2,"rgb":[40,210,40]},{"index":0.4,"rgb":[230,230,50]},{"index":0.6,"rgb":[120,70,20]},{"index":1,"rgb":[255,255,255]}],
"electric":[{"index":0,"rgb":[0,0,0]},{"index":0.15,"rgb":[30,0,100]},{"index":0.4,"rgb":[120,0,100]},{"index":0.6,"rgb":[160,90,0]},{"index":0.8,"rgb":[230,200,0]},{"index":1,"rgb":[255,250,220]}],
"alpha": [{"index":0, "rgb": [255,255,255,0]},{"index":0, "rgb": [255,255,255,1]}],
"viridis": [{"index":0,"rgb":[68,1,84]},{"index":0.13,"rgb":[71,44,122]},{"index":0.25,"rgb":[59,81,139]},{"index":0.38,"rgb":[44,113,142]},{"index":0.5,"rgb":[33,144,141]},{"index":0.63,"rgb":[39,173,129]},{"index":0.75,"rgb":[92,200,99]},{"index":0.88,"rgb":[170,220,50]},{"index":1,"rgb":[253,231,37]}],
"inferno": [{"index":0,"rgb":[0,0,4]},{"index":0.13,"rgb":[31,12,72]},{"index":0.25,"rgb":[85,15,109]},{"index":0.38,"rgb":[136,34,106]},{"index":0.5,"rgb":[186,54,85]},{"index":0.63,"rgb":[227,89,51]},{"index":0.75,"rgb":[249,140,10]},{"index":0.88,"rgb":[249,201,50]},{"index":1,"rgb":[252,255,164]}],
"magma": [{"index":0,"rgb":[0,0,4]},{"index":0.13,"rgb":[28,16,68]},{"index":0.25,"rgb":[79,18,123]},{"index":0.38,"rgb":[129,37,129]},{"index":0.5,"rgb":[181,54,122]},{"index":0.63,"rgb":[229,80,100]},{"index":0.75,"rgb":[251,135,97]},{"index":0.88,"rgb":[254,194,135]},{"index":1,"rgb":[252,253,191]}],
"plasma": [{"index":0,"rgb":[13,8,135]},{"index":0.13,"rgb":[75,3,161]},{"index":0.25,"rgb":[125,3,168]},{"index":0.38,"rgb":[168,34,150]},{"index":0.5,"rgb":[203,70,121]},{"index":0.63,"rgb":[229,107,93]},{"index":0.75,"rgb":[248,148,65]},{"index":0.88,"rgb":[253,195,40]},{"index":1,"rgb":[240,249,33]}],
"warm": [{"index":0,"rgb":[125,0,179]},{"index":0.13,"rgb":[172,0,187]},{"index":0.25,"rgb":[219,0,170]},{"index":0.38,"rgb":[255,0,130]},{"index":0.5,"rgb":[255,63,74]},{"index":0.63,"rgb":[255,123,0]},{"index":0.75,"rgb":[234,176,0]},{"index":0.88,"rgb":[190,228,0]},{"index":1,"rgb":[147,255,0]}],
"cool": [{"index":0,"rgb":[125,0,179]},{"index":0.13,"rgb":[116,0,218]},{"index":0.25,"rgb":[98,74,237]},{"index":0.38,"rgb":[68,146,231]},{"index":0.5,"rgb":[0,204,197]},{"index":0.63,"rgb":[0,247,146]},{"index":0.75,"rgb":[0,255,88]},{"index":0.88,"rgb":[40,255,8]},{"index":1,"rgb":[147,255,0]}],
"rainbow-soft": [{"index":0,"rgb":[125,0,179]},{"index":0.1,"rgb":[199,0,180]},{"index":0.2,"rgb":[255,0,121]},{"index":0.3,"rgb":[255,108,0]},{"index":0.4,"rgb":[222,194,0]},{"index":0.5,"rgb":[150,255,0]},{"index":0.6,"rgb":[0,255,55]},{"index":0.7,"rgb":[0,246,150]},{"index":0.8,"rgb":[50,167,222]},{"index":0.9,"rgb":[103,51,235]},{"index":1,"rgb":[124,0,186]}],
"bathymetry": [{"index":0,"rgb":[40,26,44]},{"index":0.13,"rgb":[59,49,90]},{"index":0.25,"rgb":[64,76,139]},{"index":0.38,"rgb":[63,110,151]},{"index":0.5,"rgb":[72,142,158]},{"index":0.63,"rgb":[85,174,163]},{"index":0.75,"rgb":[120,206,163]},{"index":0.88,"rgb":[187,230,172]},{"index":1,"rgb":[253,254,204]}],
"cdom": [{"index":0,"rgb":[47,15,62]},{"index":0.13,"rgb":[87,23,86]},{"index":0.25,"rgb":[130,28,99]},{"index":0.38,"rgb":[171,41,96]},{"index":0.5,"rgb":[206,67,86]},{"index":0.63,"rgb":[230,106,84]},{"index":0.75,"rgb":[242,149,103]},{"index":0.88,"rgb":[249,193,135]},{"index":1,"rgb":[254,237,176]}],
"chlorophyll": [{"index":0,"rgb":[18,36,20]},{"index":0.13,"rgb":[25,63,41]},{"index":0.25,"rgb":[24,91,59]},{"index":0.38,"rgb":[13,119,72]},{"index":0.5,"rgb":[18,148,80]},{"index":0.63,"rgb":[80,173,89]},{"index":0.75,"rgb":[132,196,122]},{"index":0.88,"rgb":[175,221,162]},{"index":1,"rgb":[215,249,208]}],
"density": [{"index":0,"rgb":[54,14,36]},{"index":0.13,"rgb":[89,23,80]},{"index":0.25,"rgb":[110,45,132]},{"index":0.38,"rgb":[120,77,178]},{"index":0.5,"rgb":[120,113,213]},{"index":0.63,"rgb":[115,151,228]},{"index":0.75,"rgb":[134,185,227]},{"index":0.88,"rgb":[177,214,227]},{"index":1,"rgb":[230,241,241]}],
"freesurface-blue": [{"index":0,"rgb":[30,4,110]},{"index":0.13,"rgb":[47,14,176]},{"index":0.25,"rgb":[41,45,236]},{"index":0.38,"rgb":[25,99,212]},{"index":0.5,"rgb":[68,131,200]},{"index":0.63,"rgb":[114,156,197]},{"index":0.75,"rgb":[157,181,203]},{"index":0.88,"rgb":[200,208,216]},{"index":1,"rgb":[241,237,236]}],
"freesurface-red": [{"index":0,"rgb":[60,9,18]},{"index":0.13,"rgb":[100,17,27]},{"index":0.25,"rgb":[142,20,29]},{"index":0.38,"rgb":[177,43,27]},{"index":0.5,"rgb":[192,87,63]},{"index":0.63,"rgb":[205,125,105]},{"index":0.75,"rgb":[216,162,148]},{"index":0.88,"rgb":[227,199,193]},{"index":1,"rgb":[241,237,236]}],
"oxygen": [{"index":0,"rgb":[64,5,5]},{"index":0.13,"rgb":[106,6,15]},{"index":0.25,"rgb":[144,26,7]},{"index":0.38,"rgb":[168,64,3]},{"index":0.5,"rgb":[188,100,4]},{"index":0.63,"rgb":[206,136,11]},{"index":0.75,"rgb":[220,174,25]},{"index":0.88,"rgb":[231,215,44]},{"index":1,"rgb":[248,254,105]}],
"par": [{"index":0,"rgb":[51,20,24]},{"index":0.13,"rgb":[90,32,35]},{"index":0.25,"rgb":[129,44,34]},{"index":0.38,"rgb":[159,68,25]},{"index":0.5,"rgb":[182,99,19]},{"index":0.63,"rgb":[199,134,22]},{"index":0.75,"rgb":[212,171,35]},{"index":0.88,"rgb":[221,210,54]},{"index":1,"rgb":[225,253,75]}],
"phase": [{"index":0,"rgb":[145,105,18]},{"index":0.13,"rgb":[184,71,38]},{"index":0.25,"rgb":[186,58,115]},{"index":0.38,"rgb":[160,71,185]},{"index":0.5,"rgb":[110,97,218]},{"index":0.63,"rgb":[50,123,164]},{"index":0.75,"rgb":[31,131,110]},{"index":0.88,"rgb":[77,129,34]},{"index":1,"rgb":[145,105,18]}],
"salinity": [{"index":0,"rgb":[42,24,108]},{"index":0.13,"rgb":[33,50,162]},{"index":0.25,"rgb":[15,90,145]},{"index":0.38,"rgb":[40,118,137]},{"index":0.5,"rgb":[59,146,135]},{"index":0.63,"rgb":[79,175,126]},{"index":0.75,"rgb":[120,203,104]},{"index":0.88,"rgb":[193,221,100]},{"index":1,"rgb":[253,239,154]}],
"temperature": [{"index":0,"rgb":[4,35,51]},{"index":0.13,"rgb":[23,51,122]},{"index":0.25,"rgb":[85,59,157]},{"index":0.38,"rgb":[129,79,143]},{"index":0.5,"rgb":[175,95,130]},{"index":0.63,"rgb":[222,112,101]},{"index":0.75,"rgb":[249,146,66]},{"index":0.88,"rgb":[249,196,65]},{"index":1,"rgb":[232,250,91]}],
"turbidity": [{"index":0,"rgb":[34,31,27]},{"index":0.13,"rgb":[65,50,41]},{"index":0.25,"rgb":[98,69,52]},{"index":0.38,"rgb":[131,89,57]},{"index":0.5,"rgb":[161,112,59]},{"index":0.63,"rgb":[185,140,66]},{"index":0.75,"rgb":[202,174,88]},{"index":0.88,"rgb":[216,209,126]},{"index":1,"rgb":[233,246,171]}],
"velocity-blue": [{"index":0,"rgb":[17,32,64]},{"index":0.13,"rgb":[35,52,116]},{"index":0.25,"rgb":[29,81,156]},{"index":0.38,"rgb":[31,113,162]},{"index":0.5,"rgb":[50,144,169]},{"index":0.63,"rgb":[87,173,176]},{"index":0.75,"rgb":[149,196,189]},{"index":0.88,"rgb":[203,221,211]},{"index":1,"rgb":[254,251,230]}],
"velocity-green": [{"index":0,"rgb":[23,35,19]},{"index":0.13,"rgb":[24,64,38]},{"index":0.25,"rgb":[11,95,45]},{"index":0.38,"rgb":[39,123,35]},{"index":0.5,"rgb":[95,146,12]},{"index":0.63,"rgb":[152,165,18]},{"index":0.75,"rgb":[201,186,69]},{"index":0.88,"rgb":[233,216,137]},{"index":1,"rgb":[255,253,205]}],
"cubehelix": [{"index":0,"rgb":[0,0,0]},{"index":0.07,"rgb":[22,5,59]},{"index":0.13,"rgb":[60,4,105]},{"index":0.2,"rgb":[109,1,135]},{"index":0.27,"rgb":[161,0,147]},{"index":0.33,"rgb":[210,2,142]},{"index":0.4,"rgb":[251,11,123]},{"index":0.47,"rgb":[255,29,97]},{"index":0.53,"rgb":[255,54,69]},{"index":0.6,"rgb":[255,85,46]},{"index":0.67,"rgb":[255,120,34]},{"index":0.73,"rgb":[255,157,37]},{"index":0.8,"rgb":[241,191,57]},{"index":0.87,"rgb":[224,220,93]},{"index":0.93,"rgb":[218,241,142]},{"index":1,"rgb":[227,253,198]}]
};
},{}],95:[function(require,module,exports){
/*
* Ben Postlethwaite
* January 2013
* License MIT
*/
'use strict';
var at = require('arraytools');
var clone = require('clone');
var colorScale = require('./colorScales');
module.exports = createColormap;
function createColormap (spec) {
/*
* Default Options
*/
var indicies, rgba, fromrgba, torgba,
nsteps, cmap, colormap, format,
nshades, colors, alpha, index, i,
r = [],
g = [],
b = [],
a = [];
if ( !at.isPlainObject(spec) ) spec = {};
nshades = spec.nshades || 72;
format = spec.format || 'hex';
colormap = spec.colormap;
if (!colormap) colormap = 'jet';
if (typeof colormap === 'string') {
colormap = colormap.toLowerCase();
if (!colorScale[colormap]) {
throw Error(colormap + ' not a supported colorscale');
}
cmap = clone(colorScale[colormap]);
} else if (Array.isArray(colormap)) {
cmap = clone(colormap);
} else {
throw Error('unsupported colormap option', colormap);
}
if (cmap.length > nshades) {
throw new Error(
colormap+' map requires nshades to be at least size '+cmap.length
);
}
if (!Array.isArray(spec.alpha)) {
if (typeof spec.alpha === 'number') {
alpha = [spec.alpha, spec.alpha];
} else {
alpha = [1, 1];
}
} else if (spec.alpha.length !== 2) {
alpha = [1, 1];
} else {
alpha = clone(spec.alpha);
}
/*
* map index points from 0->1 to 0 -> n-1
*/
indicies = cmap.map(function(c) {
return Math.round(c.index * nshades);
});
/*
* Add alpha channel to the map
*/
if (alpha[0] < 0) alpha[0] = 0;
if (alpha[1] < 0) alpha[0] = 0;
if (alpha[0] > 1) alpha[0] = 1;
if (alpha[1] > 1) alpha[0] = 1;
for (i = 0; i < indicies.length; ++i) {
index = cmap[i].index;
rgba = cmap[i].rgb;
// if user supplies their own map use it
if (rgba.length === 4 && rgba[3] >= 0 && rgba[3] <= 1) continue;
rgba[3] = alpha[0] + (alpha[1] - alpha[0])*index;
}
/*
* map increasing linear values between indicies to
* linear steps in colorvalues
*/
for (i = 0; i < indicies.length-1; ++i) {
nsteps = indicies[i+1] - indicies[i];
fromrgba = cmap[i].rgb;
torgba = cmap[i+1].rgb;
r = r.concat(at.linspace(fromrgba[0], torgba[0], nsteps ) );
g = g.concat(at.linspace(fromrgba[1], torgba[1], nsteps ) );
b = b.concat(at.linspace(fromrgba[2], torgba[2], nsteps ) );
a = a.concat(at.linspace(fromrgba[3], torgba[3], nsteps ) );
}
r = r.map( Math.round );
g = g.map( Math.round );
b = b.map( Math.round );
colors = at.zip(r, g, b, a);
if (format === 'hex') colors = colors.map( rgb2hex );
if (format === 'rgbaString') colors = colors.map( rgbaStr );
return colors;
};
function rgb2hex (rgba) {
var dig, hex = '#';
for (var i = 0; i < 3; ++i) {
dig = rgba[i];
dig = dig.toString(16);
hex += ('00' + dig).substr( dig.length );
}
return hex;
}
function rgbaStr (rgba) {
return 'rgba(' + rgba.join(',') + ')';
}
},{"./colorScales":94,"arraytools":42,"clone":87}],96:[function(require,module,exports){
"use strict"
module.exports = compareAngle
var orient = require("robust-orientation")
var sgn = require("signum")
var twoSum = require("two-sum")
var robustProduct = require("robust-product")
var robustSum = require("robust-sum")
function testInterior(a, b, c) {
var x0 = twoSum(a[0], -b[0])
var y0 = twoSum(a[1], -b[1])
var x1 = twoSum(c[0], -b[0])
var y1 = twoSum(c[1], -b[1])
var d = robustSum(
robustProduct(x0, x1),
robustProduct(y0, y1))
return d[d.length-1] >= 0
}
function compareAngle(a, b, c, d) {
var bcd = orient(b, c, d)
if(bcd === 0) {
//Handle degenerate cases
var sabc = sgn(orient(a, b, c))
var sabd = sgn(orient(a, b, d))
if(sabc === sabd) {
if(sabc === 0) {
var ic = testInterior(a, b, c)
var id = testInterior(a, b, d)
if(ic === id) {
return 0
} else if(ic) {
return 1
} else {
return -1
}
}
return 0
} else if(sabd === 0) {
if(sabc > 0) {
return -1
} else if(testInterior(a, b, d)) {
return -1
} else {
return 1
}
} else if(sabc === 0) {
if(sabd > 0) {
return 1
} else if(testInterior(a, b, c)) {
return 1
} else {
return -1
}
}
return sgn(sabd - sabc)
}
var abc = orient(a, b, c)
if(abc > 0) {
if(bcd > 0 && orient(a, b, d) > 0) {
return 1
}
return -1
} else if(abc < 0) {
if(bcd > 0 || orient(a, b, d) > 0) {
return 1
}
return -1
} else {
var abd = orient(a, b, d)
if(abd > 0) {
return 1
} else {
if(testInterior(a, b, c)) {
return 1
} else {
return -1
}
}
}
}
},{"robust-orientation":500,"robust-product":501,"robust-sum":505,"signum":507,"two-sum":532}],97:[function(require,module,exports){
module.exports = compareCells
var min = Math.min
function compareInt(a, b) {
return a - b
}
function compareCells(a, b) {
var n = a.length
, t = a.length - b.length
if(t) {
return t
}
switch(n) {
case 0:
return 0
case 1:
return a[0] - b[0]
case 2:
return (a[0]+a[1]-b[0]-b[1]) ||
min(a[0],a[1]) - min(b[0],b[1])
case 3:
var l1 = a[0]+a[1]
, m1 = b[0]+b[1]
t = l1+a[2] - (m1+b[2])
if(t) {
return t
}
var l0 = min(a[0], a[1])
, m0 = min(b[0], b[1])
return min(l0, a[2]) - min(m0, b[2]) ||
min(l0+a[2], l1) - min(m0+b[2], m1)
case 4:
var aw=a[0], ax=a[1], ay=a[2], az=a[3]
, bw=b[0], bx=b[1], by=b[2], bz=b[3]
return (aw+ax+ay+az)-(bw+bx+by+bz) ||
min(aw,ax,ay,az)-min(bw,bx,by,bz,bw) ||
min(aw+ax,aw+ay,aw+az,ax+ay,ax+az,ay+az) -
min(bw+bx,bw+by,bw+bz,bx+by,bx+bz,by+bz) ||
min(aw+ax+ay,aw+ax+az,aw+ay+az,ax+ay+az) -
min(bw+bx+by,bw+bx+bz,bw+by+bz,bx+by+bz)
default:
var as = a.slice().sort(compareInt)
var bs = b.slice().sort(compareInt)
for(var i=0; i points[hi][0]) {
hi = i
}
}
if(lo < hi) {
return [[lo], [hi]]
} else if(lo > hi) {
return [[hi], [lo]]
} else {
return [[lo]]
}
}
},{}],101:[function(require,module,exports){
'use strict'
module.exports = convexHull2D
var monotoneHull = require('monotone-convex-hull-2d')
function convexHull2D(points) {
var hull = monotoneHull(points)
var h = hull.length
if(h <= 2) {
return []
}
var edges = new Array(h)
var a = hull[h-1]
for(var i=0; i= front[k]) {
x += 1
}
}
c[j] = x
}
}
}
return cells
}
function convexHullnD(points, d) {
try {
return ich(points, true)
} catch(e) {
//If point set is degenerate, try to find a basis and rerun it
var ah = aff(points)
if(ah.length <= d) {
//No basis, no try
return []
}
var npoints = permute(points, ah)
var nhull = ich(npoints, true)
return invPermute(nhull, ah)
}
}
},{"affine-hull":39,"incremental-convex-hull":284}],103:[function(require,module,exports){
module.exports = {
AFG: 'afghan',
ALA: '\\b\\wland',
ALB: 'albania',
DZA: 'algeria',
ASM: '^(?=.*americ).*samoa',
AND: 'andorra',
AGO: 'angola',
AIA: 'anguill?a',
ATA: 'antarctica',
ATG: 'antigua',
ARG: 'argentin',
ARM: 'armenia',
ABW: '^(?!.*bonaire).*\\baruba',
AUS: 'australia',
AUT: '^(?!.*hungary).*austria|\\baustri.*\\bemp',
AZE: 'azerbaijan',
BHS: 'bahamas',
BHR: 'bahrain',
BGD: 'bangladesh|^(?=.*east).*paki?stan',
BRB: 'barbados',
BLR: 'belarus|byelo',
BEL: '^(?!.*luxem).*belgium',
BLZ: 'belize|^(?=.*british).*honduras',
BEN: 'benin|dahome',
BMU: 'bermuda',
BTN: 'bhutan',
BOL: 'bolivia',
BES: '^(?=.*bonaire).*eustatius|^(?=.*carib).*netherlands|\\bbes.?islands',
BIH: 'herzegovina|bosnia',
BWA: 'botswana|bechuana',
BVT: 'bouvet',
BRA: 'brazil',
IOT: 'british.?indian.?ocean',
BRN: 'brunei',
BGR: 'bulgaria',
BFA: 'burkina|\\bfaso|upper.?volta',
BDI: 'burundi',
CPV: 'verde',
KHM: 'cambodia|kampuchea|khmer',
CMR: 'cameroon',
CAN: 'canada',
CYM: 'cayman',
CAF: '\\bcentral.african.republic',
TCD: '\\bchad',
CHL: '\\bchile',
CHN: '^(?!.*\\bmac)(?!.*\\bhong)(?!.*\\btai)(?!.*\\brep).*china|^(?=.*peo)(?=.*rep).*china',
CXR: 'christmas',
CCK: '\\bcocos|keeling',
COL: 'colombia',
COM: 'comoro',
COG: '^(?!.*\\bdem)(?!.*\\bd[\\.]?r)(?!.*kinshasa)(?!.*zaire)(?!.*belg)(?!.*l.opoldville)(?!.*free).*\\bcongo',
COK: '\\bcook',
CRI: 'costa.?rica',
CIV: 'ivoire|ivory',
HRV: 'croatia',
CUB: '\\bcuba',
CUW: '^(?!.*bonaire).*\\bcura(c|ç)ao',
CYP: 'cyprus',
CSK: 'czechoslovakia',
CZE: '^(?=.*rep).*czech|czechia|bohemia',
COD: '\\bdem.*congo|congo.*\\bdem|congo.*\\bd[\\.]?r|\\bd[\\.]?r.*congo|belgian.?congo|congo.?free.?state|kinshasa|zaire|l.opoldville|drc|droc|rdc',
DNK: 'denmark',
DJI: 'djibouti',
DMA: 'dominica(?!n)',
DOM: 'dominican.rep',
ECU: 'ecuador',
EGY: 'egypt',
SLV: 'el.?salvador',
GNQ: 'guine.*eq|eq.*guine|^(?=.*span).*guinea',
ERI: 'eritrea',
EST: 'estonia',
ETH: 'ethiopia|abyssinia',
FLK: 'falkland|malvinas',
FRO: 'faroe|faeroe',
FJI: 'fiji',
FIN: 'finland',
FRA: '^(?!.*\\bdep)(?!.*martinique).*france|french.?republic|\\bgaul',
GUF: '^(?=.*french).*guiana',
PYF: 'french.?polynesia|tahiti',
ATF: 'french.?southern',
GAB: 'gabon',
GMB: 'gambia',
GEO: '^(?!.*south).*georgia',
DDR: 'german.?democratic.?republic|democratic.?republic.*germany|east.germany',
DEU: '^(?!.*east).*germany|^(?=.*\\bfed.*\\brep).*german',
GHA: 'ghana|gold.?coast',
GIB: 'gibraltar',
GRC: 'greece|hellenic|hellas',
GRL: 'greenland',
GRD: 'grenada',
GLP: 'guadeloupe',
GUM: '\\bguam',
GTM: 'guatemala',
GGY: 'guernsey',
GIN: '^(?!.*eq)(?!.*span)(?!.*bissau)(?!.*portu)(?!.*new).*guinea',
GNB: 'bissau|^(?=.*portu).*guinea',
GUY: 'guyana|british.?guiana',
HTI: 'haiti',
HMD: 'heard.*mcdonald',
VAT: 'holy.?see|vatican|papal.?st',
HND: '^(?!.*brit).*honduras',
HKG: 'hong.?kong',
HUN: '^(?!.*austr).*hungary',
ISL: 'iceland',
IND: 'india(?!.*ocea)',
IDN: 'indonesia',
IRN: '\\biran|persia',
IRQ: '\\biraq|mesopotamia',
IRL: '(^ireland)|(^republic.*ireland)',
IMN: '^(?=.*isle).*\\bman',
ISR: 'israel',
ITA: 'italy',
JAM: 'jamaica',
JPN: 'japan',
JEY: 'jersey',
JOR: 'jordan',
KAZ: 'kazak',
KEN: 'kenya|british.?east.?africa|east.?africa.?prot',
KIR: 'kiribati',
PRK: '^(?=.*democrat|people|north|d.*p.*.r).*\\bkorea|dprk|korea.*(d.*p.*r)',
KWT: 'kuwait',
KGZ: 'kyrgyz|kirghiz',
LAO: '\\blaos?\\b',
LVA: 'latvia',
LBN: 'lebanon',
LSO: 'lesotho|basuto',
LBR: 'liberia',
LBY: 'libya',
LIE: 'liechtenstein',
LTU: 'lithuania',
LUX: '^(?!.*belg).*luxem',
MAC: 'maca(o|u)',
MDG: 'madagascar|malagasy',
MWI: 'malawi|nyasa',
MYS: 'malaysia',
MDV: 'maldive',
MLI: '\\bmali\\b',
MLT: '\\bmalta',
MHL: 'marshall',
MTQ: 'martinique',
MRT: 'mauritania',
MUS: 'mauritius',
MYT: '\\bmayotte',
MEX: '\\bmexic',
FSM: 'fed.*micronesia|micronesia.*fed',
MCO: 'monaco',
MNG: 'mongolia',
MNE: '^(?!.*serbia).*montenegro',
MSR: 'montserrat',
MAR: 'morocco|\\bmaroc',
MOZ: 'mozambique',
MMR: 'myanmar|burma',
NAM: 'namibia',
NRU: 'nauru',
NPL: 'nepal',
NLD: '^(?!.*\\bant)(?!.*\\bcarib).*netherlands',
ANT: '^(?=.*\\bant).*(nether|dutch)',
NCL: 'new.?caledonia',
NZL: 'new.?zealand',
NIC: 'nicaragua',
NER: '\\bniger(?!ia)',
NGA: 'nigeria',
NIU: 'niue',
NFK: 'norfolk',
MNP: 'mariana',
NOR: 'norway',
OMN: '\\boman|trucial',
PAK: '^(?!.*east).*paki?stan',
PLW: 'palau',
PSE: 'palestin|\\bgaza|west.?bank',
PAN: 'panama',
PNG: 'papua|new.?guinea',
PRY: 'paraguay',
PER: 'peru',
PHL: 'philippines',
PCN: 'pitcairn',
POL: 'poland',
PRT: 'portugal',
PRI: 'puerto.?rico',
QAT: 'qatar',
KOR: '^(?!.*d.*p.*r)(?!.*democrat)(?!.*people)(?!.*north).*\\bkorea(?!.*d.*p.*r)',
MDA: 'moldov|b(a|e)ssarabia',
REU: 'r(e|é)union',
ROU: 'r(o|u|ou)mania',
RUS: '\\brussia|soviet.?union|u\\.?s\\.?s\\.?r|socialist.?republics',
RWA: 'rwanda',
BLM: 'barth(e|é)lemy',
SHN: 'helena',
KNA: 'kitts|\\bnevis',
LCA: '\\blucia',
MAF: '^(?=.*collectivity).*martin|^(?=.*france).*martin(?!ique)|^(?=.*french).*martin(?!ique)',
SPM: 'miquelon',
VCT: 'vincent',
WSM: '^(?!.*amer).*samoa',
SMR: 'san.?marino',
STP: '\\bs(a|ã)o.?tom(e|é)',
SAU: '\\bsa\\w*.?arabia',
SEN: 'senegal',
SRB: '^(?!.*monte).*serbia',
SYC: 'seychell',
SLE: 'sierra',
SGP: 'singapore',
SXM: '^(?!.*martin)(?!.*saba).*maarten',
SVK: '^(?!.*cze).*slovak',
SVN: 'slovenia',
SLB: 'solomon',
SOM: 'somali',
ZAF: 'south.africa|s\\\\..?africa',
SGS: 'south.?georgia|sandwich',
SSD: '\\bs\\w*.?sudan',
ESP: 'spain',
LKA: 'sri.?lanka|ceylon',
SDN: '^(?!.*\\bs(?!u)).*sudan',
SUR: 'surinam|dutch.?guiana',
SJM: 'svalbard',
SWZ: 'swaziland',
SWE: 'sweden',
CHE: 'switz|swiss',
SYR: 'syria',
TWN: 'taiwan|taipei|formosa|^(?!.*peo)(?=.*rep).*china',
TJK: 'tajik',
THA: 'thailand|\\bsiam',
MKD: 'macedonia|fyrom',
TLS: '^(?=.*leste).*timor|^(?=.*east).*timor',
TGO: 'togo',
TKL: 'tokelau',
TON: 'tonga',
TTO: 'trinidad|tobago',
TUN: 'tunisia',
TUR: 'turkey',
TKM: 'turkmen',
TCA: 'turks',
TUV: 'tuvalu',
UGA: 'uganda',
UKR: 'ukrain',
ARE: 'emirates|^u\\.?a\\.?e\\.?$|united.?arab.?em',
GBR: 'united.?kingdom|britain|^u\\.?k\\.?$',
TZA: 'tanzania',
USA: 'united.?states\\b(?!.*islands)|\\bu\\.?s\\.?a\\.?\\b|^\\s*u\\.?s\\.?\\b(?!.*islands)',
UMI: 'minor.?outlying.?is',
URY: 'uruguay',
UZB: 'uzbek',
VUT: 'vanuatu|new.?hebrides',
VEN: 'venezuela',
VNM: '^(?!.*republic).*viet.?nam|^(?=.*socialist).*viet.?nam',
VGB: '^(?=.*\\bu\\.?\\s?k).*virgin|^(?=.*brit).*virgin|^(?=.*kingdom).*virgin',
VIR: '^(?=.*\\bu\\.?\\s?s).*virgin|^(?=.*states).*virgin',
WLF: 'futuna|wallis',
ESH: 'western.sahara',
YEM: '^(?!.*arab)(?!.*north)(?!.*sana)(?!.*peo)(?!.*dem)(?!.*south)(?!.*aden)(?!.*\\bp\\.?d\\.?r).*yemen',
YMD: '^(?=.*peo).*yemen|^(?!.*rep)(?=.*dem).*yemen|^(?=.*south).*yemen|^(?=.*aden).*yemen|^(?=.*\\bp\\.?d\\.?r).*yemen',
YUG: 'yugoslavia',
ZMB: 'zambia|northern.?rhodesia',
EAZ: 'zanzibar',
ZWE: 'zimbabwe|^(?!.*northern).*rhodesia'
}
},{}],104:[function(require,module,exports){
// (c) Dean McNamee , 2012.
//
// https://github.com/deanm/css-color-parser-js
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// http://www.w3.org/TR/css3-color/
var kCSSColorTable = {
"transparent": [0,0,0,0], "aliceblue": [240,248,255,1],
"antiquewhite": [250,235,215,1], "aqua": [0,255,255,1],
"aquamarine": [127,255,212,1], "azure": [240,255,255,1],
"beige": [245,245,220,1], "bisque": [255,228,196,1],
"black": [0,0,0,1], "blanchedalmond": [255,235,205,1],
"blue": [0,0,255,1], "blueviolet": [138,43,226,1],
"brown": [165,42,42,1], "burlywood": [222,184,135,1],
"cadetblue": [95,158,160,1], "chartreuse": [127,255,0,1],
"chocolate": [210,105,30,1], "coral": [255,127,80,1],
"cornflowerblue": [100,149,237,1], "cornsilk": [255,248,220,1],
"crimson": [220,20,60,1], "cyan": [0,255,255,1],
"darkblue": [0,0,139,1], "darkcyan": [0,139,139,1],
"darkgoldenrod": [184,134,11,1], "darkgray": [169,169,169,1],
"darkgreen": [0,100,0,1], "darkgrey": [169,169,169,1],
"darkkhaki": [189,183,107,1], "darkmagenta": [139,0,139,1],
"darkolivegreen": [85,107,47,1], "darkorange": [255,140,0,1],
"darkorchid": [153,50,204,1], "darkred": [139,0,0,1],
"darksalmon": [233,150,122,1], "darkseagreen": [143,188,143,1],
"darkslateblue": [72,61,139,1], "darkslategray": [47,79,79,1],
"darkslategrey": [47,79,79,1], "darkturquoise": [0,206,209,1],
"darkviolet": [148,0,211,1], "deeppink": [255,20,147,1],
"deepskyblue": [0,191,255,1], "dimgray": [105,105,105,1],
"dimgrey": [105,105,105,1], "dodgerblue": [30,144,255,1],
"firebrick": [178,34,34,1], "floralwhite": [255,250,240,1],
"forestgreen": [34,139,34,1], "fuchsia": [255,0,255,1],
"gainsboro": [220,220,220,1], "ghostwhite": [248,248,255,1],
"gold": [255,215,0,1], "goldenrod": [218,165,32,1],
"gray": [128,128,128,1], "green": [0,128,0,1],
"greenyellow": [173,255,47,1], "grey": [128,128,128,1],
"honeydew": [240,255,240,1], "hotpink": [255,105,180,1],
"indianred": [205,92,92,1], "indigo": [75,0,130,1],
"ivory": [255,255,240,1], "khaki": [240,230,140,1],
"lavender": [230,230,250,1], "lavenderblush": [255,240,245,1],
"lawngreen": [124,252,0,1], "lemonchiffon": [255,250,205,1],
"lightblue": [173,216,230,1], "lightcoral": [240,128,128,1],
"lightcyan": [224,255,255,1], "lightgoldenrodyellow": [250,250,210,1],
"lightgray": [211,211,211,1], "lightgreen": [144,238,144,1],
"lightgrey": [211,211,211,1], "lightpink": [255,182,193,1],
"lightsalmon": [255,160,122,1], "lightseagreen": [32,178,170,1],
"lightskyblue": [135,206,250,1], "lightslategray": [119,136,153,1],
"lightslategrey": [119,136,153,1], "lightsteelblue": [176,196,222,1],
"lightyellow": [255,255,224,1], "lime": [0,255,0,1],
"limegreen": [50,205,50,1], "linen": [250,240,230,1],
"magenta": [255,0,255,1], "maroon": [128,0,0,1],
"mediumaquamarine": [102,205,170,1], "mediumblue": [0,0,205,1],
"mediumorchid": [186,85,211,1], "mediumpurple": [147,112,219,1],
"mediumseagreen": [60,179,113,1], "mediumslateblue": [123,104,238,1],
"mediumspringgreen": [0,250,154,1], "mediumturquoise": [72,209,204,1],
"mediumvioletred": [199,21,133,1], "midnightblue": [25,25,112,1],
"mintcream": [245,255,250,1], "mistyrose": [255,228,225,1],
"moccasin": [255,228,181,1], "navajowhite": [255,222,173,1],
"navy": [0,0,128,1], "oldlace": [253,245,230,1],
"olive": [128,128,0,1], "olivedrab": [107,142,35,1],
"orange": [255,165,0,1], "orangered": [255,69,0,1],
"orchid": [218,112,214,1], "palegoldenrod": [238,232,170,1],
"palegreen": [152,251,152,1], "paleturquoise": [175,238,238,1],
"palevioletred": [219,112,147,1], "papayawhip": [255,239,213,1],
"peachpuff": [255,218,185,1], "peru": [205,133,63,1],
"pink": [255,192,203,1], "plum": [221,160,221,1],
"powderblue": [176,224,230,1], "purple": [128,0,128,1],
"rebeccapurple": [102,51,153,1],
"red": [255,0,0,1], "rosybrown": [188,143,143,1],
"royalblue": [65,105,225,1], "saddlebrown": [139,69,19,1],
"salmon": [250,128,114,1], "sandybrown": [244,164,96,1],
"seagreen": [46,139,87,1], "seashell": [255,245,238,1],
"sienna": [160,82,45,1], "silver": [192,192,192,1],
"skyblue": [135,206,235,1], "slateblue": [106,90,205,1],
"slategray": [112,128,144,1], "slategrey": [112,128,144,1],
"snow": [255,250,250,1], "springgreen": [0,255,127,1],
"steelblue": [70,130,180,1], "tan": [210,180,140,1],
"teal": [0,128,128,1], "thistle": [216,191,216,1],
"tomato": [255,99,71,1], "turquoise": [64,224,208,1],
"violet": [238,130,238,1], "wheat": [245,222,179,1],
"white": [255,255,255,1], "whitesmoke": [245,245,245,1],
"yellow": [255,255,0,1], "yellowgreen": [154,205,50,1]}
function clamp_css_byte(i) { // Clamp to integer 0 .. 255.
i = Math.round(i); // Seems to be what Chrome does (vs truncation).
return i < 0 ? 0 : i > 255 ? 255 : i;
}
function clamp_css_float(f) { // Clamp to float 0.0 .. 1.0.
return f < 0 ? 0 : f > 1 ? 1 : f;
}
function parse_css_int(str) { // int or percentage.
if (str[str.length - 1] === '%')
return clamp_css_byte(parseFloat(str) / 100 * 255);
return clamp_css_byte(parseInt(str));
}
function parse_css_float(str) { // float or percentage.
if (str[str.length - 1] === '%')
return clamp_css_float(parseFloat(str) / 100);
return clamp_css_float(parseFloat(str));
}
function css_hue_to_rgb(m1, m2, h) {
if (h < 0) h += 1;
else if (h > 1) h -= 1;
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
if (h * 2 < 1) return m2;
if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
return m1;
}
function parseCSSColor(css_str) {
// Remove all whitespace, not compliant, but should just be more accepting.
var str = css_str.replace(/ /g, '').toLowerCase();
// Color keywords (and transparent) lookup.
if (str in kCSSColorTable) return kCSSColorTable[str].slice(); // dup.
// #abc and #abc123 syntax.
if (str[0] === '#') {
if (str.length === 4) {
var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
if (!(iv >= 0 && iv <= 0xfff)) return null; // Covers NaN.
return [((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
(iv & 0xf0) | ((iv & 0xf0) >> 4),
(iv & 0xf) | ((iv & 0xf) << 4),
1];
} else if (str.length === 7) {
var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing.
if (!(iv >= 0 && iv <= 0xffffff)) return null; // Covers NaN.
return [(iv & 0xff0000) >> 16,
(iv & 0xff00) >> 8,
iv & 0xff,
1];
}
return null;
}
var op = str.indexOf('('), ep = str.indexOf(')');
if (op !== -1 && ep + 1 === str.length) {
var fname = str.substr(0, op);
var params = str.substr(op+1, ep-(op+1)).split(',');
var alpha = 1; // To allow case fallthrough.
switch (fname) {
case 'rgba':
if (params.length !== 4) return null;
alpha = parse_css_float(params.pop());
// Fall through.
case 'rgb':
if (params.length !== 3) return null;
return [parse_css_int(params[0]),
parse_css_int(params[1]),
parse_css_int(params[2]),
alpha];
case 'hsla':
if (params.length !== 4) return null;
alpha = parse_css_float(params.pop());
// Fall through.
case 'hsl':
if (params.length !== 3) return null;
var h = (((parseFloat(params[0]) % 360) + 360) % 360) / 360; // 0 .. 1
// NOTE(deanm): According to the CSS spec s/l should only be
// percentages, but we don't bother and let float or percentage.
var s = parse_css_float(params[1]);
var l = parse_css_float(params[2]);
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
var m1 = l * 2 - m2;
return [clamp_css_byte(css_hue_to_rgb(m1, m2, h+1/3) * 255),
clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255),
clamp_css_byte(css_hue_to_rgb(m1, m2, h-1/3) * 255),
alpha];
default:
return null;
}
}
return null;
}
try { exports.parseCSSColor = parseCSSColor } catch(e) { }
},{}],105:[function(require,module,exports){
"use strict"
function dcubicHermite(p0, v0, p1, v1, t, f) {
var dh00 = 6*t*t-6*t,
dh10 = 3*t*t-4*t + 1,
dh01 = -6*t*t+6*t,
dh11 = 3*t*t-2*t
if(p0.length) {
if(!f) {
f = new Array(p0.length)
}
for(var i=p0.length-1; i>=0; --i) {
f[i] = dh00*p0[i] + dh10*v0[i] + dh01*p1[i] + dh11*v1[i]
}
return f
}
return dh00*p0 + dh10*v0 + dh01*p1[i] + dh11*v1
}
function cubicHermite(p0, v0, p1, v1, t, f) {
var ti = (t-1), t2 = t*t, ti2 = ti*ti,
h00 = (1+2*t)*ti2,
h10 = t*ti2,
h01 = t2*(3-2*t),
h11 = t2*ti
if(p0.length) {
if(!f) {
f = new Array(p0.length)
}
for(var i=p0.length-1; i>=0; --i) {
f[i] = h00*p0[i] + h10*v0[i] + h01*p1[i] + h11*v1[i]
}
return f
}
return h00*p0 + h10*v0 + h01*p1 + h11*v1
}
module.exports = cubicHermite
module.exports.derivative = dcubicHermite
},{}],106:[function(require,module,exports){
"use strict"
var createThunk = require("./lib/thunk.js")
function Procedure() {
this.argTypes = []
this.shimArgs = []
this.arrayArgs = []
this.arrayBlockIndices = []
this.scalarArgs = []
this.offsetArgs = []
this.offsetArgIndex = []
this.indexArgs = []
this.shapeArgs = []
this.funcName = ""
this.pre = null
this.body = null
this.post = null
this.debug = false
}
function compileCwise(user_args) {
//Create procedure
var proc = new Procedure()
//Parse blocks
proc.pre = user_args.pre
proc.body = user_args.body
proc.post = user_args.post
//Parse arguments
var proc_args = user_args.args.slice(0)
proc.argTypes = proc_args
for(var i=0; i0) {
throw new Error("cwise: pre() block may not reference array args")
}
if(i < proc.post.args.length && proc.post.args[i].count>0) {
throw new Error("cwise: post() block may not reference array args")
}
} else if(arg_type === "scalar") {
proc.scalarArgs.push(i)
proc.shimArgs.push("scalar" + i)
} else if(arg_type === "index") {
proc.indexArgs.push(i)
if(i < proc.pre.args.length && proc.pre.args[i].count > 0) {
throw new Error("cwise: pre() block may not reference array index")
}
if(i < proc.body.args.length && proc.body.args[i].lvalue) {
throw new Error("cwise: body() block may not write to array index")
}
if(i < proc.post.args.length && proc.post.args[i].count > 0) {
throw new Error("cwise: post() block may not reference array index")
}
} else if(arg_type === "shape") {
proc.shapeArgs.push(i)
if(i < proc.pre.args.length && proc.pre.args[i].lvalue) {
throw new Error("cwise: pre() block may not write to array shape")
}
if(i < proc.body.args.length && proc.body.args[i].lvalue) {
throw new Error("cwise: body() block may not write to array shape")
}
if(i < proc.post.args.length && proc.post.args[i].lvalue) {
throw new Error("cwise: post() block may not write to array shape")
}
} else if(typeof arg_type === "object" && arg_type.offset) {
proc.argTypes[i] = "offset"
proc.offsetArgs.push({ array: arg_type.array, offset:arg_type.offset })
proc.offsetArgIndex.push(i)
} else {
throw new Error("cwise: Unknown argument type " + proc_args[i])
}
}
//Make sure at least one array argument was specified
if(proc.arrayArgs.length <= 0) {
throw new Error("cwise: No array arguments specified")
}
//Make sure arguments are correct
if(proc.pre.args.length > proc_args.length) {
throw new Error("cwise: Too many arguments in pre() block")
}
if(proc.body.args.length > proc_args.length) {
throw new Error("cwise: Too many arguments in body() block")
}
if(proc.post.args.length > proc_args.length) {
throw new Error("cwise: Too many arguments in post() block")
}
//Check debug flag
proc.debug = !!user_args.printCode || !!user_args.debug
//Retrieve name
proc.funcName = user_args.funcName || "cwise"
//Read in block size
proc.blockSize = user_args.blockSize || 64
return createThunk(proc)
}
module.exports = compileCwise
},{"./lib/thunk.js":108}],107:[function(require,module,exports){
"use strict"
var uniq = require("uniq")
// This function generates very simple loops analogous to how you typically traverse arrays (the outermost loop corresponds to the slowest changing index, the innermost loop to the fastest changing index)
// TODO: If two arrays have the same strides (and offsets) there is potential for decreasing the number of "pointers" and related variables. The drawback is that the type signature would become more specific and that there would thus be less potential for caching, but it might still be worth it, especially when dealing with large numbers of arguments.
function innerFill(order, proc, body) {
var dimension = order.length
, nargs = proc.arrayArgs.length
, has_index = proc.indexArgs.length>0
, code = []
, vars = []
, idx=0, pidx=0, i, j
for(i=0; i=0; --i) { // Start at largest stride and work your way inwards
idx = order[i]
code.push(["for(i",i,"=0;i",i," 0) {
code.push(["index[",pidx,"]-=s",pidx].join(""))
}
code.push(["++index[",idx,"]"].join(""))
}
code.push("}")
}
return code.join("\n")
}
// Generate "outer" loops that loop over blocks of data, applying "inner" loops to the blocks by manipulating the local variables in such a way that the inner loop only "sees" the current block.
// TODO: If this is used, then the previous declaration (done by generateCwiseOp) of s* is essentially unnecessary.
// I believe the s* are not used elsewhere (in particular, I don't think they're used in the pre/post parts and "shape" is defined independently), so it would be possible to make defining the s* dependent on what loop method is being used.
function outerFill(matched, order, proc, body) {
var dimension = order.length
, nargs = proc.arrayArgs.length
, blockSize = proc.blockSize
, has_index = proc.indexArgs.length > 0
, code = []
for(var i=0; i0;){"].join("")) // Iterate back to front
code.push(["if(j",i,"<",blockSize,"){"].join("")) // Either decrease j by blockSize (s = blockSize), or set it to zero (after setting s = j).
code.push(["s",order[i],"=j",i].join(""))
code.push(["j",i,"=0"].join(""))
code.push(["}else{s",order[i],"=",blockSize].join(""))
code.push(["j",i,"-=",blockSize,"}"].join(""))
if(has_index) {
code.push(["index[",order[i],"]=j",i].join(""))
}
}
for(var i=0; i 0) {
allEqual = allEqual && summary[i] === summary[i-1]
}
}
if(allEqual) {
return summary[0]
}
return summary.join("")
}
//Generates a cwise operator
function generateCWiseOp(proc, typesig) {
//Compute dimension
// Arrays get put first in typesig, and there are two entries per array (dtype and order), so this gets the number of dimensions in the first array arg.
var dimension = (typesig[1].length - Math.abs(proc.arrayBlockIndices[0]))|0
var orders = new Array(proc.arrayArgs.length)
var dtypes = new Array(proc.arrayArgs.length)
for(var i=0; i 0) {
vars.push("shape=SS.slice(0)") // Makes the shape over which we iterate available to the user defined functions (so you can use width/height for example)
}
if(proc.indexArgs.length > 0) {
// Prepare an array to keep track of the (logical) indices, initialized to dimension zeroes.
var zeros = new Array(dimension)
for(var i=0; i 3) {
code.push(processBlock(proc.pre, proc, dtypes))
}
//Process body
var body = processBlock(proc.body, proc, dtypes)
var matched = countMatches(loopOrders)
if(matched < dimension) {
code.push(outerFill(matched, loopOrders[0], proc, body)) // TODO: Rather than passing loopOrders[0], it might be interesting to look at passing an order that represents the majority of the arguments for example.
} else {
code.push(innerFill(loopOrders[0], proc, body))
}
//Inline epilog
if(proc.post.body.length > 3) {
code.push(processBlock(proc.post, proc, dtypes))
}
if(proc.debug) {
console.log("-----Generated cwise routine for ", typesig, ":\n" + code.join("\n") + "\n----------")
}
var loopName = [(proc.funcName||"unnamed"), "_cwise_loop_", orders[0].join("s"),"m",matched,typeSummary(dtypes)].join("")
var f = new Function(["function ",loopName,"(", arglist.join(","),"){", code.join("\n"),"} return ", loopName].join(""))
return f()
}
module.exports = generateCWiseOp
},{"uniq":535}],108:[function(require,module,exports){
"use strict"
// The function below is called when constructing a cwise function object, and does the following:
// A function object is constructed which accepts as argument a compilation function and returns another function.
// It is this other function that is eventually returned by createThunk, and this function is the one that actually
// checks whether a certain pattern of arguments has already been used before and compiles new loops as needed.
// The compilation passed to the first function object is used for compiling new functions.
// Once this function object is created, it is called with compile as argument, where the first argument of compile
// is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise).
// So createThunk roughly works like this:
// function createThunk(proc) {
// var thunk = function(compileBound) {
// var CACHED = {}
// return function(arrays and scalars) {
// if (dtype and order of arrays in CACHED) {
// var func = CACHED[dtype and order of arrays]
// } else {
// var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays)
// }
// return func(arrays and scalars)
// }
// }
// return thunk(compile.bind1(proc))
// }
var compile = require("./compile.js")
function createThunk(proc) {
var code = ["'use strict'", "var CACHED={}"]
var vars = []
var thunkName = proc.funcName + "_cwise_thunk"
//Build thunk
code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join(""))
var typesig = []
var string_typesig = []
var proc_args = [["array",proc.arrayArgs[0],".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS).
Math.max(0,proc.arrayBlockIndices[0]),proc.arrayBlockIndices[0]<0?(","+proc.arrayBlockIndices[0]+")"):")"].join("")]
var shapeLengthConditions = [], shapeConditions = []
// Process array arguments
for(var i=0; i0) { // Gather conditions to check for shape equality (ignoring block indices)
shapeLengthConditions.push("array" + proc.arrayArgs[0] + ".shape.length===array" + j + ".shape.length+" + (Math.abs(proc.arrayBlockIndices[0])-Math.abs(proc.arrayBlockIndices[i])))
shapeConditions.push("array" + proc.arrayArgs[0] + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[0]) + "]===array" + j + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[i]) + "]")
}
}
// Check for shape equality
if (proc.arrayArgs.length > 1) {
code.push("if (!(" + shapeLengthConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same dimensionality!')")
code.push("for(var shapeIndex=array" + proc.arrayArgs[0] + ".shape.length-" + Math.abs(proc.arrayBlockIndices[0]) + "; shapeIndex-->0;) {")
code.push("if (!(" + shapeConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same shape!')")
code.push("}")
}
// Process scalar arguments
for(var i=0; i b ? 1 : a >= b ? 0 : NaN;
};
var bisector = function(compare) {
if (compare.length === 1) compare = ascendingComparator(compare);
return {
left: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
}
return lo;
},
right: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) > 0) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
};
function ascendingComparator(f) {
return function(d, x) {
return ascending(f(d), x);
};
}
var ascendingBisect = bisector(ascending);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
var pairs = function(array, f) {
if (f == null) f = pair;
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = f(p, p = array[++i]);
return pairs;
};
function pair(a, b) {
return [a, b];
}
var cross = function(values0, values1, reduce) {
var n0 = values0.length,
n1 = values1.length,
values = new Array(n0 * n1),
i0,
i1,
i,
value0;
if (reduce == null) reduce = pair;
for (i0 = i = 0; i0 < n0; ++i0) {
for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
values[i] = reduce(value0, values1[i1]);
}
}
return values;
};
var descending = function(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
};
var number = function(x) {
return x === null ? NaN : +x;
};
var variance = function(values, valueof) {
var n = values.length,
m = 0,
i = -1,
mean = 0,
value,
delta,
sum = 0;
if (valueof == null) {
while (++i < n) {
if (!isNaN(value = number(values[i]))) {
delta = value - mean;
mean += delta / ++m;
sum += delta * (value - mean);
}
}
}
else {
while (++i < n) {
if (!isNaN(value = number(valueof(values[i], i, values)))) {
delta = value - mean;
mean += delta / ++m;
sum += delta * (value - mean);
}
}
}
if (m > 1) return sum / (m - 1);
};
var deviation = function(array, f) {
var v = variance(array, f);
return v ? Math.sqrt(v) : v;
};
var extent = function(values, valueof) {
var n = values.length,
i = -1,
value,
min,
max;
if (valueof == null) {
while (++i < n) { // Find the first comparable value.
if ((value = values[i]) != null && value >= value) {
min = max = value;
while (++i < n) { // Compare the remaining values.
if ((value = values[i]) != null) {
if (min > value) min = value;
if (max < value) max = value;
}
}
}
}
}
else {
while (++i < n) { // Find the first comparable value.
if ((value = valueof(values[i], i, values)) != null && value >= value) {
min = max = value;
while (++i < n) { // Compare the remaining values.
if ((value = valueof(values[i], i, values)) != null) {
if (min > value) min = value;
if (max < value) max = value;
}
}
}
}
}
return [min, max];
};
var array = Array.prototype;
var slice = array.slice;
var map = array.map;
var constant = function(x) {
return function() {
return x;
};
};
var identity = function(x) {
return x;
};
var range = function(start, stop, step) {
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
var i = -1,
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
range = new Array(n);
while (++i < n) {
range[i] = start + i * step;
}
return range;
};
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
var ticks = function(start, stop, count) {
var reverse = stop < start,
i = -1,
n,
ticks,
step;
if (reverse) n = start, start = stop, stop = n;
if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
if (step > 0) {
start = Math.ceil(start / step);
stop = Math.floor(stop / step);
ticks = new Array(n = Math.ceil(stop - start + 1));
while (++i < n) ticks[i] = (start + i) * step;
} else {
start = Math.floor(start * step);
stop = Math.ceil(stop * step);
ticks = new Array(n = Math.ceil(start - stop + 1));
while (++i < n) ticks[i] = (start - i) / step;
}
if (reverse) ticks.reverse();
return ticks;
};
function tickIncrement(start, stop, count) {
var step = (stop - start) / Math.max(0, count),
power = Math.floor(Math.log(step) / Math.LN10),
error = step / Math.pow(10, power);
return power >= 0
? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
: -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
}
function tickStep(start, stop, count) {
var step0 = Math.abs(stop - start) / Math.max(0, count),
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
error = step0 / step1;
if (error >= e10) step1 *= 10;
else if (error >= e5) step1 *= 5;
else if (error >= e2) step1 *= 2;
return stop < start ? -step1 : step1;
}
var sturges = function(values) {
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
};
var histogram = function() {
var value = identity,
domain = extent,
threshold = sturges;
function histogram(data) {
var i,
n = data.length,
x,
values = new Array(n);
for (i = 0; i < n; ++i) {
values[i] = value(data[i], i, data);
}
var xz = domain(values),
x0 = xz[0],
x1 = xz[1],
tz = threshold(values, x0, x1);
// Convert number of thresholds into uniform thresholds.
if (!Array.isArray(tz)) {
tz = tickStep(x0, x1, tz);
tz = range(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
}
// Remove any thresholds outside the domain.
var m = tz.length;
while (tz[0] <= x0) tz.shift(), --m;
while (tz[m - 1] > x1) tz.pop(), --m;
var bins = new Array(m + 1),
bin;
// Initialize bins.
for (i = 0; i <= m; ++i) {
bin = bins[i] = [];
bin.x0 = i > 0 ? tz[i - 1] : x0;
bin.x1 = i < m ? tz[i] : x1;
}
// Assign data to bins by value, ignoring any outside the domain.
for (i = 0; i < n; ++i) {
x = values[i];
if (x0 <= x && x <= x1) {
bins[bisectRight(tz, x, 0, m)].push(data[i]);
}
}
return bins;
}
histogram.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
};
histogram.domain = function(_) {
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
};
histogram.thresholds = function(_) {
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
};
return histogram;
};
var quantile = function(values, p, valueof) {
if (valueof == null) valueof = number;
if (!(n = values.length)) return;
if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
if (p >= 1) return +valueof(values[n - 1], n - 1, values);
var n,
i = (n - 1) * p,
i0 = Math.floor(i),
value0 = +valueof(values[i0], i0, values),
value1 = +valueof(values[i0 + 1], i0 + 1, values);
return value0 + (value1 - value0) * (i - i0);
};
var freedmanDiaconis = function(values, min, max) {
values = map.call(values, number).sort(ascending);
return Math.ceil((max - min) / (2 * (quantile(values, 0.75) - quantile(values, 0.25)) * Math.pow(values.length, -1 / 3)));
};
var scott = function(values, min, max) {
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
};
var max = function(values, valueof) {
var n = values.length,
i = -1,
value,
max;
if (valueof == null) {
while (++i < n) { // Find the first comparable value.
if ((value = values[i]) != null && value >= value) {
max = value;
while (++i < n) { // Compare the remaining values.
if ((value = values[i]) != null && value > max) {
max = value;
}
}
}
}
}
else {
while (++i < n) { // Find the first comparable value.
if ((value = valueof(values[i], i, values)) != null && value >= value) {
max = value;
while (++i < n) { // Compare the remaining values.
if ((value = valueof(values[i], i, values)) != null && value > max) {
max = value;
}
}
}
}
}
return max;
};
var mean = function(values, valueof) {
var n = values.length,
m = n,
i = -1,
value,
sum = 0;
if (valueof == null) {
while (++i < n) {
if (!isNaN(value = number(values[i]))) sum += value;
else --m;
}
}
else {
while (++i < n) {
if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
else --m;
}
}
if (m) return sum / m;
};
var median = function(values, valueof) {
var n = values.length,
i = -1,
value,
numbers = [];
if (valueof == null) {
while (++i < n) {
if (!isNaN(value = number(values[i]))) {
numbers.push(value);
}
}
}
else {
while (++i < n) {
if (!isNaN(value = number(valueof(values[i], i, values)))) {
numbers.push(value);
}
}
}
return quantile(numbers.sort(ascending), 0.5);
};
var merge = function(arrays) {
var n = arrays.length,
m,
i = -1,
j = 0,
merged,
array;
while (++i < n) j += arrays[i].length;
merged = new Array(j);
while (--n >= 0) {
array = arrays[n];
m = array.length;
while (--m >= 0) {
merged[--j] = array[m];
}
}
return merged;
};
var min = function(values, valueof) {
var n = values.length,
i = -1,
value,
min;
if (valueof == null) {
while (++i < n) { // Find the first comparable value.
if ((value = values[i]) != null && value >= value) {
min = value;
while (++i < n) { // Compare the remaining values.
if ((value = values[i]) != null && min > value) {
min = value;
}
}
}
}
}
else {
while (++i < n) { // Find the first comparable value.
if ((value = valueof(values[i], i, values)) != null && value >= value) {
min = value;
while (++i < n) { // Compare the remaining values.
if ((value = valueof(values[i], i, values)) != null && min > value) {
min = value;
}
}
}
}
}
return min;
};
var permute = function(array, indexes) {
var i = indexes.length, permutes = new Array(i);
while (i--) permutes[i] = array[indexes[i]];
return permutes;
};
var scan = function(values, compare) {
if (!(n = values.length)) return;
var n,
i = 0,
j = 0,
xi,
xj = values[j];
if (compare == null) compare = ascending;
while (++i < n) {
if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
xj = xi, j = i;
}
}
if (compare(xj, xj) === 0) return j;
};
var shuffle = function(array, i0, i1) {
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
t,
i;
while (m) {
i = Math.random() * m-- | 0;
t = array[m + i0];
array[m + i0] = array[i + i0];
array[i + i0] = t;
}
return array;
};
var sum = function(values, valueof) {
var n = values.length,
i = -1,
value,
sum = 0;
if (valueof == null) {
while (++i < n) {
if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
}
}
else {
while (++i < n) {
if (value = +valueof(values[i], i, values)) sum += value;
}
}
return sum;
};
var transpose = function(matrix) {
if (!(n = matrix.length)) return [];
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
row[j] = matrix[j][i];
}
}
return transpose;
};
function length(d) {
return d.length;
}
var zip = function() {
return transpose(arguments);
};
exports.bisect = bisectRight;
exports.bisectRight = bisectRight;
exports.bisectLeft = bisectLeft;
exports.ascending = ascending;
exports.bisector = bisector;
exports.cross = cross;
exports.descending = descending;
exports.deviation = deviation;
exports.extent = extent;
exports.histogram = histogram;
exports.thresholdFreedmanDiaconis = freedmanDiaconis;
exports.thresholdScott = scott;
exports.thresholdSturges = sturges;
exports.max = max;
exports.mean = mean;
exports.median = median;
exports.merge = merge;
exports.min = min;
exports.pairs = pairs;
exports.permute = permute;
exports.quantile = quantile;
exports.range = range;
exports.scan = scan;
exports.shuffle = shuffle;
exports.sum = sum;
exports.ticks = ticks;
exports.tickIncrement = tickIncrement;
exports.tickStep = tickStep;
exports.transpose = transpose;
exports.variance = variance;
exports.zip = zip;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],111:[function(require,module,exports){
// https://d3js.org/d3-collection/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var prefix = "$";
function Map() {}
Map.prototype = map.prototype = {
constructor: Map,
has: function(key) {
return (prefix + key) in this;
},
get: function(key) {
return this[prefix + key];
},
set: function(key, value) {
this[prefix + key] = value;
return this;
},
remove: function(key) {
var property = prefix + key;
return property in this && delete this[property];
},
clear: function() {
for (var property in this) if (property[0] === prefix) delete this[property];
},
keys: function() {
var keys = [];
for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
return keys;
},
values: function() {
var values = [];
for (var property in this) if (property[0] === prefix) values.push(this[property]);
return values;
},
entries: function() {
var entries = [];
for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
return entries;
},
size: function() {
var size = 0;
for (var property in this) if (property[0] === prefix) ++size;
return size;
},
empty: function() {
for (var property in this) if (property[0] === prefix) return false;
return true;
},
each: function(f) {
for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
}
};
function map(object, f) {
var map = new Map;
// Copy constructor.
if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
// Index array by numeric index or specified key function.
else if (Array.isArray(object)) {
var i = -1,
n = object.length,
o;
if (f == null) while (++i < n) map.set(i, object[i]);
else while (++i < n) map.set(f(o = object[i], i, object), o);
}
// Convert object to map.
else if (object) for (var key in object) map.set(key, object[key]);
return map;
}
var nest = function() {
var keys = [],
sortKeys = [],
sortValues,
rollup,
nest;
function apply(array, depth, createResult, setResult) {
if (depth >= keys.length) return rollup != null
? rollup(array) : (sortValues != null
? array.sort(sortValues)
: array);
var i = -1,
n = array.length,
key = keys[depth++],
keyValue,
value,
valuesByKey = map(),
values,
result = createResult();
while (++i < n) {
if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
values.push(value);
} else {
valuesByKey.set(keyValue, [value]);
}
}
valuesByKey.each(function(values, key) {
setResult(result, key, apply(values, depth, createResult, setResult));
});
return result;
}
function entries(map$$1, depth) {
if (++depth > keys.length) return map$$1;
var array, sortKey = sortKeys[depth - 1];
if (rollup != null && depth >= keys.length) array = map$$1.entries();
else array = [], map$$1.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
}
return nest = {
object: function(array) { return apply(array, 0, createObject, setObject); },
map: function(array) { return apply(array, 0, createMap, setMap); },
entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
key: function(d) { keys.push(d); return nest; },
sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
sortValues: function(order) { sortValues = order; return nest; },
rollup: function(f) { rollup = f; return nest; }
};
};
function createObject() {
return {};
}
function setObject(object, key, value) {
object[key] = value;
}
function createMap() {
return map();
}
function setMap(map$$1, key, value) {
map$$1.set(key, value);
}
function Set() {}
var proto = map.prototype;
Set.prototype = set.prototype = {
constructor: Set,
has: proto.has,
add: function(value) {
value += "";
this[prefix + value] = value;
return this;
},
remove: proto.remove,
clear: proto.clear,
values: proto.keys,
size: proto.size,
empty: proto.empty,
each: proto.each
};
function set(object, f) {
var set = new Set;
// Copy constructor.
if (object instanceof Set) object.each(function(value) { set.add(value); });
// Otherwise, assume it’s an array.
else if (object) {
var i = -1, n = object.length;
if (f == null) while (++i < n) set.add(object[i]);
else while (++i < n) set.add(f(object[i], i, object));
}
return set;
}
var keys = function(map) {
var keys = [];
for (var key in map) keys.push(key);
return keys;
};
var values = function(map) {
var values = [];
for (var key in map) values.push(map[key]);
return values;
};
var entries = function(map) {
var entries = [];
for (var key in map) entries.push({key: key, value: map[key]});
return entries;
};
exports.nest = nest;
exports.set = set;
exports.map = map;
exports.keys = keys;
exports.values = values;
exports.entries = entries;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],112:[function(require,module,exports){
// https://d3js.org/d3-color/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var define = function(constructor, factory, prototype) {
constructor.prototype = factory.prototype = prototype;
prototype.constructor = constructor;
};
function extend(parent, definition) {
var prototype = Object.create(parent.prototype);
for (var key in definition) prototype[key] = definition[key];
return prototype;
}
function Color() {}
var darker = 0.7;
var brighter = 1 / darker;
var reI = "\\s*([+-]?\\d+)\\s*";
var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
var reHex3 = /^#([0-9a-f]{3})$/;
var reHex6 = /^#([0-9a-f]{6})$/;
var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
var named = {
aliceblue: 0xf0f8ff,
antiquewhite: 0xfaebd7,
aqua: 0x00ffff,
aquamarine: 0x7fffd4,
azure: 0xf0ffff,
beige: 0xf5f5dc,
bisque: 0xffe4c4,
black: 0x000000,
blanchedalmond: 0xffebcd,
blue: 0x0000ff,
blueviolet: 0x8a2be2,
brown: 0xa52a2a,
burlywood: 0xdeb887,
cadetblue: 0x5f9ea0,
chartreuse: 0x7fff00,
chocolate: 0xd2691e,
coral: 0xff7f50,
cornflowerblue: 0x6495ed,
cornsilk: 0xfff8dc,
crimson: 0xdc143c,
cyan: 0x00ffff,
darkblue: 0x00008b,
darkcyan: 0x008b8b,
darkgoldenrod: 0xb8860b,
darkgray: 0xa9a9a9,
darkgreen: 0x006400,
darkgrey: 0xa9a9a9,
darkkhaki: 0xbdb76b,
darkmagenta: 0x8b008b,
darkolivegreen: 0x556b2f,
darkorange: 0xff8c00,
darkorchid: 0x9932cc,
darkred: 0x8b0000,
darksalmon: 0xe9967a,
darkseagreen: 0x8fbc8f,
darkslateblue: 0x483d8b,
darkslategray: 0x2f4f4f,
darkslategrey: 0x2f4f4f,
darkturquoise: 0x00ced1,
darkviolet: 0x9400d3,
deeppink: 0xff1493,
deepskyblue: 0x00bfff,
dimgray: 0x696969,
dimgrey: 0x696969,
dodgerblue: 0x1e90ff,
firebrick: 0xb22222,
floralwhite: 0xfffaf0,
forestgreen: 0x228b22,
fuchsia: 0xff00ff,
gainsboro: 0xdcdcdc,
ghostwhite: 0xf8f8ff,
gold: 0xffd700,
goldenrod: 0xdaa520,
gray: 0x808080,
green: 0x008000,
greenyellow: 0xadff2f,
grey: 0x808080,
honeydew: 0xf0fff0,
hotpink: 0xff69b4,
indianred: 0xcd5c5c,
indigo: 0x4b0082,
ivory: 0xfffff0,
khaki: 0xf0e68c,
lavender: 0xe6e6fa,
lavenderblush: 0xfff0f5,
lawngreen: 0x7cfc00,
lemonchiffon: 0xfffacd,
lightblue: 0xadd8e6,
lightcoral: 0xf08080,
lightcyan: 0xe0ffff,
lightgoldenrodyellow: 0xfafad2,
lightgray: 0xd3d3d3,
lightgreen: 0x90ee90,
lightgrey: 0xd3d3d3,
lightpink: 0xffb6c1,
lightsalmon: 0xffa07a,
lightseagreen: 0x20b2aa,
lightskyblue: 0x87cefa,
lightslategray: 0x778899,
lightslategrey: 0x778899,
lightsteelblue: 0xb0c4de,
lightyellow: 0xffffe0,
lime: 0x00ff00,
limegreen: 0x32cd32,
linen: 0xfaf0e6,
magenta: 0xff00ff,
maroon: 0x800000,
mediumaquamarine: 0x66cdaa,
mediumblue: 0x0000cd,
mediumorchid: 0xba55d3,
mediumpurple: 0x9370db,
mediumseagreen: 0x3cb371,
mediumslateblue: 0x7b68ee,
mediumspringgreen: 0x00fa9a,
mediumturquoise: 0x48d1cc,
mediumvioletred: 0xc71585,
midnightblue: 0x191970,
mintcream: 0xf5fffa,
mistyrose: 0xffe4e1,
moccasin: 0xffe4b5,
navajowhite: 0xffdead,
navy: 0x000080,
oldlace: 0xfdf5e6,
olive: 0x808000,
olivedrab: 0x6b8e23,
orange: 0xffa500,
orangered: 0xff4500,
orchid: 0xda70d6,
palegoldenrod: 0xeee8aa,
palegreen: 0x98fb98,
paleturquoise: 0xafeeee,
palevioletred: 0xdb7093,
papayawhip: 0xffefd5,
peachpuff: 0xffdab9,
peru: 0xcd853f,
pink: 0xffc0cb,
plum: 0xdda0dd,
powderblue: 0xb0e0e6,
purple: 0x800080,
rebeccapurple: 0x663399,
red: 0xff0000,
rosybrown: 0xbc8f8f,
royalblue: 0x4169e1,
saddlebrown: 0x8b4513,
salmon: 0xfa8072,
sandybrown: 0xf4a460,
seagreen: 0x2e8b57,
seashell: 0xfff5ee,
sienna: 0xa0522d,
silver: 0xc0c0c0,
skyblue: 0x87ceeb,
slateblue: 0x6a5acd,
slategray: 0x708090,
slategrey: 0x708090,
snow: 0xfffafa,
springgreen: 0x00ff7f,
steelblue: 0x4682b4,
tan: 0xd2b48c,
teal: 0x008080,
thistle: 0xd8bfd8,
tomato: 0xff6347,
turquoise: 0x40e0d0,
violet: 0xee82ee,
wheat: 0xf5deb3,
white: 0xffffff,
whitesmoke: 0xf5f5f5,
yellow: 0xffff00,
yellowgreen: 0x9acd32
};
define(Color, color, {
displayable: function() {
return this.rgb().displayable();
},
toString: function() {
return this.rgb() + "";
}
});
function color(format) {
var m;
format = (format + "").trim().toLowerCase();
return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
: (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
: (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
: (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
: (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
: (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
: (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
: (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
: named.hasOwnProperty(format) ? rgbn(named[format])
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
: null;
}
function rgbn(n) {
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
}
function rgba(r, g, b, a) {
if (a <= 0) r = g = b = NaN;
return new Rgb(r, g, b, a);
}
function rgbConvert(o) {
if (!(o instanceof Color)) o = color(o);
if (!o) return new Rgb;
o = o.rgb();
return new Rgb(o.r, o.g, o.b, o.opacity);
}
function rgb(r, g, b, opacity) {
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g, b, opacity) {
this.r = +r;
this.g = +g;
this.b = +b;
this.opacity = +opacity;
}
define(Rgb, rgb, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
rgb: function() {
return this;
},
displayable: function() {
return (0 <= this.r && this.r <= 255)
&& (0 <= this.g && this.g <= 255)
&& (0 <= this.b && this.b <= 255)
&& (0 <= this.opacity && this.opacity <= 1);
},
toString: function() {
var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
return (a === 1 ? "rgb(" : "rgba(")
+ Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.b) || 0))
+ (a === 1 ? ")" : ", " + a + ")");
}
}));
function hsla(h, s, l, a) {
if (a <= 0) h = s = l = NaN;
else if (l <= 0 || l >= 1) h = s = NaN;
else if (s <= 0) h = NaN;
return new Hsl(h, s, l, a);
}
function hslConvert(o) {
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Color)) o = color(o);
if (!o) return new Hsl;
if (o instanceof Hsl) return o;
o = o.rgb();
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
min = Math.min(r, g, b),
max = Math.max(r, g, b),
h = NaN,
s = max - min,
l = (max + min) / 2;
if (s) {
if (r === max) h = (g - b) / s + (g < b) * 6;
else if (g === max) h = (b - r) / s + 2;
else h = (r - g) / s + 4;
s /= l < 0.5 ? max + min : 2 - max - min;
h *= 60;
} else {
s = l > 0 && l < 1 ? 0 : h;
}
return new Hsl(h, s, l, o.opacity);
}
function hsl(h, s, l, opacity) {
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Hsl, hsl, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = this.h % 360 + (this.h < 0) * 360,
s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
l = this.l,
m2 = l + (l < 0.5 ? l : 1 - l) * s,
m1 = 2 * l - m2;
return new Rgb(
hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
hsl2rgb(h, m1, m2),
hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
this.opacity
);
},
displayable: function() {
return (0 <= this.s && this.s <= 1 || isNaN(this.s))
&& (0 <= this.l && this.l <= 1)
&& (0 <= this.opacity && this.opacity <= 1);
}
}));
/* From FvD 13.37, CSS Color Module Level 3 */
function hsl2rgb(h, m1, m2) {
return (h < 60 ? m1 + (m2 - m1) * h / 60
: h < 180 ? m2
: h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
: m1) * 255;
}
var deg2rad = Math.PI / 180;
var rad2deg = 180 / Math.PI;
var Kn = 18;
var Xn = 0.950470;
var Yn = 1;
var Zn = 1.088830;
var t0 = 4 / 29;
var t1 = 6 / 29;
var t2 = 3 * t1 * t1;
var t3 = t1 * t1 * t1;
function labConvert(o) {
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
if (o instanceof Hcl) {
var h = o.h * deg2rad;
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
}
if (!(o instanceof Rgb)) o = rgbConvert(o);
var b = rgb2xyz(o.r),
a = rgb2xyz(o.g),
l = rgb2xyz(o.b),
x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}
function lab(l, a, b, opacity) {
return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}
function Lab(l, a, b, opacity) {
this.l = +l;
this.a = +a;
this.b = +b;
this.opacity = +opacity;
}
define(Lab, lab, extend(Color, {
brighter: function(k) {
return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
darker: function(k) {
return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
rgb: function() {
var y = (this.l + 16) / 116,
x = isNaN(this.a) ? y : y + this.a / 500,
z = isNaN(this.b) ? y : y - this.b / 200;
y = Yn * lab2xyz(y);
x = Xn * lab2xyz(x);
z = Zn * lab2xyz(z);
return new Rgb(
xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
this.opacity
);
}
}));
function xyz2lab(t) {
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}
function lab2xyz(t) {
return t > t1 ? t * t * t : t2 * (t - t0);
}
function xyz2rgb(x) {
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}
function rgb2xyz(x) {
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
function hclConvert(o) {
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
if (!(o instanceof Lab)) o = labConvert(o);
var h = Math.atan2(o.b, o.a) * rad2deg;
return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}
function hcl(h, c, l, opacity) {
return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}
function Hcl(h, c, l, opacity) {
this.h = +h;
this.c = +c;
this.l = +l;
this.opacity = +opacity;
}
define(Hcl, hcl, extend(Color, {
brighter: function(k) {
return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
},
darker: function(k) {
return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
},
rgb: function() {
return labConvert(this).rgb();
}
}));
var A = -0.14861;
var B = +1.78277;
var C = -0.29227;
var D = -0.90649;
var E = +1.97294;
var ED = E * D;
var EB = E * B;
var BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Rgb)) o = rgbConvert(o);
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
bl = b - l,
k = (E * (g - l) - C * bl) / D,
s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
function cubehelix(h, s, l, opacity) {
return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
}
function Cubehelix(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
l = +this.l,
a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
cosh = Math.cos(h),
sinh = Math.sin(h);
return new Rgb(
255 * (l + a * (A * cosh + B * sinh)),
255 * (l + a * (C * cosh + D * sinh)),
255 * (l + a * (E * cosh)),
this.opacity
);
}
}));
exports.color = color;
exports.rgb = rgb;
exports.hsl = hsl;
exports.lab = lab;
exports.hcl = hcl;
exports.cubehelix = cubehelix;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],113:[function(require,module,exports){
// https://d3js.org/d3-dispatch/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var noop = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
exports.dispatch = dispatch;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],114:[function(require,module,exports){
// https://d3js.org/d3-force/ Version 1.0.6. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-quadtree'), require('d3-collection'), require('d3-dispatch'), require('d3-timer')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-quadtree', 'd3-collection', 'd3-dispatch', 'd3-timer'], factory) :
(factory((global.d3 = global.d3 || {}),global.d3,global.d3,global.d3,global.d3));
}(this, (function (exports,d3Quadtree,d3Collection,d3Dispatch,d3Timer) { 'use strict';
var center = function(x, y) {
var nodes;
if (x == null) x = 0;
if (y == null) y = 0;
function force() {
var i,
n = nodes.length,
node,
sx = 0,
sy = 0;
for (i = 0; i < n; ++i) {
node = nodes[i], sx += node.x, sy += node.y;
}
for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
node = nodes[i], node.x -= sx, node.y -= sy;
}
}
force.initialize = function(_) {
nodes = _;
};
force.x = function(_) {
return arguments.length ? (x = +_, force) : x;
};
force.y = function(_) {
return arguments.length ? (y = +_, force) : y;
};
return force;
};
var constant = function(x) {
return function() {
return x;
};
};
var jiggle = function() {
return (Math.random() - 0.5) * 1e-6;
};
function x(d) {
return d.x + d.vx;
}
function y(d) {
return d.y + d.vy;
}
var collide = function(radius) {
var nodes,
radii,
strength = 1,
iterations = 1;
if (typeof radius !== "function") radius = constant(radius == null ? 1 : +radius);
function force() {
var i, n = nodes.length,
tree,
node,
xi,
yi,
ri,
ri2;
for (var k = 0; k < iterations; ++k) {
tree = d3Quadtree.quadtree(nodes, x, y).visitAfter(prepare);
for (i = 0; i < n; ++i) {
node = nodes[i];
ri = radii[node.index], ri2 = ri * ri;
xi = node.x + node.vx;
yi = node.y + node.vy;
tree.visit(apply);
}
}
function apply(quad, x0, y0, x1, y1) {
var data = quad.data, rj = quad.r, r = ri + rj;
if (data) {
if (data.index > node.index) {
var x = xi - data.x - data.vx,
y = yi - data.y - data.vy,
l = x * x + y * y;
if (l < r * r) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
l = (r - (l = Math.sqrt(l))) / l * strength;
node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
node.vy += (y *= l) * r;
data.vx -= x * (r = 1 - r);
data.vy -= y * r;
}
}
return;
}
return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
}
}
function prepare(quad) {
if (quad.data) return quad.r = radii[quad.data.index];
for (var i = quad.r = 0; i < 4; ++i) {
if (quad[i] && quad[i].r > quad.r) {
quad.r = quad[i].r;
}
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length, node;
radii = new Array(n);
for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = +_, force) : strength;
};
force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
};
return force;
};
function index(d) {
return d.index;
}
function find(nodeById, nodeId) {
var node = nodeById.get(nodeId);
if (!node) throw new Error("missing: " + nodeId);
return node;
}
var link = function(links) {
var id = index,
strength = defaultStrength,
strengths,
distance = constant(30),
distances,
nodes,
count,
bias,
iterations = 1;
if (links == null) links = [];
function defaultStrength(link) {
return 1 / Math.min(count[link.source.index], count[link.target.index]);
}
function force(alpha) {
for (var k = 0, n = links.length; k < iterations; ++k) {
for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
link = links[i], source = link.source, target = link.target;
x = target.x + target.vx - source.x - source.vx || jiggle();
y = target.y + target.vy - source.y - source.vy || jiggle();
l = Math.sqrt(x * x + y * y);
l = (l - distances[i]) / l * alpha * strengths[i];
x *= l, y *= l;
target.vx -= x * (b = bias[i]);
target.vy -= y * b;
source.vx += x * (b = 1 - b);
source.vy += y * b;
}
}
}
function initialize() {
if (!nodes) return;
var i,
n = nodes.length,
m = links.length,
nodeById = d3Collection.map(nodes, id),
link;
for (i = 0, count = new Array(n); i < m; ++i) {
link = links[i], link.index = i;
if (typeof link.source !== "object") link.source = find(nodeById, link.source);
if (typeof link.target !== "object") link.target = find(nodeById, link.target);
count[link.source.index] = (count[link.source.index] || 0) + 1;
count[link.target.index] = (count[link.target.index] || 0) + 1;
}
for (i = 0, bias = new Array(m); i < m; ++i) {
link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
}
strengths = new Array(m), initializeStrength();
distances = new Array(m), initializeDistance();
}
function initializeStrength() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
strengths[i] = +strength(links[i], i, links);
}
}
function initializeDistance() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
distances[i] = +distance(links[i], i, links);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.links = function(_) {
return arguments.length ? (links = _, initialize(), force) : links;
};
force.id = function(_) {
return arguments.length ? (id = _, force) : id;
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength;
};
force.distance = function(_) {
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance;
};
return force;
};
function x$1(d) {
return d.x;
}
function y$1(d) {
return d.y;
}
var initialRadius = 10;
var initialAngle = Math.PI * (3 - Math.sqrt(5));
var simulation = function(nodes) {
var simulation,
alpha = 1,
alphaMin = 0.001,
alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
alphaTarget = 0,
velocityDecay = 0.6,
forces = d3Collection.map(),
stepper = d3Timer.timer(step),
event = d3Dispatch.dispatch("tick", "end");
if (nodes == null) nodes = [];
function step() {
tick();
event.call("tick", simulation);
if (alpha < alphaMin) {
stepper.stop();
event.call("end", simulation);
}
}
function tick() {
var i, n = nodes.length, node;
alpha += (alphaTarget - alpha) * alphaDecay;
forces.each(function(force) {
force(alpha);
});
for (i = 0; i < n; ++i) {
node = nodes[i];
if (node.fx == null) node.x += node.vx *= velocityDecay;
else node.x = node.fx, node.vx = 0;
if (node.fy == null) node.y += node.vy *= velocityDecay;
else node.y = node.fy, node.vy = 0;
}
}
function initializeNodes() {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.index = i;
if (isNaN(node.x) || isNaN(node.y)) {
var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
node.x = radius * Math.cos(angle);
node.y = radius * Math.sin(angle);
}
if (isNaN(node.vx) || isNaN(node.vy)) {
node.vx = node.vy = 0;
}
}
}
function initializeForce(force) {
if (force.initialize) force.initialize(nodes);
return force;
}
initializeNodes();
return simulation = {
tick: tick,
restart: function() {
return stepper.restart(step), simulation;
},
stop: function() {
return stepper.stop(), simulation;
},
nodes: function(_) {
return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
},
alpha: function(_) {
return arguments.length ? (alpha = +_, simulation) : alpha;
},
alphaMin: function(_) {
return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
},
alphaDecay: function(_) {
return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
},
alphaTarget: function(_) {
return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
},
velocityDecay: function(_) {
return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
},
force: function(name, _) {
return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
},
find: function(x, y, radius) {
var i = 0,
n = nodes.length,
dx,
dy,
d2,
node,
closest;
if (radius == null) radius = Infinity;
else radius *= radius;
for (i = 0; i < n; ++i) {
node = nodes[i];
dx = x - node.x;
dy = y - node.y;
d2 = dx * dx + dy * dy;
if (d2 < radius) closest = node, radius = d2;
}
return closest;
},
on: function(name, _) {
return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
}
};
};
var manyBody = function() {
var nodes,
node,
alpha,
strength = constant(-30),
strengths,
distanceMin2 = 1,
distanceMax2 = Infinity,
theta2 = 0.81;
function force(_) {
var i, n = nodes.length, tree = d3Quadtree.quadtree(nodes, x$1, y$1).visitAfter(accumulate);
for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length, node;
strengths = new Array(n);
for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
}
function accumulate(quad) {
var strength = 0, q, c, x$$1, y$$1, i;
// For internal nodes, accumulate forces from child quadrants.
if (quad.length) {
for (x$$1 = y$$1 = i = 0; i < 4; ++i) {
if ((q = quad[i]) && (c = q.value)) {
strength += c, x$$1 += c * q.x, y$$1 += c * q.y;
}
}
quad.x = x$$1 / strength;
quad.y = y$$1 / strength;
}
// For leaf nodes, accumulate forces from coincident quadrants.
else {
q = quad;
q.x = q.data.x;
q.y = q.data.y;
do strength += strengths[q.data.index];
while (q = q.next);
}
quad.value = strength;
}
function apply(quad, x1, _, x2) {
if (!quad.value) return true;
var x$$1 = quad.x - node.x,
y$$1 = quad.y - node.y,
w = x2 - x1,
l = x$$1 * x$$1 + y$$1 * y$$1;
// Apply the Barnes-Hut approximation if possible.
// Limit forces for very close nodes; randomize direction if coincident.
if (w * w / theta2 < l) {
if (l < distanceMax2) {
if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
node.vx += x$$1 * quad.value * alpha / l;
node.vy += y$$1 * quad.value * alpha / l;
}
return true;
}
// Otherwise, process points directly.
else if (quad.length || l >= distanceMax2) return;
// Limit forces for very close nodes; randomize direction if coincident.
if (quad.data !== node || quad.next) {
if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
}
do if (quad.data !== node) {
w = strengths[quad.data.index] * alpha / l;
node.vx += x$$1 * w;
node.vy += y$$1 * w;
} while (quad = quad.next);
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
};
force.distanceMin = function(_) {
return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
};
force.distanceMax = function(_) {
return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
};
force.theta = function(_) {
return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
};
return force;
};
var x$2 = function(x) {
var strength = constant(0.1),
nodes,
strengths,
xz;
if (typeof x !== "function") x = constant(x == null ? 0 : +x);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
xz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
};
force.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), initialize(), force) : x;
};
return force;
};
var y$2 = function(y) {
var strength = constant(0.1),
nodes,
strengths,
yz;
if (typeof y !== "function") y = constant(y == null ? 0 : +y);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
yz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
};
force.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), initialize(), force) : y;
};
return force;
};
exports.forceCenter = center;
exports.forceCollide = collide;
exports.forceLink = link;
exports.forceManyBody = manyBody;
exports.forceSimulation = simulation;
exports.forceX = x$2;
exports.forceY = y$2;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{"d3-collection":111,"d3-dispatch":113,"d3-quadtree":116,"d3-timer":117}],115:[function(require,module,exports){
// https://d3js.org/d3-interpolate/ Version 1.1.4. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-color')) :
typeof define === 'function' && define.amd ? define(['exports', 'd3-color'], factory) :
(factory((global.d3 = global.d3 || {}),global.d3));
}(this, (function (exports,d3Color) { 'use strict';
function basis(t1, v0, v1, v2, v3) {
var t2 = t1 * t1, t3 = t2 * t1;
return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ (4 - 6 * t2 + 3 * t3) * v1
+ (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ t3 * v3) / 6;
}
var basis$1 = function(values) {
var n = values.length - 1;
return function(t) {
var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
v1 = values[i],
v2 = values[i + 1],
v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
return basis((t - i / n) * n, v0, v1, v2, v3);
};
};
var basisClosed = function(values) {
var n = values.length;
return function(t) {
var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
v0 = values[(i + n - 1) % n],
v1 = values[i % n],
v2 = values[(i + 1) % n],
v3 = values[(i + 2) % n];
return basis((t - i / n) * n, v0, v1, v2, v3);
};
};
var constant = function(x) {
return function() {
return x;
};
};
function linear(a, d) {
return function(t) {
return a + t * d;
};
}
function exponential(a, b, y) {
return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
return Math.pow(a + t * b, y);
};
}
function hue(a, b) {
var d = b - a;
return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);
}
function gamma(y) {
return (y = +y) === 1 ? nogamma : function(a, b) {
return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);
};
}
function nogamma(a, b) {
var d = b - a;
return d ? linear(a, d) : constant(isNaN(a) ? b : a);
}
var rgb$1 = ((function rgbGamma(y) {
var color$$1 = gamma(y);
function rgb$$1(start, end) {
var r = color$$1((start = d3Color.rgb(start)).r, (end = d3Color.rgb(end)).r),
g = color$$1(start.g, end.g),
b = color$$1(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.r = r(t);
start.g = g(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
rgb$$1.gamma = rgbGamma;
return rgb$$1;
}))(1);
function rgbSpline(spline) {
return function(colors) {
var n = colors.length,
r = new Array(n),
g = new Array(n),
b = new Array(n),
i, color$$1;
for (i = 0; i < n; ++i) {
color$$1 = d3Color.rgb(colors[i]);
r[i] = color$$1.r || 0;
g[i] = color$$1.g || 0;
b[i] = color$$1.b || 0;
}
r = spline(r);
g = spline(g);
b = spline(b);
color$$1.opacity = 1;
return function(t) {
color$$1.r = r(t);
color$$1.g = g(t);
color$$1.b = b(t);
return color$$1 + "";
};
};
}
var rgbBasis = rgbSpline(basis$1);
var rgbBasisClosed = rgbSpline(basisClosed);
var array = function(a, b) {
var nb = b ? b.length : 0,
na = a ? Math.min(nb, a.length) : 0,
x = new Array(nb),
c = new Array(nb),
i;
for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);
for (; i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < na; ++i) c[i] = x[i](t);
return c;
};
};
var date = function(a, b) {
var d = new Date;
return a = +a, b -= a, function(t) {
return d.setTime(a + b * t), d;
};
};
var number = function(a, b) {
return a = +a, b -= a, function(t) {
return a + b * t;
};
};
var object = function(a, b) {
var i = {},
c = {},
k;
if (a === null || typeof a !== "object") a = {};
if (b === null || typeof b !== "object") b = {};
for (k in b) {
if (k in a) {
i[k] = value(a[k], b[k]);
} else {
c[k] = b[k];
}
}
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
};
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var reB = new RegExp(reA.source, "g");
function zero(b) {
return function() {
return b;
};
}
function one(b) {
return function(t) {
return b(t) + "";
};
}
var string = function(a, b) {
var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
am, // current match in a
bm, // current match in b
bs, // string preceding current number in b, if any
i = -1, // index in s
s = [], // string constants and placeholders
q = []; // number interpolators
// Coerce inputs to strings.
a = a + "", b = b + "";
// Interpolate pairs of numbers in a & b.
while ((am = reA.exec(a))
&& (bm = reB.exec(b))) {
if ((bs = bm.index) > bi) { // a string precedes the next number in b
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
if (s[i]) s[i] += bm; // coalesce with previous string
else s[++i] = bm;
} else { // interpolate non-matching numbers
s[++i] = null;
q.push({i: i, x: number(am, bm)});
}
bi = reB.lastIndex;
}
// Add remains of b.
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string.
return s.length < 2 ? (q[0]
? one(q[0].x)
: zero(b))
: (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
};
var value = function(a, b) {
var t = typeof b, c;
return b == null || t === "boolean" ? constant(b)
: (t === "number" ? number
: t === "string" ? ((c = d3Color.color(b)) ? (b = c, rgb$1) : string)
: b instanceof d3Color.color ? rgb$1
: b instanceof Date ? date
: Array.isArray(b) ? array
: isNaN(b) ? object
: number)(a, b);
};
var round = function(a, b) {
return a = +a, b -= a, function(t) {
return Math.round(a + b * t);
};
};
var degrees = 180 / Math.PI;
var identity = {
translateX: 0,
translateY: 0,
rotate: 0,
skewX: 0,
scaleX: 1,
scaleY: 1
};
var decompose = function(a, b, c, d, e, f) {
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * degrees,
skewX: Math.atan(skewX) * degrees,
scaleX: scaleX,
scaleY: scaleY
};
};
var cssNode;
var cssRoot;
var cssView;
var svgNode;
function parseCss(value) {
if (value === "none") return identity;
if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
cssNode.style.transform = value;
value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
cssRoot.removeChild(cssNode);
value = value.slice(7, -1).split(",");
return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
}
function parseSvg(value) {
if (value == null) return identity;
if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
svgNode.setAttribute("transform", value);
if (!(value = svgNode.transform.baseVal.consolidate())) return identity;
value = value.matrix;
return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
}
function interpolateTransform(parse, pxComma, pxParen, degParen) {
function pop(s) {
return s.length ? s.pop() + " " : "";
}
function translate(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push("translate(", null, pxComma, null, pxParen);
q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
} else if (xb || yb) {
s.push("translate(" + xb + pxComma + yb + pxParen);
}
}
function rotate(a, b, s, q) {
if (a !== b) {
if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: number(a, b)});
} else if (b) {
s.push(pop(s) + "rotate(" + b + degParen);
}
}
function skewX(a, b, s, q) {
if (a !== b) {
q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: number(a, b)});
} else if (b) {
s.push(pop(s) + "skewX(" + b + degParen);
}
}
function scale(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push(pop(s) + "scale(", null, ",", null, ")");
q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});
} else if (xb !== 1 || yb !== 1) {
s.push(pop(s) + "scale(" + xb + "," + yb + ")");
}
}
return function(a, b) {
var s = [], // string constants and placeholders
q = []; // number interpolators
a = parse(a), b = parse(b);
translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
rotate(a.rotate, b.rotate, s, q);
skewX(a.skewX, b.skewX, s, q);
scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
a = b = null; // gc
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
};
}
var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
var rho = Math.SQRT2;
var rho2 = 2;
var rho4 = 4;
var epsilon2 = 1e-12;
function cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
// p0 = [ux0, uy0, w0]
// p1 = [ux1, uy1, w1]
var zoom = function(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
dx = ux1 - ux0,
dy = uy1 - uy0,
d2 = dx * dx + dy * dy,
i,
S;
// Special case for u0 ≅ u1.
if (d2 < epsilon2) {
S = Math.log(w1 / w0) / rho;
i = function(t) {
return [
ux0 + t * dx,
uy0 + t * dy,
w0 * Math.exp(rho * t * S)
];
};
}
// General case.
else {
var d1 = Math.sqrt(d2),
b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
S = (r1 - r0) / rho;
i = function(t) {
var s = t * S,
coshr0 = cosh(r0),
u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
return [
ux0 + u * dx,
uy0 + u * dy,
w0 * coshr0 / cosh(rho * s + r0)
];
};
}
i.duration = S * 1000;
return i;
};
function hsl$1(hue$$1) {
return function(start, end) {
var h = hue$$1((start = d3Color.hsl(start)).h, (end = d3Color.hsl(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hsl$2 = hsl$1(hue);
var hslLong = hsl$1(nogamma);
function lab$1(start, end) {
var l = nogamma((start = d3Color.lab(start)).l, (end = d3Color.lab(end)).l),
a = nogamma(start.a, end.a),
b = nogamma(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.l = l(t);
start.a = a(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
function hcl$1(hue$$1) {
return function(start, end) {
var h = hue$$1((start = d3Color.hcl(start)).h, (end = d3Color.hcl(end)).h),
c = nogamma(start.c, end.c),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.c = c(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hcl$2 = hcl$1(hue);
var hclLong = hcl$1(nogamma);
function cubehelix$1(hue$$1) {
return (function cubehelixGamma(y) {
y = +y;
function cubehelix$$1(start, end) {
var h = hue$$1((start = d3Color.cubehelix(start)).h, (end = d3Color.cubehelix(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(Math.pow(t, y));
start.opacity = opacity(t);
return start + "";
};
}
cubehelix$$1.gamma = cubehelixGamma;
return cubehelix$$1;
})(1);
}
var cubehelix$2 = cubehelix$1(hue);
var cubehelixLong = cubehelix$1(nogamma);
var quantize = function(interpolator, n) {
var samples = new Array(n);
for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
return samples;
};
exports.interpolate = value;
exports.interpolateArray = array;
exports.interpolateBasis = basis$1;
exports.interpolateBasisClosed = basisClosed;
exports.interpolateDate = date;
exports.interpolateNumber = number;
exports.interpolateObject = object;
exports.interpolateRound = round;
exports.interpolateString = string;
exports.interpolateTransformCss = interpolateTransformCss;
exports.interpolateTransformSvg = interpolateTransformSvg;
exports.interpolateZoom = zoom;
exports.interpolateRgb = rgb$1;
exports.interpolateRgbBasis = rgbBasis;
exports.interpolateRgbBasisClosed = rgbBasisClosed;
exports.interpolateHsl = hsl$2;
exports.interpolateHslLong = hslLong;
exports.interpolateLab = lab$1;
exports.interpolateHcl = hcl$2;
exports.interpolateHclLong = hclLong;
exports.interpolateCubehelix = cubehelix$2;
exports.interpolateCubehelixLong = cubehelixLong;
exports.quantize = quantize;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{"d3-color":112}],116:[function(require,module,exports){
// https://d3js.org/d3-quadtree/ Version 1.0.3. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var tree_add = function(d) {
var x = +this._x.call(null, d),
y = +this._y.call(null, d);
return add(this.cover(x, y), x, y, d);
};
function add(tree, x, y, d) {
if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
var parent,
node = tree._root,
leaf = {data: d},
x0 = tree._x0,
y0 = tree._y0,
x1 = tree._x1,
y1 = tree._y1,
xm,
ym,
xp,
yp,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return tree._root = leaf, tree;
// Find the existing leaf for the new point, or add it.
while (node.length) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
}
// Is the new point is exactly coincident with the existing point?
xp = +tree._x.call(null, node.data);
yp = +tree._y.call(null, node.data);
if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
// Otherwise, split the leaf node until the old and new point are separated.
do {
parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
} while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
return parent[j] = node, parent[i] = leaf, tree;
}
function addAll(data) {
var d, i, n = data.length,
x,
y,
xz = new Array(n),
yz = new Array(n),
x0 = Infinity,
y0 = Infinity,
x1 = -Infinity,
y1 = -Infinity;
// Compute the points and their extent.
for (i = 0; i < n; ++i) {
if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
xz[i] = x;
yz[i] = y;
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
// If there were no (valid) points, inherit the existing extent.
if (x1 < x0) x0 = this._x0, x1 = this._x1;
if (y1 < y0) y0 = this._y0, y1 = this._y1;
// Expand the tree to cover the new points.
this.cover(x0, y0).cover(x1, y1);
// Add the new points.
for (i = 0; i < n; ++i) {
add(this, xz[i], yz[i], data[i]);
}
return this;
}
var tree_cover = function(x, y) {
if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
var x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1;
// If the quadtree has no extent, initialize them.
// Integer extent are necessary so that if we later double the extent,
// the existing quadrant boundaries don’t change due to floating point error!
if (isNaN(x0)) {
x1 = (x0 = Math.floor(x)) + 1;
y1 = (y0 = Math.floor(y)) + 1;
}
// Otherwise, double repeatedly to cover.
else if (x0 > x || x > x1 || y0 > y || y > y1) {
var z = x1 - x0,
node = this._root,
parent,
i;
switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
case 0: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
break;
}
case 1: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
break;
}
case 2: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
break;
}
case 3: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
break;
}
}
if (this._root && this._root.length) this._root = node;
}
// If the quadtree covers the point already, just return.
else return this;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
return this;
};
var tree_data = function() {
var data = [];
this.visit(function(node) {
if (!node.length) do data.push(node.data); while (node = node.next)
});
return data;
};
var tree_extent = function(_) {
return arguments.length
? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
: isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
};
var Quad = function(node, x0, y0, x1, y1) {
this.node = node;
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
};
var tree_find = function(x, y, radius) {
var data,
x0 = this._x0,
y0 = this._y0,
x1,
y1,
x2,
y2,
x3 = this._x1,
y3 = this._y1,
quads = [],
node = this._root,
q,
i;
if (node) quads.push(new Quad(node, x0, y0, x3, y3));
if (radius == null) radius = Infinity;
else {
x0 = x - radius, y0 = y - radius;
x3 = x + radius, y3 = y + radius;
radius *= radius;
}
while (q = quads.pop()) {
// Stop searching if this quadrant can’t contain a closer node.
if (!(node = q.node)
|| (x1 = q.x0) > x3
|| (y1 = q.y0) > y3
|| (x2 = q.x1) < x0
|| (y2 = q.y1) < y0) continue;
// Bisect the current quadrant.
if (node.length) {
var xm = (x1 + x2) / 2,
ym = (y1 + y2) / 2;
quads.push(
new Quad(node[3], xm, ym, x2, y2),
new Quad(node[2], x1, ym, xm, y2),
new Quad(node[1], xm, y1, x2, ym),
new Quad(node[0], x1, y1, xm, ym)
);
// Visit the closest quadrant first.
if (i = (y >= ym) << 1 | (x >= xm)) {
q = quads[quads.length - 1];
quads[quads.length - 1] = quads[quads.length - 1 - i];
quads[quads.length - 1 - i] = q;
}
}
// Visit this point. (Visiting coincident points isn’t necessary!)
else {
var dx = x - +this._x.call(null, node.data),
dy = y - +this._y.call(null, node.data),
d2 = dx * dx + dy * dy;
if (d2 < radius) {
var d = Math.sqrt(radius = d2);
x0 = x - d, y0 = y - d;
x3 = x + d, y3 = y + d;
data = node.data;
}
}
}
return data;
};
var tree_remove = function(d) {
if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
var parent,
node = this._root,
retainer,
previous,
next,
x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1,
x,
y,
xm,
ym,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return this;
// Find the leaf node for the point.
// While descending, also retain the deepest parent with a non-removed sibling.
if (node.length) while (true) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
if (!node.length) break;
if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
}
// Find the point to remove.
while (node.data !== d) if (!(previous = node, node = node.next)) return this;
if (next = node.next) delete node.next;
// If there are multiple coincident points, remove just the point.
if (previous) return (next ? previous.next = next : delete previous.next), this;
// If this is the root point, remove it.
if (!parent) return this._root = next, this;
// Remove this leaf.
next ? parent[i] = next : delete parent[i];
// If the parent now contains exactly one leaf, collapse superfluous parents.
if ((node = parent[0] || parent[1] || parent[2] || parent[3])
&& node === (parent[3] || parent[2] || parent[1] || parent[0])
&& !node.length) {
if (retainer) retainer[j] = node;
else this._root = node;
}
return this;
};
function removeAll(data) {
for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
return this;
}
var tree_root = function() {
return this._root;
};
var tree_size = function() {
var size = 0;
this.visit(function(node) {
if (!node.length) do ++size; while (node = node.next)
});
return size;
};
var tree_visit = function(callback) {
var quads = [], q, node = this._root, child, x0, y0, x1, y1;
if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
}
}
return this;
};
var tree_visitAfter = function(callback) {
var quads = [], next = [], q;
if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
var node = q.node;
if (node.length) {
var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
}
next.push(q);
}
while (q = next.pop()) {
callback(q.node, q.x0, q.y0, q.x1, q.y1);
}
return this;
};
function defaultX(d) {
return d[0];
}
var tree_x = function(_) {
return arguments.length ? (this._x = _, this) : this._x;
};
function defaultY(d) {
return d[1];
}
var tree_y = function(_) {
return arguments.length ? (this._y = _, this) : this._y;
};
function quadtree(nodes, x, y) {
var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
return nodes == null ? tree : tree.addAll(nodes);
}
function Quadtree(x, y, x0, y0, x1, y1) {
this._x = x;
this._y = y;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
this._root = undefined;
}
function leaf_copy(leaf) {
var copy = {data: leaf.data}, next = copy;
while (leaf = leaf.next) next = next.next = {data: leaf.data};
return copy;
}
var treeProto = quadtree.prototype = Quadtree.prototype;
treeProto.copy = function() {
var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
node = this._root,
nodes,
child;
if (!node) return copy;
if (!node.length) return copy._root = leaf_copy(node), copy;
nodes = [{source: node, target: copy._root = new Array(4)}];
while (node = nodes.pop()) {
for (var i = 0; i < 4; ++i) {
if (child = node.source[i]) {
if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
else node.target[i] = leaf_copy(child);
}
}
}
return copy;
};
treeProto.add = tree_add;
treeProto.addAll = addAll;
treeProto.cover = tree_cover;
treeProto.data = tree_data;
treeProto.extent = tree_extent;
treeProto.find = tree_find;
treeProto.remove = tree_remove;
treeProto.removeAll = removeAll;
treeProto.root = tree_root;
treeProto.size = tree_size;
treeProto.visit = tree_visit;
treeProto.visitAfter = tree_visitAfter;
treeProto.x = tree_x;
treeProto.y = tree_y;
exports.quadtree = quadtree;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],117:[function(require,module,exports){
// https://d3js.org/d3-timer/ Version 1.0.5. Copyright 2017 Mike Bostock.
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, (function (exports) { 'use strict';
var frame = 0;
var timeout = 0;
var interval = 0;
var pokeDelay = 1000;
var taskHead;
var taskTail;
var clockLast = 0;
var clockNow = 0;
var clockSkew = 0;
var clock = typeof performance === "object" && performance.now ? performance : Date;
var setFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : function(f) { setTimeout(f, 17); };
function now() {
return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
}
function clearNow() {
clockNow = 0;
}
function Timer() {
this._call =
this._time =
this._next = null;
}
Timer.prototype = timer.prototype = {
constructor: Timer,
restart: function(callback, delay, time) {
if (typeof callback !== "function") throw new TypeError("callback is not a function");
time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
if (!this._next && taskTail !== this) {
if (taskTail) taskTail._next = this;
else taskHead = this;
taskTail = this;
}
this._call = callback;
this._time = time;
sleep();
},
stop: function() {
if (this._call) {
this._call = null;
this._time = Infinity;
sleep();
}
}
};
function timer(callback, delay, time) {
var t = new Timer;
t.restart(callback, delay, time);
return t;
}
function timerFlush() {
now(); // Get the current time, if not already set.
++frame; // Pretend we’ve set an alarm, if we haven’t already.
var t = taskHead, e;
while (t) {
if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
t = t._next;
}
--frame;
}
function wake() {
clockNow = (clockLast = clock.now()) + clockSkew;
frame = timeout = 0;
try {
timerFlush();
} finally {
frame = 0;
nap();
clockNow = 0;
}
}
function poke() {
var now = clock.now(), delay = now - clockLast;
if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
}
function nap() {
var t0, t1 = taskHead, t2, time = Infinity;
while (t1) {
if (t1._call) {
if (time > t1._time) time = t1._time;
t0 = t1, t1 = t1._next;
} else {
t2 = t1._next, t1._next = null;
t1 = t0 ? t0._next = t2 : taskHead = t2;
}
}
taskTail = t0;
sleep(time);
}
function sleep(time) {
if (frame) return; // Soonest alarm already set, or will be.
if (timeout) timeout = clearTimeout(timeout);
var delay = time - clockNow;
if (delay > 24) {
if (time < Infinity) timeout = setTimeout(wake, delay);
if (interval) interval = clearInterval(interval);
} else {
if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
frame = 1, setFrame(wake);
}
}
var timeout$1 = function(callback, delay, time) {
var t = new Timer;
delay = delay == null ? 0 : +delay;
t.restart(function(elapsed) {
t.stop();
callback(elapsed + delay);
}, delay, time);
return t;
};
var interval$1 = function(callback, delay, time) {
var t = new Timer, total = delay;
if (delay == null) return t.restart(callback, delay, time), t;
delay = +delay, time = time == null ? now() : +time;
t.restart(function tick(elapsed) {
elapsed += total;
t.restart(tick, total += delay, time);
callback(elapsed);
}, delay, time);
return t;
};
exports.now = now;
exports.timer = timer;
exports.timerFlush = timerFlush;
exports.timeout = timeout$1;
exports.interval = interval$1;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}],118:[function(require,module,exports){
!function() {
var d3 = {
version: "3.5.17"
};
var d3_arraySlice = [].slice, d3_array = function(list) {
return d3_arraySlice.call(list);
};
var d3_document = this.document;
function d3_documentElement(node) {
return node && (node.ownerDocument || node.document || node).documentElement;
}
function d3_window(node) {
return node && (node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView);
}
if (d3_document) {
try {
d3_array(d3_document.documentElement.childNodes)[0].nodeType;
} catch (e) {
d3_array = function(list) {
var i = list.length, array = new Array(i);
while (i--) array[i] = list[i];
return array;
};
}
}
if (!Date.now) Date.now = function() {
return +new Date();
};
if (d3_document) {
try {
d3_document.createElement("DIV").style.setProperty("opacity", 0, "");
} catch (error) {
var d3_element_prototype = this.Element.prototype, d3_element_setAttribute = d3_element_prototype.setAttribute, d3_element_setAttributeNS = d3_element_prototype.setAttributeNS, d3_style_prototype = this.CSSStyleDeclaration.prototype, d3_style_setProperty = d3_style_prototype.setProperty;
d3_element_prototype.setAttribute = function(name, value) {
d3_element_setAttribute.call(this, name, value + "");
};
d3_element_prototype.setAttributeNS = function(space, local, value) {
d3_element_setAttributeNS.call(this, space, local, value + "");
};
d3_style_prototype.setProperty = function(name, value, priority) {
d3_style_setProperty.call(this, name, value + "", priority);
};
}
}
d3.ascending = d3_ascending;
function d3_ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
d3.descending = function(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
};
d3.min = function(array, f) {
var i = -1, n = array.length, a, b;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
}
return a;
};
d3.max = function(array, f) {
var i = -1, n = array.length, a, b;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = array[i]) != null && b > a) a = b;
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
}
return a;
};
d3.extent = function(array, f) {
var i = -1, n = array.length, a, b, c;
if (arguments.length === 1) {
while (++i < n) if ((b = array[i]) != null && b >= b) {
a = c = b;
break;
}
while (++i < n) if ((b = array[i]) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
} else {
while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) {
a = c = b;
break;
}
while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
return [ a, c ];
};
function d3_number(x) {
return x === null ? NaN : +x;
}
function d3_numeric(x) {
return !isNaN(x);
}
d3.sum = function(array, f) {
var s = 0, n = array.length, a, i = -1;
if (arguments.length === 1) {
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};
d3.mean = function(array, f) {
var s = 0, n = array.length, a, i = -1, j = n;
if (arguments.length === 1) {
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
} else {
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
}
if (j) return s / j;
};
d3.quantile = function(values, p) {
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;
};
d3.median = function(array, f) {
var numbers = [], n = array.length, a, i = -1;
if (arguments.length === 1) {
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);
} else {
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);
}
if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);
};
d3.variance = function(array, f) {
var n = array.length, m = 0, a, d, s = 0, i = -1, j = 0;
if (arguments.length === 1) {
while (++i < n) {
if (d3_numeric(a = d3_number(array[i]))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
} else {
while (++i < n) {
if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
if (j > 1) return s / (j - 1);
};
d3.deviation = function() {
var v = d3.variance.apply(this, arguments);
return v ? Math.sqrt(v) : v;
};
function d3_bisector(compare) {
return {
left: function(a, x, lo, hi) {
if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1; else hi = mid;
}
return lo;
},
right: function(a, x, lo, hi) {
if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) > 0) hi = mid; else lo = mid + 1;
}
return lo;
}
};
}
var d3_bisect = d3_bisector(d3_ascending);
d3.bisectLeft = d3_bisect.left;
d3.bisect = d3.bisectRight = d3_bisect.right;
d3.bisector = function(f) {
return d3_bisector(f.length === 1 ? function(d, x) {
return d3_ascending(f(d), x);
} : f);
};
d3.shuffle = function(array, i0, i1) {
if ((m = arguments.length) < 3) {
i1 = array.length;
if (m < 2) i0 = 0;
}
var m = i1 - i0, t, i;
while (m) {
i = Math.random() * m-- | 0;
t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;
}
return array;
};
d3.permute = function(array, indexes) {
var i = indexes.length, permutes = new Array(i);
while (i--) permutes[i] = array[indexes[i]];
return permutes;
};
d3.pairs = function(array) {
var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = [ p0 = p1, p1 = array[++i] ];
return pairs;
};
d3.transpose = function(matrix) {
if (!(n = matrix.length)) return [];
for (var i = -1, m = d3.min(matrix, d3_transposeLength), transpose = new Array(m); ++i < m; ) {
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n; ) {
row[j] = matrix[j][i];
}
}
return transpose;
};
function d3_transposeLength(d) {
return d.length;
}
d3.zip = function() {
return d3.transpose(arguments);
};
d3.keys = function(map) {
var keys = [];
for (var key in map) keys.push(key);
return keys;
};
d3.values = function(map) {
var values = [];
for (var key in map) values.push(map[key]);
return values;
};
d3.entries = function(map) {
var entries = [];
for (var key in map) entries.push({
key: key,
value: map[key]
});
return entries;
};
d3.merge = function(arrays) {
var n = arrays.length, m, i = -1, j = 0, merged, array;
while (++i < n) j += arrays[i].length;
merged = new Array(j);
while (--n >= 0) {
array = arrays[n];
m = array.length;
while (--m >= 0) {
merged[--j] = array[m];
}
}
return merged;
};
var abs = Math.abs;
d3.range = function(start, stop, step) {
if (arguments.length < 3) {
step = 1;
if (arguments.length < 2) {
stop = start;
start = 0;
}
}
if ((stop - start) / step === Infinity) throw new Error("infinite range");
var range = [], k = d3_range_integerScale(abs(step)), i = -1, j;
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);
return range;
};
function d3_range_integerScale(x) {
var k = 1;
while (x * k % 1) k *= 10;
return k;
}
function d3_class(ctor, properties) {
for (var key in properties) {
Object.defineProperty(ctor.prototype, key, {
value: properties[key],
enumerable: false
});
}
}
d3.map = function(object, f) {
var map = new d3_Map();
if (object instanceof d3_Map) {
object.forEach(function(key, value) {
map.set(key, value);
});
} else if (Array.isArray(object)) {
var i = -1, n = object.length, o;
if (arguments.length === 1) while (++i < n) map.set(i, object[i]); else while (++i < n) map.set(f.call(object, o = object[i], i), o);
} else {
for (var key in object) map.set(key, object[key]);
}
return map;
};
function d3_Map() {
this._ = Object.create(null);
}
var d3_map_proto = "__proto__", d3_map_zero = "\x00";
d3_class(d3_Map, {
has: d3_map_has,
get: function(key) {
return this._[d3_map_escape(key)];
},
set: function(key, value) {
return this._[d3_map_escape(key)] = value;
},
remove: d3_map_remove,
keys: d3_map_keys,
values: function() {
var values = [];
for (var key in this._) values.push(this._[key]);
return values;
},
entries: function() {
var entries = [];
for (var key in this._) entries.push({
key: d3_map_unescape(key),
value: this._[key]
});
return entries;
},
size: d3_map_size,
empty: d3_map_empty,
forEach: function(f) {
for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);
}
});
function d3_map_escape(key) {
return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
}
function d3_map_unescape(key) {
return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
}
function d3_map_has(key) {
return d3_map_escape(key) in this._;
}
function d3_map_remove(key) {
return (key = d3_map_escape(key)) in this._ && delete this._[key];
}
function d3_map_keys() {
var keys = [];
for (var key in this._) keys.push(d3_map_unescape(key));
return keys;
}
function d3_map_size() {
var size = 0;
for (var key in this._) ++size;
return size;
}
function d3_map_empty() {
for (var key in this._) return false;
return true;
}
d3.nest = function() {
var nest = {}, keys = [], sortKeys = [], sortValues, rollup;
function map(mapType, array, depth) {
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, setter, valuesByKey = new d3_Map(), values;
while (++i < n) {
if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
values.push(object);
} else {
valuesByKey.set(keyValue, [ object ]);
}
}
if (mapType) {
object = mapType();
setter = function(keyValue, values) {
object.set(keyValue, map(mapType, values, depth));
};
} else {
object = {};
setter = function(keyValue, values) {
object[keyValue] = map(mapType, values, depth);
};
}
valuesByKey.forEach(setter);
return object;
}
function entries(map, depth) {
if (depth >= keys.length) return map;
var array = [], sortKey = sortKeys[depth++];
map.forEach(function(key, keyMap) {
array.push({
key: key,
values: entries(keyMap, depth)
});
});
return sortKey ? array.sort(function(a, b) {
return sortKey(a.key, b.key);
}) : array;
}
nest.map = function(array, mapType) {
return map(mapType, array, 0);
};
nest.entries = function(array) {
return entries(map(d3.map, array, 0), 0);
};
nest.key = function(d) {
keys.push(d);
return nest;
};
nest.sortKeys = function(order) {
sortKeys[keys.length - 1] = order;
return nest;
};
nest.sortValues = function(order) {
sortValues = order;
return nest;
};
nest.rollup = function(f) {
rollup = f;
return nest;
};
return nest;
};
d3.set = function(array) {
var set = new d3_Set();
if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
return set;
};
function d3_Set() {
this._ = Object.create(null);
}
d3_class(d3_Set, {
has: d3_map_has,
add: function(key) {
this._[d3_map_escape(key += "")] = true;
return key;
},
remove: d3_map_remove,
values: d3_map_keys,
size: d3_map_size,
empty: d3_map_empty,
forEach: function(f) {
for (var key in this._) f.call(this, d3_map_unescape(key));
}
});
d3.behavior = {};
function d3_identity(d) {
return d;
}
d3.rebind = function(target, source) {
var i = 1, n = arguments.length, method;
while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
return target;
};
function d3_rebind(target, source, method) {
return function() {
var value = method.apply(source, arguments);
return value === source ? target : value;
};
}
function d3_vendorSymbol(object, name) {
if (name in object) return name;
name = name.charAt(0).toUpperCase() + name.slice(1);
for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
var prefixName = d3_vendorPrefixes[i] + name;
if (prefixName in object) return prefixName;
}
}
var d3_vendorPrefixes = [ "webkit", "ms", "moz", "Moz", "o", "O" ];
function d3_noop() {}
d3.dispatch = function() {
var dispatch = new d3_dispatch(), i = -1, n = arguments.length;
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
return dispatch;
};
function d3_dispatch() {}
d3_dispatch.prototype.on = function(type, listener) {
var i = type.indexOf("."), name = "";
if (i >= 0) {
name = type.slice(i + 1);
type = type.slice(0, i);
}
if (type) return arguments.length < 2 ? this[type].on(name) : this[type].on(name, listener);
if (arguments.length === 2) {
if (listener == null) for (type in this) {
if (this.hasOwnProperty(type)) this[type].on(name, null);
}
return this;
}
};
function d3_dispatch_event(dispatch) {
var listeners = [], listenerByName = new d3_Map();
function event() {
var z = listeners, i = -1, n = z.length, l;
while (++i < n) if (l = z[i].on) l.apply(this, arguments);
return dispatch;
}
event.on = function(name, listener) {
var l = listenerByName.get(name), i;
if (arguments.length < 2) return l && l.on;
if (l) {
l.on = null;
listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
listenerByName.remove(name);
}
if (listener) listeners.push(listenerByName.set(name, {
on: listener
}));
return dispatch;
};
return event;
}
d3.event = null;
function d3_eventPreventDefault() {
d3.event.preventDefault();
}
function d3_eventSource() {
var e = d3.event, s;
while (s = e.sourceEvent) e = s;
return e;
}
function d3_eventDispatch(target) {
var dispatch = new d3_dispatch(), i = 0, n = arguments.length;
while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
dispatch.of = function(thiz, argumentz) {
return function(e1) {
try {
var e0 = e1.sourceEvent = d3.event;
e1.target = target;
d3.event = e1;
dispatch[e1.type].apply(thiz, argumentz);
} finally {
d3.event = e0;
}
};
};
return dispatch;
}
d3.requote = function(s) {
return s.replace(d3_requote_re, "\\$&");
};
var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
var d3_subclass = {}.__proto__ ? function(object, prototype) {
object.__proto__ = prototype;
} : function(object, prototype) {
for (var property in prototype) object[property] = prototype[property];
};
function d3_selection(groups) {
d3_subclass(groups, d3_selectionPrototype);
return groups;
}
var d3_select = function(s, n) {
return n.querySelector(s);
}, d3_selectAll = function(s, n) {
return n.querySelectorAll(s);
}, d3_selectMatches = function(n, s) {
var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")];
d3_selectMatches = function(n, s) {
return d3_selectMatcher.call(n, s);
};
return d3_selectMatches(n, s);
};
if (typeof Sizzle === "function") {
d3_select = function(s, n) {
return Sizzle(s, n)[0] || null;
};
d3_selectAll = Sizzle;
d3_selectMatches = Sizzle.matchesSelector;
}
d3.selection = function() {
return d3.select(d3_document.documentElement);
};
var d3_selectionPrototype = d3.selection.prototype = [];
d3_selectionPrototype.select = function(selector) {
var subgroups = [], subgroup, subnode, group, node;
selector = d3_selection_selector(selector);
for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []);
subgroup.parentNode = (group = this[j]).parentNode;
for (var i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) {
subgroup.push(subnode = selector.call(node, node.__data__, i, j));
if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
}
}
}
return d3_selection(subgroups);
};
function d3_selection_selector(selector) {
return typeof selector === "function" ? selector : function() {
return d3_select(selector, this);
};
}
d3_selectionPrototype.selectAll = function(selector) {
var subgroups = [], subgroup, node;
selector = d3_selection_selectorAll(selector);
for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) {
subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
subgroup.parentNode = node;
}
}
}
return d3_selection(subgroups);
};
function d3_selection_selectorAll(selector) {
return typeof selector === "function" ? selector : function() {
return d3_selectAll(selector, this);
};
}
var d3_nsXhtml = "http://www.w3.org/1999/xhtml";
var d3_nsPrefix = {
svg: "http://www.w3.org/2000/svg",
xhtml: d3_nsXhtml,
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
d3.ns = {
prefix: d3_nsPrefix,
qualify: function(name) {
var i = name.indexOf(":"), prefix = name;
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return d3_nsPrefix.hasOwnProperty(prefix) ? {
space: d3_nsPrefix[prefix],
local: name
} : name;
}
};
d3_selectionPrototype.attr = function(name, value) {
if (arguments.length < 2) {
if (typeof name === "string") {
var node = this.node();
name = d3.ns.qualify(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]));
return this;
}
return this.each(d3_selection_attr(name, value));
};
function d3_selection_attr(name, value) {
name = d3.ns.qualify(name);
function attrNull() {
this.removeAttribute(name);
}
function attrNullNS() {
this.removeAttributeNS(name.space, name.local);
}
function attrConstant() {
this.setAttribute(name, value);
}
function attrConstantNS() {
this.setAttributeNS(name.space, name.local, value);
}
function attrFunction() {
var x = value.apply(this, arguments);
if (x == null) this.removeAttribute(name); else this.setAttribute(name, x);
}
function attrFunctionNS() {
var x = value.apply(this, arguments);
if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
}
return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
}
function d3_collapse(s) {
return s.trim().replace(/\s+/g, " ");
}
d3_selectionPrototype.classed = function(name, value) {
if (arguments.length < 2) {
if (typeof name === "string") {
var node = this.node(), n = (name = d3_selection_classes(name)).length, i = -1;
if (value = node.classList) {
while (++i < n) if (!value.contains(name[i])) return false;
} else {
value = node.getAttribute("class");
while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
}
return true;
}
for (value in name) this.each(d3_selection_classed(value, name[value]));
return this;
}
return this.each(d3_selection_classed(name, value));
};
function d3_selection_classedRe(name) {
return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
}
function d3_selection_classes(name) {
return (name + "").trim().split(/^|\s+/);
}
function d3_selection_classed(name, value) {
name = d3_selection_classes(name).map(d3_selection_classedName);
var n = name.length;
function classedConstant() {
var i = -1;
while (++i < n) name[i](this, value);
}
function classedFunction() {
var i = -1, x = value.apply(this, arguments);
while (++i < n) name[i](this, x);
}
return typeof value === "function" ? classedFunction : classedConstant;
}
function d3_selection_classedName(name) {
var re = d3_selection_classedRe(name);
return function(node, value) {
if (c = node.classList) return value ? c.add(name) : c.remove(name);
var c = node.getAttribute("class") || "";
if (value) {
re.lastIndex = 0;
if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
} else {
node.setAttribute("class", d3_collapse(c.replace(re, " ")));
}
};
}
d3_selectionPrototype.style = function(name, value, priority) {
var n = arguments.length;
if (n < 3) {
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
return this;
}
if (n < 2) {
var node = this.node();
return d3_window(node).getComputedStyle(node, null).getPropertyValue(name);
}
priority = "";
}
return this.each(d3_selection_style(name, value, priority));
};
function d3_selection_style(name, value, priority) {
function styleNull() {
this.style.removeProperty(name);
}
function styleConstant() {
this.style.setProperty(name, value, priority);
}
function styleFunction() {
var x = value.apply(this, arguments);
if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
}
return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
}
d3_selectionPrototype.property = function(name, value) {
if (arguments.length < 2) {
if (typeof name === "string") return this.node()[name];
for (value in name) this.each(d3_selection_property(value, name[value]));
return this;
}
return this.each(d3_selection_property(name, value));
};
function d3_selection_property(name, value) {
function propertyNull() {
delete this[name];
}
function propertyConstant() {
this[name] = value;
}
function propertyFunction() {
var x = value.apply(this, arguments);
if (x == null) delete this[name]; else this[name] = x;
}
return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
}
d3_selectionPrototype.text = function(value) {
return arguments.length ? this.each(typeof value === "function" ? function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
} : value == null ? function() {
this.textContent = "";
} : function() {
this.textContent = value;
}) : this.node().textContent;
};
d3_selectionPrototype.html = function(value) {
return arguments.length ? this.each(typeof value === "function" ? function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
} : value == null ? function() {
this.innerHTML = "";
} : function() {
this.innerHTML = value;
}) : this.node().innerHTML;
};
d3_selectionPrototype.append = function(name) {
name = d3_selection_creator(name);
return this.select(function() {
return this.appendChild(name.apply(this, arguments));
});
};
function d3_selection_creator(name) {
function create() {
var document = this.ownerDocument, namespace = this.namespaceURI;
return namespace === d3_nsXhtml && document.documentElement.namespaceURI === d3_nsXhtml ? document.createElement(name) : document.createElementNS(namespace, name);
}
function createNS() {
return this.ownerDocument.createElementNS(name.space, name.local);
}
return typeof name === "function" ? name : (name = d3.ns.qualify(name)).local ? createNS : create;
}
d3_selectionPrototype.insert = function(name, before) {
name = d3_selection_creator(name);
before = d3_selection_selector(before);
return this.select(function() {
return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
});
};
d3_selectionPrototype.remove = function() {
return this.each(d3_selectionRemove);
};
function d3_selectionRemove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
d3_selectionPrototype.data = function(value, key) {
var i = -1, n = this.length, group, node;
if (!arguments.length) {
value = new Array(n = (group = this[0]).length);
while (++i < n) {
if (node = group[i]) {
value[i] = node.__data__;
}
}
return value;
}
function bind(group, groupData) {
var i, n = group.length, m = groupData.length, n0 = Math.min(n, m), updateNodes = new Array(m), enterNodes = new Array(m), exitNodes = new Array(n), node, nodeData;
if (key) {
var nodeByKeyValue = new d3_Map(), keyValues = new Array(n), keyValue;
for (i = -1; ++i < n; ) {
if (node = group[i]) {
if (nodeByKeyValue.has(keyValue = key.call(node, node.__data__, i))) {
exitNodes[i] = node;
} else {
nodeByKeyValue.set(keyValue, node);
}
keyValues[i] = keyValue;
}
}
for (i = -1; ++i < m; ) {
if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {
enterNodes[i] = d3_selection_dataNode(nodeData);
} else if (node !== true) {
updateNodes[i] = node;
node.__data__ = nodeData;
}
nodeByKeyValue.set(keyValue, true);
}
for (i = -1; ++i < n; ) {
if (i in keyValues && nodeByKeyValue.get(keyValues[i]) !== true) {
exitNodes[i] = group[i];
}
}
} else {
for (i = -1; ++i < n0; ) {
node = group[i];
nodeData = groupData[i];
if (node) {
node.__data__ = nodeData;
updateNodes[i] = node;
} else {
enterNodes[i] = d3_selection_dataNode(nodeData);
}
}
for (;i < m; ++i) {
enterNodes[i] = d3_selection_dataNode(groupData[i]);
}
for (;i < n; ++i) {
exitNodes[i] = group[i];
}
}
enterNodes.update = updateNodes;
enterNodes.parentNode = updateNodes.parentNode = exitNodes.parentNode = group.parentNode;
enter.push(enterNodes);
update.push(updateNodes);
exit.push(exitNodes);
}
var enter = d3_selection_enter([]), update = d3_selection([]), exit = d3_selection([]);
if (typeof value === "function") {
while (++i < n) {
bind(group = this[i], value.call(group, group.parentNode.__data__, i));
}
} else {
while (++i < n) {
bind(group = this[i], value);
}
}
update.enter = function() {
return enter;
};
update.exit = function() {
return exit;
};
return update;
};
function d3_selection_dataNode(data) {
return {
__data__: data
};
}
d3_selectionPrototype.datum = function(value) {
return arguments.length ? this.property("__data__", value) : this.property("__data__");
};
d3_selectionPrototype.filter = function(filter) {
var subgroups = [], subgroup, group, node;
if (typeof filter !== "function") filter = d3_selection_filter(filter);
for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []);
subgroup.parentNode = (group = this[j]).parentNode;
for (var i = 0, n = group.length; i < n; i++) {
if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
subgroup.push(node);
}
}
}
return d3_selection(subgroups);
};
function d3_selection_filter(selector) {
return function() {
return d3_selectMatches(this, selector);
};
}
d3_selectionPrototype.order = function() {
for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
if (node = group[i]) {
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
next = node;
}
}
}
return this;
};
d3_selectionPrototype.sort = function(comparator) {
comparator = d3_selection_sortComparator.apply(this, arguments);
for (var j = -1, m = this.length; ++j < m; ) this[j].sort(comparator);
return this.order();
};
function d3_selection_sortComparator(comparator) {
if (!arguments.length) comparator = d3_ascending;
return function(a, b) {
return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
};
}
d3_selectionPrototype.each = function(callback) {
return d3_selection_each(this, function(node, i, j) {
callback.call(node, node.__data__, i, j);
});
};
function d3_selection_each(groups, callback) {
for (var j = 0, m = groups.length; j < m; j++) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
if (node = group[i]) callback(node, i, j);
}
}
return groups;
}
d3_selectionPrototype.call = function(callback) {
var args = d3_array(arguments);
callback.apply(args[0] = this, args);
return this;
};
d3_selectionPrototype.empty = function() {
return !this.node();
};
d3_selectionPrototype.node = function() {
for (var j = 0, m = this.length; j < m; j++) {
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
var node = group[i];
if (node) return node;
}
}
return null;
};
d3_selectionPrototype.size = function() {
var n = 0;
d3_selection_each(this, function() {
++n;
});
return n;
};
function d3_selection_enter(selection) {
d3_subclass(selection, d3_selection_enterPrototype);
return selection;
}
var d3_selection_enterPrototype = [];
d3.selection.enter = d3_selection_enter;
d3.selection.enter.prototype = d3_selection_enterPrototype;
d3_selection_enterPrototype.append = d3_selectionPrototype.append;
d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
d3_selection_enterPrototype.node = d3_selectionPrototype.node;
d3_selection_enterPrototype.call = d3_selectionPrototype.call;
d3_selection_enterPrototype.size = d3_selectionPrototype.size;
d3_selection_enterPrototype.select = function(selector) {
var subgroups = [], subgroup, subnode, upgroup, group, node;
for (var j = -1, m = this.length; ++j < m; ) {
upgroup = (group = this[j]).update;
subgroups.push(subgroup = []);
subgroup.parentNode = group.parentNode;
for (var i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) {
subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
subnode.__data__ = node.__data__;
} else {
subgroup.push(null);
}
}
}
return d3_selection(subgroups);
};
d3_selection_enterPrototype.insert = function(name, before) {
if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
return d3_selectionPrototype.insert.call(this, name, before);
};
function d3_selection_enterInsertBefore(enter) {
var i0, j0;
return function(d, i, j) {
var group = enter[j].update, n = group.length, node;
if (j != j0) j0 = j, i0 = 0;
if (i >= i0) i0 = i + 1;
while (!(node = group[i0]) && ++i0 < n) ;
return node;
};
}
d3.select = function(node) {
var group;
if (typeof node === "string") {
group = [ d3_select(node, d3_document) ];
group.parentNode = d3_document.documentElement;
} else {
group = [ node ];
group.parentNode = d3_documentElement(node);
}
return d3_selection([ group ]);
};
d3.selectAll = function(nodes) {
var group;
if (typeof nodes === "string") {
group = d3_array(d3_selectAll(nodes, d3_document));
group.parentNode = d3_document.documentElement;
} else {
group = d3_array(nodes);
group.parentNode = null;
}
return d3_selection([ group ]);
};
d3_selectionPrototype.on = function(type, listener, capture) {
var n = arguments.length;
if (n < 3) {
if (typeof type !== "string") {
if (n < 2) listener = false;
for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
return this;
}
if (n < 2) return (n = this.node()["__on" + type]) && n._;
capture = false;
}
return this.each(d3_selection_on(type, listener, capture));
};
function d3_selection_on(type, listener, capture) {
var name = "__on" + type, i = type.indexOf("."), wrap = d3_selection_onListener;
if (i > 0) type = type.slice(0, i);
var filter = d3_selection_onFilters.get(type);
if (filter) type = filter, wrap = d3_selection_onFilter;
function onRemove() {
var l = this[name];
if (l) {
this.removeEventListener(type, l, l.$);
delete this[name];
}
}
function onAdd() {
var l = wrap(listener, d3_array(arguments));
onRemove.call(this);
this.addEventListener(type, this[name] = l, l.$ = capture);
l._ = listener;
}
function removeAll() {
var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), match;
for (var name in this) {
if (match = name.match(re)) {
var l = this[name];
this.removeEventListener(match[1], l, l.$);
delete this[name];
}
}
}
return i ? listener ? onAdd : onRemove : listener ? d3_noop : removeAll;
}
var d3_selection_onFilters = d3.map({
mouseenter: "mouseover",
mouseleave: "mouseout"
});
if (d3_document) {
d3_selection_onFilters.forEach(function(k) {
if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
});
}
function d3_selection_onListener(listener, argumentz) {
return function(e) {
var o = d3.event;
d3.event = e;
argumentz[0] = this.__data__;
try {
listener.apply(this, argumentz);
} finally {
d3.event = o;
}
};
}
function d3_selection_onFilter(listener, argumentz) {
var l = d3_selection_onListener(listener, argumentz);
return function(e) {
var target = this, related = e.relatedTarget;
if (!related || related !== target && !(related.compareDocumentPosition(target) & 8)) {
l.call(target, e);
}
};
}
var d3_event_dragSelect, d3_event_dragId = 0;
function d3_event_dragSuppress(node) {
var name = ".dragsuppress-" + ++d3_event_dragId, click = "click" + name, w = d3.select(d3_window(node)).on("touchmove" + name, d3_eventPreventDefault).on("dragstart" + name, d3_eventPreventDefault).on("selectstart" + name, d3_eventPreventDefault);
if (d3_event_dragSelect == null) {
d3_event_dragSelect = "onselectstart" in node ? false : d3_vendorSymbol(node.style, "userSelect");
}
if (d3_event_dragSelect) {
var style = d3_documentElement(node).style, select = style[d3_event_dragSelect];
style[d3_event_dragSelect] = "none";
}
return function(suppressClick) {
w.on(name, null);
if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
if (suppressClick) {
var off = function() {
w.on(click, null);
};
w.on(click, function() {
d3_eventPreventDefault();
off();
}, true);
setTimeout(off, 0);
}
};
}
d3.mouse = function(container) {
return d3_mousePoint(container, d3_eventSource());
};
var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0;
function d3_mousePoint(container, e) {
if (e.changedTouches) e = e.changedTouches[0];
var svg = container.ownerSVGElement || container;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
if (d3_mouse_bug44083 < 0) {
var window = d3_window(container);
if (window.scrollX || window.scrollY) {
svg = d3.select("body").append("svg").style({
position: "absolute",
top: 0,
left: 0,
margin: 0,
padding: 0,
border: "none"
}, "important");
var ctm = svg[0][0].getScreenCTM();
d3_mouse_bug44083 = !(ctm.f || ctm.e);
svg.remove();
}
}
if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; else point.x = e.clientX,
point.y = e.clientY;
point = point.matrixTransform(container.getScreenCTM().inverse());
return [ point.x, point.y ];
}
var rect = container.getBoundingClientRect();
return [ e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop ];
}
d3.touch = function(container, touches, identifier) {
if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
if ((touch = touches[i]).identifier === identifier) {
return d3_mousePoint(container, touch);
}
}
};
d3.behavior.drag = function() {
var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), origin = null, mousedown = dragstart(d3_noop, d3.mouse, d3_window, "mousemove", "mouseup"), touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_identity, "touchmove", "touchend");
function drag() {
this.on("mousedown.drag", mousedown).on("touchstart.drag", touchstart);
}
function dragstart(id, position, subject, move, end) {
return function() {
var that = this, target = d3.event.target.correspondingElement || d3.event.target, parent = that.parentNode, dispatch = event.of(that, arguments), dragged = 0, dragId = id(), dragName = ".drag" + (dragId == null ? "" : "-" + dragId), dragOffset, dragSubject = d3.select(subject(target)).on(move + dragName, moved).on(end + dragName, ended), dragRestore = d3_event_dragSuppress(target), position0 = position(parent, dragId);
if (origin) {
dragOffset = origin.apply(that, arguments);
dragOffset = [ dragOffset.x - position0[0], dragOffset.y - position0[1] ];
} else {
dragOffset = [ 0, 0 ];
}
dispatch({
type: "dragstart"
});
function moved() {
var position1 = position(parent, dragId), dx, dy;
if (!position1) return;
dx = position1[0] - position0[0];
dy = position1[1] - position0[1];
dragged |= dx | dy;
position0 = position1;
dispatch({
type: "drag",
x: position1[0] + dragOffset[0],
y: position1[1] + dragOffset[1],
dx: dx,
dy: dy
});
}
function ended() {
if (!position(parent, dragId)) return;
dragSubject.on(move + dragName, null).on(end + dragName, null);
dragRestore(dragged);
dispatch({
type: "dragend"
});
}
};
}
drag.origin = function(x) {
if (!arguments.length) return origin;
origin = x;
return drag;
};
return d3.rebind(drag, event, "on");
};
function d3_behavior_dragTouchId() {
return d3.event.changedTouches[0].identifier;
}
d3.touches = function(container, touches) {
if (arguments.length < 2) touches = d3_eventSource().touches;
return touches ? d3_array(touches).map(function(touch) {
var point = d3_mousePoint(container, touch);
point.identifier = touch.identifier;
return point;
}) : [];
};
var ε = 1e-6, ε2 = ε * ε, π = Math.PI, τ = 2 * π, τε = τ - ε, halfπ = π / 2, d3_radians = π / 180, d3_degrees = 180 / π;
function d3_sgn(x) {
return x > 0 ? 1 : x < 0 ? -1 : 0;
}
function d3_cross2d(a, b, c) {
return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
}
function d3_acos(x) {
return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
}
function d3_asin(x) {
return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
}
function d3_sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function d3_cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function d3_tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
function d3_haversin(x) {
return (x = Math.sin(x / 2)) * x;
}
var ρ = Math.SQRT2, ρ2 = 2, ρ4 = 4;
d3.interpolateZoom = function(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S;
if (d2 < ε2) {
S = Math.log(w1 / w0) / ρ;
i = function(t) {
return [ ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(ρ * t * S) ];
};
} else {
var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
S = (r1 - r0) / ρ;
i = function(t) {
var s = t * S, coshr0 = d3_cosh(r0), u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
return [ ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / d3_cosh(ρ * s + r0) ];
};
}
i.duration = S * 1e3;
return i;
};
d3.behavior.zoom = function() {
var view = {
x: 0,
y: 0,
k: 1
}, translate0, center0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, duration = 250, zooming = 0, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
if (!d3_behavior_zoomWheel) {
d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() {
return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1);
}, "wheel") : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() {
return d3.event.wheelDelta;
}, "mousewheel") : (d3_behavior_zoomDelta = function() {
return -d3.event.detail;
}, "MozMousePixelScroll");
}
function zoom(g) {
g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
}
zoom.event = function(g) {
g.each(function() {
var dispatch = event.of(this, arguments), view1 = view;
if (d3_transitionInheritId) {
d3.select(this).transition().each("start.zoom", function() {
view = this.__chart__ || {
x: 0,
y: 0,
k: 1
};
zoomstarted(dispatch);
}).tween("zoom:zoom", function() {
var dx = size[0], dy = size[1], cx = center0 ? center0[0] : dx / 2, cy = center0 ? center0[1] : dy / 2, i = d3.interpolateZoom([ (cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k ], [ (cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k ]);
return function(t) {
var l = i(t), k = dx / l[2];
this.__chart__ = view = {
x: cx - l[0] * k,
y: cy - l[1] * k,
k: k
};
zoomed(dispatch);
};
}).each("interrupt.zoom", function() {
zoomended(dispatch);
}).each("end.zoom", function() {
zoomended(dispatch);
});
} else {
this.__chart__ = view;
zoomstarted(dispatch);
zoomed(dispatch);
zoomended(dispatch);
}
});
};
zoom.translate = function(_) {
if (!arguments.length) return [ view.x, view.y ];
view = {
x: +_[0],
y: +_[1],
k: view.k
};
rescale();
return zoom;
};
zoom.scale = function(_) {
if (!arguments.length) return view.k;
view = {
x: view.x,
y: view.y,
k: null
};
scaleTo(+_);
rescale();
return zoom;
};
zoom.scaleExtent = function(_) {
if (!arguments.length) return scaleExtent;
scaleExtent = _ == null ? d3_behavior_zoomInfinity : [ +_[0], +_[1] ];
return zoom;
};
zoom.center = function(_) {
if (!arguments.length) return center;
center = _ && [ +_[0], +_[1] ];
return zoom;
};
zoom.size = function(_) {
if (!arguments.length) return size;
size = _ && [ +_[0], +_[1] ];
return zoom;
};
zoom.duration = function(_) {
if (!arguments.length) return duration;
duration = +_;
return zoom;
};
zoom.x = function(z) {
if (!arguments.length) return x1;
x1 = z;
x0 = z.copy();
view = {
x: 0,
y: 0,
k: 1
};
return zoom;
};
zoom.y = function(z) {
if (!arguments.length) return y1;
y1 = z;
y0 = z.copy();
view = {
x: 0,
y: 0,
k: 1
};
return zoom;
};
function location(p) {
return [ (p[0] - view.x) / view.k, (p[1] - view.y) / view.k ];
}
function point(l) {
return [ l[0] * view.k + view.x, l[1] * view.k + view.y ];
}
function scaleTo(s) {
view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
}
function translateTo(p, l) {
l = point(l);
view.x += p[0] - l[0];
view.y += p[1] - l[1];
}
function zoomTo(that, p, l, k) {
that.__chart__ = {
x: view.x,
y: view.y,
k: view.k
};
scaleTo(Math.pow(2, k));
translateTo(center0 = p, l);
that = d3.select(that);
if (duration > 0) that = that.transition().duration(duration);
that.call(zoom.event);
}
function rescale() {
if (x1) x1.domain(x0.range().map(function(x) {
return (x - view.x) / view.k;
}).map(x0.invert));
if (y1) y1.domain(y0.range().map(function(y) {
return (y - view.y) / view.k;
}).map(y0.invert));
}
function zoomstarted(dispatch) {
if (!zooming++) dispatch({
type: "zoomstart"
});
}
function zoomed(dispatch) {
rescale();
dispatch({
type: "zoom",
scale: view.k,
translate: [ view.x, view.y ]
});
}
function zoomended(dispatch) {
if (!--zooming) dispatch({
type: "zoomend"
}), center0 = null;
}
function mousedowned() {
var that = this, dispatch = event.of(that, arguments), dragged = 0, subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), location0 = location(d3.mouse(that)), dragRestore = d3_event_dragSuppress(that);
d3_selection_interrupt.call(that);
zoomstarted(dispatch);
function moved() {
dragged = 1;
translateTo(d3.mouse(that), location0);
zoomed(dispatch);
}
function ended() {
subject.on(mousemove, null).on(mouseup, null);
dragRestore(dragged);
zoomended(dispatch);
}
}
function touchstarted() {
var that = this, dispatch = event.of(that, arguments), locations0 = {}, distance0 = 0, scale0, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, touchmove = "touchmove" + zoomName, touchend = "touchend" + zoomName, targets = [], subject = d3.select(that), dragRestore = d3_event_dragSuppress(that);
started();
zoomstarted(dispatch);
subject.on(mousedown, null).on(touchstart, started);
function relocate() {
var touches = d3.touches(that);
scale0 = view.k;
touches.forEach(function(t) {
if (t.identifier in locations0) locations0[t.identifier] = location(t);
});
return touches;
}
function started() {
var target = d3.event.target;
d3.select(target).on(touchmove, moved).on(touchend, ended);
targets.push(target);
var changed = d3.event.changedTouches;
for (var i = 0, n = changed.length; i < n; ++i) {
locations0[changed[i].identifier] = null;
}
var touches = relocate(), now = Date.now();
if (touches.length === 1) {
if (now - touchtime < 500) {
var p = touches[0];
zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
d3_eventPreventDefault();
}
touchtime = now;
} else if (touches.length > 1) {
var p = touches[0], q = touches[1], dx = p[0] - q[0], dy = p[1] - q[1];
distance0 = dx * dx + dy * dy;
}
}
function moved() {
var touches = d3.touches(that), p0, l0, p1, l1;
d3_selection_interrupt.call(that);
for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
p1 = touches[i];
if (l1 = locations0[p1.identifier]) {
if (l0) break;
p0 = p1, l0 = l1;
}
}
if (l1) {
var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, scale1 = distance0 && Math.sqrt(distance1 / distance0);
p0 = [ (p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2 ];
l0 = [ (l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2 ];
scaleTo(scale1 * scale0);
}
touchtime = null;
translateTo(p0, l0);
zoomed(dispatch);
}
function ended() {
if (d3.event.touches.length) {
var changed = d3.event.changedTouches;
for (var i = 0, n = changed.length; i < n; ++i) {
delete locations0[changed[i].identifier];
}
for (var identifier in locations0) {
return void relocate();
}
}
d3.selectAll(targets).on(zoomName, null);
subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
dragRestore();
zoomended(dispatch);
}
}
function mousewheeled() {
var dispatch = event.of(this, arguments);
if (mousewheelTimer) clearTimeout(mousewheelTimer); else d3_selection_interrupt.call(this),
translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch);
mousewheelTimer = setTimeout(function() {
mousewheelTimer = null;
zoomended(dispatch);
}, 50);
d3_eventPreventDefault();
scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
translateTo(center0, translate0);
zoomed(dispatch);
}
function dblclicked() {
var p = d3.mouse(this), k = Math.log(view.k) / Math.LN2;
zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
}
return d3.rebind(zoom, event, "on");
};
var d3_behavior_zoomInfinity = [ 0, Infinity ], d3_behavior_zoomDelta, d3_behavior_zoomWheel;
d3.color = d3_color;
function d3_color() {}
d3_color.prototype.toString = function() {
return this.rgb() + "";
};
d3.hsl = d3_hsl;
function d3_hsl(h, s, l) {
return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) : arguments.length < 2 ? h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl) : new d3_hsl(h, s, l);
}
var d3_hslPrototype = d3_hsl.prototype = new d3_color();
d3_hslPrototype.brighter = function(k) {
k = Math.pow(.7, arguments.length ? k : 1);
return new d3_hsl(this.h, this.s, this.l / k);
};
d3_hslPrototype.darker = function(k) {
k = Math.pow(.7, arguments.length ? k : 1);
return new d3_hsl(this.h, this.s, k * this.l);
};
d3_hslPrototype.rgb = function() {
return d3_hsl_rgb(this.h, this.s, this.l);
};
function d3_hsl_rgb(h, s, l) {
var m1, m2;
h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
l = l < 0 ? 0 : l > 1 ? 1 : l;
m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
m1 = 2 * l - m2;
function v(h) {
if (h > 360) h -= 360; else if (h < 0) h += 360;
if (h < 60) return m1 + (m2 - m1) * h / 60;
if (h < 180) return m2;
if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
return m1;
}
function vv(h) {
return Math.round(v(h) * 255);
}
return new d3_rgb(vv(h + 120), vv(h), vv(h - 120));
}
d3.hcl = d3_hcl;
function d3_hcl(h, c, l) {
return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) : arguments.length < 2 ? h instanceof d3_hcl ? new 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) : new d3_hcl(h, c, l);
}
var d3_hclPrototype = d3_hcl.prototype = new d3_color();
d3_hclPrototype.brighter = function(k) {
return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
};
d3_hclPrototype.darker = function(k) {
return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
};
d3_hclPrototype.rgb = function() {
return d3_hcl_lab(this.h, this.c, this.l).rgb();
};
function d3_hcl_lab(h, c, l) {
if (isNaN(h)) h = 0;
if (isNaN(c)) c = 0;
return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
}
d3.lab = d3_lab;
function d3_lab(l, a, b) {
return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) : arguments.length < 2 ? l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) : l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b) : new d3_lab(l, a, b);
}
var d3_lab_K = 18;
var d3_lab_X = .95047, d3_lab_Y = 1, d3_lab_Z = 1.08883;
var d3_labPrototype = d3_lab.prototype = new d3_color();
d3_labPrototype.brighter = function(k) {
return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
};
d3_labPrototype.darker = function(k) {
return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
};
d3_labPrototype.rgb = function() {
return d3_lab_rgb(this.l, this.a, this.b);
};
function d3_lab_rgb(l, a, b) {
var y = (l + 16) / 116, x = y + a / 500, z = y - b / 200;
x = d3_lab_xyz(x) * d3_lab_X;
y = d3_lab_xyz(y) * d3_lab_Y;
z = d3_lab_xyz(z) * d3_lab_Z;
return new 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) {
return l > 0 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) : new d3_hcl(NaN, NaN, l);
}
function d3_lab_xyz(x) {
return x > .206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
}
function d3_xyz_lab(x) {
return x > .008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
}
function d3_xyz_rgb(r) {
return Math.round(255 * (r <= .00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - .055));
}
d3.rgb = d3_rgb;
function d3_rgb(r, g, b) {
return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) : arguments.length < 2 ? r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb) : new d3_rgb(r, g, b);
}
function d3_rgbNumber(value) {
return new d3_rgb(value >> 16, value >> 8 & 255, value & 255);
}
function d3_rgbString(value) {
return d3_rgbNumber(value) + "";
}
var d3_rgbPrototype = d3_rgb.prototype = new d3_color();
d3_rgbPrototype.brighter = function(k) {
k = Math.pow(.7, arguments.length ? k : 1);
var r = this.r, g = this.g, b = this.b, i = 30;
if (!r && !g && !b) return new d3_rgb(i, i, i);
if (r && r < i) r = i;
if (g && g < i) g = i;
if (b && b < i) b = i;
return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));
};
d3_rgbPrototype.darker = function(k) {
k = Math.pow(.7, arguments.length ? k : 1);
return new d3_rgb(k * this.r, k * this.g, k * this.b);
};
d3_rgbPrototype.hsl = function() {
return d3_rgb_hsl(this.r, this.g, this.b);
};
d3_rgbPrototype.toString = function() {
return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
};
function d3_rgb_hex(v) {
return v < 16 ? "0" + Math.max(0, v).toString(16) : Math.min(255, v).toString(16);
}
function d3_rgb_parse(format, rgb, hsl) {
var r = 0, g = 0, b = 0, m1, m2, color;
m1 = /([a-z]+)\((.*)\)/.exec(format = format.toLowerCase());
if (m1) {
m2 = m1[2].split(",");
switch (m1[1]) {
case "hsl":
{
return hsl(parseFloat(m2[0]), parseFloat(m2[1]) / 100, parseFloat(m2[2]) / 100);
}
case "rgb":
{
return rgb(d3_rgb_parseNumber(m2[0]), d3_rgb_parseNumber(m2[1]), d3_rgb_parseNumber(m2[2]));
}
}
}
if (color = d3_rgb_names.get(format)) {
return rgb(color.r, color.g, color.b);
}
if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) {
if (format.length === 4) {
r = (color & 3840) >> 4;
r = r >> 4 | r;
g = color & 240;
g = g >> 4 | g;
b = color & 15;
b = b << 4 | b;
} else if (format.length === 7) {
r = (color & 16711680) >> 16;
g = (color & 65280) >> 8;
b = color & 255;
}
}
return rgb(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;
if (d) {
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;
h *= 60;
} else {
h = NaN;
s = l > 0 && l < 1 ? 0 : h;
}
return new d3_hsl(h, s, l);
}
function d3_rgb_lab(r, g, b) {
r = d3_rgb_xyz(r);
g = d3_rgb_xyz(g);
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);
return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
}
function d3_rgb_xyz(r) {
return (r /= 255) <= .04045 ? r / 12.92 : Math.pow((r + .055) / 1.055, 2.4);
}
function d3_rgb_parseNumber(c) {
var f = parseFloat(c);
return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
}
var d3_rgb_names = d3.map({
aliceblue: 15792383,
antiquewhite: 16444375,
aqua: 65535,
aquamarine: 8388564,
azure: 15794175,
beige: 16119260,
bisque: 16770244,
black: 0,
blanchedalmond: 16772045,
blue: 255,
blueviolet: 9055202,
brown: 10824234,
burlywood: 14596231,
cadetblue: 6266528,
chartreuse: 8388352,
chocolate: 13789470,
coral: 16744272,
cornflowerblue: 6591981,
cornsilk: 16775388,
crimson: 14423100,
cyan: 65535,
darkblue: 139,
darkcyan: 35723,
darkgoldenrod: 12092939,
darkgray: 11119017,
darkgreen: 25600,
darkgrey: 11119017,
darkkhaki: 12433259,
darkmagenta: 9109643,
darkolivegreen: 5597999,
darkorange: 16747520,
darkorchid: 10040012,
darkred: 9109504,
darksalmon: 15308410,
darkseagreen: 9419919,
darkslateblue: 4734347,
darkslategray: 3100495,
darkslategrey: 3100495,
darkturquoise: 52945,
darkviolet: 9699539,
deeppink: 16716947,
deepskyblue: 49151,
dimgray: 6908265,
dimgrey: 6908265,
dodgerblue: 2003199,
firebrick: 11674146,
floralwhite: 16775920,
forestgreen: 2263842,
fuchsia: 16711935,
gainsboro: 14474460,
ghostwhite: 16316671,
gold: 16766720,
goldenrod: 14329120,
gray: 8421504,
green: 32768,
greenyellow: 11403055,
grey: 8421504,
honeydew: 15794160,
hotpink: 16738740,
indianred: 13458524,
indigo: 4915330,
ivory: 16777200,
khaki: 15787660,
lavender: 15132410,
lavenderblush: 16773365,
lawngreen: 8190976,
lemonchiffon: 16775885,
lightblue: 11393254,
lightcoral: 15761536,
lightcyan: 14745599,
lightgoldenrodyellow: 16448210,
lightgray: 13882323,
lightgreen: 9498256,
lightgrey: 13882323,
lightpink: 16758465,
lightsalmon: 16752762,
lightseagreen: 2142890,
lightskyblue: 8900346,
lightslategray: 7833753,
lightslategrey: 7833753,
lightsteelblue: 11584734,
lightyellow: 16777184,
lime: 65280,
limegreen: 3329330,
linen: 16445670,
magenta: 16711935,
maroon: 8388608,
mediumaquamarine: 6737322,
mediumblue: 205,
mediumorchid: 12211667,
mediumpurple: 9662683,
mediumseagreen: 3978097,
mediumslateblue: 8087790,
mediumspringgreen: 64154,
mediumturquoise: 4772300,
mediumvioletred: 13047173,
midnightblue: 1644912,
mintcream: 16121850,
mistyrose: 16770273,
moccasin: 16770229,
navajowhite: 16768685,
navy: 128,
oldlace: 16643558,
olive: 8421376,
olivedrab: 7048739,
orange: 16753920,
orangered: 16729344,
orchid: 14315734,
palegoldenrod: 15657130,
palegreen: 10025880,
paleturquoise: 11529966,
palevioletred: 14381203,
papayawhip: 16773077,
peachpuff: 16767673,
peru: 13468991,
pink: 16761035,
plum: 14524637,
powderblue: 11591910,
purple: 8388736,
rebeccapurple: 6697881,
red: 16711680,
rosybrown: 12357519,
royalblue: 4286945,
saddlebrown: 9127187,
salmon: 16416882,
sandybrown: 16032864,
seagreen: 3050327,
seashell: 16774638,
sienna: 10506797,
silver: 12632256,
skyblue: 8900331,
slateblue: 6970061,
slategray: 7372944,
slategrey: 7372944,
snow: 16775930,
springgreen: 65407,
steelblue: 4620980,
tan: 13808780,
teal: 32896,
thistle: 14204888,
tomato: 16737095,
turquoise: 4251856,
violet: 15631086,
wheat: 16113331,
white: 16777215,
whitesmoke: 16119285,
yellow: 16776960,
yellowgreen: 10145074
});
d3_rgb_names.forEach(function(key, value) {
d3_rgb_names.set(key, d3_rgbNumber(value));
});
function d3_functor(v) {
return typeof v === "function" ? v : function() {
return v;
};
}
d3.functor = d3_functor;
d3.xhr = d3_xhrType(d3_identity);
function d3_xhrType(response) {
return function(url, mimeType, callback) {
if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType,
mimeType = null;
return d3_xhr(url, mimeType, response, callback);
};
}
function d3_xhr(url, mimeType, response, callback) {
var xhr = {}, dispatch = d3.dispatch("beforesend", "progress", "load", "error"), headers = {}, request = new XMLHttpRequest(), responseType = null;
if (this.XDomainRequest && !("withCredentials" in request) && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
"onload" in request ? request.onload = request.onerror = respond : request.onreadystatechange = function() {
request.readyState > 3 && respond();
};
function respond() {
var status = request.status, result;
if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
try {
result = response.call(xhr, request);
} catch (e) {
dispatch.error.call(xhr, e);
return;
}
dispatch.load.call(xhr, result);
} else {
dispatch.error.call(xhr, request);
}
}
request.onprogress = function(event) {
var o = d3.event;
d3.event = event;
try {
dispatch.progress.call(xhr, request);
} finally {
d3.event = o;
}
};
xhr.header = function(name, value) {
name = (name + "").toLowerCase();
if (arguments.length < 2) return headers[name];
if (value == null) delete headers[name]; else headers[name] = value + "";
return xhr;
};
xhr.mimeType = function(value) {
if (!arguments.length) return mimeType;
mimeType = value == null ? null : value + "";
return xhr;
};
xhr.responseType = function(value) {
if (!arguments.length) return responseType;
responseType = value;
return xhr;
};
xhr.response = function(value) {
response = value;
return xhr;
};
[ "get", "post" ].forEach(function(method) {
xhr[method] = function() {
return xhr.send.apply(xhr, [ method ].concat(d3_array(arguments)));
};
});
xhr.send = function(method, data, callback) {
if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
request.open(method, url, true);
if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
if (responseType != null) request.responseType = responseType;
if (callback != null) xhr.on("error", callback).on("load", function(request) {
callback(null, request);
});
dispatch.beforesend.call(xhr, request);
request.send(data == null ? null : data);
return xhr;
};
xhr.abort = function() {
request.abort();
return xhr;
};
d3.rebind(xhr, dispatch, "on");
return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
}
function d3_xhr_fixCallback(callback) {
return callback.length === 1 ? function(error, request) {
callback(error == null ? request : null);
} : callback;
}
function d3_xhrHasResponse(request) {
var type = request.responseType;
return type && type !== "text" ? request.response : request.responseText;
}
d3.dsv = function(delimiter, mimeType) {
var reFormat = new RegExp('["' + delimiter + "\n]"), delimiterCode = delimiter.charCodeAt(0);
function dsv(url, row, callback) {
if (arguments.length < 3) callback = row, row = null;
var xhr = d3_xhr(url, mimeType, row == null ? response : typedResponse(row), callback);
xhr.row = function(_) {
return arguments.length ? xhr.response((row = _) == null ? response : typedResponse(_)) : row;
};
return xhr;
}
function response(request) {
return dsv.parse(request.responseText);
}
function typedResponse(f) {
return function(request) {
return dsv.parse(request.responseText, f);
};
}
dsv.parse = function(text, f) {
var o;
return dsv.parseRows(text, function(row, i) {
if (o) return o(row, i - 1);
var a = new Function("d", "return {" + row.map(function(name, i) {
return JSON.stringify(name) + ": d[" + i + "]";
}).join(",") + "}");
o = f ? function(row, i) {
return f(a(row), i);
} : a;
});
};
dsv.parseRows = function(text, f) {
var EOL = {}, EOF = {}, rows = [], N = text.length, I = 0, n = 0, t, eol;
function token() {
if (I >= N) return EOF;
if (eol) return eol = false, EOL;
var j = I;
if (text.charCodeAt(j) === 34) {
var i = j;
while (i++ < N) {
if (text.charCodeAt(i) === 34) {
if (text.charCodeAt(i + 1) !== 34) break;
++i;
}
}
I = i + 2;
var c = text.charCodeAt(i + 1);
if (c === 13) {
eol = true;
if (text.charCodeAt(i + 2) === 10) ++I;
} else if (c === 10) {
eol = true;
}
return text.slice(j + 1, i).replace(/""/g, '"');
}
while (I < N) {
var c = text.charCodeAt(I++), k = 1;
if (c === 10) eol = true; else if (c === 13) {
eol = true;
if (text.charCodeAt(I) === 10) ++I, ++k;
} else if (c !== delimiterCode) continue;
return text.slice(j, I - k);
}
return text.slice(j);
}
while ((t = token()) !== EOF) {
var a = [];
while (t !== EOL && t !== EOF) {
a.push(t);
t = token();
}
if (f && (a = f(a, n++)) == null) continue;
rows.push(a);
}
return rows;
};
dsv.format = function(rows) {
if (Array.isArray(rows[0])) return dsv.formatRows(rows);
var fieldSet = new d3_Set(), fields = [];
rows.forEach(function(row) {
for (var field in row) {
if (!fieldSet.has(field)) {
fields.push(fieldSet.add(field));
}
}
});
return [ fields.map(formatValue).join(delimiter) ].concat(rows.map(function(row) {
return fields.map(function(field) {
return formatValue(row[field]);
}).join(delimiter);
})).join("\n");
};
dsv.formatRows = function(rows) {
return rows.map(formatRow).join("\n");
};
function formatRow(row) {
return row.map(formatValue).join(delimiter);
}
function formatValue(text) {
return reFormat.test(text) ? '"' + text.replace(/\"/g, '""') + '"' : text;
}
return dsv;
};
d3.csv = d3.dsv(",", "text/csv");
d3.tsv = d3.dsv(" ", "text/tab-separated-values");
var d3_timer_queueHead, d3_timer_queueTail, d3_timer_interval, d3_timer_timeout, d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) {
setTimeout(callback, 17);
};
d3.timer = function() {
d3_timer.apply(this, arguments);
};
function d3_timer(callback, delay, then) {
var n = arguments.length;
if (n < 2) delay = 0;
if (n < 3) then = Date.now();
var time = then + delay, timer = {
c: callback,
t: time,
n: null
};
if (d3_timer_queueTail) d3_timer_queueTail.n = timer; else d3_timer_queueHead = timer;
d3_timer_queueTail = timer;
if (!d3_timer_interval) {
d3_timer_timeout = clearTimeout(d3_timer_timeout);
d3_timer_interval = 1;
d3_timer_frame(d3_timer_step);
}
return timer;
}
function d3_timer_step() {
var now = d3_timer_mark(), delay = d3_timer_sweep() - now;
if (delay > 24) {
if (isFinite(delay)) {
clearTimeout(d3_timer_timeout);
d3_timer_timeout = setTimeout(d3_timer_step, delay);
}
d3_timer_interval = 0;
} else {
d3_timer_interval = 1;
d3_timer_frame(d3_timer_step);
}
}
d3.timer.flush = function() {
d3_timer_mark();
d3_timer_sweep();
};
function d3_timer_mark() {
var now = Date.now(), timer = d3_timer_queueHead;
while (timer) {
if (now >= timer.t && timer.c(now - timer.t)) timer.c = null;
timer = timer.n;
}
return now;
}
function d3_timer_sweep() {
var t0, t1 = d3_timer_queueHead, time = Infinity;
while (t1) {
if (t1.c) {
if (t1.t < time) time = t1.t;
t1 = (t0 = t1).n;
} else {
t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
}
}
d3_timer_queueTail = t0;
return time;
}
function d3_format_precision(x, p) {
return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
}
d3.round = function(x, n) {
return n ? Math.round(x * (n = Math.pow(10, n))) / n : Math.round(x);
};
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) {
var i = 0;
if (value = +value) {
if (value < 0) value *= -1;
if (precision) value = d3.round(value, d3_format_precision(value, precision));
i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
}
return d3_formatPrefixes[8 + i / 3];
};
function d3_formatPrefix(d, i) {
var k = Math.pow(10, abs(8 - i) * 3);
return {
scale: i > 8 ? function(d) {
return d / k;
} : function(d) {
return d * k;
},
symbol: d
};
}
function d3_locale_numberFormat(locale) {
var locale_decimal = locale.decimal, locale_thousands = locale.thousands, locale_grouping = locale.grouping, locale_currency = locale.currency, formatGroup = locale_grouping && locale_thousands ? function(value, width) {
var i = value.length, t = [], j = 0, g = locale_grouping[0], length = 0;
while (i > 0 && g > 0) {
if (length + g + 1 > width) g = Math.max(1, width - length);
t.push(value.substring(i -= g, i + g));
if ((length += g + 1) > width) break;
g = locale_grouping[j = (j + 1) % locale_grouping.length];
}
return t.reverse().join(locale_thousands);
} : d3_identity;
return function(specifier) {
var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false, exponent = true;
if (precision) precision = +precision.substring(1);
if (zfill || fill === "0" && align === "=") {
zfill = fill = "0";
align = "=";
}
switch (type) {
case "n":
comma = true;
type = "g";
break;
case "%":
scale = 100;
suffix = "%";
type = "f";
break;
case "p":
scale = 100;
suffix = "%";
type = "r";
break;
case "b":
case "o":
case "x":
case "X":
if (symbol === "#") prefix = "0" + type.toLowerCase();
case "c":
exponent = false;
case "d":
integer = true;
precision = 0;
break;
case "s":
scale = -1;
type = "r";
break;
}
if (symbol === "$") prefix = locale_currency[0], suffix = locale_currency[1];
if (type == "r" && !precision) type = "g";
if (precision != null) {
if (type == "g") precision = Math.max(1, Math.min(21, precision)); else if (type == "e" || type == "f") precision = Math.max(0, Math.min(20, precision));
}
type = d3_format_types.get(type) || d3_format_typeDefault;
var zcomma = zfill && comma;
return function(value) {
var fullSuffix = suffix;
if (integer && value % 1) return "";
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign;
if (scale < 0) {
var unit = d3.formatPrefix(value, precision);
value = unit.scale(value);
fullSuffix = unit.symbol + suffix;
} else {
value *= scale;
}
value = type(value, precision);
var i = value.lastIndexOf("."), before, after;
if (i < 0) {
var j = exponent ? value.lastIndexOf("e") : -1;
if (j < 0) before = value, after = ""; else before = value.substring(0, j), after = value.substring(j);
} else {
before = value.substring(0, i);
after = locale_decimal + value.substring(i + 1);
}
if (!zfill && comma) before = formatGroup(before, Infinity);
var length = prefix.length + before.length + after.length + (zcomma ? 0 : negative.length), padding = length < width ? new Array(length = width - length + 1).join(fill) : "";
if (zcomma) before = formatGroup(padding + before, padding.length ? width - after.length : Infinity);
negative += prefix;
value = before + after;
return (align === "<" ? negative + value + padding : align === ">" ? padding + negative + value : align === "^" ? padding.substring(0, length >>= 1) + negative + value + padding.substring(length) : negative + (zcomma ? value : padding + value)) + fullSuffix;
};
};
}
var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i;
var d3_format_types = d3.map({
b: function(x) {
return x.toString(2);
},
c: function(x) {
return String.fromCharCode(x);
},
o: function(x) {
return x.toString(8);
},
x: function(x) {
return x.toString(16);
},
X: function(x) {
return x.toString(16).toUpperCase();
},
g: function(x, p) {
return x.toPrecision(p);
},
e: function(x, p) {
return x.toExponential(p);
},
f: function(x, p) {
return x.toFixed(p);
},
r: function(x, p) {
return (x = d3.round(x, d3_format_precision(x, p))).toFixed(Math.max(0, Math.min(20, d3_format_precision(x * (1 + 1e-15), p))));
}
});
function d3_format_typeDefault(x) {
return x + "";
}
var d3_time = d3.time = {}, d3_date = Date;
function d3_date_utc() {
this._ = new Date(arguments.length > 1 ? Date.UTC.apply(this, arguments) : arguments[0]);
}
d3_date_utc.prototype = {
getDate: function() {
return this._.getUTCDate();
},
getDay: function() {
return this._.getUTCDay();
},
getFullYear: function() {
return this._.getUTCFullYear();
},
getHours: function() {
return this._.getUTCHours();
},
getMilliseconds: function() {
return this._.getUTCMilliseconds();
},
getMinutes: function() {
return this._.getUTCMinutes();
},
getMonth: function() {
return this._.getUTCMonth();
},
getSeconds: function() {
return this._.getUTCSeconds();
},
getTime: function() {
return this._.getTime();
},
getTimezoneOffset: function() {
return 0;
},
valueOf: function() {
return this._.valueOf();
},
setDate: function() {
d3_time_prototype.setUTCDate.apply(this._, arguments);
},
setDay: function() {
d3_time_prototype.setUTCDay.apply(this._, arguments);
},
setFullYear: function() {
d3_time_prototype.setUTCFullYear.apply(this._, arguments);
},
setHours: function() {
d3_time_prototype.setUTCHours.apply(this._, arguments);
},
setMilliseconds: function() {
d3_time_prototype.setUTCMilliseconds.apply(this._, arguments);
},
setMinutes: function() {
d3_time_prototype.setUTCMinutes.apply(this._, arguments);
},
setMonth: function() {
d3_time_prototype.setUTCMonth.apply(this._, arguments);
},
setSeconds: function() {
d3_time_prototype.setUTCSeconds.apply(this._, arguments);
},
setTime: function() {
d3_time_prototype.setTime.apply(this._, arguments);
}
};
var d3_time_prototype = Date.prototype;
function d3_time_interval(local, step, number) {
function round(date) {
var d0 = local(date), d1 = offset(d0, 1);
return date - d0 < d1 - date ? d0 : d1;
}
function ceil(date) {
step(date = local(new d3_date(date - 1)), 1);
return date;
}
function offset(date, k) {
step(date = new d3_date(+date), k);
return date;
}
function range(t0, t1, dt) {
var time = ceil(t0), times = [];
if (dt > 1) {
while (time < t1) {
if (!(number(time) % dt)) times.push(new Date(+time));
step(time, 1);
}
} else {
while (time < t1) times.push(new Date(+time)), step(time, 1);
}
return times;
}
function range_utc(t0, t1, dt) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = t0;
return range(utc, t1, dt);
} finally {
d3_date = Date;
}
}
local.floor = local;
local.round = round;
local.ceil = ceil;
local.offset = offset;
local.range = range;
var utc = local.utc = d3_time_interval_utc(local);
utc.floor = utc;
utc.round = d3_time_interval_utc(round);
utc.ceil = d3_time_interval_utc(ceil);
utc.offset = d3_time_interval_utc(offset);
utc.range = range_utc;
return local;
}
function d3_time_interval_utc(method) {
return function(date, k) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = date;
return method(utc, k)._;
} finally {
d3_date = Date;
}
};
}
d3_time.year = d3_time_interval(function(date) {
date = d3_time.day(date);
date.setMonth(0, 1);
return date;
}, function(date, offset) {
date.setFullYear(date.getFullYear() + offset);
}, function(date) {
return date.getFullYear();
});
d3_time.years = d3_time.year.range;
d3_time.years.utc = d3_time.year.utc.range;
d3_time.day = d3_time_interval(function(date) {
var day = new d3_date(2e3, 0);
day.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());
return day;
}, function(date, offset) {
date.setDate(date.getDate() + offset);
}, function(date) {
return date.getDate() - 1;
});
d3_time.days = d3_time.day.range;
d3_time.days.utc = d3_time.day.utc.range;
d3_time.dayOfYear = function(date) {
var year = d3_time.year(date);
return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
};
[ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ].forEach(function(day, i) {
i = 7 - i;
var interval = d3_time[day] = d3_time_interval(function(date) {
(date = d3_time.day(date)).setDate(date.getDate() - (date.getDay() + i) % 7);
return date;
}, function(date, offset) {
date.setDate(date.getDate() + Math.floor(offset) * 7);
}, function(date) {
var day = d3_time.year(date).getDay();
return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7) - (day !== i);
});
d3_time[day + "s"] = interval.range;
d3_time[day + "s"].utc = interval.utc.range;
d3_time[day + "OfYear"] = function(date) {
var day = d3_time.year(date).getDay();
return Math.floor((d3_time.dayOfYear(date) + (day + i) % 7) / 7);
};
});
d3_time.week = d3_time.sunday;
d3_time.weeks = d3_time.sunday.range;
d3_time.weeks.utc = d3_time.sunday.utc.range;
d3_time.weekOfYear = d3_time.sundayOfYear;
function d3_locale_timeFormat(locale) {
var locale_dateTime = locale.dateTime, locale_date = locale.date, locale_time = locale.time, locale_periods = locale.periods, locale_days = locale.days, locale_shortDays = locale.shortDays, locale_months = locale.months, locale_shortMonths = locale.shortMonths;
function d3_time_format(template) {
var n = template.length;
function format(date) {
var string = [], i = -1, j = 0, c, p, f;
while (++i < n) {
if (template.charCodeAt(i) === 37) {
string.push(template.slice(j, i));
if ((p = d3_time_formatPads[c = template.charAt(++i)]) != null) c = template.charAt(++i);
if (f = d3_time_formats[c]) c = f(date, p == null ? c === "e" ? " " : "0" : p);
string.push(c);
j = i + 1;
}
}
string.push(template.slice(j, i));
return string.join("");
}
format.parse = function(string) {
var d = {
y: 1900,
m: 0,
d: 1,
H: 0,
M: 0,
S: 0,
L: 0,
Z: null
}, i = d3_time_parse(d, template, string, 0);
if (i != string.length) return null;
if ("p" in d) d.H = d.H % 12 + d.p * 12;
var localZ = d.Z != null && d3_date !== d3_date_utc, date = new (localZ ? d3_date_utc : d3_date)();
if ("j" in d) date.setFullYear(d.y, 0, d.j); else if ("W" in d || "U" in d) {
if (!("w" in d)) d.w = "W" in d ? 1 : 0;
date.setFullYear(d.y, 0, 1);
date.setFullYear(d.y, 0, "W" in d ? (d.w + 6) % 7 + d.W * 7 - (date.getDay() + 5) % 7 : d.w + d.U * 7 - (date.getDay() + 6) % 7);
} else date.setFullYear(d.y, d.m, d.d);
date.setHours(d.H + (d.Z / 100 | 0), d.M + d.Z % 100, d.S, d.L);
return localZ ? date._ : date;
};
format.toString = function() {
return template;
};
return format;
}
function d3_time_parse(date, template, string, j) {
var c, p, t, i = 0, n = template.length, m = string.length;
while (i < n) {
if (j >= m) return -1;
c = template.charCodeAt(i++);
if (c === 37) {
t = template.charAt(i++);
p = d3_time_parsers[t in d3_time_formatPads ? template.charAt(i++) : t];
if (!p || (j = p(date, string, j)) < 0) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
}
}
return j;
}
d3_time_format.utc = function(template) {
var local = d3_time_format(template);
function format(date) {
try {
d3_date = d3_date_utc;
var utc = new d3_date();
utc._ = date;
return local(utc);
} finally {
d3_date = Date;
}
}
format.parse = function(string) {
try {
d3_date = d3_date_utc;
var date = local.parse(string);
return date && date._;
} finally {
d3_date = Date;
}
};
format.toString = local.toString;
return format;
};
d3_time_format.multi = d3_time_format.utc.multi = d3_time_formatMulti;
var d3_time_periodLookup = d3.map(), d3_time_dayRe = d3_time_formatRe(locale_days), d3_time_dayLookup = d3_time_formatLookup(locale_days), d3_time_dayAbbrevRe = d3_time_formatRe(locale_shortDays), d3_time_dayAbbrevLookup = d3_time_formatLookup(locale_shortDays), d3_time_monthRe = d3_time_formatRe(locale_months), d3_time_monthLookup = d3_time_formatLookup(locale_months), d3_time_monthAbbrevRe = d3_time_formatRe(locale_shortMonths), d3_time_monthAbbrevLookup = d3_time_formatLookup(locale_shortMonths);
locale_periods.forEach(function(p, i) {
d3_time_periodLookup.set(p.toLowerCase(), i);
});
var d3_time_formats = {
a: function(d) {
return locale_shortDays[d.getDay()];
},
A: function(d) {
return locale_days[d.getDay()];
},
b: function(d) {
return locale_shortMonths[d.getMonth()];
},
B: function(d) {
return locale_months[d.getMonth()];
},
c: d3_time_format(locale_dateTime),
d: function(d, p) {
return d3_time_formatPad(d.getDate(), p, 2);
},
e: function(d, p) {
return d3_time_formatPad(d.getDate(), p, 2);
},
H: function(d, p) {
return d3_time_formatPad(d.getHours(), p, 2);
},
I: function(d, p) {
return d3_time_formatPad(d.getHours() % 12 || 12, p, 2);
},
j: function(d, p) {
return d3_time_formatPad(1 + d3_time.dayOfYear(d), p, 3);
},
L: function(d, p) {
return d3_time_formatPad(d.getMilliseconds(), p, 3);
},
m: function(d, p) {
return d3_time_formatPad(d.getMonth() + 1, p, 2);
},
M: function(d, p) {
return d3_time_formatPad(d.getMinutes(), p, 2);
},
p: function(d) {
return locale_periods[+(d.getHours() >= 12)];
},
S: function(d, p) {
return d3_time_formatPad(d.getSeconds(), p, 2);
},
U: function(d, p) {
return d3_time_formatPad(d3_time.sundayOfYear(d), p, 2);
},
w: function(d) {
return d.getDay();
},
W: function(d, p) {
return d3_time_formatPad(d3_time.mondayOfYear(d), p, 2);
},
x: d3_time_format(locale_date),
X: d3_time_format(locale_time),
y: function(d, p) {
return d3_time_formatPad(d.getFullYear() % 100, p, 2);
},
Y: function(d, p) {
return d3_time_formatPad(d.getFullYear() % 1e4, p, 4);
},
Z: d3_time_zone,
"%": function() {
return "%";
}
};
var d3_time_parsers = {
a: d3_time_parseWeekdayAbbrev,
A: d3_time_parseWeekday,
b: d3_time_parseMonthAbbrev,
B: d3_time_parseMonth,
c: d3_time_parseLocaleFull,
d: d3_time_parseDay,
e: d3_time_parseDay,
H: d3_time_parseHour24,
I: d3_time_parseHour24,
j: d3_time_parseDayOfYear,
L: d3_time_parseMilliseconds,
m: d3_time_parseMonthNumber,
M: d3_time_parseMinutes,
p: d3_time_parseAmPm,
S: d3_time_parseSeconds,
U: d3_time_parseWeekNumberSunday,
w: d3_time_parseWeekdayNumber,
W: d3_time_parseWeekNumberMonday,
x: d3_time_parseLocaleDate,
X: d3_time_parseLocaleTime,
y: d3_time_parseYear,
Y: d3_time_parseFullYear,
Z: d3_time_parseZone,
"%": d3_time_parseLiteralPercent
};
function d3_time_parseWeekdayAbbrev(date, string, i) {
d3_time_dayAbbrevRe.lastIndex = 0;
var n = d3_time_dayAbbrevRe.exec(string.slice(i));
return n ? (date.w = d3_time_dayAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function d3_time_parseWeekday(date, string, i) {
d3_time_dayRe.lastIndex = 0;
var n = d3_time_dayRe.exec(string.slice(i));
return n ? (date.w = d3_time_dayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function d3_time_parseMonthAbbrev(date, string, i) {
d3_time_monthAbbrevRe.lastIndex = 0;
var n = d3_time_monthAbbrevRe.exec(string.slice(i));
return n ? (date.m = d3_time_monthAbbrevLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function d3_time_parseMonth(date, string, i) {
d3_time_monthRe.lastIndex = 0;
var n = d3_time_monthRe.exec(string.slice(i));
return n ? (date.m = d3_time_monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function d3_time_parseLocaleFull(date, string, i) {
return d3_time_parse(date, d3_time_formats.c.toString(), string, i);
}
function d3_time_parseLocaleDate(date, string, i) {
return d3_time_parse(date, d3_time_formats.x.toString(), string, i);
}
function d3_time_parseLocaleTime(date, string, i) {
return d3_time_parse(date, d3_time_formats.X.toString(), string, i);
}
function d3_time_parseAmPm(date, string, i) {
var n = d3_time_periodLookup.get(string.slice(i, i += 2).toLowerCase());
return n == null ? -1 : (date.p = n, i);
}
return d3_time_format;
}
var d3_time_formatPads = {
"-": "",
_: " ",
"0": "0"
}, d3_time_numberRe = /^\s*\d+/, d3_time_percentRe = /^%/;
function d3_time_formatPad(value, fill, width) {
var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}
function d3_time_formatRe(names) {
return new RegExp("^(?:" + names.map(d3.requote).join("|") + ")", "i");
}
function d3_time_formatLookup(names) {
var map = new d3_Map(), i = -1, n = names.length;
while (++i < n) map.set(names[i].toLowerCase(), i);
return map;
}
function d3_time_parseWeekdayNumber(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 1));
return n ? (date.w = +n[0], i + n[0].length) : -1;
}
function d3_time_parseWeekNumberSunday(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i));
return n ? (date.U = +n[0], i + n[0].length) : -1;
}
function d3_time_parseWeekNumberMonday(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i));
return n ? (date.W = +n[0], i + n[0].length) : -1;
}
function d3_time_parseFullYear(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 4));
return n ? (date.y = +n[0], i + n[0].length) : -1;
}
function d3_time_parseYear(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.y = d3_time_expandYear(+n[0]), i + n[0].length) : -1;
}
function d3_time_parseZone(date, string, i) {
return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5)) ? (date.Z = -string,
i + 5) : -1;
}
function d3_time_expandYear(d) {
return d + (d > 68 ? 1900 : 2e3);
}
function d3_time_parseMonthNumber(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.m = n[0] - 1, i + n[0].length) : -1;
}
function d3_time_parseDay(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.d = +n[0], i + n[0].length) : -1;
}
function d3_time_parseDayOfYear(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 3));
return n ? (date.j = +n[0], i + n[0].length) : -1;
}
function d3_time_parseHour24(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.H = +n[0], i + n[0].length) : -1;
}
function d3_time_parseMinutes(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.M = +n[0], i + n[0].length) : -1;
}
function d3_time_parseSeconds(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 2));
return n ? (date.S = +n[0], i + n[0].length) : -1;
}
function d3_time_parseMilliseconds(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.slice(i, i + 3));
return n ? (date.L = +n[0], i + n[0].length) : -1;
}
function d3_time_zone(d) {
var z = d.getTimezoneOffset(), zs = z > 0 ? "-" : "+", zh = abs(z) / 60 | 0, zm = abs(z) % 60;
return zs + d3_time_formatPad(zh, "0", 2) + d3_time_formatPad(zm, "0", 2);
}
function d3_time_parseLiteralPercent(date, string, i) {
d3_time_percentRe.lastIndex = 0;
var n = d3_time_percentRe.exec(string.slice(i, i + 1));
return n ? i + n[0].length : -1;
}
function d3_time_formatMulti(formats) {
var n = formats.length, i = -1;
while (++i < n) formats[i][0] = this(formats[i][0]);
return function(date) {
var i = 0, f = formats[i];
while (!f[1](date)) f = formats[++i];
return f[0](date);
};
}
d3.locale = function(locale) {
return {
numberFormat: d3_locale_numberFormat(locale),
timeFormat: d3_locale_timeFormat(locale)
};
};
var d3_locale_enUS = d3.locale({
decimal: ".",
thousands: ",",
grouping: [ 3 ],
currency: [ "$", "" ],
dateTime: "%a %b %e %X %Y",
date: "%m/%d/%Y",
time: "%H:%M:%S",
periods: [ "AM", "PM" ],
days: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ],
shortDays: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
shortMonths: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
});
d3.format = d3_locale_enUS.numberFormat;
d3.geo = {};
function d3_adder() {}
d3_adder.prototype = {
s: 0,
t: 0,
add: function(y) {
d3_adderSum(y, this.t, d3_adderTemp);
d3_adderSum(d3_adderTemp.s, this.s, this);
if (this.s) this.t += d3_adderTemp.t; else this.s = d3_adderTemp.t;
},
reset: function() {
this.s = this.t = 0;
},
valueOf: function() {
return this.s;
}
};
var d3_adderTemp = new d3_adder();
function d3_adderSum(a, b, o) {
var x = o.s = a + b, bv = x - a, av = x - bv;
o.t = a - av + (b - bv);
}
d3.geo.stream = function(object, listener) {
if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
d3_geo_streamObjectType[object.type](object, listener);
} else {
d3_geo_streamGeometry(object, listener);
}
};
function d3_geo_streamGeometry(geometry, listener) {
if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
d3_geo_streamGeometryType[geometry.type](geometry, listener);
}
}
var d3_geo_streamObjectType = {
Feature: function(feature, listener) {
d3_geo_streamGeometry(feature.geometry, listener);
},
FeatureCollection: function(object, listener) {
var features = object.features, i = -1, n = features.length;
while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
}
};
var d3_geo_streamGeometryType = {
Sphere: function(object, listener) {
listener.sphere();
},
Point: function(object, listener) {
object = object.coordinates;
listener.point(object[0], object[1], object[2]);
},
MultiPoint: function(object, listener) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
},
LineString: function(object, listener) {
d3_geo_streamLine(object.coordinates, listener, 0);
},
MultiLineString: function(object, listener) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
},
Polygon: function(object, listener) {
d3_geo_streamPolygon(object.coordinates, listener);
},
MultiPolygon: function(object, listener) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
},
GeometryCollection: function(object, listener) {
var geometries = object.geometries, i = -1, n = geometries.length;
while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
}
};
function d3_geo_streamLine(coordinates, listener, closed) {
var i = -1, n = coordinates.length - closed, coordinate;
listener.lineStart();
while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
listener.lineEnd();
}
function d3_geo_streamPolygon(coordinates, listener) {
var i = -1, n = coordinates.length;
listener.polygonStart();
while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
listener.polygonEnd();
}
d3.geo.area = function(object) {
d3_geo_areaSum = 0;
d3.geo.stream(object, d3_geo_area);
return d3_geo_areaSum;
};
var d3_geo_areaSum, d3_geo_areaRingSum = new d3_adder();
var d3_geo_area = {
sphere: function() {
d3_geo_areaSum += 4 * π;
},
point: d3_noop,
lineStart: d3_noop,
lineEnd: d3_noop,
polygonStart: function() {
d3_geo_areaRingSum.reset();
d3_geo_area.lineStart = d3_geo_areaRingStart;
},
polygonEnd: function() {
var area = 2 * d3_geo_areaRingSum;
d3_geo_areaSum += area < 0 ? 4 * π + area : area;
d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
}
};
function d3_geo_areaRingStart() {
var λ00, φ00, λ0, cosφ0, sinφ0;
d3_geo_area.point = function(λ, φ) {
d3_geo_area.point = nextPoint;
λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4),
sinφ0 = Math.sin(φ);
};
function nextPoint(λ, φ) {
λ *= d3_radians;
φ = φ * d3_radians / 2 + π / 4;
var dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, cosφ = Math.cos(φ), sinφ = Math.sin(φ), k = sinφ0 * sinφ, u = cosφ0 * cosφ + k * Math.cos(adλ), v = k * sdλ * Math.sin(adλ);
d3_geo_areaRingSum.add(Math.atan2(v, u));
λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
}
d3_geo_area.lineEnd = function() {
nextPoint(λ00, φ00);
};
}
function d3_geo_cartesian(spherical) {
var λ = spherical[0], φ = spherical[1], cosφ = Math.cos(φ);
return [ cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ) ];
}
function d3_geo_cartesianDot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function d3_geo_cartesianCross(a, b) {
return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] ];
}
function d3_geo_cartesianAdd(a, b) {
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
}
function d3_geo_cartesianScale(vector, k) {
return [ vector[0] * k, vector[1] * k, vector[2] * k ];
}
function d3_geo_cartesianNormalize(d) {
var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
d[0] /= l;
d[1] /= l;
d[2] /= l;
}
function d3_geo_spherical(cartesian) {
return [ Math.atan2(cartesian[1], cartesian[0]), d3_asin(cartesian[2]) ];
}
function d3_geo_sphericalEqual(a, b) {
return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
}
d3.geo.bounds = function() {
var λ0, φ0, λ1, φ1, λ_, λ__, φ__, p0, dλSum, ranges, range;
var bound = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
bound.point = ringPoint;
bound.lineStart = ringStart;
bound.lineEnd = ringEnd;
dλSum = 0;
d3_geo_area.polygonStart();
},
polygonEnd: function() {
d3_geo_area.polygonEnd();
bound.point = point;
bound.lineStart = lineStart;
bound.lineEnd = lineEnd;
if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); else if (dλSum > ε) φ1 = 90; else if (dλSum < -ε) φ0 = -90;
range[0] = λ0, range[1] = λ1;
}
};
function point(λ, φ) {
ranges.push(range = [ λ0 = λ, λ1 = λ ]);
if (φ < φ0) φ0 = φ;
if (φ > φ1) φ1 = φ;
}
function linePoint(λ, φ) {
var p = d3_geo_cartesian([ λ * d3_radians, φ * d3_radians ]);
if (p0) {
var normal = d3_geo_cartesianCross(p0, p), equatorial = [ normal[1], -normal[0], 0 ], inflection = d3_geo_cartesianCross(equatorial, normal);
d3_geo_cartesianNormalize(inflection);
inflection = d3_geo_spherical(inflection);
var dλ = λ - λ_, s = dλ > 0 ? 1 : -1, λi = inflection[0] * d3_degrees * s, antimeridian = abs(dλ) > 180;
if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
var φi = inflection[1] * d3_degrees;
if (φi > φ1) φ1 = φi;
} else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
var φi = -inflection[1] * d3_degrees;
if (φi < φ0) φ0 = φi;
} else {
if (φ < φ0) φ0 = φ;
if (φ > φ1) φ1 = φ;
}
if (antimeridian) {
if (λ < λ_) {
if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
} else {
if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
}
} else {
if (λ1 >= λ0) {
if (λ < λ0) λ0 = λ;
if (λ > λ1) λ1 = λ;
} else {
if (λ > λ_) {
if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
} else {
if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
}
}
}
} else {
point(λ, φ);
}
p0 = p, λ_ = λ;
}
function lineStart() {
bound.point = linePoint;
}
function lineEnd() {
range[0] = λ0, range[1] = λ1;
bound.point = point;
p0 = null;
}
function ringPoint(λ, φ) {
if (p0) {
var dλ = λ - λ_;
dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
} else λ__ = λ, φ__ = φ;
d3_geo_area.point(λ, φ);
linePoint(λ, φ);
}
function ringStart() {
d3_geo_area.lineStart();
}
function ringEnd() {
ringPoint(λ__, φ__);
d3_geo_area.lineEnd();
if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
range[0] = λ0, range[1] = λ1;
p0 = null;
}
function angle(λ0, λ1) {
return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1;
}
function compareRanges(a, b) {
return a[0] - b[0];
}
function withinRange(x, range) {
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
}
return function(feature) {
φ1 = λ1 = -(λ0 = φ0 = Infinity);
ranges = [];
d3.geo.stream(feature, bound);
var n = ranges.length;
if (n) {
ranges.sort(compareRanges);
for (var i = 1, a = ranges[0], b, merged = [ a ]; i < n; ++i) {
b = ranges[i];
if (withinRange(b[0], a) || withinRange(b[1], a)) {
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
} else {
merged.push(a = b);
}
}
var best = -Infinity, dλ;
for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
b = merged[i];
if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
}
}
ranges = range = null;
return λ0 === Infinity || φ0 === Infinity ? [ [ NaN, NaN ], [ NaN, NaN ] ] : [ [ λ0, φ0 ], [ λ1, φ1 ] ];
};
}();
d3.geo.centroid = function(object) {
d3_geo_centroidW0 = d3_geo_centroidW1 = d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
d3.geo.stream(object, d3_geo_centroid);
var x = d3_geo_centroidX2, y = d3_geo_centroidY2, z = d3_geo_centroidZ2, m = x * x + y * y + z * z;
if (m < ε2) {
x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
m = x * x + y * y + z * z;
if (m < ε2) return [ NaN, NaN ];
}
return [ Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees ];
};
var d3_geo_centroidW0, d3_geo_centroidW1, d3_geo_centroidX0, d3_geo_centroidY0, d3_geo_centroidZ0, d3_geo_centroidX1, d3_geo_centroidY1, d3_geo_centroidZ1, d3_geo_centroidX2, d3_geo_centroidY2, d3_geo_centroidZ2;
var d3_geo_centroid = {
sphere: d3_noop,
point: d3_geo_centroidPoint,
lineStart: d3_geo_centroidLineStart,
lineEnd: d3_geo_centroidLineEnd,
polygonStart: function() {
d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
},
polygonEnd: function() {
d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
}
};
function d3_geo_centroidPoint(λ, φ) {
λ *= d3_radians;
var cosφ = Math.cos(φ *= d3_radians);
d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
}
function d3_geo_centroidPointXYZ(x, y, z) {
++d3_geo_centroidW0;
d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
}
function d3_geo_centroidLineStart() {
var x0, y0, z0;
d3_geo_centroid.point = function(λ, φ) {
λ *= d3_radians;
var cosφ = Math.cos(φ *= d3_radians);
x0 = cosφ * Math.cos(λ);
y0 = cosφ * Math.sin(λ);
z0 = Math.sin(φ);
d3_geo_centroid.point = nextPoint;
d3_geo_centroidPointXYZ(x0, y0, z0);
};
function nextPoint(λ, φ) {
λ *= d3_radians;
var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), w = Math.atan2(Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
d3_geo_centroidW1 += w;
d3_geo_centroidX1 += w * (x0 + (x0 = x));
d3_geo_centroidY1 += w * (y0 + (y0 = y));
d3_geo_centroidZ1 += w * (z0 + (z0 = z));
d3_geo_centroidPointXYZ(x0, y0, z0);
}
}
function d3_geo_centroidLineEnd() {
d3_geo_centroid.point = d3_geo_centroidPoint;
}
function d3_geo_centroidRingStart() {
var λ00, φ00, x0, y0, z0;
d3_geo_centroid.point = function(λ, φ) {
λ00 = λ, φ00 = φ;
d3_geo_centroid.point = nextPoint;
λ *= d3_radians;
var cosφ = Math.cos(φ *= d3_radians);
x0 = cosφ * Math.cos(λ);
y0 = cosφ * Math.sin(λ);
z0 = Math.sin(φ);
d3_geo_centroidPointXYZ(x0, y0, z0);
};
d3_geo_centroid.lineEnd = function() {
nextPoint(λ00, φ00);
d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
d3_geo_centroid.point = d3_geo_centroidPoint;
};
function nextPoint(λ, φ) {
λ *= d3_radians;
var cosφ = Math.cos(φ *= d3_radians), x = cosφ * Math.cos(λ), y = cosφ * Math.sin(λ), z = Math.sin(φ), cx = y0 * z - z0 * y, cy = z0 * x - x0 * z, cz = x0 * y - y0 * x, m = Math.sqrt(cx * cx + cy * cy + cz * cz), u = x0 * x + y0 * y + z0 * z, v = m && -d3_acos(u) / m, w = Math.atan2(m, u);
d3_geo_centroidX2 += v * cx;
d3_geo_centroidY2 += v * cy;
d3_geo_centroidZ2 += v * cz;
d3_geo_centroidW1 += w;
d3_geo_centroidX1 += w * (x0 + (x0 = x));
d3_geo_centroidY1 += w * (y0 + (y0 = y));
d3_geo_centroidZ1 += w * (z0 + (z0 = z));
d3_geo_centroidPointXYZ(x0, y0, z0);
}
}
function d3_geo_compose(a, b) {
function compose(x, y) {
return x = a(x, y), b(x[0], x[1]);
}
if (a.invert && b.invert) compose.invert = function(x, y) {
return x = b.invert(x, y), x && a.invert(x[0], x[1]);
};
return compose;
}
function d3_true() {
return true;
}
function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
var subject = [], clip = [];
segments.forEach(function(segment) {
if ((n = segment.length - 1) <= 0) return;
var n, p0 = segment[0], p1 = segment[n];
if (d3_geo_sphericalEqual(p0, p1)) {
listener.lineStart();
for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
listener.lineEnd();
return;
}
var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
a.o = b;
subject.push(a);
clip.push(b);
a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
a.o = b;
subject.push(a);
clip.push(b);
});
clip.sort(compare);
d3_geo_clipPolygonLinkCircular(subject);
d3_geo_clipPolygonLinkCircular(clip);
if (!subject.length) return;
for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
clip[i].e = entry = !entry;
}
var start = subject[0], points, point;
while (1) {
var current = start, isSubject = true;
while (current.v) if ((current = current.n) === start) return;
points = current.z;
listener.lineStart();
do {
current.v = current.o.v = true;
if (current.e) {
if (isSubject) {
for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.n.x, 1, listener);
}
current = current.n;
} else {
if (isSubject) {
points = current.p.z;
for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.p.x, -1, listener);
}
current = current.p;
}
current = current.o;
points = current.z;
isSubject = !isSubject;
} while (!current.v);
listener.lineEnd();
}
}
function d3_geo_clipPolygonLinkCircular(array) {
if (!(n = array.length)) return;
var n, i = 0, a = array[0], b;
while (++i < n) {
a.n = b = array[i];
b.p = a;
a = b;
}
a.n = b = array[0];
b.p = a;
}
function d3_geo_clipPolygonIntersection(point, points, other, entry) {
this.x = point;
this.z = points;
this.o = other;
this.e = entry;
this.v = false;
this.n = this.p = null;
}
function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
return function(rotate, listener) {
var line = clipLine(listener), rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
var clip = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
clip.point = pointRing;
clip.lineStart = ringStart;
clip.lineEnd = ringEnd;
segments = [];
polygon = [];
},
polygonEnd: function() {
clip.point = point;
clip.lineStart = lineStart;
clip.lineEnd = lineEnd;
segments = d3.merge(segments);
var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
if (segments.length) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
} else if (clipStartInside) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineStart();
interpolate(null, null, 1, listener);
listener.lineEnd();
}
if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
segments = polygon = null;
},
sphere: function() {
listener.polygonStart();
listener.lineStart();
interpolate(null, null, 1, listener);
listener.lineEnd();
listener.polygonEnd();
}
};
function point(λ, φ) {
var point = rotate(λ, φ);
if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
}
function pointLine(λ, φ) {
var point = rotate(λ, φ);
line.point(point[0], point[1]);
}
function lineStart() {
clip.point = pointLine;
line.lineStart();
}
function lineEnd() {
clip.point = point;
line.lineEnd();
}
var segments;
var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring;
function pointRing(λ, φ) {
ring.push([ λ, φ ]);
var point = rotate(λ, φ);
ringListener.point(point[0], point[1]);
}
function ringStart() {
ringListener.lineStart();
ring = [];
}
function ringEnd() {
pointRing(ring[0][0], ring[0][1]);
ringListener.lineEnd();
var clean = ringListener.clean(), ringSegments = buffer.buffer(), segment, n = ringSegments.length;
ring.pop();
polygon.push(ring);
ring = null;
if (!n) return;
if (clean & 1) {
segment = ringSegments[0];
var n = segment.length - 1, i = -1, point;
if (n > 0) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineStart();
while (++i < n) listener.point((point = segment[i])[0], point[1]);
listener.lineEnd();
}
return;
}
if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
}
return clip;
};
}
function d3_geo_clipSegmentLength1(segment) {
return segment.length > 1;
}
function d3_geo_clipBufferListener() {
var lines = [], line;
return {
lineStart: function() {
lines.push(line = []);
},
point: function(λ, φ) {
line.push([ λ, φ ]);
},
lineEnd: d3_noop,
buffer: function() {
var buffer = lines;
lines = [];
line = null;
return buffer;
},
rejoin: function() {
if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
}
};
}
function d3_geo_clipSort(a, b) {
return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
}
var d3_geo_clipAntimeridian = d3_geo_clip(d3_true, d3_geo_clipAntimeridianLine, d3_geo_clipAntimeridianInterpolate, [ -π, -π / 2 ]);
function d3_geo_clipAntimeridianLine(listener) {
var λ0 = NaN, φ0 = NaN, sλ0 = NaN, clean;
return {
lineStart: function() {
listener.lineStart();
clean = 1;
},
point: function(λ1, φ1) {
var sλ1 = λ1 > 0 ? π : -π, dλ = abs(λ1 - λ0);
if (abs(dλ - π) < ε) {
listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
listener.point(sλ0, φ0);
listener.lineEnd();
listener.lineStart();
listener.point(sλ1, φ0);
listener.point(λ1, φ0);
clean = 0;
} else if (sλ0 !== sλ1 && dλ >= π) {
if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
listener.point(sλ0, φ0);
listener.lineEnd();
listener.lineStart();
listener.point(sλ1, φ0);
clean = 0;
}
listener.point(λ0 = λ1, φ0 = φ1);
sλ0 = sλ1;
},
lineEnd: function() {
listener.lineEnd();
λ0 = φ0 = NaN;
},
clean: function() {
return 2 - clean;
}
};
}
function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
var cosφ0, cosφ1, sinλ0_λ1 = Math.sin(λ0 - λ1);
return abs(sinλ0_λ1) > ε ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) / (cosφ0 * cosφ1 * sinλ0_λ1)) : (φ0 + φ1) / 2;
}
function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
var φ;
if (from == null) {
φ = direction * halfπ;
listener.point(-π, φ);
listener.point(0, φ);
listener.point(π, φ);
listener.point(π, 0);
listener.point(π, -φ);
listener.point(0, -φ);
listener.point(-π, -φ);
listener.point(-π, 0);
listener.point(-π, φ);
} else if (abs(from[0] - to[0]) > ε) {
var s = from[0] < to[0] ? π : -π;
φ = direction * s / 2;
listener.point(-s, φ);
listener.point(0, φ);
listener.point(s, φ);
} else {
listener.point(to[0], to[1]);
}
}
function d3_geo_pointInPolygon(point, polygon) {
var meridian = point[0], parallel = point[1], meridianNormal = [ Math.sin(meridian), -Math.cos(meridian), 0 ], polarAngle = 0, winding = 0;
d3_geo_areaRingSum.reset();
for (var i = 0, n = polygon.length; i < n; ++i) {
var ring = polygon[i], m = ring.length;
if (!m) continue;
var point0 = ring[0], λ0 = point0[0], φ0 = point0[1] / 2 + π / 4, sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), j = 1;
while (true) {
if (j === m) j = 0;
point = ring[j];
var λ = point[0], φ = point[1] / 2 + π / 4, sinφ = Math.sin(φ), cosφ = Math.cos(φ), dλ = λ - λ0, sdλ = dλ >= 0 ? 1 : -1, adλ = sdλ * dλ, antimeridian = adλ > π, k = sinφ0 * sinφ;
d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
d3_geo_cartesianNormalize(arc);
var intersection = d3_geo_cartesianCross(meridianNormal, arc);
d3_geo_cartesianNormalize(intersection);
var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
winding += antimeridian ^ dλ >= 0 ? 1 : -1;
}
}
if (!j++) break;
λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
}
}
return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < -ε) ^ winding & 1;
}
function d3_geo_clipCircle(radius) {
var cr = Math.cos(radius), smallRadius = cr > 0, notHemisphere = abs(cr) > ε, interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [ 0, -radius ] : [ -π, radius - π ]);
function visible(λ, φ) {
return Math.cos(λ) * Math.cos(φ) > cr;
}
function clipLine(listener) {
var point0, c0, v0, v00, clean;
return {
lineStart: function() {
v00 = v0 = false;
clean = 1;
},
point: function(λ, φ) {
var point1 = [ λ, φ ], point2, v = visible(λ, φ), c = smallRadius ? v ? 0 : code(λ, φ) : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
if (!point0 && (v00 = v0 = v)) listener.lineStart();
if (v !== v0) {
point2 = intersect(point0, point1);
if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
point1[0] += ε;
point1[1] += ε;
v = visible(point1[0], point1[1]);
}
}
if (v !== v0) {
clean = 0;
if (v) {
listener.lineStart();
point2 = intersect(point1, point0);
listener.point(point2[0], point2[1]);
} else {
point2 = intersect(point0, point1);
listener.point(point2[0], point2[1]);
listener.lineEnd();
}
point0 = point2;
} else if (notHemisphere && point0 && smallRadius ^ v) {
var t;
if (!(c & c0) && (t = intersect(point1, point0, true))) {
clean = 0;
if (smallRadius) {
listener.lineStart();
listener.point(t[0][0], t[0][1]);
listener.point(t[1][0], t[1][1]);
listener.lineEnd();
} else {
listener.point(t[1][0], t[1][1]);
listener.lineEnd();
listener.lineStart();
listener.point(t[0][0], t[0][1]);
}
}
}
if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
listener.point(point1[0], point1[1]);
}
point0 = point1, v0 = v, c0 = c;
},
lineEnd: function() {
if (v0) listener.lineEnd();
point0 = null;
},
clean: function() {
return clean | (v00 && v0) << 1;
}
};
}
function intersect(a, b, two) {
var pa = d3_geo_cartesian(a), pb = d3_geo_cartesian(b);
var n1 = [ 1, 0, 0 ], n2 = d3_geo_cartesianCross(pa, pb), n2n2 = d3_geo_cartesianDot(n2, n2), n1n2 = n2[0], determinant = n2n2 - n1n2 * n1n2;
if (!determinant) return !two && a;
var c1 = cr * n2n2 / determinant, c2 = -cr * n1n2 / determinant, n1xn2 = d3_geo_cartesianCross(n1, n2), A = d3_geo_cartesianScale(n1, c1), B = d3_geo_cartesianScale(n2, c2);
d3_geo_cartesianAdd(A, B);
var u = n1xn2, w = d3_geo_cartesianDot(A, u), uu = d3_geo_cartesianDot(u, u), t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
if (t2 < 0) return;
var t = Math.sqrt(t2), q = d3_geo_cartesianScale(u, (-w - t) / uu);
d3_geo_cartesianAdd(q, A);
q = d3_geo_spherical(q);
if (!two) return q;
var λ0 = a[0], λ1 = b[0], φ0 = a[1], φ1 = b[1], z;
if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
var δλ = λ1 - λ0, polar = abs(δλ - π) < ε, meridian = polar || δλ < ε;
if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
if (meridian ? polar ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) : φ0 <= q[1] && q[1] <= φ1 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
d3_geo_cartesianAdd(q1, A);
return [ q, d3_geo_spherical(q1) ];
}
}
function code(λ, φ) {
var r = smallRadius ? radius : π - radius, code = 0;
if (λ < -r) code |= 1; else if (λ > r) code |= 2;
if (φ < -r) code |= 4; else if (φ > r) code |= 8;
return code;
}
}
function d3_geom_clipLine(x0, y0, x1, y1) {
return function(line) {
var a = line.a, b = line.b, ax = a.x, ay = a.y, bx = b.x, by = b.y, t0 = 0, t1 = 1, dx = bx - ax, dy = by - ay, r;
r = x0 - ax;
if (!dx && r > 0) return;
r /= dx;
if (dx < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dx > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = x1 - ax;
if (!dx && r < 0) return;
r /= dx;
if (dx < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dx > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
r = y0 - ay;
if (!dy && r > 0) return;
r /= dy;
if (dy < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dy > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = y1 - ay;
if (!dy && r < 0) return;
r /= dy;
if (dy < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dy > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
if (t0 > 0) line.a = {
x: ax + t0 * dx,
y: ay + t0 * dy
};
if (t1 < 1) line.b = {
x: ax + t1 * dx,
y: ay + t1 * dy
};
return line;
};
}
var d3_geo_clipExtentMAX = 1e9;
d3.geo.clipExtent = function() {
var x0, y0, x1, y1, stream, clip, clipExtent = {
stream: function(output) {
if (stream) stream.valid = false;
stream = clip(output);
stream.valid = true;
return stream;
},
extent: function(_) {
if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
if (stream) stream.valid = false, stream = null;
return clipExtent;
}
};
return clipExtent.extent([ [ 0, 0 ], [ 960, 500 ] ]);
};
function d3_geo_clipExtent(x0, y0, x1, y1) {
return function(listener) {
var listener_ = listener, bufferListener = d3_geo_clipBufferListener(), clipLine = d3_geom_clipLine(x0, y0, x1, y1), segments, polygon, ring;
var clip = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
listener = bufferListener;
segments = [];
polygon = [];
clean = true;
},
polygonEnd: function() {
listener = listener_;
segments = d3.merge(segments);
var clipStartInside = insidePolygon([ x0, y1 ]), inside = clean && clipStartInside, visible = segments.length;
if (inside || visible) {
listener.polygonStart();
if (inside) {
listener.lineStart();
interpolate(null, null, 1, listener);
listener.lineEnd();
}
if (visible) {
d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
}
listener.polygonEnd();
}
segments = polygon = ring = null;
}
};
function insidePolygon(p) {
var wn = 0, n = polygon.length, y = p[1];
for (var i = 0; i < n; ++i) {
for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
b = v[j];
if (a[1] <= y) {
if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
} else {
if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
}
a = b;
}
}
return wn !== 0;
}
function interpolate(from, to, direction, listener) {
var a = 0, a1 = 0;
if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoints(from, to) < 0 ^ direction > 0) {
do {
listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
} while ((a = (a + direction + 4) % 4) !== a1);
} else {
listener.point(to[0], to[1]);
}
}
function pointVisible(x, y) {
return x0 <= x && x <= x1 && y0 <= y && y <= y1;
}
function point(x, y) {
if (pointVisible(x, y)) listener.point(x, y);
}
var x__, y__, v__, x_, y_, v_, first, clean;
function lineStart() {
clip.point = linePoint;
if (polygon) polygon.push(ring = []);
first = true;
v_ = false;
x_ = y_ = NaN;
}
function lineEnd() {
if (segments) {
linePoint(x__, y__);
if (v__ && v_) bufferListener.rejoin();
segments.push(bufferListener.buffer());
}
clip.point = point;
if (v_) listener.lineEnd();
}
function linePoint(x, y) {
x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
var v = pointVisible(x, y);
if (polygon) ring.push([ x, y ]);
if (first) {
x__ = x, y__ = y, v__ = v;
first = false;
if (v) {
listener.lineStart();
listener.point(x, y);
}
} else {
if (v && v_) listener.point(x, y); else {
var l = {
a: {
x: x_,
y: y_
},
b: {
x: x,
y: y
}
};
if (clipLine(l)) {
if (!v_) {
listener.lineStart();
listener.point(l.a.x, l.a.y);
}
listener.point(l.b.x, l.b.y);
if (!v) listener.lineEnd();
clean = false;
} else if (v) {
listener.lineStart();
listener.point(x, y);
clean = false;
}
}
}
x_ = x, y_ = y, v_ = v;
}
return clip;
};
function corner(p, direction) {
return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2;
}
function compare(a, b) {
return comparePoints(a.x, b.x);
}
function comparePoints(a, b) {
var ca = corner(a, 1), cb = corner(b, 1);
return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
}
}
function d3_geo_conic(projectAt) {
var φ0 = 0, φ1 = π / 3, m = d3_geo_projectionMutator(projectAt), p = m(φ0, φ1);
p.parallels = function(_) {
if (!arguments.length) return [ φ0 / π * 180, φ1 / π * 180 ];
return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
};
return p;
}
function d3_geo_conicEqualArea(φ0, φ1) {
var sinφ0 = Math.sin(φ0), n = (sinφ0 + Math.sin(φ1)) / 2, C = 1 + sinφ0 * (2 * n - sinφ0), ρ0 = Math.sqrt(C) / n;
function forward(λ, φ) {
var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
return [ ρ * Math.sin(λ *= n), ρ0 - ρ * Math.cos(λ) ];
}
forward.invert = function(x, y) {
var ρ0_y = ρ0 - y;
return [ Math.atan2(x, ρ0_y) / n, d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) ];
};
return forward;
}
(d3.geo.conicEqualArea = function() {
return d3_geo_conic(d3_geo_conicEqualArea);
}).raw = d3_geo_conicEqualArea;
d3.geo.albers = function() {
return d3.geo.conicEqualArea().rotate([ 96, 0 ]).center([ -.6, 38.7 ]).parallels([ 29.5, 45.5 ]).scale(1070);
};
d3.geo.albersUsa = function() {
var lower48 = d3.geo.albers();
var alaska = d3.geo.conicEqualArea().rotate([ 154, 0 ]).center([ -2, 58.5 ]).parallels([ 55, 65 ]);
var hawaii = d3.geo.conicEqualArea().rotate([ 157, 0 ]).center([ -3, 19.9 ]).parallels([ 8, 18 ]);
var point, pointStream = {
point: function(x, y) {
point = [ x, y ];
}
}, lower48Point, alaskaPoint, hawaiiPoint;
function albersUsa(coordinates) {
var x = coordinates[0], y = coordinates[1];
point = null;
(lower48Point(x, y), point) || (alaskaPoint(x, y), point) || hawaiiPoint(x, y);
return point;
}
albersUsa.invert = function(coordinates) {
var k = lower48.scale(), t = lower48.translate(), x = (coordinates[0] - t[0]) / k, y = (coordinates[1] - t[1]) / k;
return (y >= .12 && y < .234 && x >= -.425 && x < -.214 ? alaska : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii : lower48).invert(coordinates);
};
albersUsa.stream = function(stream) {
var lower48Stream = lower48.stream(stream), alaskaStream = alaska.stream(stream), hawaiiStream = hawaii.stream(stream);
return {
point: function(x, y) {
lower48Stream.point(x, y);
alaskaStream.point(x, y);
hawaiiStream.point(x, y);
},
sphere: function() {
lower48Stream.sphere();
alaskaStream.sphere();
hawaiiStream.sphere();
},
lineStart: function() {
lower48Stream.lineStart();
alaskaStream.lineStart();
hawaiiStream.lineStart();
},
lineEnd: function() {
lower48Stream.lineEnd();
alaskaStream.lineEnd();
hawaiiStream.lineEnd();
},
polygonStart: function() {
lower48Stream.polygonStart();
alaskaStream.polygonStart();
hawaiiStream.polygonStart();
},
polygonEnd: function() {
lower48Stream.polygonEnd();
alaskaStream.polygonEnd();
hawaiiStream.polygonEnd();
}
};
};
albersUsa.precision = function(_) {
if (!arguments.length) return lower48.precision();
lower48.precision(_);
alaska.precision(_);
hawaii.precision(_);
return albersUsa;
};
albersUsa.scale = function(_) {
if (!arguments.length) return lower48.scale();
lower48.scale(_);
alaska.scale(_ * .35);
hawaii.scale(_);
return albersUsa.translate(lower48.translate());
};
albersUsa.translate = function(_) {
if (!arguments.length) return lower48.translate();
var k = lower48.scale(), x = +_[0], y = +_[1];
lower48Point = lower48.translate(_).clipExtent([ [ x - .455 * k, y - .238 * k ], [ x + .455 * k, y + .238 * k ] ]).stream(pointStream).point;
alaskaPoint = alaska.translate([ x - .307 * k, y + .201 * k ]).clipExtent([ [ x - .425 * k + ε, y + .12 * k + ε ], [ x - .214 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
hawaiiPoint = hawaii.translate([ x - .205 * k, y + .212 * k ]).clipExtent([ [ x - .214 * k + ε, y + .166 * k + ε ], [ x - .115 * k - ε, y + .234 * k - ε ] ]).stream(pointStream).point;
return albersUsa;
};
return albersUsa.scale(1070);
};
var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
point: d3_noop,
lineStart: d3_noop,
lineEnd: d3_noop,
polygonStart: function() {
d3_geo_pathAreaPolygon = 0;
d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
},
polygonEnd: function() {
d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
}
};
function d3_geo_pathAreaRingStart() {
var x00, y00, x0, y0;
d3_geo_pathArea.point = function(x, y) {
d3_geo_pathArea.point = nextPoint;
x00 = x0 = x, y00 = y0 = y;
};
function nextPoint(x, y) {
d3_geo_pathAreaPolygon += y0 * x - x0 * y;
x0 = x, y0 = y;
}
d3_geo_pathArea.lineEnd = function() {
nextPoint(x00, y00);
};
}
var d3_geo_pathBoundsX0, d3_geo_pathBoundsY0, d3_geo_pathBoundsX1, d3_geo_pathBoundsY1;
var d3_geo_pathBounds = {
point: d3_geo_pathBoundsPoint,
lineStart: d3_noop,
lineEnd: d3_noop,
polygonStart: d3_noop,
polygonEnd: d3_noop
};
function d3_geo_pathBoundsPoint(x, y) {
if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
}
function d3_geo_pathBuffer() {
var pointCircle = d3_geo_pathBufferCircle(4.5), buffer = [];
var stream = {
point: point,
lineStart: function() {
stream.point = pointLineStart;
},
lineEnd: lineEnd,
polygonStart: function() {
stream.lineEnd = lineEndPolygon;
},
polygonEnd: function() {
stream.lineEnd = lineEnd;
stream.point = point;
},
pointRadius: function(_) {
pointCircle = d3_geo_pathBufferCircle(_);
return stream;
},
result: function() {
if (buffer.length) {
var result = buffer.join("");
buffer = [];
return result;
}
}
};
function point(x, y) {
buffer.push("M", x, ",", y, pointCircle);
}
function pointLineStart(x, y) {
buffer.push("M", x, ",", y);
stream.point = pointLine;
}
function pointLine(x, y) {
buffer.push("L", x, ",", y);
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
buffer.push("Z");
}
return stream;
}
function d3_geo_pathBufferCircle(radius) {
return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
}
var d3_geo_pathCentroid = {
point: d3_geo_pathCentroidPoint,
lineStart: d3_geo_pathCentroidLineStart,
lineEnd: d3_geo_pathCentroidLineEnd,
polygonStart: function() {
d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
},
polygonEnd: function() {
d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
}
};
function d3_geo_pathCentroidPoint(x, y) {
d3_geo_centroidX0 += x;
d3_geo_centroidY0 += y;
++d3_geo_centroidZ0;
}
function d3_geo_pathCentroidLineStart() {
var x0, y0;
d3_geo_pathCentroid.point = function(x, y) {
d3_geo_pathCentroid.point = nextPoint;
d3_geo_pathCentroidPoint(x0 = x, y0 = y);
};
function nextPoint(x, y) {
var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
d3_geo_centroidX1 += z * (x0 + x) / 2;
d3_geo_centroidY1 += z * (y0 + y) / 2;
d3_geo_centroidZ1 += z;
d3_geo_pathCentroidPoint(x0 = x, y0 = y);
}
}
function d3_geo_pathCentroidLineEnd() {
d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
}
function d3_geo_pathCentroidRingStart() {
var x00, y00, x0, y0;
d3_geo_pathCentroid.point = function(x, y) {
d3_geo_pathCentroid.point = nextPoint;
d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
};
function nextPoint(x, y) {
var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
d3_geo_centroidX1 += z * (x0 + x) / 2;
d3_geo_centroidY1 += z * (y0 + y) / 2;
d3_geo_centroidZ1 += z;
z = y0 * x - x0 * y;
d3_geo_centroidX2 += z * (x0 + x);
d3_geo_centroidY2 += z * (y0 + y);
d3_geo_centroidZ2 += z * 3;
d3_geo_pathCentroidPoint(x0 = x, y0 = y);
}
d3_geo_pathCentroid.lineEnd = function() {
nextPoint(x00, y00);
};
}
function d3_geo_pathContext(context) {
var pointRadius = 4.5;
var stream = {
point: point,
lineStart: function() {
stream.point = pointLineStart;
},
lineEnd: lineEnd,
polygonStart: function() {
stream.lineEnd = lineEndPolygon;
},
polygonEnd: function() {
stream.lineEnd = lineEnd;
stream.point = point;
},
pointRadius: function(_) {
pointRadius = _;
return stream;
},
result: d3_noop
};
function point(x, y) {
context.moveTo(x + pointRadius, y);
context.arc(x, y, pointRadius, 0, τ);
}
function pointLineStart(x, y) {
context.moveTo(x, y);
stream.point = pointLine;
}
function pointLine(x, y) {
context.lineTo(x, y);
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
context.closePath();
}
return stream;
}
function d3_geo_resample(project) {
var δ2 = .5, cosMinDistance = Math.cos(30 * d3_radians), maxDepth = 16;
function resample(stream) {
return (maxDepth ? resampleRecursive : resampleNone)(stream);
}
function resampleNone(stream) {
return d3_geo_transformPoint(stream, function(x, y) {
x = project(x, y);
stream.point(x[0], x[1]);
});
}
function resampleRecursive(stream) {
var λ00, φ00, x00, y00, a00, b00, c00, λ0, x0, y0, a0, b0, c0;
var resample = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
stream.polygonStart();
resample.lineStart = ringStart;
},
polygonEnd: function() {
stream.polygonEnd();
resample.lineStart = lineStart;
}
};
function point(x, y) {
x = project(x, y);
stream.point(x[0], x[1]);
}
function lineStart() {
x0 = NaN;
resample.point = linePoint;
stream.lineStart();
}
function linePoint(λ, φ) {
var c = d3_geo_cartesian([ λ, φ ]), p = project(λ, φ);
resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
stream.point(x0, y0);
}
function lineEnd() {
resample.point = point;
stream.lineEnd();
}
function ringStart() {
lineStart();
resample.point = ringPoint;
resample.lineEnd = ringEnd;
}
function ringPoint(λ, φ) {
linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
resample.point = linePoint;
}
function ringEnd() {
resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
resample.lineEnd = lineEnd;
lineEnd();
}
return resample;
}
function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
var dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
if (d2 > 4 * δ2 && depth--) {
var a = a0 + a1, b = b0 + b1, c = c0 + c1, m = Math.sqrt(a * a + b * b + c * c), φ2 = Math.asin(c /= m), λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), p = project(λ2, φ2), x2 = p[0], y2 = p[1], dx2 = x2 - x0, dy2 = y2 - y0, dz = dy * dx2 - dx * dy2;
if (dz * dz / d2 > δ2 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
stream.point(x2, y2);
resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
}
}
}
resample.precision = function(_) {
if (!arguments.length) return Math.sqrt(δ2);
maxDepth = (δ2 = _ * _) > 0 && 16;
return resample;
};
return resample;
}
d3.geo.path = function() {
var pointRadius = 4.5, projection, context, projectStream, contextStream, cacheStream;
function path(object) {
if (object) {
if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
d3.geo.stream(object, cacheStream);
}
return contextStream.result();
}
path.area = function(object) {
d3_geo_pathAreaSum = 0;
d3.geo.stream(object, projectStream(d3_geo_pathArea));
return d3_geo_pathAreaSum;
};
path.centroid = function(object) {
d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
return d3_geo_centroidZ2 ? [ d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2 ] : d3_geo_centroidZ1 ? [ d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1 ] : d3_geo_centroidZ0 ? [ d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0 ] : [ NaN, NaN ];
};
path.bounds = function(object) {
d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
d3.geo.stream(object, projectStream(d3_geo_pathBounds));
return [ [ d3_geo_pathBoundsX0, d3_geo_pathBoundsY0 ], [ d3_geo_pathBoundsX1, d3_geo_pathBoundsY1 ] ];
};
path.projection = function(_) {
if (!arguments.length) return projection;
projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
return reset();
};
path.context = function(_) {
if (!arguments.length) return context;
contextStream = (context = _) == null ? new d3_geo_pathBuffer() : new d3_geo_pathContext(_);
if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
return reset();
};
path.pointRadius = function(_) {
if (!arguments.length) return pointRadius;
pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
return path;
};
function reset() {
cacheStream = null;
return path;
}
return path.projection(d3.geo.albersUsa()).context(null);
};
function d3_geo_pathProjectStream(project) {
var resample = d3_geo_resample(function(x, y) {
return project([ x * d3_degrees, y * d3_degrees ]);
});
return function(stream) {
return d3_geo_projectionRadians(resample(stream));
};
}
d3.geo.transform = function(methods) {
return {
stream: function(stream) {
var transform = new d3_geo_transform(stream);
for (var k in methods) transform[k] = methods[k];
return transform;
}
};
};
function d3_geo_transform(stream) {
this.stream = stream;
}
d3_geo_transform.prototype = {
point: function(x, y) {
this.stream.point(x, y);
},
sphere: function() {
this.stream.sphere();
},
lineStart: function() {
this.stream.lineStart();
},
lineEnd: function() {
this.stream.lineEnd();
},
polygonStart: function() {
this.stream.polygonStart();
},
polygonEnd: function() {
this.stream.polygonEnd();
}
};
function d3_geo_transformPoint(stream, point) {
return {
point: point,
sphere: function() {
stream.sphere();
},
lineStart: function() {
stream.lineStart();
},
lineEnd: function() {
stream.lineEnd();
},
polygonStart: function() {
stream.polygonStart();
},
polygonEnd: function() {
stream.polygonEnd();
}
};
}
d3.geo.projection = d3_geo_projection;
d3.geo.projectionMutator = d3_geo_projectionMutator;
function d3_geo_projection(project) {
return d3_geo_projectionMutator(function() {
return project;
})();
}
function d3_geo_projectionMutator(projectAt) {
var project, rotate, projectRotate, projectResample = d3_geo_resample(function(x, y) {
x = project(x, y);
return [ x[0] * k + δx, δy - x[1] * k ];
}), k = 150, x = 480, y = 250, λ = 0, φ = 0, δλ = 0, δφ = 0, δγ = 0, δx, δy, preclip = d3_geo_clipAntimeridian, postclip = d3_identity, clipAngle = null, clipExtent = null, stream;
function projection(point) {
point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
return [ point[0] * k + δx, δy - point[1] * k ];
}
function invert(point) {
point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
return point && [ point[0] * d3_degrees, point[1] * d3_degrees ];
}
projection.stream = function(output) {
if (stream) stream.valid = false;
stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
stream.valid = true;
return stream;
};
projection.clipAngle = function(_) {
if (!arguments.length) return clipAngle;
preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
return invalidate();
};
projection.clipExtent = function(_) {
if (!arguments.length) return clipExtent;
clipExtent = _;
postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
return invalidate();
};
projection.scale = function(_) {
if (!arguments.length) return k;
k = +_;
return reset();
};
projection.translate = function(_) {
if (!arguments.length) return [ x, y ];
x = +_[0];
y = +_[1];
return reset();
};
projection.center = function(_) {
if (!arguments.length) return [ λ * d3_degrees, φ * d3_degrees ];
λ = _[0] % 360 * d3_radians;
φ = _[1] % 360 * d3_radians;
return reset();
};
projection.rotate = function(_) {
if (!arguments.length) return [ δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees ];
δλ = _[0] % 360 * d3_radians;
δφ = _[1] % 360 * d3_radians;
δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
return reset();
};
d3.rebind(projection, projectResample, "precision");
function reset() {
projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
var center = project(λ, φ);
δx = x - center[0] * k;
δy = y + center[1] * k;
return invalidate();
}
function invalidate() {
if (stream) stream.valid = false, stream = null;
return projection;
}
return function() {
project = projectAt.apply(this, arguments);
projection.invert = project.invert && invert;
return reset();
};
}
function d3_geo_projectionRadians(stream) {
return d3_geo_transformPoint(stream, function(x, y) {
stream.point(x * d3_radians, y * d3_radians);
});
}
function d3_geo_equirectangular(λ, φ) {
return [ λ, φ ];
}
(d3.geo.equirectangular = function() {
return d3_geo_projection(d3_geo_equirectangular);
}).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
d3.geo.rotation = function(rotate) {
rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
function forward(coordinates) {
coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
}
forward.invert = function(coordinates) {
coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
};
return forward;
};
function d3_geo_identityRotation(λ, φ) {
return [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
}
d3_geo_identityRotation.invert = d3_geo_equirectangular;
function d3_geo_rotation(δλ, δφ, δγ) {
return δλ ? δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) : d3_geo_rotationλ(δλ) : δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) : d3_geo_identityRotation;
}
function d3_geo_forwardRotationλ(δλ) {
return function(λ, φ) {
return λ += δλ, [ λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ ];
};
}
function d3_geo_rotationλ(δλ) {
var rotation = d3_geo_forwardRotationλ(δλ);
rotation.invert = d3_geo_forwardRotationλ(-δλ);
return rotation;
}
function d3_geo_rotationφγ(δφ, δγ) {
var cosδφ = Math.cos(δφ), sinδφ = Math.sin(δφ), cosδγ = Math.cos(δγ), sinδγ = Math.sin(δγ);
function rotation(λ, φ) {
var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδφ + x * sinδφ;
return [ Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), d3_asin(k * cosδγ + y * sinδγ) ];
}
rotation.invert = function(λ, φ) {
var cosφ = Math.cos(φ), x = Math.cos(λ) * cosφ, y = Math.sin(λ) * cosφ, z = Math.sin(φ), k = z * cosδγ - y * sinδγ;
return [ Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), d3_asin(k * cosδφ - x * sinδφ) ];
};
return rotation;
}
d3.geo.circle = function() {
var origin = [ 0, 0 ], angle, precision = 6, interpolate;
function circle() {
var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, ring = [];
interpolate(null, null, 1, {
point: function(x, y) {
ring.push(x = rotate(x, y));
x[0] *= d3_degrees, x[1] *= d3_degrees;
}
});
return {
type: "Polygon",
coordinates: [ ring ]
};
}
circle.origin = function(x) {
if (!arguments.length) return origin;
origin = x;
return circle;
};
circle.angle = function(x) {
if (!arguments.length) return angle;
interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
return circle;
};
circle.precision = function(_) {
if (!arguments.length) return precision;
interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
return circle;
};
return circle.angle(90);
};
function d3_geo_circleInterpolate(radius, precision) {
var cr = Math.cos(radius), sr = Math.sin(radius);
return function(from, to, direction, listener) {
var step = direction * precision;
if (from != null) {
from = d3_geo_circleAngle(cr, from);
to = d3_geo_circleAngle(cr, to);
if (direction > 0 ? from < to : from > to) from += direction * τ;
} else {
from = radius + direction * τ;
to = radius - .5 * step;
}
for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
listener.point((point = d3_geo_spherical([ cr, -sr * Math.cos(t), -sr * Math.sin(t) ]))[0], point[1]);
}
};
}
function d3_geo_circleAngle(cr, point) {
var a = d3_geo_cartesian(point);
a[0] -= cr;
d3_geo_cartesianNormalize(a);
var angle = d3_acos(-a[1]);
return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
}
d3.geo.distance = function(a, b) {
var Δλ = (b[0] - a[0]) * d3_radians, φ0 = a[1] * d3_radians, φ1 = b[1] * d3_radians, sinΔλ = Math.sin(Δλ), cosΔλ = Math.cos(Δλ), sinφ0 = Math.sin(φ0), cosφ0 = Math.cos(φ0), sinφ1 = Math.sin(φ1), cosφ1 = Math.cos(φ1), t;
return Math.atan2(Math.sqrt((t = cosφ1 * sinΔλ) * t + (t = cosφ0 * sinφ1 - sinφ0 * cosφ1 * cosΔλ) * t), sinφ0 * sinφ1 + cosφ0 * cosφ1 * cosΔλ);
};
d3.geo.graticule = function() {
var x1, x0, X1, X0, y1, y0, Y1, Y0, dx = 10, dy = dx, DX = 90, DY = 360, x, y, X, Y, precision = 2.5;
function graticule() {
return {
type: "MultiLineString",
coordinates: lines()
};
}
function lines() {
return d3.range(Math.ceil(X0 / DX) * DX, X1, DX).map(X).concat(d3.range(Math.ceil(Y0 / DY) * DY, Y1, DY).map(Y)).concat(d3.range(Math.ceil(x0 / dx) * dx, x1, dx).filter(function(x) {
return abs(x % DX) > ε;
}).map(x)).concat(d3.range(Math.ceil(y0 / dy) * dy, y1, dy).filter(function(y) {
return abs(y % DY) > ε;
}).map(y));
}
graticule.lines = function() {
return lines().map(function(coordinates) {
return {
type: "LineString",
coordinates: coordinates
};
});
};
graticule.outline = function() {
return {
type: "Polygon",
coordinates: [ X(X0).concat(Y(Y1).slice(1), X(X1).reverse().slice(1), Y(Y0).reverse().slice(1)) ]
};
};
graticule.extent = function(_) {
if (!arguments.length) return graticule.minorExtent();
return graticule.majorExtent(_).minorExtent(_);
};
graticule.majorExtent = function(_) {
if (!arguments.length) return [ [ X0, Y0 ], [ X1, Y1 ] ];
X0 = +_[0][0], X1 = +_[1][0];
Y0 = +_[0][1], Y1 = +_[1][1];
if (X0 > X1) _ = X0, X0 = X1, X1 = _;
if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
return graticule.precision(precision);
};
graticule.minorExtent = function(_) {
if (!arguments.length) return [ [ x0, y0 ], [ x1, y1 ] ];
x0 = +_[0][0], x1 = +_[1][0];
y0 = +_[0][1], y1 = +_[1][1];
if (x0 > x1) _ = x0, x0 = x1, x1 = _;
if (y0 > y1) _ = y0, y0 = y1, y1 = _;
return graticule.precision(precision);
};
graticule.step = function(_) {
if (!arguments.length) return graticule.minorStep();
return graticule.majorStep(_).minorStep(_);
};
graticule.majorStep = function(_) {
if (!arguments.length) return [ DX, DY ];
DX = +_[0], DY = +_[1];
return graticule;
};
graticule.minorStep = function(_) {
if (!arguments.length) return [ dx, dy ];
dx = +_[0], dy = +_[1];
return graticule;
};
graticule.precision = function(_) {
if (!arguments.length) return precision;
precision = +_;
x = d3_geo_graticuleX(y0, y1, 90);
y = d3_geo_graticuleY(x0, x1, precision);
X = d3_geo_graticuleX(Y0, Y1, 90);
Y = d3_geo_graticuleY(X0, X1, precision);
return graticule;
};
return graticule.majorExtent([ [ -180, -90 + ε ], [ 180, 90 - ε ] ]).minorExtent([ [ -180, -80 - ε ], [ 180, 80 + ε ] ]);
};
function d3_geo_graticuleX(y0, y1, dy) {
var y = d3.range(y0, y1 - ε, dy).concat(y1);
return function(x) {
return y.map(function(y) {
return [ x, y ];
});
};
}
function d3_geo_graticuleY(x0, x1, dx) {
var x = d3.range(x0, x1 - ε, dx).concat(x1);
return function(y) {
return x.map(function(x) {
return [ x, y ];
});
};
}
function d3_source(d) {
return d.source;
}
function d3_target(d) {
return d.target;
}
d3.geo.greatArc = function() {
var source = d3_source, source_, target = d3_target, target_;
function greatArc() {
return {
type: "LineString",
coordinates: [ source_ || source.apply(this, arguments), target_ || target.apply(this, arguments) ]
};
}
greatArc.distance = function() {
return d3.geo.distance(source_ || source.apply(this, arguments), target_ || target.apply(this, arguments));
};
greatArc.source = function(_) {
if (!arguments.length) return source;
source = _, source_ = typeof _ === "function" ? null : _;
return greatArc;
};
greatArc.target = function(_) {
if (!arguments.length) return target;
target = _, target_ = typeof _ === "function" ? null : _;
return greatArc;
};
greatArc.precision = function() {
return arguments.length ? greatArc : 0;
};
return greatArc;
};
d3.geo.interpolate = function(source, target) {
return d3_geo_interpolate(source[0] * d3_radians, source[1] * d3_radians, target[0] * d3_radians, target[1] * d3_radians);
};
function d3_geo_interpolate(x0, y0, x1, y1) {
var cy0 = Math.cos(y0), sy0 = Math.sin(y0), cy1 = Math.cos(y1), sy1 = Math.sin(y1), kx0 = cy0 * Math.cos(x0), ky0 = cy0 * Math.sin(x0), kx1 = cy1 * Math.cos(x1), ky1 = cy1 * Math.sin(x1), d = 2 * Math.asin(Math.sqrt(d3_haversin(y1 - y0) + cy0 * cy1 * d3_haversin(x1 - x0))), k = 1 / Math.sin(d);
var interpolate = d ? function(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;
return [ Math.atan2(y, x) * d3_degrees, Math.atan2(z, Math.sqrt(x * x + y * y)) * d3_degrees ];
} : function() {
return [ x0 * d3_degrees, y0 * d3_degrees ];
};
interpolate.distance = d;
return interpolate;
}
d3.geo.length = function(object) {
d3_geo_lengthSum = 0;
d3.geo.stream(object, d3_geo_length);
return d3_geo_lengthSum;
};
var d3_geo_lengthSum;
var d3_geo_length = {
sphere: d3_noop,
point: d3_noop,
lineStart: d3_geo_lengthLineStart,
lineEnd: d3_noop,
polygonStart: d3_noop,
polygonEnd: d3_noop
};
function d3_geo_lengthLineStart() {
var λ0, sinφ0, cosφ0;
d3_geo_length.point = function(λ, φ) {
λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
d3_geo_length.point = nextPoint;
};
d3_geo_length.lineEnd = function() {
d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
};
function nextPoint(λ, φ) {
var sinφ = Math.sin(φ *= d3_radians), cosφ = Math.cos(φ), t = abs((λ *= d3_radians) - λ0), cosΔλ = Math.cos(t);
d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
}
}
function d3_geo_azimuthal(scale, angle) {
function azimuthal(λ, φ) {
var cosλ = Math.cos(λ), cosφ = Math.cos(φ), k = scale(cosλ * cosφ);
return [ k * cosφ * Math.sin(λ), k * Math.sin(φ) ];
}
azimuthal.invert = function(x, y) {
var ρ = Math.sqrt(x * x + y * y), c = angle(ρ), sinc = Math.sin(c), cosc = Math.cos(c);
return [ Math.atan2(x * sinc, ρ * cosc), Math.asin(ρ && y * sinc / ρ) ];
};
return azimuthal;
}
var d3_geo_azimuthalEqualArea = d3_geo_azimuthal(function(cosλcosφ) {
return Math.sqrt(2 / (1 + cosλcosφ));
}, function(ρ) {
return 2 * Math.asin(ρ / 2);
});
(d3.geo.azimuthalEqualArea = function() {
return d3_geo_projection(d3_geo_azimuthalEqualArea);
}).raw = d3_geo_azimuthalEqualArea;
var d3_geo_azimuthalEquidistant = d3_geo_azimuthal(function(cosλcosφ) {
var c = Math.acos(cosλcosφ);
return c && c / Math.sin(c);
}, d3_identity);
(d3.geo.azimuthalEquidistant = function() {
return d3_geo_projection(d3_geo_azimuthalEquidistant);
}).raw = d3_geo_azimuthalEquidistant;
function d3_geo_conicConformal(φ0, φ1) {
var cosφ0 = Math.cos(φ0), t = function(φ) {
return Math.tan(π / 4 + φ / 2);
}, n = φ0 === φ1 ? Math.sin(φ0) : Math.log(cosφ0 / Math.cos(φ1)) / Math.log(t(φ1) / t(φ0)), F = cosφ0 * Math.pow(t(φ0), n) / n;
if (!n) return d3_geo_mercator;
function forward(λ, φ) {
if (F > 0) {
if (φ < -halfπ + ε) φ = -halfπ + ε;
} else {
if (φ > halfπ - ε) φ = halfπ - ε;
}
var ρ = F / Math.pow(t(φ), n);
return [ ρ * Math.sin(n * λ), F - ρ * Math.cos(n * λ) ];
}
forward.invert = function(x, y) {
var ρ0_y = F - y, ρ = d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y);
return [ Math.atan2(x, ρ0_y) / n, 2 * Math.atan(Math.pow(F / ρ, 1 / n)) - halfπ ];
};
return forward;
}
(d3.geo.conicConformal = function() {
return d3_geo_conic(d3_geo_conicConformal);
}).raw = d3_geo_conicConformal;
function d3_geo_conicEquidistant(φ0, φ1) {
var cosφ0 = Math.cos(φ0), n = φ0 === φ1 ? Math.sin(φ0) : (cosφ0 - Math.cos(φ1)) / (φ1 - φ0), G = cosφ0 / n + φ0;
if (abs(n) < ε) return d3_geo_equirectangular;
function forward(λ, φ) {
var ρ = G - φ;
return [ ρ * Math.sin(n * λ), G - ρ * Math.cos(n * λ) ];
}
forward.invert = function(x, y) {
var ρ0_y = G - y;
return [ Math.atan2(x, ρ0_y) / n, G - d3_sgn(n) * Math.sqrt(x * x + ρ0_y * ρ0_y) ];
};
return forward;
}
(d3.geo.conicEquidistant = function() {
return d3_geo_conic(d3_geo_conicEquidistant);
}).raw = d3_geo_conicEquidistant;
var d3_geo_gnomonic = d3_geo_azimuthal(function(cosλcosφ) {
return 1 / cosλcosφ;
}, Math.atan);
(d3.geo.gnomonic = function() {
return d3_geo_projection(d3_geo_gnomonic);
}).raw = d3_geo_gnomonic;
function d3_geo_mercator(λ, φ) {
return [ λ, Math.log(Math.tan(π / 4 + φ / 2)) ];
}
d3_geo_mercator.invert = function(x, y) {
return [ x, 2 * Math.atan(Math.exp(y)) - halfπ ];
};
function d3_geo_mercatorProjection(project) {
var m = d3_geo_projection(project), scale = m.scale, translate = m.translate, clipExtent = m.clipExtent, clipAuto;
m.scale = function() {
var v = scale.apply(m, arguments);
return v === m ? clipAuto ? m.clipExtent(null) : m : v;
};
m.translate = function() {
var v = translate.apply(m, arguments);
return v === m ? clipAuto ? m.clipExtent(null) : m : v;
};
m.clipExtent = function(_) {
var v = clipExtent.apply(m, arguments);
if (v === m) {
if (clipAuto = _ == null) {
var k = π * scale(), t = translate();
clipExtent([ [ t[0] - k, t[1] - k ], [ t[0] + k, t[1] + k ] ]);
}
} else if (clipAuto) {
v = null;
}
return v;
};
return m.clipExtent(null);
}
(d3.geo.mercator = function() {
return d3_geo_mercatorProjection(d3_geo_mercator);
}).raw = d3_geo_mercator;
var d3_geo_orthographic = d3_geo_azimuthal(function() {
return 1;
}, Math.asin);
(d3.geo.orthographic = function() {
return d3_geo_projection(d3_geo_orthographic);
}).raw = d3_geo_orthographic;
var d3_geo_stereographic = d3_geo_azimuthal(function(cosλcosφ) {
return 1 / (1 + cosλcosφ);
}, function(ρ) {
return 2 * Math.atan(ρ);
});
(d3.geo.stereographic = function() {
return d3_geo_projection(d3_geo_stereographic);
}).raw = d3_geo_stereographic;
function d3_geo_transverseMercator(λ, φ) {
return [ Math.log(Math.tan(π / 4 + φ / 2)), -λ ];
}
d3_geo_transverseMercator.invert = function(x, y) {
return [ -y, 2 * Math.atan(Math.exp(x)) - halfπ ];
};
(d3.geo.transverseMercator = function() {
var projection = d3_geo_mercatorProjection(d3_geo_transverseMercator), center = projection.center, rotate = projection.rotate;
projection.center = function(_) {
return _ ? center([ -_[1], _[0] ]) : (_ = center(), [ _[1], -_[0] ]);
};
projection.rotate = function(_) {
return _ ? rotate([ _[0], _[1], _.length > 2 ? _[2] + 90 : 90 ]) : (_ = rotate(),
[ _[0], _[1], _[2] - 90 ]);
};
return rotate([ 0, 0, 90 ]);
}).raw = d3_geo_transverseMercator;
d3.geom = {};
function d3_geom_pointX(d) {
return d[0];
}
function d3_geom_pointY(d) {
return d[1];
}
d3.geom.hull = function(vertices) {
var x = d3_geom_pointX, y = d3_geom_pointY;
if (arguments.length) return hull(vertices);
function hull(data) {
if (data.length < 3) return [];
var fx = d3_functor(x), fy = d3_functor(y), i, n = data.length, points = [], flippedPoints = [];
for (i = 0; i < n; i++) {
points.push([ +fx.call(this, data[i], i), +fy.call(this, data[i], i), i ]);
}
points.sort(d3_geom_hullOrder);
for (i = 0; i < n; i++) flippedPoints.push([ points[i][0], -points[i][1] ]);
var upper = d3_geom_hullUpper(points), lower = d3_geom_hullUpper(flippedPoints);
var skipLeft = lower[0] === upper[0], skipRight = lower[lower.length - 1] === upper[upper.length - 1], polygon = [];
for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
return polygon;
}
hull.x = function(_) {
return arguments.length ? (x = _, hull) : x;
};
hull.y = function(_) {
return arguments.length ? (y = _, hull) : y;
};
return hull;
};
function d3_geom_hullUpper(points) {
var n = points.length, hull = [ 0, 1 ], hs = 2;
for (var i = 2; i < n; i++) {
while (hs > 1 && d3_cross2d(points[hull[hs - 2]], points[hull[hs - 1]], points[i]) <= 0) --hs;
hull[hs++] = i;
}
return hull.slice(0, hs);
}
function d3_geom_hullOrder(a, b) {
return a[0] - b[0] || a[1] - b[1];
}
d3.geom.polygon = function(coordinates) {
d3_subclass(coordinates, d3_geom_polygonPrototype);
return coordinates;
};
var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
d3_geom_polygonPrototype.area = function() {
var i = -1, n = this.length, a, b = this[n - 1], area = 0;
while (++i < n) {
a = b;
b = this[i];
area += a[1] * b[0] - a[0] * b[1];
}
return area * .5;
};
d3_geom_polygonPrototype.centroid = function(k) {
var i = -1, n = this.length, x = 0, y = 0, a, b = this[n - 1], c;
if (!arguments.length) k = -1 / (6 * this.area());
while (++i < n) {
a = b;
b = this[i];
c = a[0] * b[1] - b[0] * a[1];
x += (a[0] + b[0]) * c;
y += (a[1] + b[1]) * c;
}
return [ x * k, y * k ];
};
d3_geom_polygonPrototype.clip = function(subject) {
var input, closed = d3_geom_polygonClosed(subject), i = -1, n = this.length - d3_geom_polygonClosed(this), j, m, a = this[n - 1], b, c, d;
while (++i < n) {
input = subject.slice();
subject.length = 0;
b = this[i];
c = input[(m = input.length - closed) - 1];
j = -1;
while (++j < m) {
d = input[j];
if (d3_geom_polygonInside(d, a, b)) {
if (!d3_geom_polygonInside(c, a, b)) {
subject.push(d3_geom_polygonIntersect(c, d, a, b));
}
subject.push(d);
} else if (d3_geom_polygonInside(c, a, b)) {
subject.push(d3_geom_polygonIntersect(c, d, a, b));
}
c = d;
}
if (closed) subject.push(subject[0]);
a = b;
}
return subject;
};
function d3_geom_polygonInside(p, a, b) {
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) {
var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
return [ x1 + ua * x21, y1 + ua * y21 ];
}
function d3_geom_polygonClosed(coordinates) {
var a = coordinates[0], b = coordinates[coordinates.length - 1];
return !(a[0] - b[0] || a[1] - b[1]);
}
var d3_geom_voronoiEdges, d3_geom_voronoiCells, d3_geom_voronoiBeaches, d3_geom_voronoiBeachPool = [], d3_geom_voronoiFirstCircle, d3_geom_voronoiCircles, d3_geom_voronoiCirclePool = [];
function d3_geom_voronoiBeach() {
d3_geom_voronoiRedBlackNode(this);
this.edge = this.site = this.circle = null;
}
function d3_geom_voronoiCreateBeach(site) {
var beach = d3_geom_voronoiBeachPool.pop() || new d3_geom_voronoiBeach();
beach.site = site;
return beach;
}
function d3_geom_voronoiDetachBeach(beach) {
d3_geom_voronoiDetachCircle(beach);
d3_geom_voronoiBeaches.remove(beach);
d3_geom_voronoiBeachPool.push(beach);
d3_geom_voronoiRedBlackNode(beach);
}
function d3_geom_voronoiRemoveBeach(beach) {
var circle = beach.circle, x = circle.x, y = circle.cy, vertex = {
x: x,
y: y
}, previous = beach.P, next = beach.N, disappearing = [ beach ];
d3_geom_voronoiDetachBeach(beach);
var lArc = previous;
while (lArc.circle && abs(x - lArc.circle.x) < ε && abs(y - lArc.circle.cy) < ε) {
previous = lArc.P;
disappearing.unshift(lArc);
d3_geom_voronoiDetachBeach(lArc);
lArc = previous;
}
disappearing.unshift(lArc);
d3_geom_voronoiDetachCircle(lArc);
var rArc = next;
while (rArc.circle && abs(x - rArc.circle.x) < ε && abs(y - rArc.circle.cy) < ε) {
next = rArc.N;
disappearing.push(rArc);
d3_geom_voronoiDetachBeach(rArc);
rArc = next;
}
disappearing.push(rArc);
d3_geom_voronoiDetachCircle(rArc);
var nArcs = disappearing.length, iArc;
for (iArc = 1; iArc < nArcs; ++iArc) {
rArc = disappearing[iArc];
lArc = disappearing[iArc - 1];
d3_geom_voronoiSetEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
}
lArc = disappearing[0];
rArc = disappearing[nArcs - 1];
rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, rArc.site, null, vertex);
d3_geom_voronoiAttachCircle(lArc);
d3_geom_voronoiAttachCircle(rArc);
}
function d3_geom_voronoiAddBeach(site) {
var x = site.x, directrix = site.y, lArc, rArc, dxl, dxr, node = d3_geom_voronoiBeaches._;
while (node) {
dxl = d3_geom_voronoiLeftBreakPoint(node, directrix) - x;
if (dxl > ε) node = node.L; else {
dxr = x - d3_geom_voronoiRightBreakPoint(node, directrix);
if (dxr > ε) {
if (!node.R) {
lArc = node;
break;
}
node = node.R;
} else {
if (dxl > -ε) {
lArc = node.P;
rArc = node;
} else if (dxr > -ε) {
lArc = node;
rArc = node.N;
} else {
lArc = rArc = node;
}
break;
}
}
}
var newArc = d3_geom_voronoiCreateBeach(site);
d3_geom_voronoiBeaches.insert(lArc, newArc);
if (!lArc && !rArc) return;
if (lArc === rArc) {
d3_geom_voronoiDetachCircle(lArc);
rArc = d3_geom_voronoiCreateBeach(lArc.site);
d3_geom_voronoiBeaches.insert(newArc, rArc);
newArc.edge = rArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
d3_geom_voronoiAttachCircle(lArc);
d3_geom_voronoiAttachCircle(rArc);
return;
}
if (!rArc) {
newArc.edge = d3_geom_voronoiCreateEdge(lArc.site, newArc.site);
return;
}
d3_geom_voronoiDetachCircle(lArc);
d3_geom_voronoiDetachCircle(rArc);
var lSite = lArc.site, ax = lSite.x, ay = lSite.y, bx = site.x - ax, by = site.y - ay, rSite = rArc.site, cx = rSite.x - ax, cy = rSite.y - ay, d = 2 * (bx * cy - by * cx), hb = bx * bx + by * by, hc = cx * cx + cy * cy, vertex = {
x: (cy * hb - by * hc) / d + ax,
y: (bx * hc - cx * hb) / d + ay
};
d3_geom_voronoiSetEdgeEnd(rArc.edge, lSite, rSite, vertex);
newArc.edge = d3_geom_voronoiCreateEdge(lSite, site, null, vertex);
rArc.edge = d3_geom_voronoiCreateEdge(site, rSite, null, vertex);
d3_geom_voronoiAttachCircle(lArc);
d3_geom_voronoiAttachCircle(rArc);
}
function d3_geom_voronoiLeftBreakPoint(arc, directrix) {
var site = arc.site, rfocx = site.x, rfocy = site.y, pby2 = rfocy - directrix;
if (!pby2) return rfocx;
var lArc = arc.P;
if (!lArc) return -Infinity;
site = lArc.site;
var lfocx = site.x, lfocy = site.y, plby2 = lfocy - directrix;
if (!plby2) return lfocx;
var hl = lfocx - rfocx, aby2 = 1 / pby2 - 1 / plby2, b = hl / plby2;
if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
return (rfocx + lfocx) / 2;
}
function d3_geom_voronoiRightBreakPoint(arc, directrix) {
var rArc = arc.N;
if (rArc) return d3_geom_voronoiLeftBreakPoint(rArc, directrix);
var site = arc.site;
return site.y === directrix ? site.x : Infinity;
}
function d3_geom_voronoiCell(site) {
this.site = site;
this.edges = [];
}
d3_geom_voronoiCell.prototype.prepare = function() {
var halfEdges = this.edges, iHalfEdge = halfEdges.length, edge;
while (iHalfEdge--) {
edge = halfEdges[iHalfEdge].edge;
if (!edge.b || !edge.a) halfEdges.splice(iHalfEdge, 1);
}
halfEdges.sort(d3_geom_voronoiHalfEdgeOrder);
return halfEdges.length;
};
function d3_geom_voronoiCloseCells(extent) {
var x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], x2, y2, x3, y3, cells = d3_geom_voronoiCells, iCell = cells.length, cell, iHalfEdge, halfEdges, nHalfEdges, start, end;
while (iCell--) {
cell = cells[iCell];
if (!cell || !cell.prepare()) continue;
halfEdges = cell.edges;
nHalfEdges = halfEdges.length;
iHalfEdge = 0;
while (iHalfEdge < nHalfEdges) {
end = halfEdges[iHalfEdge].end(), x3 = end.x, y3 = end.y;
start = halfEdges[++iHalfEdge % nHalfEdges].start(), x2 = start.x, y2 = start.y;
if (abs(x3 - x2) > ε || abs(y3 - y2) > ε) {
halfEdges.splice(iHalfEdge, 0, new d3_geom_voronoiHalfEdge(d3_geom_voronoiCreateBorderEdge(cell.site, end, abs(x3 - x0) < ε && y1 - y3 > ε ? {
x: x0,
y: abs(x2 - x0) < ε ? y2 : y1
} : abs(y3 - y1) < ε && x1 - x3 > ε ? {
x: abs(y2 - y1) < ε ? x2 : x1,
y: y1
} : abs(x3 - x1) < ε && y3 - y0 > ε ? {
x: x1,
y: abs(x2 - x1) < ε ? y2 : y0
} : abs(y3 - y0) < ε && x3 - x0 > ε ? {
x: abs(y2 - y0) < ε ? x2 : x0,
y: y0
} : null), cell.site, null));
++nHalfEdges;
}
}
}
}
function d3_geom_voronoiHalfEdgeOrder(a, b) {
return b.angle - a.angle;
}
function d3_geom_voronoiCircle() {
d3_geom_voronoiRedBlackNode(this);
this.x = this.y = this.arc = this.site = this.cy = null;
}
function d3_geom_voronoiAttachCircle(arc) {
var lArc = arc.P, rArc = arc.N;
if (!lArc || !rArc) return;
var lSite = lArc.site, cSite = arc.site, rSite = rArc.site;
if (lSite === rSite) return;
var bx = cSite.x, by = cSite.y, ax = lSite.x - bx, ay = lSite.y - by, cx = rSite.x - bx, cy = rSite.y - by;
var d = 2 * (ax * cy - ay * cx);
if (d >= -ε2) return;
var ha = ax * ax + ay * ay, hc = cx * cx + cy * cy, x = (cy * ha - ay * hc) / d, y = (ax * hc - cx * ha) / d, cy = y + by;
var circle = d3_geom_voronoiCirclePool.pop() || new d3_geom_voronoiCircle();
circle.arc = arc;
circle.site = cSite;
circle.x = x + bx;
circle.y = cy + Math.sqrt(x * x + y * y);
circle.cy = cy;
arc.circle = circle;
var before = null, node = d3_geom_voronoiCircles._;
while (node) {
if (circle.y < node.y || circle.y === node.y && circle.x <= node.x) {
if (node.L) node = node.L; else {
before = node.P;
break;
}
} else {
if (node.R) node = node.R; else {
before = node;
break;
}
}
}
d3_geom_voronoiCircles.insert(before, circle);
if (!before) d3_geom_voronoiFirstCircle = circle;
}
function d3_geom_voronoiDetachCircle(arc) {
var circle = arc.circle;
if (circle) {
if (!circle.P) d3_geom_voronoiFirstCircle = circle.N;
d3_geom_voronoiCircles.remove(circle);
d3_geom_voronoiCirclePool.push(circle);
d3_geom_voronoiRedBlackNode(circle);
arc.circle = null;
}
}
function d3_geom_voronoiClipEdges(extent) {
var edges = d3_geom_voronoiEdges, clip = d3_geom_clipLine(extent[0][0], extent[0][1], extent[1][0], extent[1][1]), i = edges.length, e;
while (i--) {
e = edges[i];
if (!d3_geom_voronoiConnectEdge(e, extent) || !clip(e) || abs(e.a.x - e.b.x) < ε && abs(e.a.y - e.b.y) < ε) {
e.a = e.b = null;
edges.splice(i, 1);
}
}
}
function d3_geom_voronoiConnectEdge(edge, extent) {
var vb = edge.b;
if (vb) return true;
var va = edge.a, x0 = extent[0][0], x1 = extent[1][0], y0 = extent[0][1], y1 = extent[1][1], lSite = edge.l, rSite = edge.r, lx = lSite.x, ly = lSite.y, rx = rSite.x, ry = rSite.y, fx = (lx + rx) / 2, fy = (ly + ry) / 2, fm, fb;
if (ry === ly) {
if (fx < x0 || fx >= x1) return;
if (lx > rx) {
if (!va) va = {
x: fx,
y: y0
}; else if (va.y >= y1) return;
vb = {
x: fx,
y: y1
};
} else {
if (!va) va = {
x: fx,
y: y1
}; else if (va.y < y0) return;
vb = {
x: fx,
y: y0
};
}
} else {
fm = (lx - rx) / (ry - ly);
fb = fy - fm * fx;
if (fm < -1 || fm > 1) {
if (lx > rx) {
if (!va) va = {
x: (y0 - fb) / fm,
y: y0
}; else if (va.y >= y1) return;
vb = {
x: (y1 - fb) / fm,
y: y1
};
} else {
if (!va) va = {
x: (y1 - fb) / fm,
y: y1
}; else if (va.y < y0) return;
vb = {
x: (y0 - fb) / fm,
y: y0
};
}
} else {
if (ly < ry) {
if (!va) va = {
x: x0,
y: fm * x0 + fb
}; else if (va.x >= x1) return;
vb = {
x: x1,
y: fm * x1 + fb
};
} else {
if (!va) va = {
x: x1,
y: fm * x1 + fb
}; else if (va.x < x0) return;
vb = {
x: x0,
y: fm * x0 + fb
};
}
}
}
edge.a = va;
edge.b = vb;
return true;
}
function d3_geom_voronoiEdge(lSite, rSite) {
this.l = lSite;
this.r = rSite;
this.a = this.b = null;
}
function d3_geom_voronoiCreateEdge(lSite, rSite, va, vb) {
var edge = new d3_geom_voronoiEdge(lSite, rSite);
d3_geom_voronoiEdges.push(edge);
if (va) d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, va);
if (vb) d3_geom_voronoiSetEdgeEnd(edge, rSite, lSite, vb);
d3_geom_voronoiCells[lSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, lSite, rSite));
d3_geom_voronoiCells[rSite.i].edges.push(new d3_geom_voronoiHalfEdge(edge, rSite, lSite));
return edge;
}
function d3_geom_voronoiCreateBorderEdge(lSite, va, vb) {
var edge = new d3_geom_voronoiEdge(lSite, null);
edge.a = va;
edge.b = vb;
d3_geom_voronoiEdges.push(edge);
return edge;
}
function d3_geom_voronoiSetEdgeEnd(edge, lSite, rSite, vertex) {
if (!edge.a && !edge.b) {
edge.a = vertex;
edge.l = lSite;
edge.r = rSite;
} else if (edge.l === rSite) {
edge.b = vertex;
} else {
edge.a = vertex;
}
}
function d3_geom_voronoiHalfEdge(edge, lSite, rSite) {
var va = edge.a, vb = edge.b;
this.edge = edge;
this.site = lSite;
this.angle = rSite ? Math.atan2(rSite.y - lSite.y, rSite.x - lSite.x) : edge.l === lSite ? Math.atan2(vb.x - va.x, va.y - vb.y) : Math.atan2(va.x - vb.x, vb.y - va.y);
}
d3_geom_voronoiHalfEdge.prototype = {
start: function() {
return this.edge.l === this.site ? this.edge.a : this.edge.b;
},
end: function() {
return this.edge.l === this.site ? this.edge.b : this.edge.a;
}
};
function d3_geom_voronoiRedBlackTree() {
this._ = null;
}
function d3_geom_voronoiRedBlackNode(node) {
node.U = node.C = node.L = node.R = node.P = node.N = null;
}
d3_geom_voronoiRedBlackTree.prototype = {
insert: function(after, node) {
var parent, grandpa, uncle;
if (after) {
node.P = after;
node.N = after.N;
if (after.N) after.N.P = node;
after.N = node;
if (after.R) {
after = after.R;
while (after.L) after = after.L;
after.L = node;
} else {
after.R = node;
}
parent = after;
} else if (this._) {
after = d3_geom_voronoiRedBlackFirst(this._);
node.P = null;
node.N = after;
after.P = after.L = node;
parent = after;
} else {
node.P = node.N = null;
this._ = node;
parent = null;
}
node.L = node.R = null;
node.U = parent;
node.C = true;
after = node;
while (parent && parent.C) {
grandpa = parent.U;
if (parent === grandpa.L) {
uncle = grandpa.R;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.R) {
d3_geom_voronoiRedBlackRotateLeft(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
d3_geom_voronoiRedBlackRotateRight(this, grandpa);
}
} else {
uncle = grandpa.L;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.L) {
d3_geom_voronoiRedBlackRotateRight(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
d3_geom_voronoiRedBlackRotateLeft(this, grandpa);
}
}
parent = after.U;
}
this._.C = false;
},
remove: function(node) {
if (node.N) node.N.P = node.P;
if (node.P) node.P.N = node.N;
node.N = node.P = null;
var parent = node.U, sibling, left = node.L, right = node.R, next, red;
if (!left) next = right; else if (!right) next = left; else next = d3_geom_voronoiRedBlackFirst(right);
if (parent) {
if (parent.L === node) parent.L = next; else parent.R = next;
} else {
this._ = next;
}
if (left && right) {
red = next.C;
next.C = node.C;
next.L = left;
left.U = next;
if (next !== right) {
parent = next.U;
next.U = node.U;
node = next.R;
parent.L = node;
next.R = right;
right.U = next;
} else {
next.U = parent;
parent = next;
node = next.R;
}
} else {
red = node.C;
node = next;
}
if (node) node.U = parent;
if (red) return;
if (node && node.C) {
node.C = false;
return;
}
do {
if (node === this._) break;
if (node === parent.L) {
sibling = parent.R;
if (sibling.C) {
sibling.C = false;
parent.C = true;
d3_geom_voronoiRedBlackRotateLeft(this, parent);
sibling = parent.R;
}
if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
if (!sibling.R || !sibling.R.C) {
sibling.L.C = false;
sibling.C = true;
d3_geom_voronoiRedBlackRotateRight(this, sibling);
sibling = parent.R;
}
sibling.C = parent.C;
parent.C = sibling.R.C = false;
d3_geom_voronoiRedBlackRotateLeft(this, parent);
node = this._;
break;
}
} else {
sibling = parent.L;
if (sibling.C) {
sibling.C = false;
parent.C = true;
d3_geom_voronoiRedBlackRotateRight(this, parent);
sibling = parent.L;
}
if (sibling.L && sibling.L.C || sibling.R && sibling.R.C) {
if (!sibling.L || !sibling.L.C) {
sibling.R.C = false;
sibling.C = true;
d3_geom_voronoiRedBlackRotateLeft(this, sibling);
sibling = parent.L;
}
sibling.C = parent.C;
parent.C = sibling.L.C = false;
d3_geom_voronoiRedBlackRotateRight(this, parent);
node = this._;
break;
}
}
sibling.C = true;
node = parent;
parent = parent.U;
} while (!node.C);
if (node) node.C = false;
}
};
function d3_geom_voronoiRedBlackRotateLeft(tree, node) {
var p = node, q = node.R, parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q; else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.R = q.L;
if (p.R) p.R.U = p;
q.L = p;
}
function d3_geom_voronoiRedBlackRotateRight(tree, node) {
var p = node, q = node.L, parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q; else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.L = q.R;
if (p.L) p.L.U = p;
q.R = p;
}
function d3_geom_voronoiRedBlackFirst(node) {
while (node.L) node = node.L;
return node;
}
function d3_geom_voronoi(sites, bbox) {
var site = sites.sort(d3_geom_voronoiVertexOrder).pop(), x0, y0, circle;
d3_geom_voronoiEdges = [];
d3_geom_voronoiCells = new Array(sites.length);
d3_geom_voronoiBeaches = new d3_geom_voronoiRedBlackTree();
d3_geom_voronoiCircles = new d3_geom_voronoiRedBlackTree();
while (true) {
circle = d3_geom_voronoiFirstCircle;
if (site && (!circle || site.y < circle.y || site.y === circle.y && site.x < circle.x)) {
if (site.x !== x0 || site.y !== y0) {
d3_geom_voronoiCells[site.i] = new d3_geom_voronoiCell(site);
d3_geom_voronoiAddBeach(site);
x0 = site.x, y0 = site.y;
}
site = sites.pop();
} else if (circle) {
d3_geom_voronoiRemoveBeach(circle.arc);
} else {
break;
}
}
if (bbox) d3_geom_voronoiClipEdges(bbox), d3_geom_voronoiCloseCells(bbox);
var diagram = {
cells: d3_geom_voronoiCells,
edges: d3_geom_voronoiEdges
};
d3_geom_voronoiBeaches = d3_geom_voronoiCircles = d3_geom_voronoiEdges = d3_geom_voronoiCells = null;
return diagram;
}
function d3_geom_voronoiVertexOrder(a, b) {
return b.y - a.y || b.x - a.x;
}
d3.geom.voronoi = function(points) {
var x = d3_geom_pointX, y = d3_geom_pointY, fx = x, fy = y, clipExtent = d3_geom_voronoiClipExtent;
if (points) return voronoi(points);
function voronoi(data) {
var polygons = new Array(data.length), x0 = clipExtent[0][0], y0 = clipExtent[0][1], x1 = clipExtent[1][0], y1 = clipExtent[1][1];
d3_geom_voronoi(sites(data), clipExtent).cells.forEach(function(cell, i) {
var edges = cell.edges, site = cell.site, polygon = polygons[i] = edges.length ? edges.map(function(e) {
var s = e.start();
return [ s.x, s.y ];
}) : site.x >= x0 && site.x <= x1 && site.y >= y0 && site.y <= y1 ? [ [ x0, y1 ], [ x1, y1 ], [ x1, y0 ], [ x0, y0 ] ] : [];
polygon.point = data[i];
});
return polygons;
}
function sites(data) {
return data.map(function(d, i) {
return {
x: Math.round(fx(d, i) / ε) * ε,
y: Math.round(fy(d, i) / ε) * ε,
i: i
};
});
}
voronoi.links = function(data) {
return d3_geom_voronoi(sites(data)).edges.filter(function(edge) {
return edge.l && edge.r;
}).map(function(edge) {
return {
source: data[edge.l.i],
target: data[edge.r.i]
};
});
};
voronoi.triangles = function(data) {
var triangles = [];
d3_geom_voronoi(sites(data)).cells.forEach(function(cell, i) {
var site = cell.site, edges = cell.edges.sort(d3_geom_voronoiHalfEdgeOrder), j = -1, m = edges.length, e0, s0, e1 = edges[m - 1].edge, s1 = e1.l === site ? e1.r : e1.l;
while (++j < m) {
e0 = e1;
s0 = s1;
e1 = edges[j].edge;
s1 = e1.l === site ? e1.r : e1.l;
if (i < s0.i && i < s1.i && d3_geom_voronoiTriangleArea(site, s0, s1) < 0) {
triangles.push([ data[i], data[s0.i], data[s1.i] ]);
}
}
});
return triangles;
};
voronoi.x = function(_) {
return arguments.length ? (fx = d3_functor(x = _), voronoi) : x;
};
voronoi.y = function(_) {
return arguments.length ? (fy = d3_functor(y = _), voronoi) : y;
};
voronoi.clipExtent = function(_) {
if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent;
clipExtent = _ == null ? d3_geom_voronoiClipExtent : _;
return voronoi;
};
voronoi.size = function(_) {
if (!arguments.length) return clipExtent === d3_geom_voronoiClipExtent ? null : clipExtent && clipExtent[1];
return voronoi.clipExtent(_ && [ [ 0, 0 ], _ ]);
};
return voronoi;
};
var d3_geom_voronoiClipExtent = [ [ -1e6, -1e6 ], [ 1e6, 1e6 ] ];
function d3_geom_voronoiTriangleArea(a, b, c) {
return (a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y);
}
d3.geom.delaunay = function(vertices) {
return d3.geom.voronoi().triangles(vertices);
};
d3.geom.quadtree = function(points, x1, y1, x2, y2) {
var x = d3_geom_pointX, y = d3_geom_pointY, compat;
if (compat = arguments.length) {
x = d3_geom_quadtreeCompatX;
y = d3_geom_quadtreeCompatY;
if (compat === 3) {
y2 = y1;
x2 = x1;
y1 = x1 = 0;
}
return quadtree(points);
}
function quadtree(data) {
var d, fx = d3_functor(x), fy = d3_functor(y), xs, ys, i, n, x1_, y1_, x2_, y2_;
if (x1 != null) {
x1_ = x1, y1_ = y1, x2_ = x2, y2_ = y2;
} else {
x2_ = y2_ = -(x1_ = y1_ = Infinity);
xs = [], ys = [];
n = data.length;
if (compat) for (i = 0; i < n; ++i) {
d = data[i];
if (d.x < x1_) x1_ = d.x;
if (d.y < y1_) y1_ = d.y;
if (d.x > x2_) x2_ = d.x;
if (d.y > y2_) y2_ = d.y;
xs.push(d.x);
ys.push(d.y);
} else for (i = 0; i < n; ++i) {
var x_ = +fx(d = data[i], i), y_ = +fy(d, i);
if (x_ < x1_) x1_ = x_;
if (y_ < y1_) y1_ = y_;
if (x_ > x2_) x2_ = x_;
if (y_ > y2_) y2_ = y_;
xs.push(x_);
ys.push(y_);
}
}
var dx = x2_ - x1_, dy = y2_ - y1_;
if (dx > dy) y2_ = y1_ + dx; else x2_ = x1_ + dy;
function insert(n, d, x, y, x1, y1, x2, y2) {
if (isNaN(x) || isNaN(y)) return;
if (n.leaf) {
var nx = n.x, ny = n.y;
if (nx != null) {
if (abs(nx - x) + abs(ny - y) < .01) {
insertChild(n, d, x, y, x1, y1, x2, y2);
} else {
var nPoint = n.point;
n.x = n.y = n.point = null;
insertChild(n, nPoint, nx, ny, x1, y1, x2, y2);
insertChild(n, d, x, y, x1, y1, x2, y2);
}
} else {
n.x = x, n.y = y, n.point = d;
}
} else {
insertChild(n, d, x, y, x1, y1, x2, y2);
}
}
function insertChild(n, d, x, y, x1, y1, x2, y2) {
var xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym, i = below << 1 | right;
n.leaf = false;
n = n.nodes[i] || (n.nodes[i] = d3_geom_quadtreeNode());
if (right) x1 = xm; else x2 = xm;
if (below) y1 = ym; else y2 = ym;
insert(n, d, x, y, x1, y1, x2, y2);
}
var root = d3_geom_quadtreeNode();
root.add = function(d) {
insert(root, d, +fx(d, ++i), +fy(d, i), x1_, y1_, x2_, y2_);
};
root.visit = function(f) {
d3_geom_quadtreeVisit(f, root, x1_, y1_, x2_, y2_);
};
root.find = function(point) {
return d3_geom_quadtreeFind(root, point[0], point[1], x1_, y1_, x2_, y2_);
};
i = -1;
if (x1 == null) {
while (++i < n) {
insert(root, data[i], xs[i], ys[i], x1_, y1_, x2_, y2_);
}
--i;
} else data.forEach(root.add);
xs = ys = data = d = null;
return root;
}
quadtree.x = function(_) {
return arguments.length ? (x = _, quadtree) : x;
};
quadtree.y = function(_) {
return arguments.length ? (y = _, quadtree) : y;
};
quadtree.extent = function(_) {
if (!arguments.length) return x1 == null ? null : [ [ x1, y1 ], [ x2, y2 ] ];
if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = +_[0][0], y1 = +_[0][1], x2 = +_[1][0],
y2 = +_[1][1];
return quadtree;
};
quadtree.size = function(_) {
if (!arguments.length) return x1 == null ? null : [ x2 - x1, y2 - y1 ];
if (_ == null) x1 = y1 = x2 = y2 = null; else x1 = y1 = 0, x2 = +_[0], y2 = +_[1];
return quadtree;
};
return quadtree;
};
function d3_geom_quadtreeCompatX(d) {
return d.x;
}
function d3_geom_quadtreeCompatY(d) {
return d.y;
}
function d3_geom_quadtreeNode() {
return {
leaf: true,
nodes: [],
point: null,
x: null,
y: null
};
}
function d3_geom_quadtreeVisit(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;
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[2]) d3_geom_quadtreeVisit(f, children[2], x1, sy, sx, y2);
if (children[3]) d3_geom_quadtreeVisit(f, children[3], sx, sy, x2, y2);
}
}
function d3_geom_quadtreeFind(root, x, y, x0, y0, x3, y3) {
var minDistance2 = Infinity, closestPoint;
(function find(node, x1, y1, x2, y2) {
if (x1 > x3 || y1 > y3 || x2 < x0 || y2 < y0) return;
if (point = node.point) {
var point, dx = x - node.x, dy = y - node.y, distance2 = dx * dx + dy * dy;
if (distance2 < minDistance2) {
var distance = Math.sqrt(minDistance2 = distance2);
x0 = x - distance, y0 = y - distance;
x3 = x + distance, y3 = y + distance;
closestPoint = point;
}
}
var children = node.nodes, xm = (x1 + x2) * .5, ym = (y1 + y2) * .5, right = x >= xm, below = y >= ym;
for (var i = below << 1 | right, j = i + 4; i < j; ++i) {
if (node = children[i & 3]) switch (i & 3) {
case 0:
find(node, x1, y1, xm, ym);
break;
case 1:
find(node, xm, y1, x2, ym);
break;
case 2:
find(node, x1, ym, xm, y2);
break;
case 3:
find(node, xm, ym, x2, y2);
break;
}
}
})(root, x0, y0, x3, y3);
return closestPoint;
}
d3.interpolateRgb = d3_interpolateRgb;
function d3_interpolateRgb(a, b) {
a = d3.rgb(a);
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;
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));
};
}
d3.interpolateObject = d3_interpolateObject;
function d3_interpolateObject(a, b) {
var i = {}, c = {}, k;
for (k in a) {
if (k in b) {
i[k] = d3_interpolate(a[k], b[k]);
} else {
c[k] = a[k];
}
}
for (k in b) {
if (!(k in a)) {
c[k] = b[k];
}
}
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
}
d3.interpolateNumber = d3_interpolateNumber;
function d3_interpolateNumber(a, b) {
a = +a, b = +b;
return function(t) {
return a * (1 - t) + b * t;
};
}
d3.interpolateString = d3_interpolateString;
function d3_interpolateString(a, b) {
var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
a = a + "", b = b + "";
while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {
if ((bs = bm.index) > bi) {
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs; else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) {
if (s[i]) s[i] += bm; else s[++i] = bm;
} else {
s[++i] = null;
q.push({
i: i,
x: d3_interpolateNumber(am, bm)
});
}
bi = d3_interpolate_numberB.lastIndex;
}
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs; else s[++i] = bs;
}
return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {
return b(t) + "";
}) : function() {
return b;
} : (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
}
var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
d3.interpolate = d3_interpolate;
function d3_interpolate(a, b) {
var i = d3.interpolators.length, f;
while (--i >= 0 && !(f = d3.interpolators[i](a, b))) ;
return f;
}
d3.interpolators = [ function(a, b) {
var t = typeof b;
return (t === "string" ? d3_rgb_names.has(b.toLowerCase()) || /^(#|rgb\(|hsl\()/i.test(b) ? d3_interpolateRgb : d3_interpolateString : b instanceof d3_color ? d3_interpolateRgb : Array.isArray(b) ? d3_interpolateArray : t === "object" && isNaN(b) ? d3_interpolateObject : d3_interpolateNumber)(a, b);
} ];
d3.interpolateArray = d3_interpolateArray;
function d3_interpolateArray(a, b) {
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 < na; ++i) c[i] = a[i];
for (;i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < n0; ++i) c[i] = x[i](t);
return c;
};
}
var d3_ease_default = function() {
return d3_identity;
};
var d3_ease = d3.map({
linear: d3_ease_default,
poly: d3_ease_poly,
quad: function() {
return d3_ease_quad;
},
cubic: function() {
return d3_ease_cubic;
},
sin: function() {
return d3_ease_sin;
},
exp: function() {
return d3_ease_exp;
},
circle: function() {
return d3_ease_circle;
},
elastic: d3_ease_elastic,
back: d3_ease_back,
bounce: function() {
return d3_ease_bounce;
}
});
var d3_ease_mode = d3.map({
"in": d3_identity,
out: d3_ease_reverse,
"in-out": d3_ease_reflect,
"out-in": function(f) {
return d3_ease_reflect(d3_ease_reverse(f));
}
});
d3.ease = function(name) {
var i = name.indexOf("-"), t = i >= 0 ? name.slice(0, i) : name, m = i >= 0 ? name.slice(i + 1) : "in";
t = d3_ease.get(t) || d3_ease_default;
m = d3_ease_mode.get(m) || d3_identity;
return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
};
function d3_ease_clamp(f) {
return function(t) {
return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
};
}
function d3_ease_reverse(f) {
return function(t) {
return 1 - f(1 - t);
};
}
function d3_ease_reflect(f) {
return function(t) {
return .5 * (t < .5 ? f(2 * t) : 2 - f(2 - 2 * t));
};
}
function d3_ease_quad(t) {
return t * t;
}
function d3_ease_cubic(t) {
return t * t * t;
}
function d3_ease_cubicInOut(t) {
if (t <= 0) return 0;
if (t >= 1) return 1;
var t2 = t * t, t3 = t2 * t;
return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
}
function d3_ease_poly(e) {
return function(t) {
return Math.pow(t, e);
};
}
function d3_ease_sin(t) {
return 1 - Math.cos(t * halfπ);
}
function d3_ease_exp(t) {
return Math.pow(2, 10 * (t - 1));
}
function d3_ease_circle(t) {
return 1 - Math.sqrt(1 - t * t);
}
function d3_ease_elastic(a, p) {
var s;
if (arguments.length < 2) p = .45;
if (arguments.length) s = p / τ * Math.asin(1 / a); else a = 1, s = p / 4;
return function(t) {
return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
};
}
function d3_ease_back(s) {
if (!s) s = 1.70158;
return function(t) {
return t * t * ((s + 1) * t - s);
};
}
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;
}
d3.interpolateHcl = d3_interpolateHcl;
function d3_interpolateHcl(a, b) {
a = d3.hcl(a);
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;
if (isNaN(bc)) bc = 0, ac = isNaN(ac) ? b.c : ac;
if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
return function(t) {
return d3_hcl_lab(ah + bh * t, ac + bc * t, al + bl * t) + "";
};
}
d3.interpolateHsl = d3_interpolateHsl;
function d3_interpolateHsl(a, b) {
a = d3.hsl(a);
b = d3.hsl(b);
var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al;
if (isNaN(bs)) bs = 0, as = isNaN(as) ? b.s : as;
if (isNaN(bh)) bh = 0, ah = isNaN(ah) ? b.h : ah; else if (bh > 180) bh -= 360; else if (bh < -180) bh += 360;
return function(t) {
return d3_hsl_rgb(ah + bh * t, as + bs * t, al + bl * t) + "";
};
}
d3.interpolateLab = d3_interpolateLab;
function d3_interpolateLab(a, b) {
a = d3.lab(a);
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;
return function(t) {
return d3_lab_rgb(al + bl * t, aa + ba * t, ab + bb * t) + "";
};
}
d3.interpolateRound = d3_interpolateRound;
function d3_interpolateRound(a, b) {
b -= a;
return function(t) {
return Math.round(a + b * t);
};
}
d3.transform = function(string) {
var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
return (d3.transform = function(string) {
if (string != null) {
g.setAttribute("transform", string);
var t = g.transform.baseVal.consolidate();
}
return new d3_transform(t ? t.matrix : d3_transformIdentity);
})(string);
};
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;
if (r0[0] * r1[1] < r1[0] * r0[1]) {
r0[0] *= -1;
r0[1] *= -1;
kx *= -1;
kz *= -1;
}
this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
this.translate = [ m.e, m.f ];
this.scale = [ kx, ky ];
this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
}
d3_transform.prototype.toString = function() {
return "translate(" + this.translate + ")rotate(" + this.rotate + ")skewX(" + this.skew + ")scale(" + this.scale + ")";
};
function d3_transformDot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function d3_transformNormalize(a) {
var k = Math.sqrt(d3_transformDot(a, a));
if (k) {
a[0] /= k;
a[1] /= k;
}
return k;
}
function d3_transformCombine(a, b, k) {
a[0] += k * b[0];
a[1] += k * b[1];
return a;
}
var d3_transformIdentity = {
a: 1,
b: 0,
c: 0,
d: 1,
e: 0,
f: 0
};
d3.interpolateTransform = d3_interpolateTransform;
function d3_interpolateTransformPop(s) {
return s.length ? s.pop() + "," : "";
}
function d3_interpolateTranslate(ta, tb, s, q) {
if (ta[0] !== tb[0] || ta[1] !== tb[1]) {
var i = s.push("translate(", null, ",", null, ")");
q.push({
i: i - 4,
x: d3_interpolateNumber(ta[0], tb[0])
}, {
i: i - 2,
x: d3_interpolateNumber(ta[1], tb[1])
});
} else if (tb[0] || tb[1]) {
s.push("translate(" + tb + ")");
}
}
function d3_interpolateRotate(ra, rb, s, q) {
if (ra !== rb) {
if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360;
q.push({
i: s.push(d3_interpolateTransformPop(s) + "rotate(", null, ")") - 2,
x: d3_interpolateNumber(ra, rb)
});
} else if (rb) {
s.push(d3_interpolateTransformPop(s) + "rotate(" + rb + ")");
}
}
function d3_interpolateSkew(wa, wb, s, q) {
if (wa !== wb) {
q.push({
i: s.push(d3_interpolateTransformPop(s) + "skewX(", null, ")") - 2,
x: d3_interpolateNumber(wa, wb)
});
} else if (wb) {
s.push(d3_interpolateTransformPop(s) + "skewX(" + wb + ")");
}
}
function d3_interpolateScale(ka, kb, s, q) {
if (ka[0] !== kb[0] || ka[1] !== kb[1]) {
var i = s.push(d3_interpolateTransformPop(s) + "scale(", null, ",", null, ")");
q.push({
i: i - 4,
x: d3_interpolateNumber(ka[0], kb[0])
}, {
i: i - 2,
x: d3_interpolateNumber(ka[1], kb[1])
});
} else if (kb[0] !== 1 || kb[1] !== 1) {
s.push(d3_interpolateTransformPop(s) + "scale(" + kb + ")");
}
}
function d3_interpolateTransform(a, b) {
var s = [], q = [];
a = d3.transform(a), b = d3.transform(b);
d3_interpolateTranslate(a.translate, b.translate, s, q);
d3_interpolateRotate(a.rotate, b.rotate, s, q);
d3_interpolateSkew(a.skew, b.skew, s, q);
d3_interpolateScale(a.scale, b.scale, s, q);
a = b = null;
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
}
function d3_uninterpolateNumber(a, b) {
b = (b -= a = +a) || 1 / b;
return function(x) {
return (x - a) / b;
};
}
function d3_uninterpolateClamp(a, b) {
b = (b -= a = +a) || 1 / b;
return function(x) {
return Math.max(0, Math.min(1, (x - a) / b));
};
}
d3.layout = {};
d3.layout.bundle = function() {
return function(links) {
var paths = [], i = -1, n = links.length;
while (++i < n) paths.push(d3_layout_bundlePath(links[i]));
return paths;
};
};
function d3_layout_bundlePath(link) {
var start = link.source, end = link.target, lca = d3_layout_bundleLeastCommonAncestor(start, end), points = [ start ];
while (start !== lca) {
start = start.parent;
points.push(start);
}
var k = points.length;
while (end !== lca) {
points.splice(k, 0, end);
end = end.parent;
}
return points;
}
function d3_layout_bundleAncestors(node) {
var ancestors = [], parent = node.parent;
while (parent != null) {
ancestors.push(node);
node = parent;
parent = parent.parent;
}
ancestors.push(node);
return ancestors;
}
function d3_layout_bundleLeastCommonAncestor(a, b) {
if (a === b) return a;
var aNodes = d3_layout_bundleAncestors(a), bNodes = d3_layout_bundleAncestors(b), aNode = aNodes.pop(), bNode = bNodes.pop(), sharedNode = null;
while (aNode === bNode) {
sharedNode = aNode;
aNode = aNodes.pop();
bNode = bNodes.pop();
}
return sharedNode;
}
d3.layout.chord = function() {
var chord = {}, chords, groups, matrix, n, padding = 0, sortGroups, sortSubgroups, sortChords;
function relayout() {
var subgroups = {}, groupSums = [], groupIndex = d3.range(n), subgroupIndex = [], k, x, x0, i, j;
chords = [];
groups = [];
k = 0, i = -1;
while (++i < n) {
x = 0, j = -1;
while (++j < n) {
x += matrix[i][j];
}
groupSums.push(x);
subgroupIndex.push(d3.range(n));
k += x;
}
if (sortGroups) {
groupIndex.sort(function(a, b) {
return sortGroups(groupSums[a], groupSums[b]);
});
}
if (sortSubgroups) {
subgroupIndex.forEach(function(d, i) {
d.sort(function(a, b) {
return sortSubgroups(matrix[i][a], matrix[i][b]);
});
});
}
k = (τ - padding * n) / k;
x = 0, i = -1;
while (++i < n) {
x0 = x, j = -1;
while (++j < n) {
var di = groupIndex[i], dj = subgroupIndex[di][j], v = matrix[di][dj], a0 = x, a1 = x += v * k;
subgroups[di + "-" + dj] = {
index: di,
subindex: dj,
startAngle: a0,
endAngle: a1,
value: v
};
}
groups[di] = {
index: di,
startAngle: x0,
endAngle: x,
value: groupSums[di]
};
x += padding;
}
i = -1;
while (++i < n) {
j = i - 1;
while (++j < n) {
var source = subgroups[i + "-" + j], target = subgroups[j + "-" + i];
if (source.value || target.value) {
chords.push(source.value < target.value ? {
source: target,
target: source
} : {
source: source,
target: target
});
}
}
}
if (sortChords) resort();
}
function resort() {
chords.sort(function(a, b) {
return sortChords((a.source.value + a.target.value) / 2, (b.source.value + b.target.value) / 2);
});
}
chord.matrix = function(x) {
if (!arguments.length) return matrix;
n = (matrix = x) && matrix.length;
chords = groups = null;
return chord;
};
chord.padding = function(x) {
if (!arguments.length) return padding;
padding = x;
chords = groups = null;
return chord;
};
chord.sortGroups = function(x) {
if (!arguments.length) return sortGroups;
sortGroups = x;
chords = groups = null;
return chord;
};
chord.sortSubgroups = function(x) {
if (!arguments.length) return sortSubgroups;
sortSubgroups = x;
chords = null;
return chord;
};
chord.sortChords = function(x) {
if (!arguments.length) return sortChords;
sortChords = x;
if (chords) resort();
return chord;
};
chord.chords = function() {
if (!chords) relayout();
return chords;
};
chord.groups = function() {
if (!groups) relayout();
return groups;
};
return chord;
};
d3.layout.force = function() {
var force = {}, event = d3.dispatch("start", "tick", "end"), timer, size = [ 1, 1 ], drag, alpha, friction = .9, linkDistance = d3_layout_forceLinkDistance, linkStrength = d3_layout_forceLinkStrength, charge = -30, chargeDistance2 = d3_layout_forceChargeDistance2, gravity = .1, theta2 = .64, nodes = [], links = [], distances, strengths, charges;
function repulse(node) {
return function(quad, x1, _, x2) {
if (quad.point !== node) {
var dx = quad.cx - node.x, dy = quad.cy - node.y, dw = x2 - x1, dn = dx * dx + dy * dy;
if (dw * dw / theta2 < dn) {
if (dn < chargeDistance2) {
var k = quad.charge / dn;
node.px -= dx * k;
node.py -= dy * k;
}
return true;
}
if (quad.point && dn && dn < chargeDistance2) {
var k = quad.pointCharge / dn;
node.px -= dx * k;
node.py -= dy * k;
}
}
return !quad.charge;
};
}
force.tick = function() {
if ((alpha *= .99) < .005) {
timer = null;
event.end({
type: "end",
alpha: alpha = 0
});
return true;
}
var n = nodes.length, m = links.length, q, i, o, s, t, l, k, x, y;
for (i = 0; i < m; ++i) {
o = links[i];
s = o.source;
t = o.target;
x = t.x - s.x;
y = t.y - s.y;
if (l = x * x + y * y) {
l = alpha * strengths[i] * ((l = Math.sqrt(l)) - distances[i]) / l;
x *= l;
y *= l;
t.x -= x * (k = s.weight + t.weight ? s.weight / (s.weight + t.weight) : .5);
t.y -= y * k;
s.x += x * (k = 1 - k);
s.y += y * k;
}
}
if (k = alpha * gravity) {
x = size[0] / 2;
y = size[1] / 2;
i = -1;
if (k) while (++i < n) {
o = nodes[i];
o.x += (x - o.x) * k;
o.y += (y - o.y) * k;
}
}
if (charge) {
d3_layout_forceAccumulate(q = d3.geom.quadtree(nodes), alpha, charges);
i = -1;
while (++i < n) {
if (!(o = nodes[i]).fixed) {
q.visit(repulse(o));
}
}
}
i = -1;
while (++i < n) {
o = nodes[i];
if (o.fixed) {
o.x = o.px;
o.y = o.py;
} else {
o.x -= (o.px - (o.px = o.x)) * friction;
o.y -= (o.py - (o.py = o.y)) * friction;
}
}
event.tick({
type: "tick",
alpha: alpha
});
};
force.nodes = function(x) {
if (!arguments.length) return nodes;
nodes = x;
return force;
};
force.links = function(x) {
if (!arguments.length) return links;
links = x;
return force;
};
force.size = function(x) {
if (!arguments.length) return size;
size = x;
return force;
};
force.linkDistance = function(x) {
if (!arguments.length) return linkDistance;
linkDistance = typeof x === "function" ? x : +x;
return force;
};
force.distance = force.linkDistance;
force.linkStrength = function(x) {
if (!arguments.length) return linkStrength;
linkStrength = typeof x === "function" ? x : +x;
return force;
};
force.friction = function(x) {
if (!arguments.length) return friction;
friction = +x;
return force;
};
force.charge = function(x) {
if (!arguments.length) return charge;
charge = typeof x === "function" ? x : +x;
return force;
};
force.chargeDistance = function(x) {
if (!arguments.length) return Math.sqrt(chargeDistance2);
chargeDistance2 = x * x;
return force;
};
force.gravity = function(x) {
if (!arguments.length) return gravity;
gravity = +x;
return force;
};
force.theta = function(x) {
if (!arguments.length) return Math.sqrt(theta2);
theta2 = x * x;
return force;
};
force.alpha = function(x) {
if (!arguments.length) return alpha;
x = +x;
if (alpha) {
if (x > 0) {
alpha = x;
} else {
timer.c = null, timer.t = NaN, timer = null;
event.end({
type: "end",
alpha: alpha = 0
});
}
} else if (x > 0) {
event.start({
type: "start",
alpha: alpha = x
});
timer = d3_timer(force.tick);
}
return force;
};
force.start = function() {
var i, n = nodes.length, m = links.length, w = size[0], h = size[1], neighbors, o;
for (i = 0; i < n; ++i) {
(o = nodes[i]).index = i;
o.weight = 0;
}
for (i = 0; i < m; ++i) {
o = links[i];
if (typeof o.source == "number") o.source = nodes[o.source];
if (typeof o.target == "number") o.target = nodes[o.target];
++o.source.weight;
++o.target.weight;
}
for (i = 0; i < n; ++i) {
o = nodes[i];
if (isNaN(o.x)) o.x = position("x", w);
if (isNaN(o.y)) o.y = position("y", h);
if (isNaN(o.px)) o.px = o.x;
if (isNaN(o.py)) o.py = o.y;
}
distances = [];
if (typeof linkDistance === "function") for (i = 0; i < m; ++i) distances[i] = +linkDistance.call(this, links[i], i); else for (i = 0; i < m; ++i) distances[i] = linkDistance;
strengths = [];
if (typeof linkStrength === "function") for (i = 0; i < m; ++i) strengths[i] = +linkStrength.call(this, links[i], i); else for (i = 0; i < m; ++i) strengths[i] = linkStrength;
charges = [];
if (typeof charge === "function") for (i = 0; i < n; ++i) charges[i] = +charge.call(this, nodes[i], i); else for (i = 0; i < n; ++i) charges[i] = charge;
function position(dimension, size) {
if (!neighbors) {
neighbors = new Array(n);
for (j = 0; j < n; ++j) {
neighbors[j] = [];
}
for (j = 0; j < m; ++j) {
var o = links[j];
neighbors[o.source.index].push(o.target);
neighbors[o.target.index].push(o.source);
}
}
var candidates = neighbors[i], j = -1, l = candidates.length, x;
while (++j < l) if (!isNaN(x = candidates[j][dimension])) return x;
return Math.random() * size;
}
return force.resume();
};
force.resume = function() {
return force.alpha(.1);
};
force.stop = function() {
return force.alpha(0);
};
force.drag = function() {
if (!drag) drag = d3.behavior.drag().origin(d3_identity).on("dragstart.force", d3_layout_forceDragstart).on("drag.force", dragmove).on("dragend.force", d3_layout_forceDragend);
if (!arguments.length) return drag;
this.on("mouseover.force", d3_layout_forceMouseover).on("mouseout.force", d3_layout_forceMouseout).call(drag);
};
function dragmove(d) {
d.px = d3.event.x, d.py = d3.event.y;
force.resume();
}
return d3.rebind(force, event, "on");
};
function d3_layout_forceDragstart(d) {
d.fixed |= 2;
}
function d3_layout_forceDragend(d) {
d.fixed &= ~6;
}
function d3_layout_forceMouseover(d) {
d.fixed |= 4;
d.px = d.x, d.py = d.y;
}
function d3_layout_forceMouseout(d) {
d.fixed &= ~4;
}
function d3_layout_forceAccumulate(quad, alpha, charges) {
var cx = 0, cy = 0;
quad.charge = 0;
if (!quad.leaf) {
var nodes = quad.nodes, n = nodes.length, i = -1, c;
while (++i < n) {
c = nodes[i];
if (c == null) continue;
d3_layout_forceAccumulate(c, alpha, charges);
quad.charge += c.charge;
cx += c.charge * c.cx;
cy += c.charge * c.cy;
}
}
if (quad.point) {
if (!quad.leaf) {
quad.point.x += Math.random() - .5;
quad.point.y += Math.random() - .5;
}
var k = alpha * charges[quad.point.index];
quad.charge += quad.pointCharge = k;
cx += k * quad.point.x;
cy += k * quad.point.y;
}
quad.cx = cx / quad.charge;
quad.cy = cy / quad.charge;
}
var d3_layout_forceLinkDistance = 20, d3_layout_forceLinkStrength = 1, d3_layout_forceChargeDistance2 = Infinity;
d3.layout.hierarchy = function() {
var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue;
function hierarchy(root) {
var stack = [ root ], nodes = [], node;
root.depth = 0;
while ((node = stack.pop()) != null) {
nodes.push(node);
if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) {
var n, childs, child;
while (--n >= 0) {
stack.push(child = childs[n]);
child.parent = node;
child.depth = node.depth + 1;
}
if (value) node.value = 0;
node.children = childs;
} else {
if (value) node.value = +value.call(hierarchy, node, node.depth) || 0;
delete node.children;
}
}
d3_layout_hierarchyVisitAfter(root, function(node) {
var childs, parent;
if (sort && (childs = node.children)) childs.sort(sort);
if (value && (parent = node.parent)) parent.value += node.value;
});
return nodes;
}
hierarchy.sort = function(x) {
if (!arguments.length) return sort;
sort = x;
return hierarchy;
};
hierarchy.children = function(x) {
if (!arguments.length) return children;
children = x;
return hierarchy;
};
hierarchy.value = function(x) {
if (!arguments.length) return value;
value = x;
return hierarchy;
};
hierarchy.revalue = function(root) {
if (value) {
d3_layout_hierarchyVisitBefore(root, function(node) {
if (node.children) node.value = 0;
});
d3_layout_hierarchyVisitAfter(root, function(node) {
var parent;
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0;
if (parent = node.parent) parent.value += node.value;
});
}
return root;
};
return hierarchy;
};
function d3_layout_hierarchyRebind(object, hierarchy) {
d3.rebind(object, hierarchy, "sort", "children", "value");
object.nodes = object;
object.links = d3_layout_hierarchyLinks;
return object;
}
function d3_layout_hierarchyVisitBefore(node, callback) {
var nodes = [ node ];
while ((node = nodes.pop()) != null) {
callback(node);
if ((children = node.children) && (n = children.length)) {
var n, children;
while (--n >= 0) nodes.push(children[n]);
}
}
}
function d3_layout_hierarchyVisitAfter(node, callback) {
var nodes = [ node ], nodes2 = [];
while ((node = nodes.pop()) != null) {
nodes2.push(node);
if ((children = node.children) && (n = children.length)) {
var i = -1, n, children;
while (++i < n) nodes.push(children[i]);
}
}
while ((node = nodes2.pop()) != null) {
callback(node);
}
}
function d3_layout_hierarchyChildren(d) {
return d.children;
}
function d3_layout_hierarchyValue(d) {
return d.value;
}
function d3_layout_hierarchySort(a, b) {
return b.value - a.value;
}
function d3_layout_hierarchyLinks(nodes) {
return d3.merge(nodes.map(function(parent) {
return (parent.children || []).map(function(child) {
return {
source: parent,
target: child
};
});
}));
}
d3.layout.partition = function() {
var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ];
function position(node, x, dx, dy) {
var children = node.children;
node.x = x;
node.y = node.depth * dy;
node.dx = dx;
node.dy = dy;
if (children && (n = children.length)) {
var i = -1, n, c, d;
dx = node.value ? dx / node.value : 0;
while (++i < n) {
position(c = children[i], x, d = c.value * dx, dy);
x += d;
}
}
}
function depth(node) {
var children = node.children, d = 0;
if (children && (n = children.length)) {
var i = -1, n;
while (++i < n) d = Math.max(d, depth(children[i]));
}
return 1 + d;
}
function partition(d, i) {
var nodes = hierarchy.call(this, d, i);
position(nodes[0], 0, size[0], size[1] / depth(nodes[0]));
return nodes;
}
partition.size = function(x) {
if (!arguments.length) return size;
size = x;
return partition;
};
return d3_layout_hierarchyRebind(partition, hierarchy);
};
d3.layout.pie = function() {
var value = Number, sort = d3_layout_pieSortByValue, startAngle = 0, endAngle = τ, padAngle = 0;
function pie(data) {
var n = data.length, values = data.map(function(d, i) {
return +value.call(pie, d, i);
}), a = +(typeof startAngle === "function" ? startAngle.apply(this, arguments) : startAngle), da = (typeof endAngle === "function" ? endAngle.apply(this, arguments) : endAngle) - a, p = Math.min(Math.abs(da) / n, +(typeof padAngle === "function" ? padAngle.apply(this, arguments) : padAngle)), pa = p * (da < 0 ? -1 : 1), sum = d3.sum(values), k = sum ? (da - n * pa) / sum : 0, index = d3.range(n), arcs = [], v;
if (sort != null) index.sort(sort === d3_layout_pieSortByValue ? function(i, j) {
return values[j] - values[i];
} : function(i, j) {
return sort(data[i], data[j]);
});
index.forEach(function(i) {
arcs[i] = {
data: data[i],
value: v = values[i],
startAngle: a,
endAngle: a += v * k + pa,
padAngle: p
};
});
return arcs;
}
pie.value = function(_) {
if (!arguments.length) return value;
value = _;
return pie;
};
pie.sort = function(_) {
if (!arguments.length) return sort;
sort = _;
return pie;
};
pie.startAngle = function(_) {
if (!arguments.length) return startAngle;
startAngle = _;
return pie;
};
pie.endAngle = function(_) {
if (!arguments.length) return endAngle;
endAngle = _;
return pie;
};
pie.padAngle = function(_) {
if (!arguments.length) return padAngle;
padAngle = _;
return pie;
};
return pie;
};
var d3_layout_pieSortByValue = {};
d3.layout.stack = function() {
var values = d3_identity, order = d3_layout_stackOrderDefault, offset = d3_layout_stackOffsetZero, out = d3_layout_stackOut, x = d3_layout_stackX, y = d3_layout_stackY;
function stack(data, index) {
if (!(n = data.length)) return data;
var series = data.map(function(d, i) {
return values.call(stack, d, i);
});
var points = series.map(function(d) {
return d.map(function(v, i) {
return [ x.call(stack, v, i), y.call(stack, v, i) ];
});
});
var orders = order.call(stack, points, index);
series = d3.permute(series, orders);
points = d3.permute(points, orders);
var offsets = offset.call(stack, points, index);
var m = series[0].length, n, i, j, o;
for (j = 0; j < m; ++j) {
out.call(stack, series[0][j], o = offsets[j], points[0][j][1]);
for (i = 1; i < n; ++i) {
out.call(stack, series[i][j], o += points[i - 1][j][1], points[i][j][1]);
}
}
return data;
}
stack.values = function(x) {
if (!arguments.length) return values;
values = x;
return stack;
};
stack.order = function(x) {
if (!arguments.length) return order;
order = typeof x === "function" ? x : d3_layout_stackOrders.get(x) || d3_layout_stackOrderDefault;
return stack;
};
stack.offset = function(x) {
if (!arguments.length) return offset;
offset = typeof x === "function" ? x : d3_layout_stackOffsets.get(x) || d3_layout_stackOffsetZero;
return stack;
};
stack.x = function(z) {
if (!arguments.length) return x;
x = z;
return stack;
};
stack.y = function(z) {
if (!arguments.length) return y;
y = z;
return stack;
};
stack.out = function(z) {
if (!arguments.length) return out;
out = z;
return stack;
};
return stack;
};
function d3_layout_stackX(d) {
return d.x;
}
function d3_layout_stackY(d) {
return d.y;
}
function d3_layout_stackOut(d, y0, y) {
d.y0 = y0;
d.y = y;
}
var d3_layout_stackOrders = d3.map({
"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) {
return max[a] - max[b];
}), top = 0, bottom = 0, tops = [], bottoms = [];
for (i = 0; i < n; ++i) {
j = index[i];
if (top < bottom) {
top += sums[j];
tops.push(j);
} else {
bottom += sums[j];
bottoms.push(j);
}
}
return bottoms.reverse().concat(tops);
},
reverse: function(data) {
return d3.range(data.length).reverse();
},
"default": d3_layout_stackOrderDefault
});
var d3_layout_stackOffsets = d3.map({
silhouette: function(data) {
var n = data.length, m = data[0].length, sums = [], max = 0, i, j, o, y0 = [];
for (j = 0; j < m; ++j) {
for (i = 0, o = 0; i < n; i++) o += data[i][j][1];
if (o > max) max = o;
sums.push(o);
}
for (j = 0; j < m; ++j) {
y0[j] = (max - sums[j]) / 2;
}
return y0;
},
wiggle: function(data) {
var n = data.length, x = data[0], m = x.length, i, j, k, s1, s2, s3, dx, o, o0, y0 = [];
y0[0] = o = o0 = 0;
for (j = 1; j < m; ++j) {
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 (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;
}
s2 += s3 * data[i][j][1];
}
y0[j] = o -= s1 ? s2 / s1 * dx : 0;
if (o < o0) o0 = o;
}
for (j = 0; j < m; ++j) y0[j] -= o0;
return y0;
},
expand: function(data) {
var n = data.length, m = data[0].length, k = 1 / n, i, j, o, y0 = [];
for (j = 0; j < m; ++j) {
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;
}
for (j = 0; j < m; ++j) y0[j] = 0;
return y0;
},
zero: d3_layout_stackOffsetZero
});
function d3_layout_stackOrderDefault(data) {
return d3.range(data.length);
}
function d3_layout_stackOffsetZero(data) {
var j = -1, m = data[0].length, y0 = [];
while (++j < m) y0[j] = 0;
return y0;
}
function d3_layout_stackMaxIndex(array) {
var i = 1, j = 0, v = array[0][1], k, n = array.length;
for (;i < n; ++i) {
if ((k = array[i][1]) > v) {
j = i;
v = k;
}
}
return j;
}
function d3_layout_stackReduceSum(d) {
return d.reduce(d3_layout_stackSum, 0);
}
function d3_layout_stackSum(p, d) {
return p + d[1];
}
d3.layout.histogram = function() {
var frequency = true, valuer = Number, ranger = d3_layout_histogramRange, binner = d3_layout_histogramBinSturges;
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;
while (++i < m) {
bin = bins[i] = [];
bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
bin.y = 0;
}
if (m > 0) {
i = -1;
while (++i < n) {
x = values[i];
if (x >= range[0] && x <= range[1]) {
bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
bin.y += k;
bin.push(data[i]);
}
}
}
return bins;
}
histogram.value = function(x) {
if (!arguments.length) return valuer;
valuer = x;
return histogram;
};
histogram.range = function(x) {
if (!arguments.length) return ranger;
ranger = d3_functor(x);
return histogram;
};
histogram.bins = function(x) {
if (!arguments.length) return binner;
binner = typeof x === "number" ? function(range) {
return d3_layout_histogramBinFixed(range, x);
} : d3_functor(x);
return histogram;
};
histogram.frequency = function(x) {
if (!arguments.length) return frequency;
frequency = !!x;
return histogram;
};
return histogram;
};
function d3_layout_histogramBinSturges(range, values) {
return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));
}
function d3_layout_histogramBinFixed(range, n) {
var x = -1, b = +range[0], m = (range[1] - b) / n, f = [];
while (++x <= n) f[x] = m * x + b;
return f;
}
function d3_layout_histogramRange(values) {
return [ d3.min(values), d3.max(values) ];
}
d3.layout.pack = function() {
var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort), padding = 0, size = [ 1, 1 ], radius;
function pack(d, i) {
var nodes = hierarchy.call(this, d, i), root = nodes[0], w = size[0], h = size[1], r = radius == null ? Math.sqrt : typeof radius === "function" ? radius : function() {
return radius;
};
root.x = root.y = 0;
d3_layout_hierarchyVisitAfter(root, function(d) {
d.r = +r(d.value);
});
d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
if (padding) {
var dr = padding * (radius ? 1 : Math.max(2 * root.r / w, 2 * root.r / h)) / 2;
d3_layout_hierarchyVisitAfter(root, function(d) {
d.r += dr;
});
d3_layout_hierarchyVisitAfter(root, d3_layout_packSiblings);
d3_layout_hierarchyVisitAfter(root, function(d) {
d.r -= dr;
});
}
d3_layout_packTransform(root, w / 2, h / 2, radius ? 1 : 1 / Math.max(2 * root.r / w, 2 * root.r / h));
return nodes;
}
pack.size = function(_) {
if (!arguments.length) return size;
size = _;
return pack;
};
pack.radius = function(_) {
if (!arguments.length) return radius;
radius = _ == null || typeof _ === "function" ? _ : +_;
return pack;
};
pack.padding = function(_) {
if (!arguments.length) return padding;
padding = +_;
return pack;
};
return d3_layout_hierarchyRebind(pack, hierarchy);
};
function d3_layout_packSort(a, b) {
return a.value - b.value;
}
function d3_layout_packInsert(a, b) {
var c = a._pack_next;
a._pack_next = b;
b._pack_prev = a;
b._pack_next = c;
c._pack_prev = b;
}
function d3_layout_packSplice(a, b) {
a._pack_next = b;
b._pack_prev = a;
}
function d3_layout_packIntersects(a, b) {
var dx = b.x - a.x, dy = b.y - a.y, dr = a.r + b.r;
return .999 * dr * dr > dx * dx + dy * dy;
}
function d3_layout_packSiblings(node) {
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;
function bound(node) {
xMin = Math.min(node.x - node.r, xMin);
xMax = Math.max(node.x + node.r, xMax);
yMin = Math.min(node.y - node.r, yMin);
yMax = Math.max(node.y + node.r, yMax);
}
nodes.forEach(d3_layout_packLink);
a = nodes[0];
a.x = -a.r;
a.y = 0;
bound(a);
if (n > 1) {
b = nodes[1];
b.x = b.r;
b.y = 0;
bound(b);
if (n > 2) {
c = nodes[2];
d3_layout_packPlace(a, b, c);
bound(c);
d3_layout_packInsert(a, c);
a._pack_prev = c;
d3_layout_packInsert(c, b);
b = a._pack_next;
for (i = 3; i < n; i++) {
d3_layout_packPlace(a, b, c = nodes[i]);
var isect = 0, s1 = 1, s2 = 1;
for (j = b._pack_next; j !== b; j = j._pack_next, s1++) {
if (d3_layout_packIntersects(j, c)) {
isect = 1;
break;
}
}
if (isect == 1) {
for (k = a._pack_prev; k !== j._pack_prev; k = k._pack_prev, s2++) {
if (d3_layout_packIntersects(k, c)) {
break;
}
}
}
if (isect) {
if (s1 < s2 || s1 == s2 && b.r < a.r) d3_layout_packSplice(a, b = j); else d3_layout_packSplice(a = k, b);
i--;
} else {
d3_layout_packInsert(a, c);
b = c;
bound(c);
}
}
}
}
var cx = (xMin + xMax) / 2, cy = (yMin + yMax) / 2, cr = 0;
for (i = 0; i < n; i++) {
c = nodes[i];
c.x -= cx;
c.y -= cy;
cr = Math.max(cr, c.r + Math.sqrt(c.x * c.x + c.y * c.y));
}
node.r = cr;
nodes.forEach(d3_layout_packUnlink);
}
function d3_layout_packLink(node) {
node._pack_next = node._pack_prev = node;
}
function d3_layout_packUnlink(node) {
delete node._pack_next;
delete node._pack_prev;
}
function d3_layout_packTransform(node, x, y, k) {
var children = node.children;
node.x = x += k * node.x;
node.y = y += k * node.y;
node.r *= k;
if (children) {
var i = -1, n = children.length;
while (++i < n) d3_layout_packTransform(children[i], x, y, k);
}
}
function d3_layout_packPlace(a, b, c) {
var db = a.r + c.r, dx = b.x - a.x, dy = b.y - a.y;
if (db && (dx || dy)) {
var da = b.r + c.r, dc = dx * dx + dy * dy;
da *= da;
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);
c.x = a.x + x * dx + y * dy;
c.y = a.y + x * dy - y * dx;
} else {
c.x = a.x + db;
c.y = a.y;
}
}
d3.layout.tree = function() {
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = null;
function tree(d, i) {
var nodes = hierarchy.call(this, d, i), root0 = nodes[0], root1 = wrapTree(root0);
d3_layout_hierarchyVisitAfter(root1, firstWalk), root1.parent.m = -root1.z;
d3_layout_hierarchyVisitBefore(root1, secondWalk);
if (nodeSize) d3_layout_hierarchyVisitBefore(root0, sizeNode); else {
var left = root0, right = root0, bottom = root0;
d3_layout_hierarchyVisitBefore(root0, function(node) {
if (node.x < left.x) left = node;
if (node.x > right.x) right = node;
if (node.depth > bottom.depth) bottom = node;
});
var tx = separation(left, right) / 2 - left.x, kx = size[0] / (right.x + separation(right, left) / 2 + tx), ky = size[1] / (bottom.depth || 1);
d3_layout_hierarchyVisitBefore(root0, function(node) {
node.x = (node.x + tx) * kx;
node.y = node.depth * ky;
});
}
return nodes;
}
function wrapTree(root0) {
var root1 = {
A: null,
children: [ root0 ]
}, queue = [ root1 ], node1;
while ((node1 = queue.pop()) != null) {
for (var children = node1.children, child, i = 0, n = children.length; i < n; ++i) {
queue.push((children[i] = child = {
_: children[i],
parent: node1,
children: (child = children[i].children) && child.slice() || [],
A: null,
a: null,
z: 0,
m: 0,
c: 0,
s: 0,
t: null,
i: i
}).a = child);
}
}
return root1.children[0];
}
function firstWalk(v) {
var children = v.children, siblings = v.parent.children, w = v.i ? siblings[v.i - 1] : null;
if (children.length) {
d3_layout_treeShift(v);
var midpoint = (children[0].z + children[children.length - 1].z) / 2;
if (w) {
v.z = w.z + separation(v._, w._);
v.m = v.z - midpoint;
} else {
v.z = midpoint;
}
} else if (w) {
v.z = w.z + separation(v._, w._);
}
v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
}
function secondWalk(v) {
v._.x = v.z + v.parent.m;
v.m += v.parent.m;
}
function apportion(v, w, ancestor) {
if (w) {
var vip = v, vop = v, vim = w, vom = vip.parent.children[0], sip = vip.m, sop = vop.m, sim = vim.m, som = vom.m, shift;
while (vim = d3_layout_treeRight(vim), vip = d3_layout_treeLeft(vip), vim && vip) {
vom = d3_layout_treeLeft(vom);
vop = d3_layout_treeRight(vop);
vop.a = v;
shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
if (shift > 0) {
d3_layout_treeMove(d3_layout_treeAncestor(vim, v, ancestor), v, shift);
sip += shift;
sop += shift;
}
sim += vim.m;
sip += vip.m;
som += vom.m;
sop += vop.m;
}
if (vim && !d3_layout_treeRight(vop)) {
vop.t = vim;
vop.m += sim - sop;
}
if (vip && !d3_layout_treeLeft(vom)) {
vom.t = vip;
vom.m += sip - som;
ancestor = v;
}
}
return ancestor;
}
function sizeNode(node) {
node.x *= size[0];
node.y = node.depth * size[1];
}
tree.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
return tree;
};
tree.size = function(x) {
if (!arguments.length) return nodeSize ? null : size;
nodeSize = (size = x) == null ? sizeNode : null;
return tree;
};
tree.nodeSize = function(x) {
if (!arguments.length) return nodeSize ? size : null;
nodeSize = (size = x) == null ? null : sizeNode;
return tree;
};
return d3_layout_hierarchyRebind(tree, hierarchy);
};
function d3_layout_treeSeparation(a, b) {
return a.parent == b.parent ? 1 : 2;
}
function d3_layout_treeLeft(v) {
var children = v.children;
return children.length ? children[0] : v.t;
}
function d3_layout_treeRight(v) {
var children = v.children, n;
return (n = children.length) ? children[n - 1] : v.t;
}
function d3_layout_treeMove(wm, wp, shift) {
var change = shift / (wp.i - wm.i);
wp.c -= change;
wp.s += shift;
wm.c += change;
wp.z += shift;
wp.m += shift;
}
function d3_layout_treeShift(v) {
var shift = 0, change = 0, children = v.children, i = children.length, w;
while (--i >= 0) {
w = children[i];
w.z += shift;
w.m += shift;
shift += w.s + (change += w.c);
}
}
function d3_layout_treeAncestor(vim, v, ancestor) {
return vim.a.parent === v.parent ? vim.a : ancestor;
}
d3.layout.cluster = function() {
var hierarchy = d3.layout.hierarchy().sort(null).value(null), separation = d3_layout_treeSeparation, size = [ 1, 1 ], nodeSize = false;
function cluster(d, i) {
var nodes = hierarchy.call(this, d, i), root = nodes[0], previousNode, x = 0;
d3_layout_hierarchyVisitAfter(root, function(node) {
var children = node.children;
if (children && children.length) {
node.x = d3_layout_clusterX(children);
node.y = d3_layout_clusterY(children);
} else {
node.x = previousNode ? x += separation(node, previousNode) : 0;
node.y = 0;
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;
d3_layout_hierarchyVisitAfter(root, nodeSize ? function(node) {
node.x = (node.x - root.x) * size[0];
node.y = (root.y - node.y) * size[1];
} : function(node) {
node.x = (node.x - x0) / (x1 - x0) * size[0];
node.y = (1 - (root.y ? node.y / root.y : 1)) * size[1];
});
return nodes;
}
cluster.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
return cluster;
};
cluster.size = function(x) {
if (!arguments.length) return nodeSize ? null : size;
nodeSize = (size = x) == null;
return cluster;
};
cluster.nodeSize = function(x) {
if (!arguments.length) return nodeSize ? size : null;
nodeSize = (size = x) != null;
return cluster;
};
return d3_layout_hierarchyRebind(cluster, hierarchy);
};
function d3_layout_clusterY(children) {
return 1 + d3.max(children, function(child) {
return child.y;
});
}
function d3_layout_clusterX(children) {
return children.reduce(function(x, child) {
return x + child.x;
}, 0) / children.length;
}
function d3_layout_clusterLeft(node) {
var children = node.children;
return children && children.length ? d3_layout_clusterLeft(children[0]) : node;
}
function d3_layout_clusterRight(node) {
var children = node.children, n;
return children && (n = children.length) ? d3_layout_clusterRight(children[n - 1]) : node;
}
d3.layout.treemap = function() {
var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5));
function scale(children, k) {
var i = -1, n = children.length, child, area;
while (++i < n) {
area = (child = children[i]).value * (k < 0 ? 0 : k);
child.area = isNaN(area) || area <= 0 ? 0 : area;
}
}
function squarify(node) {
var children = node.children;
if (children && children.length) {
var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n;
scale(remaining, rect.dx * rect.dy / node.value);
row.area = 0;
while ((n = remaining.length) > 0) {
row.push(child = remaining[n - 1]);
row.area += child.area;
if (mode !== "squarify" || (score = worst(row, u)) <= best) {
remaining.pop();
best = score;
} else {
row.area -= row.pop().area;
position(row, u, rect, false);
u = Math.min(rect.dx, rect.dy);
row.length = row.area = 0;
best = Infinity;
}
}
if (row.length) {
position(row, u, rect, true);
row.length = row.area = 0;
}
children.forEach(squarify);
}
}
function stickify(node) {
var children = node.children;
if (children && children.length) {
var rect = pad(node), remaining = children.slice(), child, row = [];
scale(remaining, rect.dx * rect.dy / node.value);
row.area = 0;
while (child = remaining.pop()) {
row.push(child);
row.area += child.area;
if (child.z != null) {
position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length);
row.length = row.area = 0;
}
}
children.forEach(stickify);
}
}
function worst(row, u) {
var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length;
while (++i < n) {
if (!(r = row[i].area)) continue;
if (r < rmin) rmin = r;
if (r > rmax) rmax = r;
}
s *= s;
u *= u;
return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity;
}
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;
if (u == rect.dx) {
if (flush || v > rect.dy) v = rect.dy;
while (++i < n) {
o = row[i];
o.x = x;
o.y = y;
o.dy = v;
x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0);
}
o.z = true;
o.dx += rect.x + rect.dx - x;
rect.y += v;
rect.dy -= v;
} else {
if (flush || v > rect.dx) v = rect.dx;
while (++i < n) {
o = row[i];
o.x = x;
o.y = y;
o.dx = v;
y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0);
}
o.z = false;
o.dy += rect.y + rect.dy - y;
rect.x += v;
rect.dx -= v;
}
}
function treemap(d) {
var nodes = stickies || hierarchy(d), root = nodes[0];
root.x = root.y = 0;
if (root.value) root.dx = size[0], root.dy = size[1]; else root.dx = root.dy = 0;
if (stickies) hierarchy.revalue(root);
scale([ root ], root.dx * root.dy / root.value);
(stickies ? stickify : squarify)(root);
if (sticky) stickies = nodes;
return nodes;
}
treemap.size = function(x) {
if (!arguments.length) return size;
size = x;
return treemap;
};
treemap.padding = function(x) {
if (!arguments.length) return padding;
function padFunction(node) {
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);
}
function padConstant(node) {
return d3_layout_treemapPad(node, x);
}
var type;
pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ],
padConstant) : padConstant;
return treemap;
};
treemap.round = function(x) {
if (!arguments.length) return round != Number;
round = x ? Math.round : Number;
return treemap;
};
treemap.sticky = function(x) {
if (!arguments.length) return sticky;
sticky = x;
stickies = null;
return treemap;
};
treemap.ratio = function(x) {
if (!arguments.length) return ratio;
ratio = x;
return treemap;
};
treemap.mode = function(x) {
if (!arguments.length) return mode;
mode = x + "";
return treemap;
};
return d3_layout_hierarchyRebind(treemap, hierarchy);
};
function d3_layout_treemapPadNull(node) {
return {
x: node.x,
y: node.y,
dx: node.dx,
dy: node.dy
};
}
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];
if (dx < 0) {
x += dx / 2;
dx = 0;
}
if (dy < 0) {
y += dy / 2;
dy = 0;
}
return {
x: x,
y: y,
dx: dx,
dy: dy
};
}
d3.random = {
normal: function(µ, σ) {
var n = arguments.length;
if (n < 2) σ = 1;
if (n < 1) µ = 0;
return function() {
var x, y, r;
do {
x = Math.random() * 2 - 1;
y = Math.random() * 2 - 1;
r = x * x + y * y;
} while (!r || r > 1);
return µ + σ * x * Math.sqrt(-2 * Math.log(r) / r);
};
},
logNormal: function() {
var random = d3.random.normal.apply(d3, arguments);
return function() {
return Math.exp(random());
};
},
bates: function(m) {
var random = d3.random.irwinHall(m);
return function() {
return random() / m;
};
},
irwinHall: function(m) {
return function() {
for (var s = 0, j = 0; j < m; j++) s += Math.random();
return s;
};
}
};
d3.scale = {};
function d3_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [ start, stop ] : [ stop, start ];
}
function d3_scaleRange(scale) {
return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
}
function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
var u = uninterpolate(domain[0], domain[1]), i = interpolate(range[0], range[1]);
return function(x) {
return i(u(x));
};
}
function d3_scale_nice(domain, nice) {
var i0 = 0, i1 = domain.length - 1, x0 = domain[i0], x1 = domain[i1], dx;
if (x1 < x0) {
dx = i0, i0 = i1, i1 = dx;
dx = x0, x0 = x1, x1 = dx;
}
domain[i0] = nice.floor(x0);
domain[i1] = nice.ceil(x1);
return domain;
}
function d3_scale_niceStep(step) {
return step ? {
floor: function(x) {
return Math.floor(x / step) * step;
},
ceil: function(x) {
return Math.ceil(x / step) * step;
}
} : d3_scale_niceIdentity;
}
var d3_scale_niceIdentity = {
floor: d3_identity,
ceil: d3_identity
};
function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
var u = [], i = [], j = 0, k = Math.min(domain.length, range.length) - 1;
if (domain[k] < domain[0]) {
domain = domain.slice().reverse();
range = range.slice().reverse();
}
while (++j <= k) {
u.push(uninterpolate(domain[j - 1], domain[j]));
i.push(interpolate(range[j - 1], range[j]));
}
return function(x) {
var j = d3.bisect(domain, x, 1, k) - 1;
return i[j](u[j](x));
};
}
d3.scale.linear = function() {
return d3_scale_linear([ 0, 1 ], [ 0, 1 ], d3_interpolate, false);
};
function d3_scale_linear(domain, range, interpolate, clamp) {
var output, input;
function rescale() {
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);
input = linear(range, domain, uninterpolate, d3_interpolate);
return scale;
}
function scale(x) {
return output(x);
}
scale.invert = function(y) {
return input(y);
};
scale.domain = function(x) {
if (!arguments.length) return domain;
domain = x.map(Number);
return rescale();
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
return rescale();
};
scale.rangeRound = function(x) {
return scale.range(x).interpolate(d3_interpolateRound);
};
scale.clamp = function(x) {
if (!arguments.length) return clamp;
clamp = x;
return rescale();
};
scale.interpolate = function(x) {
if (!arguments.length) return interpolate;
interpolate = x;
return rescale();
};
scale.ticks = function(m) {
return d3_scale_linearTicks(domain, m);
};
scale.tickFormat = function(m, format) {
return d3_scale_linearTickFormat(domain, m, format);
};
scale.nice = function(m) {
d3_scale_linearNice(domain, m);
return rescale();
};
scale.copy = function() {
return d3_scale_linear(domain, range, interpolate, clamp);
};
return rescale();
}
function d3_scale_linearRebind(scale, linear) {
return d3.rebind(scale, linear, "range", "rangeRound", "interpolate", "clamp");
}
function d3_scale_linearNice(domain, m) {
d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
d3_scale_nice(domain, d3_scale_niceStep(d3_scale_linearTickRange(domain, m)[2]));
return domain;
}
function d3_scale_linearTickRange(domain, m) {
if (m == null) m = 10;
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;
extent[0] = Math.ceil(extent[0] / step) * step;
extent[1] = Math.floor(extent[1] / step) * step + step * .5;
extent[2] = step;
return extent;
}
function d3_scale_linearTicks(domain, m) {
return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
}
function d3_scale_linearTickFormat(domain, m, format) {
var range = d3_scale_linearTickRange(domain, m);
if (format) {
var match = d3_format_re.exec(format);
match.shift();
if (match[8] === "s") {
var prefix = d3.formatPrefix(Math.max(abs(range[0]), abs(range[1])));
if (!match[7]) match[7] = "." + d3_scale_linearPrecision(prefix.scale(range[2]));
match[8] = "f";
format = d3.format(match.join(""));
return function(d) {
return format(prefix.scale(d)) + prefix.symbol;
};
}
if (!match[7]) match[7] = "." + d3_scale_linearFormatPrecision(match[8], range);
format = match.join("");
} else {
format = ",." + d3_scale_linearPrecision(range[2]) + "f";
}
return d3.format(format);
}
var d3_scale_linearFormatSignificant = {
s: 1,
g: 1,
p: 1,
r: 1,
e: 1
};
function d3_scale_linearPrecision(value) {
return -Math.floor(Math.log(value) / Math.LN10 + .01);
}
function d3_scale_linearFormatPrecision(type, range) {
var p = d3_scale_linearPrecision(range[2]);
return type in d3_scale_linearFormatSignificant ? Math.abs(p - d3_scale_linearPrecision(Math.max(abs(range[0]), abs(range[1])))) + +(type !== "e") : p - (type === "%") * 2;
}
d3.scale.log = function() {
return d3_scale_log(d3.scale.linear().domain([ 0, 1 ]), 10, true, [ 1, 10 ]);
};
function d3_scale_log(linear, base, positive, domain) {
function log(x) {
return (positive ? Math.log(x < 0 ? 0 : x) : -Math.log(x > 0 ? 0 : -x)) / Math.log(base);
}
function pow(x) {
return positive ? Math.pow(base, x) : -Math.pow(base, -x);
}
function scale(x) {
return linear(log(x));
}
scale.invert = function(x) {
return pow(linear.invert(x));
};
scale.domain = function(x) {
if (!arguments.length) return domain;
positive = x[0] >= 0;
linear.domain((domain = x.map(Number)).map(log));
return scale;
};
scale.base = function(_) {
if (!arguments.length) return base;
base = +_;
linear.domain(domain.map(log));
return scale;
};
scale.nice = function() {
var niced = d3_scale_nice(domain.map(log), positive ? Math : d3_scale_logNiceNegative);
linear.domain(niced);
domain = niced.map(pow);
return scale;
};
scale.ticks = function() {
var extent = d3_scaleExtent(domain), ticks = [], u = extent[0], v = extent[1], i = Math.floor(log(u)), j = Math.ceil(log(v)), n = base % 1 ? 2 : base;
if (isFinite(j - i)) {
if (positive) {
for (;i < j; i++) for (var k = 1; k < n; k++) ticks.push(pow(i) * k);
ticks.push(pow(i));
} else {
ticks.push(pow(i));
for (;i++ < j; ) for (var k = n - 1; k > 0; k--) ticks.push(pow(i) * k);
}
for (i = 0; ticks[i] < u; i++) {}
for (j = ticks.length; ticks[j - 1] > v; j--) {}
ticks = ticks.slice(i, j);
}
return ticks;
};
scale.tickFormat = function(n, format) {
if (!arguments.length) return d3_scale_logFormat;
if (arguments.length < 2) format = d3_scale_logFormat; else if (typeof format !== "function") format = d3.format(format);
var k = Math.max(1, base * n / scale.ticks().length);
return function(d) {
var i = d / pow(Math.round(log(d)));
if (i * base < base - .5) i *= base;
return i <= k ? format(d) : "";
};
};
scale.copy = function() {
return d3_scale_log(linear.copy(), base, positive, domain);
};
return d3_scale_linearRebind(scale, linear);
}
var d3_scale_logFormat = d3.format(".0e"), d3_scale_logNiceNegative = {
floor: function(x) {
return -Math.ceil(-x);
},
ceil: function(x) {
return -Math.floor(-x);
}
};
d3.scale.pow = function() {
return d3_scale_pow(d3.scale.linear(), 1, [ 0, 1 ]);
};
function d3_scale_pow(linear, exponent, domain) {
var powp = d3_scale_powPow(exponent), powb = d3_scale_powPow(1 / exponent);
function scale(x) {
return linear(powp(x));
}
scale.invert = function(x) {
return powb(linear.invert(x));
};
scale.domain = function(x) {
if (!arguments.length) return domain;
linear.domain((domain = x.map(Number)).map(powp));
return scale;
};
scale.ticks = function(m) {
return d3_scale_linearTicks(domain, m);
};
scale.tickFormat = function(m, format) {
return d3_scale_linearTickFormat(domain, m, format);
};
scale.nice = function(m) {
return scale.domain(d3_scale_linearNice(domain, m));
};
scale.exponent = function(x) {
if (!arguments.length) return exponent;
powp = d3_scale_powPow(exponent = x);
powb = d3_scale_powPow(1 / exponent);
linear.domain(domain.map(powp));
return scale;
};
scale.copy = function() {
return d3_scale_pow(linear.copy(), exponent, domain);
};
return d3_scale_linearRebind(scale, linear);
}
function d3_scale_powPow(e) {
return function(x) {
return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
};
}
d3.scale.sqrt = function() {
return d3.scale.pow().exponent(.5);
};
d3.scale.ordinal = function() {
return d3_scale_ordinal([], {
t: "range",
a: [ [] ]
});
};
function d3_scale_ordinal(domain, ranger) {
var index, range, rangeBand;
function scale(x) {
return range[((index.get(x) || (ranger.t === "range" ? index.set(x, domain.push(x)) : NaN)) - 1) % range.length];
}
function steps(start, step) {
return d3.range(domain.length).map(function(i) {
return start + step * i;
});
}
scale.domain = function(x) {
if (!arguments.length) return domain;
domain = [];
index = new d3_Map();
var i = -1, n = x.length, xi;
while (++i < n) if (!index.has(xi = x[i])) index.set(xi, domain.push(xi));
return scale[ranger.t].apply(scale, ranger.a);
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
rangeBand = 0;
ranger = {
t: "range",
a: arguments
};
return scale;
};
scale.rangePoints = function(x, padding) {
if (arguments.length < 2) padding = 0;
var start = x[0], stop = x[1], step = domain.length < 2 ? (start = (start + stop) / 2,
0) : (stop - start) / (domain.length - 1 + padding);
range = steps(start + step * padding / 2, step);
rangeBand = 0;
ranger = {
t: "rangePoints",
a: arguments
};
return scale;
};
scale.rangeRoundPoints = function(x, padding) {
if (arguments.length < 2) padding = 0;
var start = x[0], stop = x[1], step = domain.length < 2 ? (start = stop = Math.round((start + stop) / 2),
0) : (stop - start) / (domain.length - 1 + padding) | 0;
range = steps(start + Math.round(step * padding / 2 + (stop - start - (domain.length - 1 + padding) * step) / 2), step);
rangeBand = 0;
ranger = {
t: "rangeRoundPoints",
a: arguments
};
return scale;
};
scale.rangeBands = function(x, padding, outerPadding) {
if (arguments.length < 2) padding = 0;
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);
range = steps(start + step * outerPadding, step);
if (reverse) range.reverse();
rangeBand = step * (1 - padding);
ranger = {
t: "rangeBands",
a: arguments
};
return scale;
};
scale.rangeRoundBands = function(x, padding, outerPadding) {
if (arguments.length < 2) padding = 0;
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));
range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
if (reverse) range.reverse();
rangeBand = Math.round(step * (1 - padding));
ranger = {
t: "rangeRoundBands",
a: arguments
};
return scale;
};
scale.rangeBand = function() {
return rangeBand;
};
scale.rangeExtent = function() {
return d3_scaleExtent(ranger.a[0]);
};
scale.copy = function() {
return d3_scale_ordinal(domain, ranger);
};
return scale.domain(domain);
}
d3.scale.category10 = function() {
return d3.scale.ordinal().range(d3_category10);
};
d3.scale.category20 = function() {
return d3.scale.ordinal().range(d3_category20);
};
d3.scale.category20b = function() {
return d3.scale.ordinal().range(d3_category20b);
};
d3.scale.category20c = function() {
return d3.scale.ordinal().range(d3_category20c);
};
var d3_category10 = [ 2062260, 16744206, 2924588, 14034728, 9725885, 9197131, 14907330, 8355711, 12369186, 1556175 ].map(d3_rgbString);
var d3_category20 = [ 2062260, 11454440, 16744206, 16759672, 2924588, 10018698, 14034728, 16750742, 9725885, 12955861, 9197131, 12885140, 14907330, 16234194, 8355711, 13092807, 12369186, 14408589, 1556175, 10410725 ].map(d3_rgbString);
var d3_category20b = [ 3750777, 5395619, 7040719, 10264286, 6519097, 9216594, 11915115, 13556636, 9202993, 12426809, 15186514, 15190932, 8666169, 11356490, 14049643, 15177372, 8077683, 10834324, 13528509, 14589654 ].map(d3_rgbString);
var d3_category20c = [ 3244733, 7057110, 10406625, 13032431, 15095053, 16616764, 16625259, 16634018, 3253076, 7652470, 10607003, 13101504, 7695281, 10394312, 12369372, 14342891, 6513507, 9868950, 12434877, 14277081 ].map(d3_rgbString);
d3.scale.quantile = function() {
return d3_scale_quantile([], []);
};
function d3_scale_quantile(domain, range) {
var thresholds;
function rescale() {
var k = 0, q = range.length;
thresholds = [];
while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
return scale;
}
function scale(x) {
if (!isNaN(x = +x)) return range[d3.bisect(thresholds, x)];
}
scale.domain = function(x) {
if (!arguments.length) return domain;
domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending);
return rescale();
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
return rescale();
};
scale.quantiles = function() {
return thresholds;
};
scale.invertExtent = function(y) {
y = range.indexOf(y);
return y < 0 ? [ NaN, NaN ] : [ y > 0 ? thresholds[y - 1] : domain[0], y < thresholds.length ? thresholds[y] : domain[domain.length - 1] ];
};
scale.copy = function() {
return d3_scale_quantile(domain, range);
};
return rescale();
}
d3.scale.quantize = function() {
return d3_scale_quantize(0, 1, [ 0, 1 ]);
};
function d3_scale_quantize(x0, x1, range) {
var kx, i;
function scale(x) {
return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
}
function rescale() {
kx = range.length / (x1 - x0);
i = range.length - 1;
return scale;
}
scale.domain = function(x) {
if (!arguments.length) return [ x0, x1 ];
x0 = +x[0];
x1 = +x[x.length - 1];
return rescale();
};
scale.range = function(x) {
if (!arguments.length) return range;
range = x;
return rescale();
};
scale.invertExtent = function(y) {
y = range.indexOf(y);
y = y < 0 ? NaN : y / kx + x0;
return [ y, y + 1 / kx ];
};
scale.copy = function() {
return d3_scale_quantize(x0, x1, range);
};
return rescale();
}
d3.scale.threshold = function() {
return d3_scale_threshold([ .5 ], [ 0, 1 ]);
};
function d3_scale_threshold(domain, range) {
function scale(x) {
if (x <= x) return range[d3.bisect(domain, x)];
}
scale.domain = function(_) {
if (!arguments.length) return domain;
domain = _;
return scale;
};
scale.range = function(_) {
if (!arguments.length) return range;
range = _;
return scale;
};
scale.invertExtent = function(y) {
y = range.indexOf(y);
return [ domain[y - 1], domain[y] ];
};
scale.copy = function() {
return d3_scale_threshold(domain, range);
};
return scale;
}
d3.scale.identity = function() {
return d3_scale_identity([ 0, 1 ]);
};
function d3_scale_identity(domain) {
function identity(x) {
return +x;
}
identity.invert = identity;
identity.domain = identity.range = function(x) {
if (!arguments.length) return domain;
domain = x.map(identity);
return identity;
};
identity.ticks = function(m) {
return d3_scale_linearTicks(domain, m);
};
identity.tickFormat = function(m, format) {
return d3_scale_linearTickFormat(domain, m, format);
};
identity.copy = function() {
return d3_scale_identity(domain);
};
return identity;
}
d3.svg = {};
function d3_zero() {
return 0;
}
d3.svg.arc = function() {
var innerRadius = d3_svg_arcInnerRadius, outerRadius = d3_svg_arcOuterRadius, cornerRadius = d3_zero, padRadius = d3_svg_arcAuto, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle, padAngle = d3_svg_arcPadAngle;
function arc() {
var r0 = Math.max(0, +innerRadius.apply(this, arguments)), r1 = Math.max(0, +outerRadius.apply(this, arguments)), a0 = startAngle.apply(this, arguments) - halfπ, a1 = endAngle.apply(this, arguments) - halfπ, da = Math.abs(a1 - a0), cw = a0 > a1 ? 0 : 1;
if (r1 < r0) rc = r1, r1 = r0, r0 = rc;
if (da >= τε) return circleSegment(r1, cw) + (r0 ? circleSegment(r0, 1 - cw) : "") + "Z";
var rc, cr, rp, ap, p0 = 0, p1 = 0, x0, y0, x1, y1, x2, y2, x3, y3, path = [];
if (ap = (+padAngle.apply(this, arguments) || 0) / 2) {
rp = padRadius === d3_svg_arcAuto ? Math.sqrt(r0 * r0 + r1 * r1) : +padRadius.apply(this, arguments);
if (!cw) p1 *= -1;
if (r1) p1 = d3_asin(rp / r1 * Math.sin(ap));
if (r0) p0 = d3_asin(rp / r0 * Math.sin(ap));
}
if (r1) {
x0 = r1 * Math.cos(a0 + p1);
y0 = r1 * Math.sin(a0 + p1);
x1 = r1 * Math.cos(a1 - p1);
y1 = r1 * Math.sin(a1 - p1);
var l1 = Math.abs(a1 - a0 - 2 * p1) <= π ? 0 : 1;
if (p1 && d3_svg_arcSweep(x0, y0, x1, y1) === cw ^ l1) {
var h1 = (a0 + a1) / 2;
x0 = r1 * Math.cos(h1);
y0 = r1 * Math.sin(h1);
x1 = y1 = null;
}
} else {
x0 = y0 = 0;
}
if (r0) {
x2 = r0 * Math.cos(a1 - p0);
y2 = r0 * Math.sin(a1 - p0);
x3 = r0 * Math.cos(a0 + p0);
y3 = r0 * Math.sin(a0 + p0);
var l0 = Math.abs(a0 - a1 + 2 * p0) <= π ? 0 : 1;
if (p0 && d3_svg_arcSweep(x2, y2, x3, y3) === 1 - cw ^ l0) {
var h0 = (a0 + a1) / 2;
x2 = r0 * Math.cos(h0);
y2 = r0 * Math.sin(h0);
x3 = y3 = null;
}
} else {
x2 = y2 = 0;
}
if (da > ε && (rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments))) > .001) {
cr = r0 < r1 ^ cw ? 0 : 1;
var rc1 = rc, rc0 = rc;
if (da < π) {
var oc = x3 == null ? [ x2, y2 ] : x1 == null ? [ x0, y0 ] : d3_geom_polygonIntersect([ x0, y0 ], [ x3, y3 ], [ x1, y1 ], [ x2, y2 ]), ax = x0 - oc[0], ay = y0 - oc[1], bx = x1 - oc[0], by = y1 - oc[1], kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2), lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = Math.min(rc, (r0 - lc) / (kc - 1));
rc1 = Math.min(rc, (r1 - lc) / (kc + 1));
}
if (x1 != null) {
var t30 = d3_svg_arcCornerTangents(x3 == null ? [ x2, y2 ] : [ x3, y3 ], [ x0, y0 ], r1, rc1, cw), t12 = d3_svg_arcCornerTangents([ x1, y1 ], [ x2, y2 ], r1, rc1, cw);
if (rc === rc1) {
path.push("M", t30[0], "A", rc1, ",", rc1, " 0 0,", cr, " ", t30[1], "A", r1, ",", r1, " 0 ", 1 - cw ^ d3_svg_arcSweep(t30[1][0], t30[1][1], t12[1][0], t12[1][1]), ",", cw, " ", t12[1], "A", rc1, ",", rc1, " 0 0,", cr, " ", t12[0]);
} else {
path.push("M", t30[0], "A", rc1, ",", rc1, " 0 1,", cr, " ", t12[0]);
}
} else {
path.push("M", x0, ",", y0);
}
if (x3 != null) {
var t03 = d3_svg_arcCornerTangents([ x0, y0 ], [ x3, y3 ], r0, -rc0, cw), t21 = d3_svg_arcCornerTangents([ x2, y2 ], x1 == null ? [ x0, y0 ] : [ x1, y1 ], r0, -rc0, cw);
if (rc === rc0) {
path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t21[1], "A", r0, ",", r0, " 0 ", cw ^ d3_svg_arcSweep(t21[1][0], t21[1][1], t03[1][0], t03[1][1]), ",", 1 - cw, " ", t03[1], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
} else {
path.push("L", t21[0], "A", rc0, ",", rc0, " 0 0,", cr, " ", t03[0]);
}
} else {
path.push("L", x2, ",", y2);
}
} else {
path.push("M", x0, ",", y0);
if (x1 != null) path.push("A", r1, ",", r1, " 0 ", l1, ",", cw, " ", x1, ",", y1);
path.push("L", x2, ",", y2);
if (x3 != null) path.push("A", r0, ",", r0, " 0 ", l0, ",", 1 - cw, " ", x3, ",", y3);
}
path.push("Z");
return path.join("");
}
function circleSegment(r1, cw) {
return "M0," + r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + -r1 + "A" + r1 + "," + r1 + " 0 1," + cw + " 0," + r1;
}
arc.innerRadius = function(v) {
if (!arguments.length) return innerRadius;
innerRadius = d3_functor(v);
return arc;
};
arc.outerRadius = function(v) {
if (!arguments.length) return outerRadius;
outerRadius = d3_functor(v);
return arc;
};
arc.cornerRadius = function(v) {
if (!arguments.length) return cornerRadius;
cornerRadius = d3_functor(v);
return arc;
};
arc.padRadius = function(v) {
if (!arguments.length) return padRadius;
padRadius = v == d3_svg_arcAuto ? d3_svg_arcAuto : d3_functor(v);
return arc;
};
arc.startAngle = function(v) {
if (!arguments.length) return startAngle;
startAngle = d3_functor(v);
return arc;
};
arc.endAngle = function(v) {
if (!arguments.length) return endAngle;
endAngle = d3_functor(v);
return arc;
};
arc.padAngle = function(v) {
if (!arguments.length) return padAngle;
padAngle = d3_functor(v);
return arc;
};
arc.centroid = function() {
var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - halfπ;
return [ Math.cos(a) * r, Math.sin(a) * r ];
};
return arc;
};
var d3_svg_arcAuto = "auto";
function d3_svg_arcInnerRadius(d) {
return d.innerRadius;
}
function d3_svg_arcOuterRadius(d) {
return d.outerRadius;
}
function d3_svg_arcStartAngle(d) {
return d.startAngle;
}
function d3_svg_arcEndAngle(d) {
return d.endAngle;
}
function d3_svg_arcPadAngle(d) {
return d && d.padAngle;
}
function d3_svg_arcSweep(x0, y0, x1, y1) {
return (x0 - x1) * y0 - (y0 - y1) * x0 > 0 ? 0 : 1;
}
function d3_svg_arcCornerTangents(p0, p1, r1, rc, cw) {
var x01 = p0[0] - p1[0], y01 = p0[1] - p1[1], lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x1 = p0[0] + ox, y1 = p0[1] + oy, x2 = p1[0] + ox, y2 = p1[1] + oy, x3 = (x1 + x2) / 2, y3 = (y1 + y2) / 2, dx = x2 - x1, dy = y2 - y1, d2 = dx * dx + dy * dy, r = r1 - rc, D = x1 * y2 - x2 * y1, d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x3, dy0 = cy0 - y3, dx1 = cx1 - x3, dy1 = cy1 - y3;
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
return [ [ cx0 - ox, cy0 - oy ], [ cx0 * r1 / r, cy0 * r1 / r ] ];
}
function d3_svg_line(projection) {
var x = d3_geom_pointX, y = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, tension = .7;
function line(data) {
var segments = [], points = [], i = -1, n = data.length, d, fx = d3_functor(x), fy = d3_functor(y);
function segment() {
segments.push("M", interpolate(projection(points), tension));
}
while (++i < n) {
if (defined.call(this, d = data[i], i)) {
points.push([ +fx.call(this, d, i), +fy.call(this, d, i) ]);
} else if (points.length) {
segment();
points = [];
}
}
if (points.length) segment();
return segments.length ? segments.join("") : null;
}
line.x = function(_) {
if (!arguments.length) return x;
x = _;
return line;
};
line.y = function(_) {
if (!arguments.length) return y;
y = _;
return line;
};
line.defined = function(_) {
if (!arguments.length) return defined;
defined = _;
return line;
};
line.interpolate = function(_) {
if (!arguments.length) return interpolateKey;
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
return line;
};
line.tension = function(_) {
if (!arguments.length) return tension;
tension = _;
return line;
};
return line;
}
d3.svg.line = function() {
return d3_svg_line(d3_identity);
};
var d3_svg_lineInterpolators = d3.map({
linear: d3_svg_lineLinear,
"linear-closed": d3_svg_lineLinearClosed,
step: d3_svg_lineStep,
"step-before": d3_svg_lineStepBefore,
"step-after": d3_svg_lineStepAfter,
basis: d3_svg_lineBasis,
"basis-open": d3_svg_lineBasisOpen,
"basis-closed": d3_svg_lineBasisClosed,
bundle: d3_svg_lineBundle,
cardinal: d3_svg_lineCardinal,
"cardinal-open": d3_svg_lineCardinalOpen,
"cardinal-closed": d3_svg_lineCardinalClosed,
monotone: d3_svg_lineMonotone
});
d3_svg_lineInterpolators.forEach(function(key, value) {
value.key = key;
value.closed = /-closed$/.test(key);
});
function d3_svg_lineLinear(points) {
return points.length > 1 ? points.join("L") : points + "Z";
}
function d3_svg_lineLinearClosed(points) {
return points.join("L") + "Z";
}
function d3_svg_lineStep(points) {
var i = 0, n = points.length, p = points[0], path = [ p[0], ",", p[1] ];
while (++i < n) path.push("H", (p[0] + (p = points[i])[0]) / 2, "V", p[1]);
if (n > 1) path.push("H", p[0]);
return path.join("");
}
function d3_svg_lineStepBefore(points) {
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]);
return path.join("");
}
function d3_svg_lineStepAfter(points) {
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]);
return path.join("");
}
function d3_svg_lineCardinalOpen(points, tension) {
return points.length < 4 ? d3_svg_lineLinear(points) : points[1] + d3_svg_lineHermite(points.slice(1, -1), d3_svg_lineCardinalTangents(points, tension));
}
function d3_svg_lineCardinalClosed(points, tension) {
return points.length < 3 ? d3_svg_lineLinearClosed(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) {
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) {
if (tangents.length < 1 || points.length != tangents.length && points.length != tangents.length + 2) {
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;
if (quad) {
path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3) + "," + p[0] + "," + p[1];
p0 = points[1];
pi = 2;
}
if (tangents.length > 1) {
t = tangents[1];
p = points[pi];
pi++;
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++) {
p = points[pi];
t = tangents[i];
path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1]) + "," + p[0] + "," + p[1];
}
}
if (quad) {
var lp = points[pi];
path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3) + "," + lp[0] + "," + lp[1];
}
return path;
}
function d3_svg_lineCardinalTangents(points, tension) {
var tangents = [], a = (1 - tension) / 2, p0, p1 = points[0], p2 = points[1], i = 1, n = points.length;
while (++i < n) {
p0 = p1;
p1 = p2;
p2 = points[i];
tangents.push([ a * (p2[0] - p0[0]), a * (p2[1] - p0[1]) ]);
}
return tangents;
}
function d3_svg_lineBasis(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, "L", d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
points.push(points[n - 1]);
while (++i <= n) {
pi = points[i];
px.shift();
px.push(pi[0]);
py.shift();
py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py);
}
points.pop();
path.push("L", pi);
return path.join("");
}
function d3_svg_lineBasisOpen(points) {
if (points.length < 4) return d3_svg_lineLinear(points);
var path = [], i = -1, n = points.length, pi, px = [ 0 ], py = [ 0 ];
while (++i < 3) {
pi = points[i];
px.push(pi[0]);
py.push(pi[1]);
}
path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px) + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
--i;
while (++i < n) {
pi = points[i];
px.shift();
px.push(pi[0]);
py.shift();
py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py);
}
return path.join("");
}
function d3_svg_lineBasisClosed(points) {
var path, i = -1, n = points.length, m = n + 4, pi, px = [], py = [];
while (++i < 4) {
pi = points[i % n];
px.push(pi[0]);
py.push(pi[1]);
}
path = [ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, py) ];
--i;
while (++i < m) {
pi = points[i % n];
px.shift();
px.push(pi[0]);
py.shift();
py.push(pi[1]);
d3_svg_lineBasisBezier(path, px, py);
}
return path.join("");
}
function d3_svg_lineBundle(points, tension) {
var n = points.length - 1;
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;
while (++i <= n) {
p = points[i];
t = i / n;
p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
}
}
return d3_svg_lineBasis(points);
}
function d3_svg_lineDot4(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
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 ];
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));
}
function d3_svg_lineSlope(p0, p1) {
return (p1[1] - p0[1]) / (p1[0] - p0[0]);
}
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);
while (++i < j) {
m[i] = (d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]))) / 2;
}
m[i] = d;
return m;
}
function d3_svg_lineMonotoneTangents(points) {
var tangents = [], d, a, b, s, m = d3_svg_lineFiniteDifferences(points), i = -1, j = points.length - 1;
while (++i < j) {
d = d3_svg_lineSlope(points[i], points[i + 1]);
if (abs(d) < ε) {
m[i] = m[i + 1] = 0;
} else {
a = m[i] / d;
b = m[i + 1] / d;
s = a * a + b * b;
if (s > 9) {
s = d * 3 / Math.sqrt(s);
m[i] = s * a;
m[i + 1] = s * b;
}
}
}
i = -1;
while (++i <= j) {
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 ]);
}
return tangents;
}
function d3_svg_lineMonotone(points) {
return points.length < 3 ? d3_svg_lineLinear(points) : points[0] + d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
}
d3.svg.line.radial = function() {
var line = d3_svg_line(d3_svg_lineRadial);
line.radius = line.x, delete line.x;
line.angle = line.y, delete line.y;
return line;
};
function d3_svg_lineRadial(points) {
var point, i = -1, n = points.length, r, a;
while (++i < n) {
point = points[i];
r = point[0];
a = point[1] - halfπ;
point[0] = r * Math.cos(a);
point[1] = r * Math.sin(a);
}
return points;
}
function d3_svg_area(projection) {
var x0 = d3_geom_pointX, x1 = d3_geom_pointX, y0 = 0, y1 = d3_geom_pointY, defined = d3_true, interpolate = d3_svg_lineLinear, interpolateKey = interpolate.key, interpolateReverse = interpolate, L = "L", tension = .7;
function area(data) {
var segments = [], points0 = [], points1 = [], i = -1, n = data.length, d, fx0 = d3_functor(x0), fy0 = d3_functor(y0), fx1 = x0 === x1 ? function() {
return x;
} : d3_functor(x1), fy1 = y0 === y1 ? function() {
return y;
} : d3_functor(y1), x, y;
function segment() {
segments.push("M", interpolate(projection(points1), tension), L, interpolateReverse(projection(points0.reverse()), tension), "Z");
}
while (++i < n) {
if (defined.call(this, d = data[i], 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) ]);
} else if (points0.length) {
segment();
points0 = [];
points1 = [];
}
}
if (points0.length) segment();
return segments.length ? segments.join("") : null;
}
area.x = function(_) {
if (!arguments.length) return x1;
x0 = x1 = _;
return area;
};
area.x0 = function(_) {
if (!arguments.length) return x0;
x0 = _;
return area;
};
area.x1 = function(_) {
if (!arguments.length) return x1;
x1 = _;
return area;
};
area.y = function(_) {
if (!arguments.length) return y1;
y0 = y1 = _;
return area;
};
area.y0 = function(_) {
if (!arguments.length) return y0;
y0 = _;
return area;
};
area.y1 = function(_) {
if (!arguments.length) return y1;
y1 = _;
return area;
};
area.defined = function(_) {
if (!arguments.length) return defined;
defined = _;
return area;
};
area.interpolate = function(_) {
if (!arguments.length) return interpolateKey;
if (typeof _ === "function") interpolateKey = interpolate = _; else interpolateKey = (interpolate = d3_svg_lineInterpolators.get(_) || d3_svg_lineLinear).key;
interpolateReverse = interpolate.reverse || interpolate;
L = interpolate.closed ? "M" : "L";
return area;
};
area.tension = function(_) {
if (!arguments.length) return tension;
tension = _;
return area;
};
return area;
}
d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
d3.svg.area = function() {
return d3_svg_area(d3_identity);
};
d3.svg.area.radial = function() {
var area = d3_svg_area(d3_svg_lineRadial);
area.radius = area.x, delete area.x;
area.innerRadius = area.x0, delete area.x0;
area.outerRadius = area.x1, delete area.x1;
area.angle = area.y, delete area.y;
area.startAngle = area.y0, delete area.y0;
area.endAngle = area.y1, delete area.y1;
return area;
};
d3.svg.chord = function() {
var source = d3_source, target = d3_target, radius = d3_svg_chordRadius, startAngle = d3_svg_arcStartAngle, endAngle = d3_svg_arcEndAngle;
function chord(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";
}
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) - halfπ, a1 = endAngle.call(self, subgroup, i) - halfπ;
return {
r: r,
a0: a0,
a1: a1,
p0: [ r * Math.cos(a0), r * Math.sin(a0) ],
p1: [ r * Math.cos(a1), r * Math.sin(a1) ]
};
}
function equals(a, b) {
return a.a0 == b.a0 && a.a1 == b.a1;
}
function arc(r, p, a) {
return "A" + r + "," + r + " 0 " + +(a > π) + ",1 " + p;
}
function curve(r0, p0, r1, p1) {
return "Q 0,0 " + p1;
}
chord.radius = function(v) {
if (!arguments.length) return radius;
radius = d3_functor(v);
return chord;
};
chord.source = function(v) {
if (!arguments.length) return source;
source = d3_functor(v);
return chord;
};
chord.target = function(v) {
if (!arguments.length) return target;
target = d3_functor(v);
return chord;
};
chord.startAngle = function(v) {
if (!arguments.length) return startAngle;
startAngle = d3_functor(v);
return chord;
};
chord.endAngle = function(v) {
if (!arguments.length) return endAngle;
endAngle = d3_functor(v);
return chord;
};
return chord;
};
function d3_svg_chordRadius(d) {
return d.radius;
}
d3.svg.diagonal = function() {
var source = d3_source, target = d3_target, projection = d3_svg_diagonalProjection;
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, {
x: p0.x,
y: m
}, {
x: p3.x,
y: m
}, p3 ];
p = p.map(projection);
return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
}
diagonal.source = function(x) {
if (!arguments.length) return source;
source = d3_functor(x);
return diagonal;
};
diagonal.target = function(x) {
if (!arguments.length) return target;
target = d3_functor(x);
return diagonal;
};
diagonal.projection = function(x) {
if (!arguments.length) return projection;
projection = x;
return diagonal;
};
return diagonal;
};
function d3_svg_diagonalProjection(d) {
return [ d.x, d.y ];
}
d3.svg.diagonal.radial = function() {
var diagonal = d3.svg.diagonal(), projection = d3_svg_diagonalProjection, projection_ = diagonal.projection;
diagonal.projection = function(x) {
return arguments.length ? projection_(d3_svg_diagonalRadialProjection(projection = x)) : projection;
};
return diagonal;
};
function d3_svg_diagonalRadialProjection(projection) {
return function() {
var d = projection.apply(this, arguments), r = d[0], a = d[1] - halfπ;
return [ r * Math.cos(a), r * Math.sin(a) ];
};
}
d3.svg.symbol = function() {
var type = d3_svg_symbolType, size = d3_svg_symbolSize;
function symbol(d, i) {
return (d3_svg_symbols.get(type.call(this, d, i)) || d3_svg_symbolCircle)(size.call(this, d, i));
}
symbol.type = function(x) {
if (!arguments.length) return type;
type = d3_functor(x);
return symbol;
};
symbol.size = function(x) {
if (!arguments.length) return size;
size = d3_functor(x);
return symbol;
};
return symbol;
};
function d3_svg_symbolSize() {
return 64;
}
function d3_svg_symbolType() {
return "circle";
}
function d3_svg_symbolCircle(size) {
var r = Math.sqrt(size / π);
return "M0," + r + "A" + r + "," + r + " 0 1,1 0," + -r + "A" + r + "," + r + " 0 1,1 0," + r + "Z";
}
var d3_svg_symbols = d3.map({
circle: d3_svg_symbolCircle,
cross: function(size) {
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";
},
diamond: function(size) {
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";
},
square: function(size) {
var r = Math.sqrt(size) / 2;
return "M" + -r + "," + -r + "L" + r + "," + -r + " " + r + "," + r + " " + -r + "," + r + "Z";
},
"triangle-down": function(size) {
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
return "M0," + ry + "L" + rx + "," + -ry + " " + -rx + "," + -ry + "Z";
},
"triangle-up": function(size) {
var rx = Math.sqrt(size / d3_svg_symbolSqrt3), ry = rx * d3_svg_symbolSqrt3 / 2;
return "M0," + -ry + "L" + rx + "," + ry + " " + -rx + "," + ry + "Z";
}
});
d3.svg.symbolTypes = d3_svg_symbols.keys();
var d3_svg_symbolSqrt3 = Math.sqrt(3), d3_svg_symbolTan30 = Math.tan(30 * d3_radians);
d3_selectionPrototype.transition = function(name) {
var id = d3_transitionInheritId || ++d3_transitionId, ns = d3_transitionNamespace(name), subgroups = [], subgroup, node, transition = d3_transitionInherit || {
time: Date.now(),
ease: d3_ease_cubicInOut,
delay: 0,
duration: 250
};
for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) d3_transitionNode(node, i, ns, id, transition);
subgroup.push(node);
}
}
return d3_transition(subgroups, ns, id);
};
d3_selectionPrototype.interrupt = function(name) {
return this.each(name == null ? d3_selection_interrupt : d3_selection_interruptNS(d3_transitionNamespace(name)));
};
var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());
function d3_selection_interruptNS(ns) {
return function() {
var lock, activeId, active;
if ((lock = this[ns]) && (active = lock[activeId = lock.active])) {
active.timer.c = null;
active.timer.t = NaN;
if (--lock.count) delete lock[activeId]; else delete this[ns];
lock.active += .5;
active.event && active.event.interrupt.call(this, this.__data__, active.index);
}
};
}
function d3_transition(groups, ns, id) {
d3_subclass(groups, d3_transitionPrototype);
groups.namespace = ns;
groups.id = id;
return groups;
}
var d3_transitionPrototype = [], d3_transitionId = 0, d3_transitionInheritId, d3_transitionInherit;
d3_transitionPrototype.call = d3_selectionPrototype.call;
d3_transitionPrototype.empty = d3_selectionPrototype.empty;
d3_transitionPrototype.node = d3_selectionPrototype.node;
d3_transitionPrototype.size = d3_selectionPrototype.size;
d3.transition = function(selection, name) {
return selection && selection.transition ? d3_transitionInheritId ? selection.transition(name) : selection : d3.selection().transition(selection);
};
d3.transition.prototype = d3_transitionPrototype;
d3_transitionPrototype.select = function(selector) {
var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnode, node;
selector = d3_selection_selector(selector);
for (var j = -1, m = this.length; ++j < m; ) {
subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
d3_transitionNode(subnode, i, ns, id, node[ns][id]);
subgroup.push(subnode);
} else {
subgroup.push(null);
}
}
}
return d3_transition(subgroups, ns, id);
};
d3_transitionPrototype.selectAll = function(selector) {
var id = this.id, ns = this.namespace, subgroups = [], subgroup, subnodes, node, subnode, transition;
selector = d3_selection_selectorAll(selector);
for (var j = -1, m = this.length; ++j < m; ) {
for (var group = this[j], i = -1, n = group.length; ++i < n; ) {
if (node = group[i]) {
transition = node[ns][id];
subnodes = selector.call(node, node.__data__, i, j);
subgroups.push(subgroup = []);
for (var k = -1, o = subnodes.length; ++k < o; ) {
if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
subgroup.push(subnode);
}
}
}
}
return d3_transition(subgroups, ns, id);
};
d3_transitionPrototype.filter = function(filter) {
var subgroups = [], subgroup, group, node;
if (typeof filter !== "function") filter = d3_selection_filter(filter);
for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []);
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
subgroup.push(node);
}
}
}
return d3_transition(subgroups, this.namespace, this.id);
};
d3_transitionPrototype.tween = function(name, tween) {
var id = this.id, ns = this.namespace;
if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
return d3_selection_each(this, tween == null ? function(node) {
node[ns][id].tween.remove(name);
} : function(node) {
node[ns][id].tween.set(name, tween);
});
};
function d3_transition_tween(groups, name, value, tween) {
var id = groups.id, ns = groups.namespace;
return d3_selection_each(groups, typeof value === "function" ? function(node, i, j) {
node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j)));
} : (value = tween(value), function(node) {
node[ns][id].tween.set(name, value);
}));
}
d3_transitionPrototype.attr = function(nameNS, value) {
if (arguments.length < 2) {
for (value in nameNS) this.attr(value, nameNS[value]);
return this;
}
var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, name = d3.ns.qualify(nameNS);
function attrNull() {
this.removeAttribute(name);
}
function attrNullNS() {
this.removeAttributeNS(name.space, name.local);
}
function attrTween(b) {
return b == null ? attrNull : (b += "", function() {
var a = this.getAttribute(name), i;
return a !== b && (i = interpolate(a, b), function(t) {
this.setAttribute(name, i(t));
});
});
}
function attrTweenNS(b) {
return b == null ? attrNullNS : (b += "", function() {
var a = this.getAttributeNS(name.space, name.local), i;
return a !== b && (i = interpolate(a, b), function(t) {
this.setAttributeNS(name.space, name.local, i(t));
});
});
}
return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
};
d3_transitionPrototype.attrTween = function(nameNS, tween) {
var name = d3.ns.qualify(nameNS);
function attrTween(d, i) {
var f = tween.call(this, d, i, this.getAttribute(name));
return f && function(t) {
this.setAttribute(name, f(t));
};
}
function attrTweenNS(d, i) {
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
return f && function(t) {
this.setAttributeNS(name.space, name.local, f(t));
};
}
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
};
d3_transitionPrototype.style = function(name, value, priority) {
var n = arguments.length;
if (n < 3) {
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.style(priority, name[priority], value);
return this;
}
priority = "";
}
function styleNull() {
this.style.removeProperty(name);
}
function styleString(b) {
return b == null ? styleNull : (b += "", function() {
var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;
return a !== b && (i = d3_interpolate(a, b), function(t) {
this.style.setProperty(name, i(t), priority);
});
});
}
return d3_transition_tween(this, "style." + name, value, styleString);
};
d3_transitionPrototype.styleTween = function(name, tween, priority) {
if (arguments.length < 3) priority = "";
function styleTween(d, i) {
var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));
return f && function(t) {
this.style.setProperty(name, f(t), priority);
};
}
return this.tween("style." + name, styleTween);
};
d3_transitionPrototype.text = function(value) {
return d3_transition_tween(this, "text", value, d3_transition_text);
};
function d3_transition_text(b) {
if (b == null) b = "";
return function() {
this.textContent = b;
};
}
d3_transitionPrototype.remove = function() {
var ns = this.namespace;
return this.each("end.transition", function() {
var p;
if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
});
};
d3_transitionPrototype.ease = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].ease;
if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
return d3_selection_each(this, function(node) {
node[ns][id].ease = value;
});
};
d3_transitionPrototype.delay = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].delay;
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
node[ns][id].delay = +value.call(node, node.__data__, i, j);
} : (value = +value, function(node) {
node[ns][id].delay = value;
}));
};
d3_transitionPrototype.duration = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].duration;
return d3_selection_each(this, typeof value === "function" ? function(node, i, j) {
node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j));
} : (value = Math.max(1, value), function(node) {
node[ns][id].duration = value;
}));
};
d3_transitionPrototype.each = function(type, listener) {
var id = this.id, ns = this.namespace;
if (arguments.length < 2) {
var inherit = d3_transitionInherit, inheritId = d3_transitionInheritId;
try {
d3_transitionInheritId = id;
d3_selection_each(this, function(node, i, j) {
d3_transitionInherit = node[ns][id];
type.call(node, node.__data__, i, j);
});
} finally {
d3_transitionInherit = inherit;
d3_transitionInheritId = inheritId;
}
} else {
d3_selection_each(this, function(node) {
var transition = node[ns][id];
(transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener);
});
}
return this;
};
d3_transitionPrototype.transition = function() {
var id0 = this.id, id1 = ++d3_transitionId, ns = this.namespace, subgroups = [], subgroup, group, node, transition;
for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []);
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
if (node = group[i]) {
transition = node[ns][id0];
d3_transitionNode(node, i, ns, id1, {
time: transition.time,
ease: transition.ease,
delay: transition.delay + transition.duration,
duration: transition.duration
});
}
subgroup.push(node);
}
}
return d3_transition(subgroups, ns, id1);
};
function d3_transitionNamespace(name) {
return name == null ? "__transition__" : "__transition_" + name + "__";
}
function d3_transitionNode(node, i, ns, id, inherit) {
var lock = node[ns] || (node[ns] = {
active: 0,
count: 0
}), transition = lock[id], time, timer, duration, ease, tweens;
function schedule(elapsed) {
var delay = transition.delay;
timer.t = delay + time;
if (delay <= elapsed) return start(elapsed - delay);
timer.c = start;
}
function start(elapsed) {
var activeId = lock.active, active = lock[activeId];
if (active) {
active.timer.c = null;
active.timer.t = NaN;
--lock.count;
delete lock[activeId];
active.event && active.event.interrupt.call(node, node.__data__, active.index);
}
for (var cancelId in lock) {
if (+cancelId < id) {
var cancel = lock[cancelId];
cancel.timer.c = null;
cancel.timer.t = NaN;
--lock.count;
delete lock[cancelId];
}
}
timer.c = tick;
d3_timer(function() {
if (timer.c && tick(elapsed || 1)) {
timer.c = null;
timer.t = NaN;
}
return 1;
}, 0, time);
lock.active = id;
transition.event && transition.event.start.call(node, node.__data__, i);
tweens = [];
transition.tween.forEach(function(key, value) {
if (value = value.call(node, node.__data__, i)) {
tweens.push(value);
}
});
ease = transition.ease;
duration = transition.duration;
}
function tick(elapsed) {
var t = elapsed / duration, e = ease(t), n = tweens.length;
while (n > 0) {
tweens[--n].call(node, e);
}
if (t >= 1) {
transition.event && transition.event.end.call(node, node.__data__, i);
if (--lock.count) delete lock[id]; else delete node[ns];
return 1;
}
}
if (!transition) {
time = inherit.time;
timer = d3_timer(schedule, 0, time);
transition = lock[id] = {
tween: new d3_Map(),
time: time,
timer: timer,
delay: inherit.delay,
duration: inherit.duration,
ease: inherit.ease,
index: i
};
inherit = null;
++lock.count;
}
}
d3.svg.axis = function() {
var scale = d3.scale.linear(), orient = d3_svg_axisDefaultOrient, innerTickSize = 6, outerTickSize = 6, tickPadding = 3, tickArguments_ = [ 10 ], tickValues = null, tickFormat_;
function axis(g) {
g.each(function() {
var g = d3.select(this);
var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = scale.copy();
var ticks = tickValues == null ? scale1.ticks ? scale1.ticks.apply(scale1, tickArguments_) : scale1.domain() : tickValues, tickFormat = tickFormat_ == null ? scale1.tickFormat ? scale1.tickFormat.apply(scale1, tickArguments_) : d3_identity : tickFormat_, tick = g.selectAll(".tick").data(ticks, scale1), tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", ε), tickExit = d3.transition(tick.exit()).style("opacity", ε).remove(), tickUpdate = d3.transition(tick.order()).style("opacity", 1), tickSpacing = Math.max(innerTickSize, 0) + tickPadding, tickTransform;
var range = d3_scaleRange(scale1), path = g.selectAll(".domain").data([ 0 ]), pathUpdate = (path.enter().append("path").attr("class", "domain"),
d3.transition(path));
tickEnter.append("line");
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"), sign = orient === "top" || orient === "left" ? -1 : 1, x1, x2, y1, y2;
if (orient === "bottom" || orient === "top") {
tickTransform = d3_svg_axisX, x1 = "x", y1 = "y", x2 = "x2", y2 = "y2";
text.attr("dy", sign < 0 ? "0em" : ".71em").style("text-anchor", "middle");
pathUpdate.attr("d", "M" + range[0] + "," + sign * outerTickSize + "V0H" + range[1] + "V" + sign * outerTickSize);
} else {
tickTransform = d3_svg_axisY, x1 = "y", y1 = "x", x2 = "y2", y2 = "x2";
text.attr("dy", ".32em").style("text-anchor", sign < 0 ? "end" : "start");
pathUpdate.attr("d", "M" + sign * outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + sign * outerTickSize);
}
lineEnter.attr(y2, sign * innerTickSize);
textEnter.attr(y1, sign * tickSpacing);
lineUpdate.attr(x2, 0).attr(y2, sign * innerTickSize);
textUpdate.attr(x1, 0).attr(y1, sign * tickSpacing);
if (scale1.rangeBand) {
var x = scale1, dx = x.rangeBand() / 2;
scale0 = scale1 = function(d) {
return x(d) + dx;
};
} else if (scale0.rangeBand) {
scale0 = scale1;
} else {
tickExit.call(tickTransform, scale1, scale0);
}
tickEnter.call(tickTransform, scale0, scale1);
tickUpdate.call(tickTransform, scale1, scale1);
});
}
axis.scale = function(x) {
if (!arguments.length) return scale;
scale = x;
return axis;
};
axis.orient = function(x) {
if (!arguments.length) return orient;
orient = x in d3_svg_axisOrients ? x + "" : d3_svg_axisDefaultOrient;
return axis;
};
axis.ticks = function() {
if (!arguments.length) return tickArguments_;
tickArguments_ = d3_array(arguments);
return axis;
};
axis.tickValues = function(x) {
if (!arguments.length) return tickValues;
tickValues = x;
return axis;
};
axis.tickFormat = function(x) {
if (!arguments.length) return tickFormat_;
tickFormat_ = x;
return axis;
};
axis.tickSize = function(x) {
var n = arguments.length;
if (!n) return innerTickSize;
innerTickSize = +x;
outerTickSize = +arguments[n - 1];
return axis;
};
axis.innerTickSize = function(x) {
if (!arguments.length) return innerTickSize;
innerTickSize = +x;
return axis;
};
axis.outerTickSize = function(x) {
if (!arguments.length) return outerTickSize;
outerTickSize = +x;
return axis;
};
axis.tickPadding = function(x) {
if (!arguments.length) return tickPadding;
tickPadding = +x;
return axis;
};
axis.tickSubdivide = function() {
return arguments.length && axis;
};
return axis;
};
var d3_svg_axisDefaultOrient = "bottom", d3_svg_axisOrients = {
top: 1,
right: 1,
bottom: 1,
left: 1
};
function d3_svg_axisX(selection, x0, x1) {
selection.attr("transform", function(d) {
var v0 = x0(d);
return "translate(" + (isFinite(v0) ? v0 : x1(d)) + ",0)";
});
}
function d3_svg_axisY(selection, y0, y1) {
selection.attr("transform", function(d) {
var v0 = y0(d);
return "translate(0," + (isFinite(v0) ? v0 : y1(d)) + ")";
});
}
d3.svg.brush = function() {
var event = d3_eventDispatch(brush, "brushstart", "brush", "brushend"), x = null, y = null, xExtent = [ 0, 0 ], yExtent = [ 0, 0 ], xExtentDomain, yExtentDomain, xClamp = true, yClamp = true, resizes = d3_svg_brushResizes[0];
function brush(g) {
g.each(function() {
var g = d3.select(this).style("pointer-events", "all").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)").on("mousedown.brush", brushstart).on("touchstart.brush", brushstart);
var background = g.selectAll(".background").data([ 0 ]);
background.enter().append("rect").attr("class", "background").style("visibility", "hidden").style("cursor", "crosshair");
g.selectAll(".extent").data([ 0 ]).enter().append("rect").attr("class", "extent").style("cursor", "move");
var resize = g.selectAll(".resize").data(resizes, d3_identity);
resize.exit().remove();
resize.enter().append("g").attr("class", function(d) {
return "resize " + d;
}).style("cursor", function(d) {
return d3_svg_brushCursor[d];
}).append("rect").attr("x", function(d) {
return /[ew]$/.test(d) ? -3 : null;
}).attr("y", function(d) {
return /^[ns]/.test(d) ? -3 : null;
}).attr("width", 6).attr("height", 6).style("visibility", "hidden");
resize.style("display", brush.empty() ? "none" : null);
var gUpdate = d3.transition(g), backgroundUpdate = d3.transition(background), range;
if (x) {
range = d3_scaleRange(x);
backgroundUpdate.attr("x", range[0]).attr("width", range[1] - range[0]);
redrawX(gUpdate);
}
if (y) {
range = d3_scaleRange(y);
backgroundUpdate.attr("y", range[0]).attr("height", range[1] - range[0]);
redrawY(gUpdate);
}
redraw(gUpdate);
});
}
brush.event = function(g) {
g.each(function() {
var event_ = event.of(this, arguments), extent1 = {
x: xExtent,
y: yExtent,
i: xExtentDomain,
j: yExtentDomain
}, extent0 = this.__chart__ || extent1;
this.__chart__ = extent1;
if (d3_transitionInheritId) {
d3.select(this).transition().each("start.brush", function() {
xExtentDomain = extent0.i;
yExtentDomain = extent0.j;
xExtent = extent0.x;
yExtent = extent0.y;
event_({
type: "brushstart"
});
}).tween("brush:brush", function() {
var xi = d3_interpolateArray(xExtent, extent1.x), yi = d3_interpolateArray(yExtent, extent1.y);
xExtentDomain = yExtentDomain = null;
return function(t) {
xExtent = extent1.x = xi(t);
yExtent = extent1.y = yi(t);
event_({
type: "brush",
mode: "resize"
});
};
}).each("end.brush", function() {
xExtentDomain = extent1.i;
yExtentDomain = extent1.j;
event_({
type: "brush",
mode: "resize"
});
event_({
type: "brushend"
});
});
} else {
event_({
type: "brushstart"
});
event_({
type: "brush",
mode: "resize"
});
event_({
type: "brushend"
});
}
});
};
function redraw(g) {
g.selectAll(".resize").attr("transform", function(d) {
return "translate(" + xExtent[+/e$/.test(d)] + "," + yExtent[+/^s/.test(d)] + ")";
});
}
function redrawX(g) {
g.select(".extent").attr("x", xExtent[0]);
g.selectAll(".extent,.n>rect,.s>rect").attr("width", xExtent[1] - xExtent[0]);
}
function redrawY(g) {
g.select(".extent").attr("y", yExtent[0]);
g.selectAll(".extent,.e>rect,.w>rect").attr("height", yExtent[1] - yExtent[0]);
}
function brushstart() {
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"), dragRestore = d3_event_dragSuppress(target), center, origin = d3.mouse(target), offset;
var w = d3.select(d3_window(target)).on("keydown.brush", keydown).on("keyup.brush", keyup);
if (d3.event.changedTouches) {
w.on("touchmove.brush", brushmove).on("touchend.brush", brushend);
} else {
w.on("mousemove.brush", brushmove).on("mouseup.brush", brushend);
}
g.interrupt().selectAll("*").interrupt();
if (dragging) {
origin[0] = xExtent[0] - origin[0];
origin[1] = yExtent[0] - origin[1];
} else if (resizing) {
var ex = +/w$/.test(resizing), ey = +/^n/.test(resizing);
offset = [ xExtent[1 - ex] - origin[0], yExtent[1 - ey] - origin[1] ];
origin[0] = xExtent[ex];
origin[1] = yExtent[ey];
} else if (d3.event.altKey) center = origin.slice();
g.style("pointer-events", "none").selectAll(".resize").style("display", null);
d3.select("body").style("cursor", eventTarget.style("cursor"));
event_({
type: "brushstart"
});
brushmove();
function keydown() {
if (d3.event.keyCode == 32) {
if (!dragging) {
center = null;
origin[0] -= xExtent[1];
origin[1] -= yExtent[1];
dragging = 2;
}
d3_eventPreventDefault();
}
}
function keyup() {
if (d3.event.keyCode == 32 && dragging == 2) {
origin[0] += xExtent[1];
origin[1] += yExtent[1];
dragging = 0;
d3_eventPreventDefault();
}
}
function brushmove() {
var point = d3.mouse(target), moved = false;
if (offset) {
point[0] += offset[0];
point[1] += offset[1];
}
if (!dragging) {
if (d3.event.altKey) {
if (!center) center = [ (xExtent[0] + xExtent[1]) / 2, (yExtent[0] + yExtent[1]) / 2 ];
origin[0] = xExtent[+(point[0] < center[0])];
origin[1] = yExtent[+(point[1] < center[1])];
} else center = null;
}
if (resizingX && move1(point, x, 0)) {
redrawX(g);
moved = true;
}
if (resizingY && move1(point, y, 1)) {
redrawY(g);
moved = true;
}
if (moved) {
redraw(g);
event_({
type: "brush",
mode: dragging ? "move" : "resize"
});
}
}
function move1(point, scale, i) {
var range = d3_scaleRange(scale), r0 = range[0], r1 = range[1], position = origin[i], extent = i ? yExtent : xExtent, size = extent[1] - extent[0], min, max;
if (dragging) {
r0 -= position;
r1 -= size + position;
}
min = (i ? yClamp : xClamp) ? Math.max(r0, Math.min(r1, point[i])) : point[i];
if (dragging) {
max = (min += position) + size;
} else {
if (center) position = Math.max(r0, Math.min(r1, 2 * center[i] - min));
if (position < min) {
max = min;
min = position;
} else {
max = position;
}
}
if (extent[0] != min || extent[1] != max) {
if (i) yExtentDomain = null; else xExtentDomain = null;
extent[0] = min;
extent[1] = max;
return true;
}
}
function brushend() {
brushmove();
g.style("pointer-events", "all").selectAll(".resize").style("display", brush.empty() ? "none" : 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);
dragRestore();
event_({
type: "brushend"
});
}
}
brush.x = function(z) {
if (!arguments.length) return x;
x = z;
resizes = d3_svg_brushResizes[!x << 1 | !y];
return brush;
};
brush.y = function(z) {
if (!arguments.length) return y;
y = z;
resizes = d3_svg_brushResizes[!x << 1 | !y];
return brush;
};
brush.clamp = function(z) {
if (!arguments.length) return x && y ? [ xClamp, yClamp ] : x ? xClamp : y ? yClamp : null;
if (x && y) xClamp = !!z[0], yClamp = !!z[1]; else if (x) xClamp = !!z; else if (y) yClamp = !!z;
return brush;
};
brush.extent = function(z) {
var x0, x1, y0, y1, t;
if (!arguments.length) {
if (x) {
if (xExtentDomain) {
x0 = xExtentDomain[0], x1 = xExtentDomain[1];
} else {
x0 = xExtent[0], x1 = xExtent[1];
if (x.invert) x0 = x.invert(x0), x1 = x.invert(x1);
if (x1 < x0) t = x0, x0 = x1, x1 = t;
}
}
if (y) {
if (yExtentDomain) {
y0 = yExtentDomain[0], y1 = yExtentDomain[1];
} else {
y0 = yExtent[0], y1 = yExtent[1];
if (y.invert) y0 = y.invert(y0), y1 = y.invert(y1);
if (y1 < y0) t = y0, y0 = y1, y1 = t;
}
}
return x && y ? [ [ x0, y0 ], [ x1, y1 ] ] : x ? [ x0, x1 ] : y && [ y0, y1 ];
}
if (x) {
x0 = z[0], x1 = z[1];
if (y) x0 = x0[0], x1 = x1[0];
xExtentDomain = [ x0, x1 ];
if (x.invert) x0 = x(x0), x1 = x(x1);
if (x1 < x0) t = x0, x0 = x1, x1 = t;
if (x0 != xExtent[0] || x1 != xExtent[1]) xExtent = [ x0, x1 ];
}
if (y) {
y0 = z[0], y1 = z[1];
if (x) y0 = y0[1], y1 = y1[1];
yExtentDomain = [ y0, y1 ];
if (y.invert) y0 = y(y0), y1 = y(y1);
if (y1 < y0) t = y0, y0 = y1, y1 = t;
if (y0 != yExtent[0] || y1 != yExtent[1]) yExtent = [ y0, y1 ];
}
return brush;
};
brush.clear = function() {
if (!brush.empty()) {
xExtent = [ 0, 0 ], yExtent = [ 0, 0 ];
xExtentDomain = yExtentDomain = null;
}
return brush;
};
brush.empty = function() {
return !!x && xExtent[0] == xExtent[1] || !!y && yExtent[0] == yExtent[1];
};
return d3.rebind(brush, event, "on");
};
var d3_svg_brushCursor = {
n: "ns-resize",
e: "ew-resize",
s: "ns-resize",
w: "ew-resize",
nw: "nwse-resize",
ne: "nesw-resize",
se: "nwse-resize",
sw: "nesw-resize"
};
var d3_svg_brushResizes = [ [ "n", "e", "s", "w", "nw", "ne", "se", "sw" ], [ "e", "w" ], [ "n", "s" ], [] ];
var d3_time_format = d3_time.format = d3_locale_enUS.timeFormat;
var d3_time_formatUtc = d3_time_format.utc;
var d3_time_formatIso = d3_time_formatUtc("%Y-%m-%dT%H:%M:%S.%LZ");
d3_time_format.iso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z") ? d3_time_formatIsoNative : d3_time_formatIso;
function d3_time_formatIsoNative(date) {
return date.toISOString();
}
d3_time_formatIsoNative.parse = function(string) {
var date = new Date(string);
return isNaN(date) ? null : date;
};
d3_time_formatIsoNative.toString = d3_time_formatIso.toString;
d3_time.second = d3_time_interval(function(date) {
return new d3_date(Math.floor(date / 1e3) * 1e3);
}, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 1e3);
}, function(date) {
return date.getSeconds();
});
d3_time.seconds = d3_time.second.range;
d3_time.seconds.utc = d3_time.second.utc.range;
d3_time.minute = d3_time_interval(function(date) {
return new d3_date(Math.floor(date / 6e4) * 6e4);
}, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 6e4);
}, function(date) {
return date.getMinutes();
});
d3_time.minutes = d3_time.minute.range;
d3_time.minutes.utc = d3_time.minute.utc.range;
d3_time.hour = d3_time_interval(function(date) {
var timezone = date.getTimezoneOffset() / 60;
return new d3_date((Math.floor(date / 36e5 - timezone) + timezone) * 36e5);
}, function(date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * 36e5);
}, function(date) {
return date.getHours();
});
d3_time.hours = d3_time.hour.range;
d3_time.hours.utc = d3_time.hour.utc.range;
d3_time.month = d3_time_interval(function(date) {
date = d3_time.day(date);
date.setDate(1);
return date;
}, function(date, offset) {
date.setMonth(date.getMonth() + offset);
}, function(date) {
return date.getMonth();
});
d3_time.months = d3_time.month.range;
d3_time.months.utc = d3_time.month.utc.range;
function d3_time_scale(linear, methods, format) {
function scale(x) {
return linear(x);
}
scale.invert = function(x) {
return d3_time_scaleDate(linear.invert(x));
};
scale.domain = function(x) {
if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
linear.domain(x);
return scale;
};
function tickMethod(extent, count) {
var span = extent[1] - extent[0], target = span / count, i = d3.bisect(d3_time_scaleSteps, target);
return i == d3_time_scaleSteps.length ? [ methods.year, d3_scale_linearTickRange(extent.map(function(d) {
return d / 31536e6;
}), count)[2] ] : !i ? [ d3_time_scaleMilliseconds, d3_scale_linearTickRange(extent, count)[2] ] : methods[target / d3_time_scaleSteps[i - 1] < d3_time_scaleSteps[i] / target ? i - 1 : i];
}
scale.nice = function(interval, skip) {
var domain = scale.domain(), extent = d3_scaleExtent(domain), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" && tickMethod(extent, interval);
if (method) interval = method[0], skip = method[1];
function skipped(date) {
return !isNaN(date) && !interval.range(date, d3_time_scaleDate(+date + 1), skip).length;
}
return scale.domain(d3_scale_nice(domain, skip > 1 ? {
floor: function(date) {
while (skipped(date = interval.floor(date))) date = d3_time_scaleDate(date - 1);
return date;
},
ceil: function(date) {
while (skipped(date = interval.ceil(date))) date = d3_time_scaleDate(+date + 1);
return date;
}
} : interval));
};
scale.ticks = function(interval, skip) {
var extent = d3_scaleExtent(scale.domain()), method = interval == null ? tickMethod(extent, 10) : typeof interval === "number" ? tickMethod(extent, interval) : !interval.range && [ {
range: interval
}, skip ];
if (method) interval = method[0], skip = method[1];
return interval.range(extent[0], d3_time_scaleDate(+extent[1] + 1), skip < 1 ? 1 : skip);
};
scale.tickFormat = function() {
return format;
};
scale.copy = function() {
return d3_time_scale(linear.copy(), methods, format);
};
return d3_scale_linearRebind(scale, linear);
}
function d3_time_scaleDate(t) {
return new Date(t);
}
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_scaleLocalFormat = d3_time_format.multi([ [ ".%L", function(d) {
return d.getMilliseconds();
} ], [ ":%S", function(d) {
return d.getSeconds();
} ], [ "%I:%M", function(d) {
return d.getMinutes();
} ], [ "%I %p", function(d) {
return d.getHours();
} ], [ "%a %d", function(d) {
return d.getDay() && d.getDate() != 1;
} ], [ "%b %d", function(d) {
return d.getDate() != 1;
} ], [ "%B", function(d) {
return d.getMonth();
} ], [ "%Y", d3_true ] ]);
var d3_time_scaleMilliseconds = {
range: function(start, stop, step) {
return d3.range(Math.ceil(start / step) * step, +stop, step).map(d3_time_scaleDate);
},
floor: d3_identity,
ceil: d3_identity
};
d3_time_scaleLocalMethods.year = d3_time.year;
d3_time.scale = function() {
return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);
};
var d3_time_scaleUtcMethods = d3_time_scaleLocalMethods.map(function(m) {
return [ m[0].utc, m[1] ];
});
var d3_time_scaleUtcFormat = d3_time_formatUtc.multi([ [ ".%L", function(d) {
return d.getUTCMilliseconds();
} ], [ ":%S", function(d) {
return d.getUTCSeconds();
} ], [ "%I:%M", function(d) {
return d.getUTCMinutes();
} ], [ "%I %p", function(d) {
return d.getUTCHours();
} ], [ "%a %d", function(d) {
return d.getUTCDay() && d.getUTCDate() != 1;
} ], [ "%b %d", function(d) {
return d.getUTCDate() != 1;
} ], [ "%B", function(d) {
return d.getUTCMonth();
} ], [ "%Y", d3_true ] ]);
d3_time_scaleUtcMethods.year = d3_time.year.utc;
d3_time.scale.utc = function() {
return d3_time_scale(d3.scale.linear(), d3_time_scaleUtcMethods, d3_time_scaleUtcFormat);
};
d3.text = d3_xhrType(function(request) {
return request.responseText;
});
d3.json = function(url, callback) {
return d3_xhr(url, "application/json", d3_json, callback);
};
function d3_json(request) {
return JSON.parse(request.responseText);
}
d3.html = function(url, callback) {
return d3_xhr(url, "text/html", d3_html, callback);
};
function d3_html(request) {
var range = d3_document.createRange();
range.selectNode(d3_document.body);
return range.createContextualFragment(request.responseText);
}
d3.xml = d3_xhrType(function(request) {
return request.responseXML;
});
if (typeof define === "function" && define.amd) this.d3 = d3, define(d3); else if (typeof module === "object" && module.exports) module.exports = d3; else this.d3 = d3;
}();
},{}],119:[function(require,module,exports){
"use strict"
var ch = require("incremental-convex-hull")
var uniq = require("uniq")
module.exports = triangulate
function LiftedPoint(p, i) {
this.point = p
this.index = i
}
function compareLifted(a, b) {
var ap = a.point
var bp = b.point
var d = ap.length
for(var i=0; i= 2) {
return false
}
}
cell[j] = v
}
return true
})
} else {
hull = hull.filter(function(cell) {
for(var i=0; i<=d; ++i) {
var v = dindex[cell[i]]
if(v < 0) {
return false
}
cell[i] = v
}
return true
})
}
if(d & 1) {
for(var i=0; i>> 31
}
module.exports.exponent = function(n) {
var b = module.exports.hi(n)
return ((b<<1) >>> 21) - 1023
}
module.exports.fraction = function(n) {
var lo = module.exports.lo(n)
var hi = module.exports.hi(n)
var b = hi & ((1<<20) - 1)
if(hi & 0x7ff00000) {
b += (1<<20)
}
return [lo, b]
}
module.exports.denormalized = function(n) {
var hi = module.exports.hi(n)
return !(hi & 0x7ff00000)
}
}).call(this,require("buffer").Buffer)
},{"buffer":73}],121:[function(require,module,exports){
"use strict"
function dupe_array(count, value, i) {
var c = count[i]|0
if(c <= 0) {
return []
}
var result = new Array(c), j
if(i === count.length-1) {
for(j=0; j 0) {
return dupe_number(count|0, value)
}
break
case "object":
if(typeof (count.length) === "number") {
return dupe_array(count, value, 0)
}
break
}
return []
}
module.exports = dupe
},{}],122:[function(require,module,exports){
'use strict';
module.exports = earcut;
function earcut(data, holeIndices, dim) {
dim = dim || 2;
var hasHoles = holeIndices && holeIndices.length,
outerLen = hasHoles ? holeIndices[0] * dim : data.length,
outerNode = linkedList(data, 0, outerLen, dim, true),
triangles = [];
if (!outerNode) return triangles;
var minX, minY, maxX, maxY, x, y, size;
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
if (data.length > 80 * dim) {
minX = maxX = data[0];
minY = maxY = data[1];
for (var i = dim; i < outerLen; i += dim) {
x = data[i];
y = data[i + 1];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
// minX, minY and size are later used to transform coords into integers for z-order calculation
size = Math.max(maxX - minX, maxY - minY);
}
earcutLinked(outerNode, triangles, dim, minX, minY, size);
return triangles;
}
// create a circular doubly linked list from polygon points in the specified winding order
function linkedList(data, start, end, dim, clockwise) {
var i, last;
if (clockwise === (signedArea(data, start, end, dim) > 0)) {
for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
} else {
for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
}
if (last && equals(last, last.next)) {
removeNode(last);
last = last.next;
}
return last;
}
// eliminate colinear or duplicate points
function filterPoints(start, end) {
if (!start) return start;
if (!end) end = start;
var p = start,
again;
do {
again = false;
if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
removeNode(p);
p = end = p.prev;
if (p === p.next) return null;
again = true;
} else {
p = p.next;
}
} while (again || p !== end);
return end;
}
// main ear slicing loop which triangulates a polygon (given as a linked list)
function earcutLinked(ear, triangles, dim, minX, minY, size, pass) {
if (!ear) return;
// interlink polygon nodes in z-order
if (!pass && size) indexCurve(ear, minX, minY, size);
var stop = ear,
prev, next;
// iterate through ears, slicing them one by one
while (ear.prev !== ear.next) {
prev = ear.prev;
next = ear.next;
if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) {
// cut off the triangle
triangles.push(prev.i / dim);
triangles.push(ear.i / dim);
triangles.push(next.i / dim);
removeNode(ear);
// skipping the next vertice leads to less sliver triangles
ear = next.next;
stop = next.next;
continue;
}
ear = next;
// if we looped through the whole remaining polygon and can't find any more ears
if (ear === stop) {
// try filtering points and slicing again
if (!pass) {
earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1);
// if this didn't work, try curing all small self-intersections locally
} else if (pass === 1) {
ear = cureLocalIntersections(ear, triangles, dim);
earcutLinked(ear, triangles, dim, minX, minY, size, 2);
// as a last resort, try splitting the remaining polygon into two
} else if (pass === 2) {
splitEarcut(ear, triangles, dim, minX, minY, size);
}
break;
}
}
}
// check whether a polygon node forms a valid ear with adjacent nodes
function isEar(ear) {
var a = ear.prev,
b = ear,
c = ear.next;
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
// now make sure we don't have other points inside the potential ear
var p = ear.next.next;
while (p !== ear.prev) {
if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.next;
}
return true;
}
function isEarHashed(ear, minX, minY, size) {
var a = ear.prev,
b = ear,
c = ear.next;
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
// triangle bbox; min & max are calculated like this for speed
var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);
// z-order range for the current triangle bbox;
var minZ = zOrder(minTX, minTY, minX, minY, size),
maxZ = zOrder(maxTX, maxTY, minX, minY, size);
// first look for points inside the triangle in increasing z-order
var p = ear.nextZ;
while (p && p.z <= maxZ) {
if (p !== ear.prev && p !== ear.next &&
pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.nextZ;
}
// then look for points in decreasing z-order
p = ear.prevZ;
while (p && p.z >= minZ) {
if (p !== ear.prev && p !== ear.next &&
pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
area(p.prev, p, p.next) >= 0) return false;
p = p.prevZ;
}
return true;
}
// go through all polygon nodes and cure small local self-intersections
function cureLocalIntersections(start, triangles, dim) {
var p = start;
do {
var a = p.prev,
b = p.next.next;
if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
triangles.push(a.i / dim);
triangles.push(p.i / dim);
triangles.push(b.i / dim);
// remove two nodes involved
removeNode(p);
removeNode(p.next);
p = start = b;
}
p = p.next;
} while (p !== start);
return p;
}
// try splitting polygon into two and triangulate them independently
function splitEarcut(start, triangles, dim, minX, minY, size) {
// look for a valid diagonal that divides the polygon into two
var a = start;
do {
var b = a.next.next;
while (b !== a.prev) {
if (a.i !== b.i && isValidDiagonal(a, b)) {
// split the polygon in two by the diagonal
var c = splitPolygon(a, b);
// filter colinear points around the cuts
a = filterPoints(a, a.next);
c = filterPoints(c, c.next);
// run earcut on each half
earcutLinked(a, triangles, dim, minX, minY, size);
earcutLinked(c, triangles, dim, minX, minY, size);
return;
}
b = b.next;
}
a = a.next;
} while (a !== start);
}
// link every hole into the outer loop, producing a single-ring polygon without holes
function eliminateHoles(data, holeIndices, outerNode, dim) {
var queue = [],
i, len, start, end, list;
for (i = 0, len = holeIndices.length; i < len; i++) {
start = holeIndices[i] * dim;
end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
list = linkedList(data, start, end, dim, false);
if (list === list.next) list.steiner = true;
queue.push(getLeftmost(list));
}
queue.sort(compareX);
// process holes from left to right
for (i = 0; i < queue.length; i++) {
eliminateHole(queue[i], outerNode);
outerNode = filterPoints(outerNode, outerNode.next);
}
return outerNode;
}
function compareX(a, b) {
return a.x - b.x;
}
// find a bridge between vertices that connects hole with an outer ring and and link it
function eliminateHole(hole, outerNode) {
outerNode = findHoleBridge(hole, outerNode);
if (outerNode) {
var b = splitPolygon(outerNode, hole);
filterPoints(b, b.next);
}
}
// David Eberly's algorithm for finding a bridge between hole and outer polygon
function findHoleBridge(hole, outerNode) {
var p = outerNode,
hx = hole.x,
hy = hole.y,
qx = -Infinity,
m;
// find a segment intersected by a ray from the hole's leftmost point to the left;
// segment's endpoint with lesser x will be potential connection point
do {
if (hy <= p.y && hy >= p.next.y) {
var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
if (x <= hx && x > qx) {
qx = x;
if (x === hx) {
if (hy === p.y) return p;
if (hy === p.next.y) return p.next;
}
m = p.x < p.next.x ? p : p.next;
}
}
p = p.next;
} while (p !== outerNode);
if (!m) return null;
if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint
// look for points inside the triangle of hole point, segment intersection and endpoint;
// if there are no points found, we have a valid connection;
// otherwise choose the point of the minimum angle with the ray as connection point
var stop = m,
mx = m.x,
my = m.y,
tanMin = Infinity,
tan;
p = m.next;
while (p !== stop) {
if (hx >= p.x && p.x >= mx &&
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
tan = Math.abs(hy - p.y) / (hx - p.x); // tangential
if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
m = p;
tanMin = tan;
}
}
p = p.next;
}
return m;
}
// interlink polygon nodes in z-order
function indexCurve(start, minX, minY, size) {
var p = start;
do {
if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size);
p.prevZ = p.prev;
p.nextZ = p.next;
p = p.next;
} while (p !== start);
p.prevZ.nextZ = null;
p.prevZ = null;
sortLinked(p);
}
// Simon Tatham's linked list merge sort algorithm
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
function sortLinked(list) {
var i, p, q, e, tail, numMerges, pSize, qSize,
inSize = 1;
do {
p = list;
list = null;
tail = null;
numMerges = 0;
while (p) {
numMerges++;
q = p;
pSize = 0;
for (i = 0; i < inSize; i++) {
pSize++;
q = q.nextZ;
if (!q) break;
}
qSize = inSize;
while (pSize > 0 || (qSize > 0 && q)) {
if (pSize === 0) {
e = q;
q = q.nextZ;
qSize--;
} else if (qSize === 0 || !q) {
e = p;
p = p.nextZ;
pSize--;
} else if (p.z <= q.z) {
e = p;
p = p.nextZ;
pSize--;
} else {
e = q;
q = q.nextZ;
qSize--;
}
if (tail) tail.nextZ = e;
else list = e;
e.prevZ = tail;
tail = e;
}
p = q;
}
tail.nextZ = null;
inSize *= 2;
} while (numMerges > 1);
return list;
}
// z-order of a point given coords and size of the data bounding box
function zOrder(x, y, minX, minY, size) {
// coords are transformed into non-negative 15-bit integer range
x = 32767 * (x - minX) / size;
y = 32767 * (y - minY) / size;
x = (x | (x << 8)) & 0x00FF00FF;
x = (x | (x << 4)) & 0x0F0F0F0F;
x = (x | (x << 2)) & 0x33333333;
x = (x | (x << 1)) & 0x55555555;
y = (y | (y << 8)) & 0x00FF00FF;
y = (y | (y << 4)) & 0x0F0F0F0F;
y = (y | (y << 2)) & 0x33333333;
y = (y | (y << 1)) & 0x55555555;
return x | (y << 1);
}
// find the leftmost node of a polygon ring
function getLeftmost(start) {
var p = start,
leftmost = start;
do {
if (p.x < leftmost.x) leftmost = p;
p = p.next;
} while (p !== start);
return leftmost;
}
// check if a point lies within a convex triangle
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
(ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
(bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
}
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
function isValidDiagonal(a, b) {
return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
}
// signed area of a triangle
function area(p, q, r) {
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
}
// check if two points are equal
function equals(p1, p2) {
return p1.x === p2.x && p1.y === p2.y;
}
// check if two segments intersect
function intersects(p1, q1, p2, q2) {
if ((equals(p1, q1) && equals(p2, q2)) ||
(equals(p1, q2) && equals(p2, q1))) return true;
return area(p1, q1, p2) > 0 !== area(p1, q1, q2) > 0 &&
area(p2, q2, p1) > 0 !== area(p2, q2, q1) > 0;
}
// check if a polygon diagonal intersects any polygon segments
function intersectsPolygon(a, b) {
var p = a;
do {
if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
intersects(p, p.next, a, b)) return true;
p = p.next;
} while (p !== a);
return false;
}
// check if a polygon diagonal is locally inside the polygon
function locallyInside(a, b) {
return area(a.prev, a, a.next) < 0 ?
area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :
area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
}
// check if the middle point of a polygon diagonal is inside the polygon
function middleInside(a, b) {
var p = a,
inside = false,
px = (a.x + b.x) / 2,
py = (a.y + b.y) / 2;
do {
if (((p.y > py) !== (p.next.y > py)) && (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
inside = !inside;
p = p.next;
} while (p !== a);
return inside;
}
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
function splitPolygon(a, b) {
var a2 = new Node(a.i, a.x, a.y),
b2 = new Node(b.i, b.x, b.y),
an = a.next,
bp = b.prev;
a.next = b;
b.prev = a;
a2.next = an;
an.prev = a2;
b2.next = a2;
a2.prev = b2;
bp.next = b2;
b2.prev = bp;
return b2;
}
// create a node and optionally link it with previous one (in a circular doubly linked list)
function insertNode(i, x, y, last) {
var p = new Node(i, x, y);
if (!last) {
p.prev = p;
p.next = p;
} else {
p.next = last.next;
p.prev = last;
last.next.prev = p;
last.next = p;
}
return p;
}
function removeNode(p) {
p.next.prev = p.prev;
p.prev.next = p.next;
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
}
function Node(i, x, y) {
// vertice index in coordinates array
this.i = i;
// vertex coordinates
this.x = x;
this.y = y;
// previous and next vertice nodes in a polygon ring
this.prev = null;
this.next = null;
// z-order curve value
this.z = null;
// previous and next nodes in z-order
this.prevZ = null;
this.nextZ = null;
// indicates whether this is a steiner point
this.steiner = false;
}
// return a percentage difference between the polygon area and its triangulation area;
// used to verify correctness of triangulation
earcut.deviation = function (data, holeIndices, dim, triangles) {
var hasHoles = holeIndices && holeIndices.length;
var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
if (hasHoles) {
for (var i = 0, len = holeIndices.length; i < len; i++) {
var start = holeIndices[i] * dim;
var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
polygonArea -= Math.abs(signedArea(data, start, end, dim));
}
}
var trianglesArea = 0;
for (i = 0; i < triangles.length; i += 3) {
var a = triangles[i] * dim;
var b = triangles[i + 1] * dim;
var c = triangles[i + 2] * dim;
trianglesArea += Math.abs(
(data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
(data[a] - data[b]) * (data[c + 1] - data[a + 1]));
}
return polygonArea === 0 && trianglesArea === 0 ? 0 :
Math.abs((trianglesArea - polygonArea) / polygonArea);
};
function signedArea(data, start, end, dim) {
var sum = 0;
for (var i = start, j = end - dim; i < end; i += dim) {
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
j = i;
}
return sum;
}
// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts
earcut.flatten = function (data) {
var dim = data[0][0].length,
result = {vertices: [], holes: [], dimensions: dim},
holeIndex = 0;
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].length; j++) {
for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);
}
if (i > 0) {
holeIndex += data[i - 1].length;
result.holes.push(holeIndex);
}
}
return result;
};
},{}],123:[function(require,module,exports){
"use strict"
module.exports = edgeToAdjacency
var uniq = require("uniq")
function edgeToAdjacency(edges, numVertices) {
var numEdges = edges.length
if(typeof numVertices !== "number") {
numVertices = 0
for(var i=0; i postsJSON
values[1] // => commentsJSON
return values;
});
```
@class Promise
@param {function} resolver
Useful for tooling.
@constructor
*/
function Promise(resolver) {
this[PROMISE_ID] = nextId();
this._result = this._state = undefined;
this._subscribers = [];
if (noop !== resolver) {
typeof resolver !== 'function' && needsResolver();
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
}
}
Promise.all = all;
Promise.race = race;
Promise.resolve = resolve;
Promise.reject = reject;
Promise._setScheduler = setScheduler;
Promise._setAsap = setAsap;
Promise._asap = asap;
Promise.prototype = {
constructor: Promise,
/**
The primary way of interacting with a promise is through its `then` method,
which registers callbacks to receive either a promise's eventual value or the
reason why the promise cannot be fulfilled.
```js
findUser().then(function(user){
// user is available
}, function(reason){
// user is unavailable, and you are given the reason why
});
```
Chaining
--------
The return value of `then` is itself a promise. This second, 'downstream'
promise is resolved with the return value of the first promise's fulfillment
or rejection handler, or rejected if the handler throws an exception.
```js
findUser().then(function (user) {
return user.name;
}, function (reason) {
return 'default name';
}).then(function (userName) {
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
// will be `'default name'`
});
findUser().then(function (user) {
throw new Error('Found user, but still unhappy');
}, function (reason) {
throw new Error('`findUser` rejected and we're unhappy');
}).then(function (value) {
// never reached
}, function (reason) {
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
});
```
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
```js
findUser().then(function (user) {
throw new PedagogicalException('Upstream error');
}).then(function (value) {
// never reached
}).then(function (value) {
// never reached
}, function (reason) {
// The `PedgagocialException` is propagated all the way down to here
});
```
Assimilation
------------
Sometimes the value you want to propagate to a downstream promise can only be
retrieved asynchronously. This can be achieved by returning a promise in the
fulfillment or rejection handler. The downstream promise will then be pending
until the returned promise is settled. This is called *assimilation*.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// The user's comments are now available
});
```
If the assimliated promise rejects, then the downstream promise will also reject.
```js
findUser().then(function (user) {
return findCommentsByAuthor(user);
}).then(function (comments) {
// If `findCommentsByAuthor` fulfills, we'll have the value here
}, function (reason) {
// If `findCommentsByAuthor` rejects, we'll have the reason here
});
```
Simple Example
--------------
Synchronous Example
```javascript
let result;
try {
result = findResult();
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
findResult(function(result, err){
if (err) {
// failure
} else {
// success
}
});
```
Promise Example;
```javascript
findResult().then(function(result){
// success
}, function(reason){
// failure
});
```
Advanced Example
--------------
Synchronous Example
```javascript
let author, books;
try {
author = findAuthor();
books = findBooksByAuthor(author);
// success
} catch(reason) {
// failure
}
```
Errback Example
```js
function foundBooks(books) {
}
function failure(reason) {
}
findAuthor(function(author, err){
if (err) {
failure(err);
// failure
} else {
try {
findBoooksByAuthor(author, function(books, err) {
if (err) {
failure(err);
} else {
try {
foundBooks(books);
} catch(reason) {
failure(reason);
}
}
});
} catch(error) {
failure(err);
}
// success
}
});
```
Promise Example;
```javascript
findAuthor().
then(findBooksByAuthor).
then(function(books){
// found books
}).catch(function(reason){
// something went wrong
});
```
@method then
@param {Function} onFulfilled
@param {Function} onRejected
Useful for tooling.
@return {Promise}
*/
then: then,
/**
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
as the catch block of a try/catch statement.
```js
function findAuthor(){
throw new Error('couldn't find that author');
}
// synchronous
try {
findAuthor();
} catch(reason) {
// something went wrong
}
// async with promises
findAuthor().catch(function(reason){
// something went wrong
});
```
@method catch
@param {Function} onRejection
Useful for tooling.
@return {Promise}
*/
'catch': function _catch(onRejection) {
return this.then(null, onRejection);
}
};
function polyfill() {
var local = undefined;
if (typeof global !== 'undefined') {
local = global;
} else if (typeof self !== 'undefined') {
local = self;
} else {
try {
local = Function('return this')();
} catch (e) {
throw new Error('polyfill failed because global object is unavailable in this environment');
}
}
var P = local.Promise;
if (P) {
var promiseToString = null;
try {
promiseToString = Object.prototype.toString.call(P.resolve());
} catch (e) {
// silently ignored
}
if (promiseToString === '[object Promise]' && !P.cast) {
return;
}
}
local.Promise = Promise;
}
polyfill();
// Strange compat..
Promise.polyfill = polyfill;
Promise.Promise = Promise;
return Promise;
})));
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"_process":479}],125:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
args = Array.prototype.slice.call(arguments, 1);
handler.apply(this, args);
}
} else if (isObject(handler)) {
args = Array.prototype.slice.call(arguments, 1);
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.prototype.listenerCount = function(type) {
if (this._events) {
var evlistener = this._events[type];
if (isFunction(evlistener))
return 1;
else if (evlistener)
return evlistener.length;
}
return 0;
};
EventEmitter.listenerCount = function(emitter, type) {
return emitter.listenerCount(type);
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],126:[function(require,module,exports){
"use strict"
module.exports = extractPlanes
function extractPlanes(M, zNear, zFar) {
var z = zNear || 0.0
var zf = zFar || 1.0
return [
[ M[12] + M[0], M[13] + M[1], M[14] + M[2], M[15] + M[3] ],
[ M[12] - M[0], M[13] - M[1], M[14] - M[2], M[15] - M[3] ],
[ M[12] + M[4], M[13] + M[5], M[14] + M[6], M[15] + M[7] ],
[ M[12] - M[4], M[13] - M[5], M[14] - M[6], M[15] - M[7] ],
[ z*M[12] + M[8], z*M[13] + M[9], z*M[14] + M[10], z*M[15] + M[11] ],
[ zf*M[12] - M[8], zf*M[13] - M[9], zf*M[14] - M[10], zf*M[15] - M[11] ]
]
}
},{}],127:[function(require,module,exports){
/**
* inspired by is-number
* but significantly simplified and sped up by ignoring number and string constructors
* ie these return false:
* new Number(1)
* new String('1')
*/
'use strict';
/**
* Is this string all whitespace?
* This solution kind of makes my brain hurt, but it's significantly faster
* than !str.trim() or any other solution I could find.
*
* whitespace codes from: http://en.wikipedia.org/wiki/Whitespace_character
* and verified with:
*
* for(var i = 0; i < 65536; i++) {
* var s = String.fromCharCode(i);
* if(+s===0 && !s.trim()) console.log(i, s);
* }
*
* which counts a couple of these as *not* whitespace, but finds nothing else
* that *is* whitespace. Note that charCodeAt stops at 16 bits, but it appears
* that there are no whitespace characters above this, and code points above
* this do not map onto white space characters.
*/
function allBlankCharCodes(str){
var l = str.length,
a;
for(var i = 0; i < l; i++) {
a = str.charCodeAt(i);
if((a < 9 || a > 13) && (a !== 32) && (a !== 133) && (a !== 160) &&
(a !== 5760) && (a !== 6158) && (a < 8192 || a > 8205) &&
(a !== 8232) && (a !== 8233) && (a !== 8239) && (a !== 8287) &&
(a !== 8288) && (a !== 12288) && (a !== 65279)) {
return false;
}
}
return true;
}
module.exports = function(n) {
var type = typeof n;
if(type === 'string') {
var original = n;
n = +n;
// whitespace strings cast to zero - filter them out
if(n===0 && allBlankCharCodes(original)) return false;
}
else if(type !== 'number') return false;
return n - n < 1;
};
},{}],128:[function(require,module,exports){
'use strict';
module.exports = createFilter;
var types = ['Unknown', 'Point', 'LineString', 'Polygon'];
/**
* Given a filter expressed as nested arrays, return a new function
* that evaluates whether a given feature (with a .properties or .tags property)
* passes its test.
*
* @param {Array} filter mapbox gl filter
* @returns {Function} filter-evaluating function
*/
function createFilter(filter) {
return new Function('f', 'var p = (f && f.properties || {}); return ' + compile(filter));
}
function compile(filter) {
if (!filter) return 'true';
var op = filter[0];
if (filter.length <= 1) return op === 'any' ? 'false' : 'true';
var str =
op === '==' ? compileComparisonOp(filter[1], filter[2], '===', false) :
op === '!=' ? compileComparisonOp(filter[1], filter[2], '!==', false) :
op === '<' ||
op === '>' ||
op === '<=' ||
op === '>=' ? compileComparisonOp(filter[1], filter[2], op, true) :
op === 'any' ? compileLogicalOp(filter.slice(1), '||') :
op === 'all' ? compileLogicalOp(filter.slice(1), '&&') :
op === 'none' ? compileNegation(compileLogicalOp(filter.slice(1), '||')) :
op === 'in' ? compileInOp(filter[1], filter.slice(2)) :
op === '!in' ? compileNegation(compileInOp(filter[1], filter.slice(2))) :
op === 'has' ? compileHasOp(filter[1]) :
op === '!has' ? compileNegation(compileHasOp([filter[1]])) :
'true';
return '(' + str + ')';
}
function compilePropertyReference(property) {
return property === '$type' ? 'f.type' :
property === '$id' ? 'f.id' :
'p[' + JSON.stringify(property) + ']';
}
function compileComparisonOp(property, value, op, checkType) {
var left = compilePropertyReference(property);
var right = property === '$type' ? types.indexOf(value) : JSON.stringify(value);
return (checkType ? 'typeof ' + left + '=== typeof ' + right + '&&' : '') + left + op + right;
}
function compileLogicalOp(expressions, op) {
return expressions.map(compile).join(op);
}
function compileInOp(property, values) {
if (property === '$type') values = values.map(function(value) { return types.indexOf(value); });
var left = JSON.stringify(values.sort(compare));
var right = compilePropertyReference(property);
if (values.length <= 200) return left + '.indexOf(' + right + ') !== -1';
return 'function(v, a, i, j) {' +
'while (i <= j) { var m = (i + j) >> 1;' +
' if (a[m] === v) return true; if (a[m] > v) j = m - 1; else i = m + 1;' +
'}' +
'return false; }(' + right + ', ' + left + ',0,' + (values.length - 1) + ')';
}
function compileHasOp(property) {
return JSON.stringify(property) + ' in p';
}
function compileNegation(expression) {
return '!(' + expression + ')';
}
// Comparison function to sort numbers and strings
function compare(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
},{}],129:[function(require,module,exports){
'use strict'
module.exports = createFilteredVector
var cubicHermite = require('cubic-hermite')
var bsearch = require('binary-search-bounds')
function clamp(lo, hi, x) {
return Math.min(hi, Math.max(lo, x))
}
function FilteredVector(state0, velocity0, t0) {
this.dimension = state0.length
this.bounds = [ new Array(this.dimension), new Array(this.dimension) ]
for(var i=0; i= n-1) {
var ptr = state.length-1
var tf = t - time[n-1]
for(var i=0; i= n-1) {
var ptr = state.length-1
var tf = t - time[n-1]
for(var i=0; i=0; --i) {
if(velocity[--ptr]) {
return false
}
}
return true
}
proto.jump = function(t) {
var t0 = this.lastT()
var d = this.dimension
if(t < t0 || arguments.length !== d+1) {
return
}
var state = this._state
var velocity = this._velocity
var ptr = state.length-this.dimension
var bounds = this.bounds
var lo = bounds[0]
var hi = bounds[1]
this._time.push(t0, t)
for(var j=0; j<2; ++j) {
for(var i=0; i0; --i) {
state.push(clamp(lo[i-1], hi[i-1], arguments[i]))
velocity.push(0)
}
}
proto.push = function(t) {
var t0 = this.lastT()
var d = this.dimension
if(t < t0 || arguments.length !== d+1) {
return
}
var state = this._state
var velocity = this._velocity
var ptr = state.length-this.dimension
var dt = t - t0
var bounds = this.bounds
var lo = bounds[0]
var hi = bounds[1]
var sf = (dt > 1e-6) ? 1/dt : 0
this._time.push(t)
for(var i=d; i>0; --i) {
var xc = clamp(lo[i-1], hi[i-1], arguments[i])
state.push(xc)
velocity.push((xc - state[ptr++]) * sf)
}
}
proto.set = function(t) {
var d = this.dimension
if(t < this.lastT() || arguments.length !== d+1) {
return
}
var state = this._state
var velocity = this._velocity
var bounds = this.bounds
var lo = bounds[0]
var hi = bounds[1]
this._time.push(t)
for(var i=d; i>0; --i) {
state.push(clamp(lo[i-1], hi[i-1], arguments[i]))
velocity.push(0)
}
}
proto.move = function(t) {
var t0 = this.lastT()
var d = this.dimension
if(t <= t0 || arguments.length !== d+1) {
return
}
var state = this._state
var velocity = this._velocity
var statePtr = state.length - this.dimension
var bounds = this.bounds
var lo = bounds[0]
var hi = bounds[1]
var dt = t - t0
var sf = (dt > 1e-6) ? 1/dt : 0.0
this._time.push(t)
for(var i=d; i>0; --i) {
var dx = arguments[i]
state.push(clamp(lo[i-1], hi[i-1], state[statePtr++] + dx))
velocity.push(dx * sf)
}
}
proto.idle = function(t) {
var t0 = this.lastT()
if(t < t0) {
return
}
var d = this.dimension
var state = this._state
var velocity = this._velocity
var statePtr = state.length-d
var bounds = this.bounds
var lo = bounds[0]
var hi = bounds[1]
var dt = t - t0
this._time.push(t)
for(var i=d-1; i>=0; --i) {
state.push(clamp(lo[i], hi[i], state[statePtr] + dt * velocity[statePtr]))
velocity.push(0)
statePtr += 1
}
}
function getZero(d) {
var result = new Array(d)
for(var i=0; i shape[0] - step[0]) {
x = 0
y += step[1]
}
}
// unhack tiny-sdf
sdf.ctx.textAlign = align
sdf.buffer = buffer
return canvas
function getAlignOffset (data) {
var buf = data.data, w = data.width, h = data.height
var top = 0, bottom = 0, x, y, r, line
//find top boundary
for (y = 0; y < h; y++) {
line = y * w * 4
for (x = 0; x < w; x++) {
r = buf[line + x * 4]
if (r > 0) {
top = y
break
}
}
if (top) break
}
//find bottom boundary
for (y = h; y--;) {
line = y * w * 4
for (x = 0; x < w; x++) {
r = buf[line + x * 4]
if (r > 0) {
bottom = y
break
}
}
if (bottom) break
}
return top - .5 * (top + (h - bottom))
}
}
},{"tiny-sdf":525}],131:[function(require,module,exports){
"use strict"
module.exports = createRBTree
var RED = 0
var BLACK = 1
function RBNode(color, key, value, left, right, count) {
this._color = color
this.key = key
this.value = value
this.left = left
this.right = right
this._count = count
}
function cloneNode(node) {
return new RBNode(node._color, node.key, node.value, node.left, node.right, node._count)
}
function repaint(color, node) {
return new RBNode(color, node.key, node.value, node.left, node.right, node._count)
}
function recount(node) {
node._count = 1 + (node.left ? node.left._count : 0) + (node.right ? node.right._count : 0)
}
function RedBlackTree(compare, root) {
this._compare = compare
this.root = root
}
var proto = RedBlackTree.prototype
Object.defineProperty(proto, "keys", {
get: function() {
var result = []
this.forEach(function(k,v) {
result.push(k)
})
return result
}
})
Object.defineProperty(proto, "values", {
get: function() {
var result = []
this.forEach(function(k,v) {
result.push(v)
})
return result
}
})
//Returns the number of nodes in the tree
Object.defineProperty(proto, "length", {
get: function() {
if(this.root) {
return this.root._count
}
return 0
}
})
//Insert a new item into the tree
proto.insert = function(key, value) {
var cmp = this._compare
//Find point to insert new node at
var n = this.root
var n_stack = []
var d_stack = []
while(n) {
var d = cmp(key, n.key)
n_stack.push(n)
d_stack.push(d)
if(d <= 0) {
n = n.left
} else {
n = n.right
}
}
//Rebuild path to leaf node
n_stack.push(new RBNode(RED, key, value, null, null, 1))
for(var s=n_stack.length-2; s>=0; --s) {
var n = n_stack[s]
if(d_stack[s] <= 0) {
n_stack[s] = new RBNode(n._color, n.key, n.value, n_stack[s+1], n.right, n._count+1)
} else {
n_stack[s] = new RBNode(n._color, n.key, n.value, n.left, n_stack[s+1], n._count+1)
}
}
//Rebalance tree using rotations
//console.log("start insert", key, d_stack)
for(var s=n_stack.length-1; s>1; --s) {
var p = n_stack[s-1]
var n = n_stack[s]
if(p._color === BLACK || n._color === BLACK) {
break
}
var pp = n_stack[s-2]
if(pp.left === p) {
if(p.left === n) {
var y = pp.right
if(y && y._color === RED) {
//console.log("LLr")
p._color = BLACK
pp.right = repaint(BLACK, y)
pp._color = RED
s -= 1
} else {
//console.log("LLb")
pp._color = RED
pp.left = p.right
p._color = BLACK
p.right = pp
n_stack[s-2] = p
n_stack[s-1] = n
recount(pp)
recount(p)
if(s >= 3) {
var ppp = n_stack[s-3]
if(ppp.left === pp) {
ppp.left = p
} else {
ppp.right = p
}
}
break
}
} else {
var y = pp.right
if(y && y._color === RED) {
//console.log("LRr")
p._color = BLACK
pp.right = repaint(BLACK, y)
pp._color = RED
s -= 1
} else {
//console.log("LRb")
p.right = n.left
pp._color = RED
pp.left = n.right
n._color = BLACK
n.left = p
n.right = pp
n_stack[s-2] = n
n_stack[s-1] = p
recount(pp)
recount(p)
recount(n)
if(s >= 3) {
var ppp = n_stack[s-3]
if(ppp.left === pp) {
ppp.left = n
} else {
ppp.right = n
}
}
break
}
}
} else {
if(p.right === n) {
var y = pp.left
if(y && y._color === RED) {
//console.log("RRr", y.key)
p._color = BLACK
pp.left = repaint(BLACK, y)
pp._color = RED
s -= 1
} else {
//console.log("RRb")
pp._color = RED
pp.right = p.left
p._color = BLACK
p.left = pp
n_stack[s-2] = p
n_stack[s-1] = n
recount(pp)
recount(p)
if(s >= 3) {
var ppp = n_stack[s-3]
if(ppp.right === pp) {
ppp.right = p
} else {
ppp.left = p
}
}
break
}
} else {
var y = pp.left
if(y && y._color === RED) {
//console.log("RLr")
p._color = BLACK
pp.left = repaint(BLACK, y)
pp._color = RED
s -= 1
} else {
//console.log("RLb")
p.left = n.right
pp._color = RED
pp.right = n.left
n._color = BLACK
n.right = p
n.left = pp
n_stack[s-2] = n
n_stack[s-1] = p
recount(pp)
recount(p)
recount(n)
if(s >= 3) {
var ppp = n_stack[s-3]
if(ppp.right === pp) {
ppp.right = n
} else {
ppp.left = n
}
}
break
}
}
}
}
//Return new tree
n_stack[0]._color = BLACK
return new RedBlackTree(cmp, n_stack[0])
}
//Visit all nodes inorder
function doVisitFull(visit, node) {
if(node.left) {
var v = doVisitFull(visit, node.left)
if(v) { return v }
}
var v = visit(node.key, node.value)
if(v) { return v }
if(node.right) {
return doVisitFull(visit, node.right)
}
}
//Visit half nodes in order
function doVisitHalf(lo, compare, visit, node) {
var l = compare(lo, node.key)
if(l <= 0) {
if(node.left) {
var v = doVisitHalf(lo, compare, visit, node.left)
if(v) { return v }
}
var v = visit(node.key, node.value)
if(v) { return v }
}
if(node.right) {
return doVisitHalf(lo, compare, visit, node.right)
}
}
//Visit all nodes within a range
function doVisit(lo, hi, compare, visit, node) {
var l = compare(lo, node.key)
var h = compare(hi, node.key)
var v
if(l <= 0) {
if(node.left) {
v = doVisit(lo, hi, compare, visit, node.left)
if(v) { return v }
}
if(h > 0) {
v = visit(node.key, node.value)
if(v) { return v }
}
}
if(h > 0 && node.right) {
return doVisit(lo, hi, compare, visit, node.right)
}
}
proto.forEach = function rbTreeForEach(visit, lo, hi) {
if(!this.root) {
return
}
switch(arguments.length) {
case 1:
return doVisitFull(visit, this.root)
break
case 2:
return doVisitHalf(lo, this._compare, visit, this.root)
break
case 3:
if(this._compare(lo, hi) >= 0) {
return
}
return doVisit(lo, hi, this._compare, visit, this.root)
break
}
}
//First item in list
Object.defineProperty(proto, "begin", {
get: function() {
var stack = []
var n = this.root
while(n) {
stack.push(n)
n = n.left
}
return new RedBlackTreeIterator(this, stack)
}
})
//Last item in list
Object.defineProperty(proto, "end", {
get: function() {
var stack = []
var n = this.root
while(n) {
stack.push(n)
n = n.right
}
return new RedBlackTreeIterator(this, stack)
}
})
//Find the ith item in the tree
proto.at = function(idx) {
if(idx < 0) {
return new RedBlackTreeIterator(this, [])
}
var n = this.root
var stack = []
while(true) {
stack.push(n)
if(n.left) {
if(idx < n.left._count) {
n = n.left
continue
}
idx -= n.left._count
}
if(!idx) {
return new RedBlackTreeIterator(this, stack)
}
idx -= 1
if(n.right) {
if(idx >= n.right._count) {
break
}
n = n.right
} else {
break
}
}
return new RedBlackTreeIterator(this, [])
}
proto.ge = function(key) {
var cmp = this._compare
var n = this.root
var stack = []
var last_ptr = 0
while(n) {
var d = cmp(key, n.key)
stack.push(n)
if(d <= 0) {
last_ptr = stack.length
}
if(d <= 0) {
n = n.left
} else {
n = n.right
}
}
stack.length = last_ptr
return new RedBlackTreeIterator(this, stack)
}
proto.gt = function(key) {
var cmp = this._compare
var n = this.root
var stack = []
var last_ptr = 0
while(n) {
var d = cmp(key, n.key)
stack.push(n)
if(d < 0) {
last_ptr = stack.length
}
if(d < 0) {
n = n.left
} else {
n = n.right
}
}
stack.length = last_ptr
return new RedBlackTreeIterator(this, stack)
}
proto.lt = function(key) {
var cmp = this._compare
var n = this.root
var stack = []
var last_ptr = 0
while(n) {
var d = cmp(key, n.key)
stack.push(n)
if(d > 0) {
last_ptr = stack.length
}
if(d <= 0) {
n = n.left
} else {
n = n.right
}
}
stack.length = last_ptr
return new RedBlackTreeIterator(this, stack)
}
proto.le = function(key) {
var cmp = this._compare
var n = this.root
var stack = []
var last_ptr = 0
while(n) {
var d = cmp(key, n.key)
stack.push(n)
if(d >= 0) {
last_ptr = stack.length
}
if(d < 0) {
n = n.left
} else {
n = n.right
}
}
stack.length = last_ptr
return new RedBlackTreeIterator(this, stack)
}
//Finds the item with key if it exists
proto.find = function(key) {
var cmp = this._compare
var n = this.root
var stack = []
while(n) {
var d = cmp(key, n.key)
stack.push(n)
if(d === 0) {
return new RedBlackTreeIterator(this, stack)
}
if(d <= 0) {
n = n.left
} else {
n = n.right
}
}
return new RedBlackTreeIterator(this, [])
}
//Removes item with key from tree
proto.remove = function(key) {
var iter = this.find(key)
if(iter) {
return iter.remove()
}
return this
}
//Returns the item at `key`
proto.get = function(key) {
var cmp = this._compare
var n = this.root
while(n) {
var d = cmp(key, n.key)
if(d === 0) {
return n.value
}
if(d <= 0) {
n = n.left
} else {
n = n.right
}
}
return
}
//Iterator for red black tree
function RedBlackTreeIterator(tree, stack) {
this.tree = tree
this._stack = stack
}
var iproto = RedBlackTreeIterator.prototype
//Test if iterator is valid
Object.defineProperty(iproto, "valid", {
get: function() {
return this._stack.length > 0
}
})
//Node of the iterator
Object.defineProperty(iproto, "node", {
get: function() {
if(this._stack.length > 0) {
return this._stack[this._stack.length-1]
}
return null
},
enumerable: true
})
//Makes a copy of an iterator
iproto.clone = function() {
return new RedBlackTreeIterator(this.tree, this._stack.slice())
}
//Swaps two nodes
function swapNode(n, v) {
n.key = v.key
n.value = v.value
n.left = v.left
n.right = v.right
n._color = v._color
n._count = v._count
}
//Fix up a double black node in a tree
function fixDoubleBlack(stack) {
var n, p, s, z
for(var i=stack.length-1; i>=0; --i) {
n = stack[i]
if(i === 0) {
n._color = BLACK
return
}
//console.log("visit node:", n.key, i, stack[i].key, stack[i-1].key)
p = stack[i-1]
if(p.left === n) {
//console.log("left child")
s = p.right
if(s.right && s.right._color === RED) {
//console.log("case 1: right sibling child red")
s = p.right = cloneNode(s)
z = s.right = cloneNode(s.right)
p.right = s.left
s.left = p
s.right = z
s._color = p._color
n._color = BLACK
p._color = BLACK
z._color = BLACK
recount(p)
recount(s)
if(i > 1) {
var pp = stack[i-2]
if(pp.left === p) {
pp.left = s
} else {
pp.right = s
}
}
stack[i-1] = s
return
} else if(s.left && s.left._color === RED) {
//console.log("case 1: left sibling child red")
s = p.right = cloneNode(s)
z = s.left = cloneNode(s.left)
p.right = z.left
s.left = z.right
z.left = p
z.right = s
z._color = p._color
p._color = BLACK
s._color = BLACK
n._color = BLACK
recount(p)
recount(s)
recount(z)
if(i > 1) {
var pp = stack[i-2]
if(pp.left === p) {
pp.left = z
} else {
pp.right = z
}
}
stack[i-1] = z
return
}
if(s._color === BLACK) {
if(p._color === RED) {
//console.log("case 2: black sibling, red parent", p.right.value)
p._color = BLACK
p.right = repaint(RED, s)
return
} else {
//console.log("case 2: black sibling, black parent", p.right.value)
p.right = repaint(RED, s)
continue
}
} else {
//console.log("case 3: red sibling")
s = cloneNode(s)
p.right = s.left
s.left = p
s._color = p._color
p._color = RED
recount(p)
recount(s)
if(i > 1) {
var pp = stack[i-2]
if(pp.left === p) {
pp.left = s
} else {
pp.right = s
}
}
stack[i-1] = s
stack[i] = p
if(i+1 < stack.length) {
stack[i+1] = n
} else {
stack.push(n)
}
i = i+2
}
} else {
//console.log("right child")
s = p.left
if(s.left && s.left._color === RED) {
//console.log("case 1: left sibling child red", p.value, p._color)
s = p.left = cloneNode(s)
z = s.left = cloneNode(s.left)
p.left = s.right
s.right = p
s.left = z
s._color = p._color
n._color = BLACK
p._color = BLACK
z._color = BLACK
recount(p)
recount(s)
if(i > 1) {
var pp = stack[i-2]
if(pp.right === p) {
pp.right = s
} else {
pp.left = s
}
}
stack[i-1] = s
return
} else if(s.right && s.right._color === RED) {
//console.log("case 1: right sibling child red")
s = p.left = cloneNode(s)
z = s.right = cloneNode(s.right)
p.left = z.right
s.right = z.left
z.right = p
z.left = s
z._color = p._color
p._color = BLACK
s._color = BLACK
n._color = BLACK
recount(p)
recount(s)
recount(z)
if(i > 1) {
var pp = stack[i-2]
if(pp.right === p) {
pp.right = z
} else {
pp.left = z
}
}
stack[i-1] = z
return
}
if(s._color === BLACK) {
if(p._color === RED) {
//console.log("case 2: black sibling, red parent")
p._color = BLACK
p.left = repaint(RED, s)
return
} else {
//console.log("case 2: black sibling, black parent")
p.left = repaint(RED, s)
continue
}
} else {
//console.log("case 3: red sibling")
s = cloneNode(s)
p.left = s.right
s.right = p
s._color = p._color
p._color = RED
recount(p)
recount(s)
if(i > 1) {
var pp = stack[i-2]
if(pp.right === p) {
pp.right = s
} else {
pp.left = s
}
}
stack[i-1] = s
stack[i] = p
if(i+1 < stack.length) {
stack[i+1] = n
} else {
stack.push(n)
}
i = i+2
}
}
}
}
//Removes item at iterator from tree
iproto.remove = function() {
var stack = this._stack
if(stack.length === 0) {
return this.tree
}
//First copy path to node
var cstack = new Array(stack.length)
var n = stack[stack.length-1]
cstack[cstack.length-1] = new RBNode(n._color, n.key, n.value, n.left, n.right, n._count)
for(var i=stack.length-2; i>=0; --i) {
var n = stack[i]
if(n.left === stack[i+1]) {
cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
} else {
cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
}
}
//Get node
n = cstack[cstack.length-1]
//console.log("start remove: ", n.value)
//If not leaf, then swap with previous node
if(n.left && n.right) {
//console.log("moving to leaf")
//First walk to previous leaf
var split = cstack.length
n = n.left
while(n.right) {
cstack.push(n)
n = n.right
}
//Copy path to leaf
var v = cstack[split-1]
cstack.push(new RBNode(n._color, v.key, v.value, n.left, n.right, n._count))
cstack[split-1].key = n.key
cstack[split-1].value = n.value
//Fix up stack
for(var i=cstack.length-2; i>=split; --i) {
n = cstack[i]
cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
}
cstack[split-1].left = cstack[split]
}
//console.log("stack=", cstack.map(function(v) { return v.value }))
//Remove leaf node
n = cstack[cstack.length-1]
if(n._color === RED) {
//Easy case: removing red leaf
//console.log("RED leaf")
var p = cstack[cstack.length-2]
if(p.left === n) {
p.left = null
} else if(p.right === n) {
p.right = null
}
cstack.pop()
for(var i=0; i 0) {
return this._stack[this._stack.length-1].key
}
return
},
enumerable: true
})
//Returns value
Object.defineProperty(iproto, "value", {
get: function() {
if(this._stack.length > 0) {
return this._stack[this._stack.length-1].value
}
return
},
enumerable: true
})
//Returns the position of this iterator in the sorted list
Object.defineProperty(iproto, "index", {
get: function() {
var idx = 0
var stack = this._stack
if(stack.length === 0) {
var r = this.tree.root
if(r) {
return r._count
}
return 0
} else if(stack[stack.length-1].left) {
idx = stack[stack.length-1].left._count
}
for(var s=stack.length-2; s>=0; --s) {
if(stack[s+1] === stack[s].right) {
++idx
if(stack[s].left) {
idx += stack[s].left._count
}
}
}
return idx
},
enumerable: true
})
//Advances iterator to next element in list
iproto.next = function() {
var stack = this._stack
if(stack.length === 0) {
return
}
var n = stack[stack.length-1]
if(n.right) {
n = n.right
while(n) {
stack.push(n)
n = n.left
}
} else {
stack.pop()
while(stack.length > 0 && stack[stack.length-1].right === n) {
n = stack[stack.length-1]
stack.pop()
}
}
}
//Checks if iterator is at end of tree
Object.defineProperty(iproto, "hasNext", {
get: function() {
var stack = this._stack
if(stack.length === 0) {
return false
}
if(stack[stack.length-1].right) {
return true
}
for(var s=stack.length-1; s>0; --s) {
if(stack[s-1].left === stack[s]) {
return true
}
}
return false
}
})
//Update value
iproto.update = function(value) {
var stack = this._stack
if(stack.length === 0) {
throw new Error("Can't update empty node!")
}
var cstack = new Array(stack.length)
var n = stack[stack.length-1]
cstack[cstack.length-1] = new RBNode(n._color, n.key, value, n.left, n.right, n._count)
for(var i=stack.length-2; i>=0; --i) {
n = stack[i]
if(n.left === stack[i+1]) {
cstack[i] = new RBNode(n._color, n.key, n.value, cstack[i+1], n.right, n._count)
} else {
cstack[i] = new RBNode(n._color, n.key, n.value, n.left, cstack[i+1], n._count)
}
}
return new RedBlackTree(this.tree._compare, cstack[0])
}
//Moves iterator backward one element
iproto.prev = function() {
var stack = this._stack
if(stack.length === 0) {
return
}
var n = stack[stack.length-1]
if(n.left) {
n = n.left
while(n) {
stack.push(n)
n = n.right
}
} else {
stack.pop()
while(stack.length > 0 && stack[stack.length-1].left === n) {
n = stack[stack.length-1]
stack.pop()
}
}
}
//Checks if iterator is at start of tree
Object.defineProperty(iproto, "hasPrev", {
get: function() {
var stack = this._stack
if(stack.length === 0) {
return false
}
if(stack[stack.length-1].left) {
return true
}
for(var s=stack.length-1; s>0; --s) {
if(stack[s-1].right === stack[s]) {
return true
}
}
return false
}
})
//Default comparison function
function defaultCompare(a, b) {
if(a < b) {
return -1
}
if(a > b) {
return 1
}
return 0
}
//Build a tree
function createRBTree(compare) {
return new RedBlackTree(compare || defaultCompare, null)
}
},{}],132:[function(require,module,exports){
// transliterated from the python snippet here:
// http://en.wikipedia.org/wiki/Lanczos_approximation
var g = 7;
var p = [
0.99999999999980993,
676.5203681218851,
-1259.1392167224028,
771.32342877765313,
-176.61502916214059,
12.507343278686905,
-0.13857109526572012,
9.9843695780195716e-6,
1.5056327351493116e-7
];
var g_ln = 607/128;
var p_ln = [
0.99999999999999709182,
57.156235665862923517,
-59.597960355475491248,
14.136097974741747174,
-0.49191381609762019978,
0.33994649984811888699e-4,
0.46523628927048575665e-4,
-0.98374475304879564677e-4,
0.15808870322491248884e-3,
-0.21026444172410488319e-3,
0.21743961811521264320e-3,
-0.16431810653676389022e-3,
0.84418223983852743293e-4,
-0.26190838401581408670e-4,
0.36899182659531622704e-5
];
// Spouge approximation (suitable for large arguments)
function lngamma(z) {
if(z < 0) return Number('0/0');
var x = p_ln[0];
for(var i = p_ln.length - 1; i > 0; --i) x += p_ln[i] / (z + i);
var t = z + g_ln + 0.5;
return .5*Math.log(2*Math.PI)+(z+.5)*Math.log(t)-t+Math.log(x)-Math.log(z);
}
module.exports = function gamma (z) {
if (z < 0.5) {
return Math.PI / (Math.sin(Math.PI * z) * gamma(1 - z));
}
else if(z > 100) return Math.exp(lngamma(z));
else {
z -= 1;
var x = p[0];
for (var i = 1; i < g + 2; i++) {
x += p[i] / (z + i);
}
var t = z + g + 0.5;
return Math.sqrt(2 * Math.PI)
* Math.pow(t, z + 0.5)
* Math.exp(-t)
* x
;
}
};
module.exports.log = lngamma;
},{}],133:[function(require,module,exports){
var wgs84 = require('wgs84');
module.exports.geometry = geometry;
module.exports.ring = ringArea;
function geometry(_) {
if (_.type === 'Polygon') return polygonArea(_.coordinates);
else if (_.type === 'MultiPolygon') {
var area = 0;
for (var i = 0; i < _.coordinates.length; i++) {
area += polygonArea(_.coordinates[i]);
}
return area;
} else {
return null;
}
}
function polygonArea(coords) {
var area = 0;
if (coords && coords.length > 0) {
area += Math.abs(ringArea(coords[0]));
for (var i = 1; i < coords.length; i++) {
area -= Math.abs(ringArea(coords[i]));
}
}
return area;
}
/**
* Calculate the approximate area of the polygon were it projected onto
* the earth. Note that this area will be positive if ring is oriented
* clockwise, otherwise it will be negative.
*
* Reference:
* Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
* Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
* Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
*
* Returns:
* {float} The approximate signed geodesic area of the polygon in square
* meters.
*/
function ringArea(coords) {
var area = 0;
if (coords.length > 2) {
var p1, p2;
for (var i = 0; i < coords.length - 1; i++) {
p1 = coords[i];
p2 = coords[i + 1];
area += rad(p2[0] - p1[0]) * (2 + Math.sin(rad(p1[1])) + Math.sin(rad(p2[1])));
}
area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
}
return area;
}
function rad(_) {
return _ * Math.PI / 180;
}
},{"wgs84":557}],134:[function(require,module,exports){
var geojsonArea = require('geojson-area');
module.exports = rewind;
function rewind(gj, outer) {
switch ((gj && gj.type) || null) {
case 'FeatureCollection':
gj.features = gj.features.map(curryOuter(rewind, outer));
return gj;
case 'Feature':
gj.geometry = rewind(gj.geometry, outer);
return gj;
case 'Polygon':
case 'MultiPolygon':
return correct(gj, outer);
default:
return gj;
}
}
function curryOuter(a, b) {
return function(_) { return a(_, b); };
}
function correct(_, outer) {
if (_.type === 'Polygon') {
_.coordinates = correctRings(_.coordinates, outer);
} else if (_.type === 'MultiPolygon') {
_.coordinates = _.coordinates.map(curryOuter(correctRings, outer));
}
return _;
}
function correctRings(_, outer) {
outer = !!outer;
_[0] = wind(_[0], !outer);
for (var i = 1; i < _.length; i++) {
_[i] = wind(_[i], outer);
}
return _;
}
function wind(_, dir) {
return cw(_) === dir ? _ : _.reverse();
}
function cw(_) {
return geojsonArea.ring(_) >= 0;
}
},{"geojson-area":133}],135:[function(require,module,exports){
'use strict';
module.exports = clip;
var createFeature = require('./feature');
/* clip features between two axis-parallel lines:
* | |
* ___|___ | /
* / | \____|____/
* | |
*/
function clip(features, scale, k1, k2, axis, intersect, minAll, maxAll) {
k1 /= scale;
k2 /= scale;
if (minAll >= k1 && maxAll <= k2) return features; // trivial accept
else if (minAll > k2 || maxAll < k1) return null; // trivial reject
var clipped = [];
for (var i = 0; i < features.length; i++) {
var feature = features[i],
geometry = feature.geometry,
type = feature.type,
min, max;
min = feature.min[axis];
max = feature.max[axis];
if (min >= k1 && max <= k2) { // trivial accept
clipped.push(feature);
continue;
} else if (min > k2 || max < k1) continue; // trivial reject
var slices = type === 1 ?
clipPoints(geometry, k1, k2, axis) :
clipGeometry(geometry, k1, k2, axis, intersect, type === 3);
if (slices.length) {
// if a feature got clipped, it will likely get clipped on the next zoom level as well,
// so there's no need to recalculate bboxes
clipped.push(createFeature(feature.tags, type, slices, feature.id));
}
}
return clipped.length ? clipped : null;
}
function clipPoints(geometry, k1, k2, axis) {
var slice = [];
for (var i = 0; i < geometry.length; i++) {
var a = geometry[i],
ak = a[axis];
if (ak >= k1 && ak <= k2) slice.push(a);
}
return slice;
}
function clipGeometry(geometry, k1, k2, axis, intersect, closed) {
var slices = [];
for (var i = 0; i < geometry.length; i++) {
var ak = 0,
bk = 0,
b = null,
points = geometry[i],
area = points.area,
dist = points.dist,
outer = points.outer,
len = points.length,
a, j, last;
var slice = [];
for (j = 0; j < len - 1; j++) {
a = b || points[j];
b = points[j + 1];
ak = bk || a[axis];
bk = b[axis];
if (ak < k1) {
if ((bk > k2)) { // ---|-----|-->
slice.push(intersect(a, b, k1), intersect(a, b, k2));
if (!closed) slice = newSlice(slices, slice, area, dist, outer);
} else if (bk >= k1) slice.push(intersect(a, b, k1)); // ---|--> |
} else if (ak > k2) {
if ((bk < k1)) { // <--|-----|---
slice.push(intersect(a, b, k2), intersect(a, b, k1));
if (!closed) slice = newSlice(slices, slice, area, dist, outer);
} else if (bk <= k2) slice.push(intersect(a, b, k2)); // | <--|---
} else {
slice.push(a);
if (bk < k1) { // <--|--- |
slice.push(intersect(a, b, k1));
if (!closed) slice = newSlice(slices, slice, area, dist, outer);
} else if (bk > k2) { // | ---|-->
slice.push(intersect(a, b, k2));
if (!closed) slice = newSlice(slices, slice, area, dist, outer);
}
// | --> |
}
}
// add the last point
a = points[len - 1];
ak = a[axis];
if (ak >= k1 && ak <= k2) slice.push(a);
// close the polygon if its endpoints are not the same after clipping
last = slice[slice.length - 1];
if (closed && last && (slice[0][0] !== last[0] || slice[0][1] !== last[1])) slice.push(slice[0]);
// add the final slice
newSlice(slices, slice, area, dist, outer);
}
return slices;
}
function newSlice(slices, slice, area, dist, outer) {
if (slice.length) {
// we don't recalculate the area/length of the unclipped geometry because the case where it goes
// below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work
slice.area = area;
slice.dist = dist;
if (outer !== undefined) slice.outer = outer;
slices.push(slice);
}
return [];
}
},{"./feature":137}],136:[function(require,module,exports){
'use strict';
module.exports = convert;
var simplify = require('./simplify');
var createFeature = require('./feature');
// converts GeoJSON feature into an intermediate projected JSON vector format with simplification data
function convert(data, tolerance) {
var features = [];
if (data.type === 'FeatureCollection') {
for (var i = 0; i < data.features.length; i++) {
convertFeature(features, data.features[i], tolerance);
}
} else if (data.type === 'Feature') {
convertFeature(features, data, tolerance);
} else {
// single geometry or a geometry collection
convertFeature(features, {geometry: data}, tolerance);
}
return features;
}
function convertFeature(features, feature, tolerance) {
if (feature.geometry === null) {
// ignore features with null geometry
return;
}
var geom = feature.geometry,
type = geom.type,
coords = geom.coordinates,
tags = feature.properties,
id = feature.id,
i, j, rings, projectedRing;
if (type === 'Point') {
features.push(createFeature(tags, 1, [projectPoint(coords)], id));
} else if (type === 'MultiPoint') {
features.push(createFeature(tags, 1, project(coords), id));
} else if (type === 'LineString') {
features.push(createFeature(tags, 2, [project(coords, tolerance)], id));
} else if (type === 'MultiLineString' || type === 'Polygon') {
rings = [];
for (i = 0; i < coords.length; i++) {
projectedRing = project(coords[i], tolerance);
if (type === 'Polygon') projectedRing.outer = (i === 0);
rings.push(projectedRing);
}
features.push(createFeature(tags, type === 'Polygon' ? 3 : 2, rings, id));
} else if (type === 'MultiPolygon') {
rings = [];
for (i = 0; i < coords.length; i++) {
for (j = 0; j < coords[i].length; j++) {
projectedRing = project(coords[i][j], tolerance);
projectedRing.outer = (j === 0);
rings.push(projectedRing);
}
}
features.push(createFeature(tags, 3, rings, id));
} else if (type === 'GeometryCollection') {
for (i = 0; i < geom.geometries.length; i++) {
convertFeature(features, {
geometry: geom.geometries[i],
properties: tags
}, tolerance);
}
} else {
throw new Error('Input data is not a valid GeoJSON object.');
}
}
function project(lonlats, tolerance) {
var projected = [];
for (var i = 0; i < lonlats.length; i++) {
projected.push(projectPoint(lonlats[i]));
}
if (tolerance) {
simplify(projected, tolerance);
calcSize(projected);
}
return projected;
}
function projectPoint(p) {
var sin = Math.sin(p[1] * Math.PI / 180),
x = (p[0] / 360 + 0.5),
y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
y = y < 0 ? 0 :
y > 1 ? 1 : y;
return [x, y, 0];
}
// calculate area and length of the poly
function calcSize(points) {
var area = 0,
dist = 0;
for (var i = 0, a, b; i < points.length - 1; i++) {
a = b || points[i];
b = points[i + 1];
area += a[0] * b[1] - b[0] * a[1];
// use Manhattan distance instead of Euclidian one to avoid expensive square root computation
dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]);
}
points.area = Math.abs(area / 2);
points.dist = dist;
}
},{"./feature":137,"./simplify":139}],137:[function(require,module,exports){
'use strict';
module.exports = createFeature;
function createFeature(tags, type, geom, id) {
var feature = {
id: id || null,
type: type,
geometry: geom,
tags: tags || null,
min: [Infinity, Infinity], // initial bbox values
max: [-Infinity, -Infinity]
};
calcBBox(feature);
return feature;
}
// calculate the feature bounding box for faster clipping later
function calcBBox(feature) {
var geometry = feature.geometry,
min = feature.min,
max = feature.max;
if (feature.type === 1) {
calcRingBBox(min, max, geometry);
} else {
for (var i = 0; i < geometry.length; i++) {
calcRingBBox(min, max, geometry[i]);
}
}
return feature;
}
function calcRingBBox(min, max, points) {
for (var i = 0, p; i < points.length; i++) {
p = points[i];
min[0] = Math.min(p[0], min[0]);
max[0] = Math.max(p[0], max[0]);
min[1] = Math.min(p[1], min[1]);
max[1] = Math.max(p[1], max[1]);
}
}
},{}],138:[function(require,module,exports){
'use strict';
module.exports = geojsonvt;
var convert = require('./convert'), // GeoJSON conversion and preprocessing
transform = require('./transform'), // coordinate transformation
clip = require('./clip'), // stripe clipping algorithm
wrap = require('./wrap'), // date line processing
createTile = require('./tile'); // final simplified tile generation
function geojsonvt(data, options) {
return new GeoJSONVT(data, options);
}
function GeoJSONVT(data, options) {
options = this.options = extend(Object.create(this.options), options);
var debug = options.debug;
if (debug) console.time('preprocess data');
var z2 = 1 << options.maxZoom, // 2^z
features = convert(data, options.tolerance / (z2 * options.extent));
this.tiles = {};
this.tileCoords = [];
if (debug) {
console.timeEnd('preprocess data');
console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints);
console.time('generate tiles');
this.stats = {};
this.total = 0;
}
features = wrap(features, options.buffer / options.extent, intersectX);
// start slicing from the top tile down
if (features.length) this.splitTile(features, 0, 0, 0);
if (debug) {
if (features.length) console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints);
console.timeEnd('generate tiles');
console.log('tiles generated:', this.total, JSON.stringify(this.stats));
}
}
GeoJSONVT.prototype.options = {
maxZoom: 14, // max zoom to preserve detail on
indexMaxZoom: 5, // max zoom in the tile index
indexMaxPoints: 100000, // max number of points per tile in the tile index
solidChildren: false, // whether to tile solid square tiles further
tolerance: 3, // simplification tolerance (higher means simpler)
extent: 4096, // tile extent
buffer: 64, // tile buffer on each side
debug: 0 // logging level (0, 1 or 2)
};
GeoJSONVT.prototype.splitTile = function (features, z, x, y, cz, cx, cy) {
var stack = [features, z, x, y],
options = this.options,
debug = options.debug,
solid = null;
// avoid recursion by using a processing queue
while (stack.length) {
y = stack.pop();
x = stack.pop();
z = stack.pop();
features = stack.pop();
var z2 = 1 << z,
id = toID(z, x, y),
tile = this.tiles[id],
tileTolerance = z === options.maxZoom ? 0 : options.tolerance / (z2 * options.extent);
if (!tile) {
if (debug > 1) console.time('creation');
tile = this.tiles[id] = createTile(features, z2, x, y, tileTolerance, z === options.maxZoom);
this.tileCoords.push({z: z, x: x, y: y});
if (debug) {
if (debug > 1) {
console.log('tile z%d-%d-%d (features: %d, points: %d, simplified: %d)',
z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified);
console.timeEnd('creation');
}
var key = 'z' + z;
this.stats[key] = (this.stats[key] || 0) + 1;
this.total++;
}
}
// save reference to original geometry in tile so that we can drill down later if we stop now
tile.source = features;
// if it's the first-pass tiling
if (!cz) {
// stop tiling if we reached max zoom, or if the tile is too simple
if (z === options.indexMaxZoom || tile.numPoints <= options.indexMaxPoints) continue;
// if a drilldown to a specific tile
} else {
// stop tiling if we reached base zoom or our target tile zoom
if (z === options.maxZoom || z === cz) continue;
// stop tiling if it's not an ancestor of the target tile
var m = 1 << (cz - z);
if (x !== Math.floor(cx / m) || y !== Math.floor(cy / m)) continue;
}
// stop tiling if the tile is solid clipped square
if (!options.solidChildren && isClippedSquare(tile, options.extent, options.buffer)) {
if (cz) solid = z; // and remember the zoom if we're drilling down
continue;
}
// if we slice further down, no need to keep source geometry
tile.source = null;
if (debug > 1) console.time('clipping');
// values we'll use for clipping
var k1 = 0.5 * options.buffer / options.extent,
k2 = 0.5 - k1,
k3 = 0.5 + k1,
k4 = 1 + k1,
tl, bl, tr, br, left, right;
tl = bl = tr = br = null;
left = clip(features, z2, x - k1, x + k3, 0, intersectX, tile.min[0], tile.max[0]);
right = clip(features, z2, x + k2, x + k4, 0, intersectX, tile.min[0], tile.max[0]);
if (left) {
tl = clip(left, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]);
bl = clip(left, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]);
}
if (right) {
tr = clip(right, z2, y - k1, y + k3, 1, intersectY, tile.min[1], tile.max[1]);
br = clip(right, z2, y + k2, y + k4, 1, intersectY, tile.min[1], tile.max[1]);
}
if (debug > 1) console.timeEnd('clipping');
if (features.length) {
stack.push(tl || [], z + 1, x * 2, y * 2);
stack.push(bl || [], z + 1, x * 2, y * 2 + 1);
stack.push(tr || [], z + 1, x * 2 + 1, y * 2);
stack.push(br || [], z + 1, x * 2 + 1, y * 2 + 1);
}
}
return solid;
};
GeoJSONVT.prototype.getTile = function (z, x, y) {
var options = this.options,
extent = options.extent,
debug = options.debug;
var z2 = 1 << z;
x = ((x % z2) + z2) % z2; // wrap tile x coordinate
var id = toID(z, x, y);
if (this.tiles[id]) return transform.tile(this.tiles[id], extent);
if (debug > 1) console.log('drilling down to z%d-%d-%d', z, x, y);
var z0 = z,
x0 = x,
y0 = y,
parent;
while (!parent && z0 > 0) {
z0--;
x0 = Math.floor(x0 / 2);
y0 = Math.floor(y0 / 2);
parent = this.tiles[toID(z0, x0, y0)];
}
if (!parent || !parent.source) return null;
// if we found a parent tile containing the original geometry, we can drill down from it
if (debug > 1) console.log('found parent tile z%d-%d-%d', z0, x0, y0);
// it parent tile is a solid clipped square, return it instead since it's identical
if (isClippedSquare(parent, extent, options.buffer)) return transform.tile(parent, extent);
if (debug > 1) console.time('drilling down');
var solid = this.splitTile(parent.source, z0, x0, y0, z, x, y);
if (debug > 1) console.timeEnd('drilling down');
// one of the parent tiles was a solid clipped square
if (solid !== null) {
var m = 1 << (z - solid);
id = toID(solid, Math.floor(x / m), Math.floor(y / m));
}
return this.tiles[id] ? transform.tile(this.tiles[id], extent) : null;
};
function toID(z, x, y) {
return (((1 << z) * y + x) * 32) + z;
}
function intersectX(a, b, x) {
return [x, (x - a[0]) * (b[1] - a[1]) / (b[0] - a[0]) + a[1], 1];
}
function intersectY(a, b, y) {
return [(y - a[1]) * (b[0] - a[0]) / (b[1] - a[1]) + a[0], y, 1];
}
function extend(dest, src) {
for (var i in src) dest[i] = src[i];
return dest;
}
// checks whether a tile is a whole-area fill after clipping; if it is, there's no sense slicing it further
function isClippedSquare(tile, extent, buffer) {
var features = tile.source;
if (features.length !== 1) return false;
var feature = features[0];
if (feature.type !== 3 || feature.geometry.length > 1) return false;
var len = feature.geometry[0].length;
if (len !== 5) return false;
for (var i = 0; i < len; i++) {
var p = transform.point(feature.geometry[0][i], extent, tile.z2, tile.x, tile.y);
if ((p[0] !== -buffer && p[0] !== extent + buffer) ||
(p[1] !== -buffer && p[1] !== extent + buffer)) return false;
}
return true;
}
},{"./clip":135,"./convert":136,"./tile":140,"./transform":141,"./wrap":142}],139:[function(require,module,exports){
'use strict';
module.exports = simplify;
// calculate simplification data using optimized Douglas-Peucker algorithm
function simplify(points, tolerance) {
var sqTolerance = tolerance * tolerance,
len = points.length,
first = 0,
last = len - 1,
stack = [],
i, maxSqDist, sqDist, index;
// always retain the endpoints (1 is the max value)
points[first][2] = 1;
points[last][2] = 1;
// avoid recursion by using a stack
while (last) {
maxSqDist = 0;
for (i = first + 1; i < last; i++) {
sqDist = getSqSegDist(points[i], points[first], points[last]);
if (sqDist > maxSqDist) {
index = i;
maxSqDist = sqDist;
}
}
if (maxSqDist > sqTolerance) {
points[index][2] = maxSqDist; // save the point importance in squared pixels as a z coordinate
stack.push(first);
stack.push(index);
first = index;
} else {
last = stack.pop();
first = stack.pop();
}
}
}
// square distance from a point to a segment
function getSqSegDist(p, a, b) {
var x = a[0], y = a[1],
bx = b[0], by = b[1],
px = p[0], py = p[1],
dx = bx - x,
dy = by - y;
if (dx !== 0 || dy !== 0) {
var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x = bx;
y = by;
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}
dx = px - x;
dy = py - y;
return dx * dx + dy * dy;
}
},{}],140:[function(require,module,exports){
'use strict';
module.exports = createTile;
function createTile(features, z2, tx, ty, tolerance, noSimplify) {
var tile = {
features: [],
numPoints: 0,
numSimplified: 0,
numFeatures: 0,
source: null,
x: tx,
y: ty,
z2: z2,
transformed: false,
min: [2, 1],
max: [-1, 0]
};
for (var i = 0; i < features.length; i++) {
tile.numFeatures++;
addFeature(tile, features[i], tolerance, noSimplify);
var min = features[i].min,
max = features[i].max;
if (min[0] < tile.min[0]) tile.min[0] = min[0];
if (min[1] < tile.min[1]) tile.min[1] = min[1];
if (max[0] > tile.max[0]) tile.max[0] = max[0];
if (max[1] > tile.max[1]) tile.max[1] = max[1];
}
return tile;
}
function addFeature(tile, feature, tolerance, noSimplify) {
var geom = feature.geometry,
type = feature.type,
simplified = [],
sqTolerance = tolerance * tolerance,
i, j, ring, p;
if (type === 1) {
for (i = 0; i < geom.length; i++) {
simplified.push(geom[i]);
tile.numPoints++;
tile.numSimplified++;
}
} else {
// simplify and transform projected coordinates for tile geometry
for (i = 0; i < geom.length; i++) {
ring = geom[i];
// filter out tiny polylines & polygons
if (!noSimplify && ((type === 2 && ring.dist < tolerance) ||
(type === 3 && ring.area < sqTolerance))) {
tile.numPoints += ring.length;
continue;
}
var simplifiedRing = [];
for (j = 0; j < ring.length; j++) {
p = ring[j];
// keep points with importance > tolerance
if (noSimplify || p[2] > sqTolerance) {
simplifiedRing.push(p);
tile.numSimplified++;
}
tile.numPoints++;
}
if (type === 3) rewind(simplifiedRing, ring.outer);
simplified.push(simplifiedRing);
}
}
if (simplified.length) {
var tileFeature = {
geometry: simplified,
type: type,
tags: feature.tags || null
};
if (feature.id !== null) {
tileFeature.id = feature.id;
}
tile.features.push(tileFeature);
}
}
function rewind(ring, clockwise) {
var area = signedArea(ring);
if (area < 0 === clockwise) ring.reverse();
}
function signedArea(ring) {
var sum = 0;
for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
p1 = ring[i];
p2 = ring[j];
sum += (p2[0] - p1[0]) * (p1[1] + p2[1]);
}
return sum;
}
},{}],141:[function(require,module,exports){
'use strict';
exports.tile = transformTile;
exports.point = transformPoint;
// Transforms the coordinates of each feature in the given tile from
// mercator-projected space into (extent x extent) tile space.
function transformTile(tile, extent) {
if (tile.transformed) return tile;
var z2 = tile.z2,
tx = tile.x,
ty = tile.y,
i, j, k;
for (i = 0; i < tile.features.length; i++) {
var feature = tile.features[i],
geom = feature.geometry,
type = feature.type;
if (type === 1) {
for (j = 0; j < geom.length; j++) geom[j] = transformPoint(geom[j], extent, z2, tx, ty);
} else {
for (j = 0; j < geom.length; j++) {
var ring = geom[j];
for (k = 0; k < ring.length; k++) ring[k] = transformPoint(ring[k], extent, z2, tx, ty);
}
}
}
tile.transformed = true;
return tile;
}
function transformPoint(p, extent, z2, tx, ty) {
var x = Math.round(extent * (p[0] * z2 - tx)),
y = Math.round(extent * (p[1] * z2 - ty));
return [x, y];
}
},{}],142:[function(require,module,exports){
'use strict';
var clip = require('./clip');
var createFeature = require('./feature');
module.exports = wrap;
function wrap(features, buffer, intersectX) {
var merged = features,
left = clip(features, 1, -1 - buffer, buffer, 0, intersectX, -1, 2), // left world copy
right = clip(features, 1, 1 - buffer, 2 + buffer, 0, intersectX, -1, 2); // right world copy
if (left || right) {
merged = clip(features, 1, -buffer, 1 + buffer, 0, intersectX, -1, 2) || []; // center world copy
if (left) merged = shiftFeatureCoords(left, 1).concat(merged); // merge left into center
if (right) merged = merged.concat(shiftFeatureCoords(right, -1)); // merge right into center
}
return merged;
}
function shiftFeatureCoords(features, offset) {
var newFeatures = [];
for (var i = 0; i < features.length; i++) {
var feature = features[i],
type = feature.type;
var newGeometry;
if (type === 1) {
newGeometry = shiftCoords(feature.geometry, offset);
} else {
newGeometry = [];
for (var j = 0; j < feature.geometry.length; j++) {
newGeometry.push(shiftCoords(feature.geometry[j], offset));
}
}
newFeatures.push(createFeature(feature.tags, type, newGeometry, feature.id));
}
return newFeatures;
}
function shiftCoords(points, offset) {
var newPoints = [];
newPoints.area = points.area;
newPoints.dist = points.dist;
for (var i = 0; i < points.length; i++) {
newPoints.push([points[i][0] + offset, points[i][1], points[i][2]]);
}
return newPoints;
}
},{"./clip":135,"./feature":137}],143:[function(require,module,exports){
module.exports = getCanvasContext
function getCanvasContext (type, opts) {
if (typeof type !== 'string') {
throw new TypeError('must specify type string')
}
opts = opts || {}
if (typeof document === 'undefined' && !opts.canvas) {
return null // check for Node
}
var canvas = opts.canvas || document.createElement('canvas')
if (typeof opts.width === 'number') {
canvas.width = opts.width
}
if (typeof opts.height === 'number') {
canvas.height = opts.height
}
var attribs = opts
var gl
try {
var names = [ type ]
// prefix GL contexts
if (type.indexOf('webgl') === 0) {
names.push('experimental-' + type)
}
for (var i = 0; i < names.length; i++) {
gl = canvas.getContext(names[i], attribs)
if (gl) return gl
}
} catch (e) {
gl = null
}
return (gl || null) // ensure null on fail
}
},{}],144:[function(require,module,exports){
'use strict'
module.exports = createAxes
var createText = require('./lib/text.js')
var createLines = require('./lib/lines.js')
var createBackground = require('./lib/background.js')
var getCubeProperties = require('./lib/cube.js')
var Ticks = require('./lib/ticks.js')
var identity = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1])
function copyVec3(a, b) {
a[0] = b[0]
a[1] = b[1]
a[2] = b[2]
return a
}
function Axes(gl) {
this.gl = gl
this.pixelRatio = 1
this.bounds = [ [-10, -10, -10],
[ 10, 10, 10] ]
this.ticks = [ [], [], [] ]
this.autoTicks = true
this.tickSpacing = [ 1, 1, 1 ]
this.tickEnable = [ true, true, true ]
this.tickFont = [ 'sans-serif', 'sans-serif', 'sans-serif' ]
this.tickSize = [ 12, 12, 12 ]
this.tickAngle = [ 0, 0, 0 ]
this.tickColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.tickPad = [ 10, 10, 10 ]
this.lastCubeProps = {
cubeEdges: [0,0,0],
axis: [0,0,0]
}
this.labels = [ 'x', 'y', 'z' ]
this.labelEnable = [ true, true, true ]
this.labelFont = 'sans-serif'
this.labelSize = [ 20, 20, 20 ]
this.labelAngle = [ 0, 0, 0 ]
this.labelColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.labelPad = [ 10, 10, 10 ]
this.lineEnable = [ true, true, true ]
this.lineMirror = [ false, false, false ]
this.lineWidth = [ 1, 1, 1 ]
this.lineColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.lineTickEnable = [ true, true, true ]
this.lineTickMirror = [ false, false, false ]
this.lineTickLength = [ 0, 0, 0 ]
this.lineTickWidth = [ 1, 1, 1 ]
this.lineTickColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.gridEnable = [ true, true, true ]
this.gridWidth = [ 1, 1, 1 ]
this.gridColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.zeroEnable = [ true, true, true ]
this.zeroLineColor = [ [0,0,0,1], [0,0,0,1], [0,0,0,1] ]
this.zeroLineWidth = [ 2, 2, 2 ]
this.backgroundEnable = [ false, false, false ]
this.backgroundColor = [ [0.8, 0.8, 0.8, 0.5],
[0.8, 0.8, 0.8, 0.5],
[0.8, 0.8, 0.8, 0.5] ]
this._firstInit = true
this._text = null
this._lines = null
this._background = createBackground(gl)
}
var proto = Axes.prototype
proto.update = function(options) {
options = options || {}
//Option parsing helper functions
function parseOption(nest, cons, name) {
if(name in options) {
var opt = options[name]
var prev = this[name]
var next
if(nest ? (Array.isArray(opt) && Array.isArray(opt[0])) :
Array.isArray(opt) ) {
this[name] = next = [ cons(opt[0]), cons(opt[1]), cons(opt[2]) ]
} else {
this[name] = next = [ cons(opt), cons(opt), cons(opt) ]
}
for(var i=0; i<3; ++i) {
if(next[i] !== prev[i]) {
return true
}
}
}
return false
}
var NUMBER = parseOption.bind(this, false, Number)
var BOOLEAN = parseOption.bind(this, false, Boolean)
var STRING = parseOption.bind(this, false, String)
var COLOR = parseOption.bind(this, true, function(v) {
if(Array.isArray(v)) {
if(v.length === 3) {
return [ +v[0], +v[1], +v[2], 1.0 ]
} else if(v.length === 4) {
return [ +v[0], +v[1], +v[2], +v[3] ]
}
}
return [ 0, 0, 0, 1 ]
})
//Tick marks and bounds
var nextTicks
var ticksUpdate = false
var boundsChanged = false
if('bounds' in options) {
var bounds = options.bounds
i_loop:
for(var i=0; i<2; ++i) {
for(var j=0; j<3; ++j) {
if(bounds[i][j] !== this.bounds[i][j]) {
boundsChanged = true
}
this.bounds[i][j] = bounds[i][j]
}
}
}
if('ticks' in options) {
nextTicks = options.ticks
ticksUpdate = true
this.autoTicks = false
for(var i=0; i<3; ++i) {
this.tickSpacing[i] = 0.0
}
} else if(NUMBER('tickSpacing')) {
this.autoTicks = true
boundsChanged = true
}
if(this._firstInit) {
if(!('ticks' in options || 'tickSpacing' in options)) {
this.autoTicks = true
}
//Force tick recomputation on first update
boundsChanged = true
ticksUpdate = true
this._firstInit = false
}
if(boundsChanged && this.autoTicks) {
nextTicks = Ticks.create(this.bounds, this.tickSpacing)
ticksUpdate = true
}
//Compare next ticks to previous ticks, only update if needed
if(ticksUpdate) {
for(var i=0; i<3; ++i) {
nextTicks[i].sort(function(a,b) {
return a.x-b.x
})
}
if(Ticks.equal(nextTicks, this.ticks)) {
ticksUpdate = false
} else {
this.ticks = nextTicks
}
}
//Parse tick properties
BOOLEAN('tickEnable')
if(STRING('tickFont')) {
ticksUpdate = true //If font changes, must rebuild vbo
}
NUMBER('tickSize')
NUMBER('tickAngle')
NUMBER('tickPad')
COLOR('tickColor')
//Axis labels
var labelUpdate = STRING('labels')
if(STRING('labelFont')) {
labelUpdate = true
}
BOOLEAN('labelEnable')
NUMBER('labelSize')
NUMBER('labelPad')
COLOR('labelColor')
//Axis lines
BOOLEAN('lineEnable')
BOOLEAN('lineMirror')
NUMBER('lineWidth')
COLOR('lineColor')
//Axis line ticks
BOOLEAN('lineTickEnable')
BOOLEAN('lineTickMirror')
NUMBER('lineTickLength')
NUMBER('lineTickWidth')
COLOR('lineTickColor')
//Grid lines
BOOLEAN('gridEnable')
NUMBER('gridWidth')
COLOR('gridColor')
//Zero line
BOOLEAN('zeroEnable')
COLOR('zeroLineColor')
NUMBER('zeroLineWidth')
//Background
BOOLEAN('backgroundEnable')
COLOR('backgroundColor')
//Update text if necessary
if(!this._text) {
this._text = createText(
this.gl,
this.bounds,
this.labels,
this.labelFont,
this.ticks,
this.tickFont)
} else if(this._text && (labelUpdate || ticksUpdate)) {
this._text.update(
this.bounds,
this.labels,
this.labelFont,
this.ticks,
this.tickFont)
}
//Update lines if necessary
if(this._lines && ticksUpdate) {
this._lines.dispose()
this._lines = null
}
if(!this._lines) {
this._lines = createLines(this.gl, this.bounds, this.ticks)
}
}
function OffsetInfo() {
this.primalOffset = [0,0,0]
this.primalMinor = [0,0,0]
this.mirrorOffset = [0,0,0]
this.mirrorMinor = [0,0,0]
}
var LINE_OFFSET = [ new OffsetInfo(), new OffsetInfo(), new OffsetInfo() ]
function computeLineOffset(result, i, bounds, cubeEdges, cubeAxis) {
var primalOffset = result.primalOffset
var primalMinor = result.primalMinor
var dualOffset = result.mirrorOffset
var dualMinor = result.mirrorMinor
var e = cubeEdges[i]
//Calculate offsets
for(var j=0; j<3; ++j) {
if(i === j) {
continue
}
var a = primalOffset,
b = dualOffset,
c = primalMinor,
d = dualMinor
if(e & (1< 0) {
c[j] = -1
d[j] = 0
} else {
c[j] = 0
d[j] = +1
}
}
}
var CUBE_ENABLE = [0,0,0]
var DEFAULT_PARAMS = {
model: identity,
view: identity,
projection: identity
}
proto.isOpaque = function() {
return true
}
proto.isTransparent = function() {
return false
}
proto.drawTransparent = function(params) {}
var PRIMAL_MINOR = [0,0,0]
var MIRROR_MINOR = [0,0,0]
var PRIMAL_OFFSET = [0,0,0]
proto.draw = function(params) {
params = params || DEFAULT_PARAMS
var gl = this.gl
//Geometry for camera and axes
var model = params.model || identity
var view = params.view || identity
var projection = params.projection || identity
var bounds = this.bounds
//Unpack axis info
var cubeParams = getCubeProperties(model, view, projection, bounds)
var cubeEdges = cubeParams.cubeEdges
var cubeAxis = cubeParams.axis
var cx = view[12]
var cy = view[13]
var cz = view[14]
var cw = view[15]
var pixelScaleF = this.pixelRatio * (projection[3]*cx + projection[7]*cy + projection[11]*cz + projection[15]*cw) / gl.drawingBufferHeight
for(var i=0; i<3; ++i) {
this.lastCubeProps.cubeEdges[i] = cubeEdges[i]
this.lastCubeProps.axis[i] = cubeAxis[i]
}
//Compute axis info
var lineOffset = LINE_OFFSET
for(var i=0; i<3; ++i) {
computeLineOffset(
LINE_OFFSET[i],
i,
this.bounds,
cubeEdges,
cubeAxis)
}
//Set up state parameters
var gl = this.gl
//Draw background first
var cubeEnable = CUBE_ENABLE
for(var i=0; i<3; ++i) {
if(this.backgroundEnable[i]) {
cubeEnable[i] = cubeAxis[i]
} else {
cubeEnable[i] = 0
}
}
this._background.draw(
model,
view,
projection,
bounds,
cubeEnable,
this.backgroundColor)
//Draw lines
this._lines.bind(
model,
view,
projection,
this)
//First draw grid lines and zero lines
for(var i=0; i<3; ++i) {
var x = [0,0,0]
if(cubeAxis[i] > 0) {
x[i] = bounds[1][i]
} else {
x[i] = bounds[0][i]
}
//Draw grid lines
for(var j=0; j<2; ++j) {
var u = (i + 1 + j) % 3
var v = (i + 1 + (j^1)) % 3
if(this.gridEnable[u]) {
this._lines.drawGrid(u, v, this.bounds, x, this.gridColor[u], this.gridWidth[u]*this.pixelRatio)
}
}
//Draw zero lines (need to do this AFTER all grid lines are drawn)
for(var j=0; j<2; ++j) {
var u = (i + 1 + j) % 3
var v = (i + 1 + (j^1)) % 3
if(this.zeroEnable[v]) {
//Check if zero line in bounds
if(bounds[0][v] <= 0 && bounds[1][v] >= 0) {
this._lines.drawZero(u, v, this.bounds, x, this.zeroLineColor[v], this.zeroLineWidth[v]*this.pixelRatio)
}
}
}
}
//Then draw axis lines and tick marks
for(var i=0; i<3; ++i) {
//Draw axis lines
if(this.lineEnable[i]) {
this._lines.drawAxisLine(i, this.bounds, lineOffset[i].primalOffset, this.lineColor[i], this.lineWidth[i]*this.pixelRatio)
}
if(this.lineMirror[i]) {
this._lines.drawAxisLine(i, this.bounds, lineOffset[i].mirrorOffset, this.lineColor[i], this.lineWidth[i]*this.pixelRatio)
}
//Compute minor axes
var primalMinor = copyVec3(PRIMAL_MINOR, lineOffset[i].primalMinor)
var mirrorMinor = copyVec3(MIRROR_MINOR, lineOffset[i].mirrorMinor)
var tickLength = this.lineTickLength
var op = 0
for(var j=0; j<3; ++j) {
var scaleFactor = pixelScaleF / model[5*j]
primalMinor[j] *= tickLength[j] * scaleFactor
mirrorMinor[j] *= tickLength[j] * scaleFactor
}
//Draw axis line ticks
if(this.lineTickEnable[i]) {
this._lines.drawAxisTicks(i, lineOffset[i].primalOffset, primalMinor, this.lineTickColor[i], this.lineTickWidth[i]*this.pixelRatio)
}
if(this.lineTickMirror[i]) {
this._lines.drawAxisTicks(i, lineOffset[i].mirrorOffset, mirrorMinor, this.lineTickColor[i], this.lineTickWidth[i]*this.pixelRatio)
}
}
//Draw text sprites
this._text.bind(
model,
view,
projection,
this.pixelRatio)
for(var i=0; i<3; ++i) {
var minor = lineOffset[i].primalMinor
var offset = copyVec3(PRIMAL_OFFSET, lineOffset[i].primalOffset)
for(var j=0; j<3; ++j) {
if(this.lineTickEnable[i]) {
offset[j] += pixelScaleF * minor[j] * Math.max(this.lineTickLength[j], 0) / model[5*j]
}
}
//Draw tick text
if(this.tickEnable[i]) {
//Add tick padding
for(var j=0; j<3; ++j) {
offset[j] += pixelScaleF * minor[j] * this.tickPad[j] / model[5*j]
}
//Draw axis
this._text.drawTicks(
i,
this.tickSize[i],
this.tickAngle[i],
offset,
this.tickColor[i])
}
//Draw labels
if(this.labelEnable[i]) {
//Add label padding
for(var j=0; j<3; ++j) {
offset[j] += pixelScaleF * minor[j] * this.labelPad[j] / model[5*j]
}
offset[i] += 0.5 * (bounds[0][i] + bounds[1][i])
//Draw axis
this._text.drawLabel(
i,
this.labelSize[i],
this.labelAngle[i],
offset,
this.labelColor[i])
}
}
}
proto.dispose = function() {
this._text.dispose()
this._lines.dispose()
this._background.dispose()
this._lines = null
this._text = null
this._background = null
this.gl = null
}
function createAxes(gl, options) {
var axes = new Axes(gl)
axes.update(options)
return axes
}
},{"./lib/background.js":145,"./lib/cube.js":146,"./lib/lines.js":147,"./lib/text.js":149,"./lib/ticks.js":150}],145:[function(require,module,exports){
'use strict'
module.exports = createBackgroundCube
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var createShader = require('./shaders').bg
function BackgroundCube(gl, buffer, vao, shader) {
this.gl = gl
this.buffer = buffer
this.vao = vao
this.shader = shader
}
var proto = BackgroundCube.prototype
proto.draw = function(model, view, projection, bounds, enable, colors) {
var needsBG = false
for(var i=0; i<3; ++i) {
needsBG = needsBG || enable[i]
}
if(!needsBG) {
return
}
var gl = this.gl
gl.enable(gl.POLYGON_OFFSET_FILL)
gl.polygonOffset(1, 2)
this.shader.bind()
this.shader.uniforms = {
model: model,
view: view,
projection: projection,
bounds: bounds,
enable: enable,
colors: colors
}
this.vao.bind()
this.vao.draw(this.gl.TRIANGLES, 36)
gl.disable(gl.POLYGON_OFFSET_FILL)
}
proto.dispose = function() {
this.vao.dispose()
this.buffer.dispose()
this.shader.dispose()
}
function createBackgroundCube(gl) {
//Create cube vertices
var vertices = []
var indices = []
var ptr = 0
for(var d=0; d<3; ++d) {
var u = (d+1) % 3
var v = (d+2) % 3
var x = [0,0,0]
var c = [0,0,0]
for(var s=-1; s<=1; s+=2) {
indices.push(ptr, ptr+2, ptr+1,
ptr+1, ptr+2, ptr+3)
x[d] = s
c[d] = s
for(var i=-1; i<=1; i+=2) {
x[u] = i
for(var j=-1; j<=1; j+=2) {
x[v] = j
vertices.push(x[0], x[1], x[2],
c[0], c[1], c[2])
ptr += 1
}
}
//Swap u and v
var tt = u
u = v
v = tt
}
}
//Allocate buffer and vertex array
var buffer = createBuffer(gl, new Float32Array(vertices))
var elements = createBuffer(gl, new Uint16Array(indices), gl.ELEMENT_ARRAY_BUFFER)
var vao = createVAO(gl, [
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 0,
stride: 24
},
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 12,
stride: 24
}
], elements)
//Create shader object
var shader = createShader(gl)
shader.attributes.position.location = 0
shader.attributes.normal.location = 1
return new BackgroundCube(gl, buffer, vao, shader)
}
},{"./shaders":148,"gl-buffer":152,"gl-vao":266}],146:[function(require,module,exports){
"use strict"
module.exports = getCubeEdges
var bits = require('bit-twiddle')
var multiply = require('gl-mat4/multiply')
var invert = require('gl-mat4/invert')
var splitPoly = require('split-polygon')
var orient = require('robust-orientation')
var mvp = new Array(16)
var imvp = new Array(16)
var pCubeVerts = new Array(8)
var cubeVerts = new Array(8)
var x = new Array(3)
var zero3 = [0,0,0]
;(function() {
for(var i=0; i<8; ++i) {
pCubeVerts[i] =[1,1,1,1]
cubeVerts[i] = [1,1,1]
}
})()
function transformHg(result, x, mat) {
for(var i=0; i<4; ++i) {
result[i] = mat[12+i]
for(var j=0; j<3; ++j) {
result[i] += x[j]*mat[4*j+i]
}
}
}
var FRUSTUM_PLANES = [
[ 0, 0, 1, 0, 0],
[ 0, 0,-1, 1, 0],
[ 0,-1, 0, 1, 0],
[ 0, 1, 0, 1, 0],
[-1, 0, 0, 1, 0],
[ 1, 0, 0, 1, 0]
]
function polygonArea(p) {
for(var i=0; i o0) {
closest |= 1< o0) {
closest |= 1< cubeVerts[i][1]) {
bottom = i
}
}
//Find left/right neighbors of bottom vertex
var left = -1
for(var i=0; i<3; ++i) {
var idx = bottom ^ (1< cubeVerts[right][0]) {
right = idx
}
}
//Determine edge axis coordinates
var cubeEdges = CUBE_EDGES
cubeEdges[0] = cubeEdges[1] = cubeEdges[2] = 0
cubeEdges[bits.log2(left^bottom)] = bottom&left
cubeEdges[bits.log2(bottom^right)] = bottom&right
var top = right ^ 7
if(top === closest || top === farthest) {
top = left ^ 7
cubeEdges[bits.log2(right^top)] = top&right
} else {
cubeEdges[bits.log2(left^top)] = top&left
}
//Determine visible faces
var axis = CUBE_AXIS
var cutCorner = closest
for(var d=0; d<3; ++d) {
if(cutCorner & (1<=0; --j) {
var p = positions[c[j]]
data.push(scale*p[0], -scale*p[1], t)
}
}
}
//Generate sprites for all 3 axes, store data in texture atlases
var tickOffset = [0,0,0]
var tickCount = [0,0,0]
var labelOffset = [0,0,0]
var labelCount = [0,0,0]
for(var d=0; d<3; ++d) {
//Generate label
labelOffset[d] = (data.length/VERTEX_SIZE)|0
addItem(0.5*(bounds[0][d]+bounds[1][d]), labels[d], labelFont)
labelCount[d] = ((data.length/VERTEX_SIZE)|0) - labelOffset[d]
//Generate sprites for tick marks
tickOffset[d] = (data.length/VERTEX_SIZE)|0
for(var i=0; i= 0) {
sigFigs = stepStr.length - u - 1
}
var shift = Math.pow(10, sigFigs)
var x = Math.round(spacing * i * shift)
var xstr = x + ""
if(xstr.indexOf("e") >= 0) {
return xstr
}
var xi = x / shift, xf = x % shift
if(x < 0) {
xi = -Math.ceil(xi)|0
xf = (-xf)|0
} else {
xi = Math.floor(xi)|0
xf = xf|0
}
var xis = "" + xi
if(x < 0) {
xis = "-" + xis
}
if(sigFigs) {
var xs = "" + xf
while(xs.length < sigFigs) {
xs = "0" + xs
}
return xis + "." + xs
} else {
return xis
}
}
function defaultTicks(bounds, tickSpacing) {
var array = []
for(var d=0; d<3; ++d) {
var ticks = []
var m = 0.5*(bounds[0][d]+bounds[1][d])
for(var t=0; t*tickSpacing[d]<=bounds[1][d]; ++t) {
ticks.push({x: t*tickSpacing[d], text: prettyPrint(tickSpacing[d], t)})
}
for(var t=-1; t*tickSpacing[d]>=bounds[0][d]; --t) {
ticks.push({x: t*tickSpacing[d], text: prettyPrint(tickSpacing[d], t)})
}
array.push(ticks)
}
return array
}
function ticksEqual(ticksA, ticksB) {
for(var i=0; i<3; ++i) {
if(ticksA[i].length !== ticksB[i].length) {
return false
}
for(var j=0; j len) {
throw new Error("gl-buffer: If resizing buffer, must not specify offset")
}
gl.bufferSubData(type, offset, data)
return len
}
function makeScratchTypeArray(array, dtype) {
var res = pool.malloc(array.length, dtype)
var n = array.length
for(var i=0; i=0; --i) {
if(stride[i] !== n) {
return false
}
n *= shape[i]
}
return true
}
proto.update = function(array, offset) {
if(typeof offset !== "number") {
offset = -1
}
this.bind()
if(typeof array === "object" && typeof array.shape !== "undefined") { //ndarray
var dtype = array.dtype
if(SUPPORTED_TYPES.indexOf(dtype) < 0) {
dtype = "float32"
}
if(this.type === this.gl.ELEMENT_ARRAY_BUFFER) {
var ext = gl.getExtension('OES_element_index_uint')
if(ext && dtype !== "uint16") {
dtype = "uint32"
} else {
dtype = "uint16"
}
}
if(dtype === array.dtype && isPacked(array.shape, array.stride)) {
if(array.offset === 0 && array.data.length === array.shape[0]) {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, array.data, offset)
} else {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, array.data.subarray(array.offset, array.shape[0]), offset)
}
} else {
var tmp = pool.malloc(array.size, dtype)
var ndt = ndarray(tmp, array.shape)
ops.assign(ndt, array)
if(offset < 0) {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, tmp, offset)
} else {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, tmp.subarray(0, array.size), offset)
}
pool.free(tmp)
}
} else if(Array.isArray(array)) { //Vanilla array
var t
if(this.type === this.gl.ELEMENT_ARRAY_BUFFER) {
t = makeScratchTypeArray(array, "uint16")
} else {
t = makeScratchTypeArray(array, "float32")
}
if(offset < 0) {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, t, offset)
} else {
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, t.subarray(0, array.length), offset)
}
pool.free(t)
} else if(typeof array === "object" && typeof array.length === "number") { //Typed array
this.length = updateTypeArray(this.gl, this.type, this.length, this.usage, array, offset)
} else if(typeof array === "number" || array === undefined) { //Number/default
if(offset >= 0) {
throw new Error("gl-buffer: Cannot specify offset when resizing buffer")
}
array = array | 0
if(array <= 0) {
array = 1
}
this.gl.bufferData(this.type, array|0, this.usage)
this.length = array
} else { //Error, case should not happen
throw new Error("gl-buffer: Invalid data type")
}
}
function createBuffer(gl, data, type, usage) {
type = type || gl.ARRAY_BUFFER
usage = usage || gl.DYNAMIC_DRAW
if(type !== gl.ARRAY_BUFFER && type !== gl.ELEMENT_ARRAY_BUFFER) {
throw new Error("gl-buffer: Invalid type for webgl buffer, must be either gl.ARRAY_BUFFER or gl.ELEMENT_ARRAY_BUFFER")
}
if(usage !== gl.DYNAMIC_DRAW && usage !== gl.STATIC_DRAW && usage !== gl.STREAM_DRAW) {
throw new Error("gl-buffer: Invalid usage for buffer, must be either gl.DYNAMIC_DRAW, gl.STATIC_DRAW or gl.STREAM_DRAW")
}
var handle = gl.createBuffer()
var result = new GLBuffer(gl, type, handle, 0, usage)
result.update(data)
return result
}
module.exports = createBuffer
},{"ndarray":460,"ndarray-ops":454,"typedarray-pool":533}],153:[function(require,module,exports){
module.exports = {
0: 'NONE',
1: 'ONE',
2: 'LINE_LOOP',
3: 'LINE_STRIP',
4: 'TRIANGLES',
5: 'TRIANGLE_STRIP',
6: 'TRIANGLE_FAN',
256: 'DEPTH_BUFFER_BIT',
512: 'NEVER',
513: 'LESS',
514: 'EQUAL',
515: 'LEQUAL',
516: 'GREATER',
517: 'NOTEQUAL',
518: 'GEQUAL',
519: 'ALWAYS',
768: 'SRC_COLOR',
769: 'ONE_MINUS_SRC_COLOR',
770: 'SRC_ALPHA',
771: 'ONE_MINUS_SRC_ALPHA',
772: 'DST_ALPHA',
773: 'ONE_MINUS_DST_ALPHA',
774: 'DST_COLOR',
775: 'ONE_MINUS_DST_COLOR',
776: 'SRC_ALPHA_SATURATE',
1024: 'STENCIL_BUFFER_BIT',
1028: 'FRONT',
1029: 'BACK',
1032: 'FRONT_AND_BACK',
1280: 'INVALID_ENUM',
1281: 'INVALID_VALUE',
1282: 'INVALID_OPERATION',
1285: 'OUT_OF_MEMORY',
1286: 'INVALID_FRAMEBUFFER_OPERATION',
2304: 'CW',
2305: 'CCW',
2849: 'LINE_WIDTH',
2884: 'CULL_FACE',
2885: 'CULL_FACE_MODE',
2886: 'FRONT_FACE',
2928: 'DEPTH_RANGE',
2929: 'DEPTH_TEST',
2930: 'DEPTH_WRITEMASK',
2931: 'DEPTH_CLEAR_VALUE',
2932: 'DEPTH_FUNC',
2960: 'STENCIL_TEST',
2961: 'STENCIL_CLEAR_VALUE',
2962: 'STENCIL_FUNC',
2963: 'STENCIL_VALUE_MASK',
2964: 'STENCIL_FAIL',
2965: 'STENCIL_PASS_DEPTH_FAIL',
2966: 'STENCIL_PASS_DEPTH_PASS',
2967: 'STENCIL_REF',
2968: 'STENCIL_WRITEMASK',
2978: 'VIEWPORT',
3024: 'DITHER',
3042: 'BLEND',
3088: 'SCISSOR_BOX',
3089: 'SCISSOR_TEST',
3106: 'COLOR_CLEAR_VALUE',
3107: 'COLOR_WRITEMASK',
3317: 'UNPACK_ALIGNMENT',
3333: 'PACK_ALIGNMENT',
3379: 'MAX_TEXTURE_SIZE',
3386: 'MAX_VIEWPORT_DIMS',
3408: 'SUBPIXEL_BITS',
3410: 'RED_BITS',
3411: 'GREEN_BITS',
3412: 'BLUE_BITS',
3413: 'ALPHA_BITS',
3414: 'DEPTH_BITS',
3415: 'STENCIL_BITS',
3553: 'TEXTURE_2D',
4352: 'DONT_CARE',
4353: 'FASTEST',
4354: 'NICEST',
5120: 'BYTE',
5121: 'UNSIGNED_BYTE',
5122: 'SHORT',
5123: 'UNSIGNED_SHORT',
5124: 'INT',
5125: 'UNSIGNED_INT',
5126: 'FLOAT',
5386: 'INVERT',
5890: 'TEXTURE',
6401: 'STENCIL_INDEX',
6402: 'DEPTH_COMPONENT',
6406: 'ALPHA',
6407: 'RGB',
6408: 'RGBA',
6409: 'LUMINANCE',
6410: 'LUMINANCE_ALPHA',
7680: 'KEEP',
7681: 'REPLACE',
7682: 'INCR',
7683: 'DECR',
7936: 'VENDOR',
7937: 'RENDERER',
7938: 'VERSION',
9728: 'NEAREST',
9729: 'LINEAR',
9984: 'NEAREST_MIPMAP_NEAREST',
9985: 'LINEAR_MIPMAP_NEAREST',
9986: 'NEAREST_MIPMAP_LINEAR',
9987: 'LINEAR_MIPMAP_LINEAR',
10240: 'TEXTURE_MAG_FILTER',
10241: 'TEXTURE_MIN_FILTER',
10242: 'TEXTURE_WRAP_S',
10243: 'TEXTURE_WRAP_T',
10497: 'REPEAT',
10752: 'POLYGON_OFFSET_UNITS',
16384: 'COLOR_BUFFER_BIT',
32769: 'CONSTANT_COLOR',
32770: 'ONE_MINUS_CONSTANT_COLOR',
32771: 'CONSTANT_ALPHA',
32772: 'ONE_MINUS_CONSTANT_ALPHA',
32773: 'BLEND_COLOR',
32774: 'FUNC_ADD',
32777: 'BLEND_EQUATION_RGB',
32778: 'FUNC_SUBTRACT',
32779: 'FUNC_REVERSE_SUBTRACT',
32819: 'UNSIGNED_SHORT_4_4_4_4',
32820: 'UNSIGNED_SHORT_5_5_5_1',
32823: 'POLYGON_OFFSET_FILL',
32824: 'POLYGON_OFFSET_FACTOR',
32854: 'RGBA4',
32855: 'RGB5_A1',
32873: 'TEXTURE_BINDING_2D',
32926: 'SAMPLE_ALPHA_TO_COVERAGE',
32928: 'SAMPLE_COVERAGE',
32936: 'SAMPLE_BUFFERS',
32937: 'SAMPLES',
32938: 'SAMPLE_COVERAGE_VALUE',
32939: 'SAMPLE_COVERAGE_INVERT',
32968: 'BLEND_DST_RGB',
32969: 'BLEND_SRC_RGB',
32970: 'BLEND_DST_ALPHA',
32971: 'BLEND_SRC_ALPHA',
33071: 'CLAMP_TO_EDGE',
33170: 'GENERATE_MIPMAP_HINT',
33189: 'DEPTH_COMPONENT16',
33306: 'DEPTH_STENCIL_ATTACHMENT',
33635: 'UNSIGNED_SHORT_5_6_5',
33648: 'MIRRORED_REPEAT',
33901: 'ALIASED_POINT_SIZE_RANGE',
33902: 'ALIASED_LINE_WIDTH_RANGE',
33984: 'TEXTURE0',
33985: 'TEXTURE1',
33986: 'TEXTURE2',
33987: 'TEXTURE3',
33988: 'TEXTURE4',
33989: 'TEXTURE5',
33990: 'TEXTURE6',
33991: 'TEXTURE7',
33992: 'TEXTURE8',
33993: 'TEXTURE9',
33994: 'TEXTURE10',
33995: 'TEXTURE11',
33996: 'TEXTURE12',
33997: 'TEXTURE13',
33998: 'TEXTURE14',
33999: 'TEXTURE15',
34000: 'TEXTURE16',
34001: 'TEXTURE17',
34002: 'TEXTURE18',
34003: 'TEXTURE19',
34004: 'TEXTURE20',
34005: 'TEXTURE21',
34006: 'TEXTURE22',
34007: 'TEXTURE23',
34008: 'TEXTURE24',
34009: 'TEXTURE25',
34010: 'TEXTURE26',
34011: 'TEXTURE27',
34012: 'TEXTURE28',
34013: 'TEXTURE29',
34014: 'TEXTURE30',
34015: 'TEXTURE31',
34016: 'ACTIVE_TEXTURE',
34024: 'MAX_RENDERBUFFER_SIZE',
34041: 'DEPTH_STENCIL',
34055: 'INCR_WRAP',
34056: 'DECR_WRAP',
34067: 'TEXTURE_CUBE_MAP',
34068: 'TEXTURE_BINDING_CUBE_MAP',
34069: 'TEXTURE_CUBE_MAP_POSITIVE_X',
34070: 'TEXTURE_CUBE_MAP_NEGATIVE_X',
34071: 'TEXTURE_CUBE_MAP_POSITIVE_Y',
34072: 'TEXTURE_CUBE_MAP_NEGATIVE_Y',
34073: 'TEXTURE_CUBE_MAP_POSITIVE_Z',
34074: 'TEXTURE_CUBE_MAP_NEGATIVE_Z',
34076: 'MAX_CUBE_MAP_TEXTURE_SIZE',
34338: 'VERTEX_ATTRIB_ARRAY_ENABLED',
34339: 'VERTEX_ATTRIB_ARRAY_SIZE',
34340: 'VERTEX_ATTRIB_ARRAY_STRIDE',
34341: 'VERTEX_ATTRIB_ARRAY_TYPE',
34342: 'CURRENT_VERTEX_ATTRIB',
34373: 'VERTEX_ATTRIB_ARRAY_POINTER',
34466: 'NUM_COMPRESSED_TEXTURE_FORMATS',
34467: 'COMPRESSED_TEXTURE_FORMATS',
34660: 'BUFFER_SIZE',
34661: 'BUFFER_USAGE',
34816: 'STENCIL_BACK_FUNC',
34817: 'STENCIL_BACK_FAIL',
34818: 'STENCIL_BACK_PASS_DEPTH_FAIL',
34819: 'STENCIL_BACK_PASS_DEPTH_PASS',
34877: 'BLEND_EQUATION_ALPHA',
34921: 'MAX_VERTEX_ATTRIBS',
34922: 'VERTEX_ATTRIB_ARRAY_NORMALIZED',
34930: 'MAX_TEXTURE_IMAGE_UNITS',
34962: 'ARRAY_BUFFER',
34963: 'ELEMENT_ARRAY_BUFFER',
34964: 'ARRAY_BUFFER_BINDING',
34965: 'ELEMENT_ARRAY_BUFFER_BINDING',
34975: 'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING',
35040: 'STREAM_DRAW',
35044: 'STATIC_DRAW',
35048: 'DYNAMIC_DRAW',
35632: 'FRAGMENT_SHADER',
35633: 'VERTEX_SHADER',
35660: 'MAX_VERTEX_TEXTURE_IMAGE_UNITS',
35661: 'MAX_COMBINED_TEXTURE_IMAGE_UNITS',
35663: 'SHADER_TYPE',
35664: 'FLOAT_VEC2',
35665: 'FLOAT_VEC3',
35666: 'FLOAT_VEC4',
35667: 'INT_VEC2',
35668: 'INT_VEC3',
35669: 'INT_VEC4',
35670: 'BOOL',
35671: 'BOOL_VEC2',
35672: 'BOOL_VEC3',
35673: 'BOOL_VEC4',
35674: 'FLOAT_MAT2',
35675: 'FLOAT_MAT3',
35676: 'FLOAT_MAT4',
35678: 'SAMPLER_2D',
35680: 'SAMPLER_CUBE',
35712: 'DELETE_STATUS',
35713: 'COMPILE_STATUS',
35714: 'LINK_STATUS',
35715: 'VALIDATE_STATUS',
35716: 'INFO_LOG_LENGTH',
35717: 'ATTACHED_SHADERS',
35718: 'ACTIVE_UNIFORMS',
35719: 'ACTIVE_UNIFORM_MAX_LENGTH',
35720: 'SHADER_SOURCE_LENGTH',
35721: 'ACTIVE_ATTRIBUTES',
35722: 'ACTIVE_ATTRIBUTE_MAX_LENGTH',
35724: 'SHADING_LANGUAGE_VERSION',
35725: 'CURRENT_PROGRAM',
36003: 'STENCIL_BACK_REF',
36004: 'STENCIL_BACK_VALUE_MASK',
36005: 'STENCIL_BACK_WRITEMASK',
36006: 'FRAMEBUFFER_BINDING',
36007: 'RENDERBUFFER_BINDING',
36048: 'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE',
36049: 'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME',
36050: 'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL',
36051: 'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE',
36053: 'FRAMEBUFFER_COMPLETE',
36054: 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT',
36055: 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT',
36057: 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS',
36061: 'FRAMEBUFFER_UNSUPPORTED',
36064: 'COLOR_ATTACHMENT0',
36096: 'DEPTH_ATTACHMENT',
36128: 'STENCIL_ATTACHMENT',
36160: 'FRAMEBUFFER',
36161: 'RENDERBUFFER',
36162: 'RENDERBUFFER_WIDTH',
36163: 'RENDERBUFFER_HEIGHT',
36164: 'RENDERBUFFER_INTERNAL_FORMAT',
36168: 'STENCIL_INDEX8',
36176: 'RENDERBUFFER_RED_SIZE',
36177: 'RENDERBUFFER_GREEN_SIZE',
36178: 'RENDERBUFFER_BLUE_SIZE',
36179: 'RENDERBUFFER_ALPHA_SIZE',
36180: 'RENDERBUFFER_DEPTH_SIZE',
36181: 'RENDERBUFFER_STENCIL_SIZE',
36194: 'RGB565',
36336: 'LOW_FLOAT',
36337: 'MEDIUM_FLOAT',
36338: 'HIGH_FLOAT',
36339: 'LOW_INT',
36340: 'MEDIUM_INT',
36341: 'HIGH_INT',
36346: 'SHADER_COMPILER',
36347: 'MAX_VERTEX_UNIFORM_VECTORS',
36348: 'MAX_VARYING_VECTORS',
36349: 'MAX_FRAGMENT_UNIFORM_VECTORS',
37440: 'UNPACK_FLIP_Y_WEBGL',
37441: 'UNPACK_PREMULTIPLY_ALPHA_WEBGL',
37442: 'CONTEXT_LOST_WEBGL',
37443: 'UNPACK_COLORSPACE_CONVERSION_WEBGL',
37444: 'BROWSER_DEFAULT_WEBGL'
}
},{}],154:[function(require,module,exports){
var gl10 = require('./1.0/numbers')
module.exports = function lookupConstant (number) {
return gl10[number]
}
},{"./1.0/numbers":153}],155:[function(require,module,exports){
'use strict'
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var pool = require('typedarray-pool')
var shaders = require('./lib/shaders')
module.exports = createError2D
var WEIGHTS = [
// x-error bar
[1, 0, 0, 1, 0, 0],
[1, 0, 0, -1, 0, 0],
[-1, 0, 0, -1, 0, 0],
[-1, 0, 0, -1, 0, 0],
[-1, 0, 0, 1, 0, 0],
[1, 0, 0, 1, 0, 0],
// x-error right cap
[1, 0, -1, 0, 0, 1],
[1, 0, -1, 0, 0, -1],
[1, 0, 1, 0, 0, -1],
[1, 0, 1, 0, 0, -1],
[1, 0, 1, 0, 0, 1],
[1, 0, -1, 0, 0, 1],
// x-error left cap
[-1, 0, -1, 0, 0, 1],
[-1, 0, -1, 0, 0, -1],
[-1, 0, 1, 0, 0, -1],
[-1, 0, 1, 0, 0, -1],
[-1, 0, 1, 0, 0, 1],
[-1, 0, -1, 0, 0, 1],
// y-error bar
[0, 1, 1, 0, 0, 0],
[0, 1, -1, 0, 0, 0],
[0, -1, -1, 0, 0, 0],
[0, -1, -1, 0, 0, 0],
[0, 1, 1, 0, 0, 0],
[0, -1, 1, 0, 0, 0],
// y-error top cap
[0, 1, 0, -1, 1, 0],
[0, 1, 0, -1, -1, 0],
[0, 1, 0, 1, -1, 0],
[0, 1, 0, 1, 1, 0],
[0, 1, 0, -1, 1, 0],
[0, 1, 0, 1, -1, 0],
// y-error bottom cap
[0, -1, 0, -1, 1, 0],
[0, -1, 0, -1, -1, 0],
[0, -1, 0, 1, -1, 0],
[0, -1, 0, 1, 1, 0],
[0, -1, 0, -1, 1, 0],
[0, -1, 0, 1, -1, 0]
]
function GLError2D (plot, shader, bufferHi, bufferLo) {
this.plot = plot
this.shader = shader
this.bufferHi = bufferHi
this.bufferLo = bufferLo
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
this.numPoints = 0
this.color = [0, 0, 0, 1]
}
var proto = GLError2D.prototype
proto.draw = (function () {
var SCALE_HI = new Float32Array([0, 0])
var SCALE_LO = new Float32Array([0, 0])
var TRANSLATE_HI = new Float32Array([0, 0])
var TRANSLATE_LO = new Float32Array([0, 0])
var PIXEL_SCALE = [1, 1]
return function () {
var plot = this.plot
var shader = this.shader
var bounds = this.bounds
var numPoints = this.numPoints
if (!numPoints) {
return
}
var gl = plot.gl
var dataBox = plot.dataBox
var viewBox = plot.viewBox
var pixelRatio = plot.pixelRatio
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
var scaleX = 2 * boundX / dataX
var scaleY = 2 * boundY / dataY
var translateX = (bounds[0] - dataBox[0] - 0.5 * dataX) / boundX
var translateY = (bounds[1] - dataBox[1] - 0.5 * dataY) / boundY
SCALE_HI[0] = scaleX
SCALE_HI[1] = scaleY
SCALE_LO[0] = scaleX - SCALE_HI[0]
SCALE_LO[1] = scaleY - SCALE_HI[1]
TRANSLATE_HI[0] = translateX
TRANSLATE_HI[1] = translateY
TRANSLATE_LO[0] = translateX - TRANSLATE_HI[0]
TRANSLATE_LO[1] = translateY - TRANSLATE_HI[1]
var screenX = viewBox[2] - viewBox[0]
var screenY = viewBox[3] - viewBox[1]
PIXEL_SCALE[0] = 2.0 * pixelRatio / screenX
PIXEL_SCALE[1] = 2.0 * pixelRatio / screenY
shader.bind()
shader.uniforms.scaleHi = SCALE_HI
shader.uniforms.scaleLo = SCALE_LO
shader.uniforms.translateHi = TRANSLATE_HI
shader.uniforms.translateLo = TRANSLATE_LO
shader.uniforms.pixelScale = PIXEL_SCALE
shader.uniforms.color = this.color
this.bufferLo.bind()
shader.attributes.positionLo.pointer(gl.FLOAT, false, 16, 0)
this.bufferHi.bind()
shader.attributes.positionHi.pointer(gl.FLOAT, false, 16, 0)
shader.attributes.pixelOffset.pointer(gl.FLOAT, false, 16, 8)
gl.drawArrays(gl.TRIANGLES, 0, numPoints * WEIGHTS.length)
}
})()
proto.drawPick = function (offset) { return offset }
proto.pick = function () {
return null
}
proto.update = function (options) {
options = options || {}
var i, x, y
var positions = options.positions || []
var errors = options.errors || []
var lineWidth = 1
if ('lineWidth' in options) {
lineWidth = +options.lineWidth
}
var capSize = 5
if ('capSize' in options) {
capSize = +options.capSize
}
this.color = (options.color || [0, 0, 0, 1]).slice()
var bounds = this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
var numPoints = this.numPoints = positions.length >> 1
for (i = 0; i < numPoints; ++i) {
x = positions[i * 2]
y = positions[i * 2 + 1]
bounds[0] = Math.min(x, bounds[0])
bounds[1] = Math.min(y, bounds[1])
bounds[2] = Math.max(x, bounds[2])
bounds[3] = Math.max(y, bounds[3])
}
if (bounds[2] === bounds[0]) {
bounds[2] += 1
}
if (bounds[3] === bounds[1]) {
bounds[3] += 1
}
var sx = 1.0 / (bounds[2] - bounds[0])
var sy = 1.0 / (bounds[3] - bounds[1])
var tx = bounds[0]
var ty = bounds[1]
var bufferData = pool.mallocFloat64(numPoints * WEIGHTS.length * 4)
var bufferDataHi = pool.mallocFloat32(numPoints * WEIGHTS.length * 4)
var bufferDataLo = pool.mallocFloat32(numPoints * WEIGHTS.length * 4)
var ptr = 0
for (i = 0; i < numPoints; ++i) {
x = positions[2 * i]
y = positions[2 * i + 1]
var ex0 = errors[4 * i]
var ex1 = errors[4 * i + 1]
var ey0 = errors[4 * i + 2]
var ey1 = errors[4 * i + 3]
for (var j = 0; j < WEIGHTS.length; ++j) {
var w = WEIGHTS[j]
var dx = w[0]
var dy = w[1]
if (dx < 0) {
dx *= ex0
} else if (dx > 0) {
dx *= ex1
}
if (dy < 0) {
dy *= ey0
} else if (dy > 0) {
dy *= ey1
}
bufferData[ptr++] = sx * ((x - tx) + dx)
bufferData[ptr++] = sy * ((y - ty) + dy)
bufferData[ptr++] = lineWidth * w[2] + (capSize + lineWidth) * w[4]
bufferData[ptr++] = lineWidth * w[3] + (capSize + lineWidth) * w[5]
}
}
for(i = 0; i < bufferData.length; i++) {
bufferDataHi[i] = bufferData[i]
bufferDataLo[i] = bufferData[i] - bufferDataHi[i]
}
this.bufferHi.update(bufferDataHi)
this.bufferLo.update(bufferDataLo)
pool.free(bufferData)
}
proto.dispose = function () {
this.plot.removeObject(this)
this.shader.dispose()
this.bufferHi.dispose()
this.bufferLo.dispose()
}
function createError2D (plot, options) {
var shader = createShader(plot.gl, shaders.vertex, shaders.fragment)
var bufferHi = createBuffer(plot.gl)
var bufferLo = createBuffer(plot.gl)
var errorBars = new GLError2D(plot, shader, bufferHi, bufferLo)
errorBars.update(options)
plot.addObject(errorBars)
return errorBars
}
},{"./lib/shaders":156,"gl-buffer":152,"gl-shader":250,"typedarray-pool":533}],156:[function(require,module,exports){
module.exports = {
vertex: "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 positionHi;\nattribute vec2 positionLo;\nattribute vec2 pixelOffset;\n\nuniform vec2 scaleHi, scaleLo, translateHi, translateLo, pixelScale;\n\nvec2 project(vec2 scHi, vec2 trHi, vec2 scLo, vec2 trLo, vec2 posHi, vec2 posLo) {\n return (posHi + trHi) * scHi\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo;\n}\n\nvoid main() {\n vec3 scrPosition = vec3(\n project(scaleHi, translateHi, scaleLo, translateLo, positionHi, positionLo),\n 1);\n gl_Position = vec4(\n scrPosition.xy + scrPosition.z * pixelScale * pixelOffset,\n 0,\n scrPosition.z);\n}\n",
fragment: "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec4 color;\n\nvoid main() {\n gl_FragColor = vec4(color.rgb * color.a, color.a);\n}\n"
}
},{}],157:[function(require,module,exports){
'use strict'
module.exports = createErrorBars
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var createShader = require('./shaders/index')
var IDENTITY = [1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1]
function ErrorBars(gl, buffer, vao, shader) {
this.gl = gl
this.shader = shader
this.buffer = buffer
this.vao = vao
this.pixelRatio = 1
this.bounds = [[ Infinity, Infinity, Infinity], [-Infinity,-Infinity,-Infinity]]
this.clipBounds = [[-Infinity,-Infinity,-Infinity], [ Infinity, Infinity, Infinity]]
this.lineWidth = [1,1,1]
this.capSize = [10,10,10]
this.lineCount = [0,0,0]
this.lineOffset = [0,0,0]
this.opacity = 1
}
var proto = ErrorBars.prototype
proto.isOpaque = function() {
return this.opacity >= 1
}
proto.isTransparent = function() {
return this.opacity < 1
}
proto.drawTransparent = proto.draw = function(cameraParams) {
var gl = this.gl
var uniforms = this.shader.uniforms
this.shader.bind()
var view = uniforms.view = cameraParams.view || IDENTITY
var projection = uniforms.projection = cameraParams.projection || IDENTITY
uniforms.model = cameraParams.model || IDENTITY
uniforms.clipBounds = this.clipBounds
uniforms.opacity = this.opacity
var cx = view[12]
var cy = view[13]
var cz = view[14]
var cw = view[15]
var pixelScaleF = this.pixelRatio * (projection[3]*cx + projection[7]*cy + projection[11]*cz + projection[15]*cw) / gl.drawingBufferHeight
this.vao.bind()
for(var i=0; i<3; ++i) {
gl.lineWidth(this.lineWidth[i])
uniforms.capSize = this.capSize[i] * pixelScaleF
gl.drawArrays(gl.LINES, this.lineOffset[i], this.lineCount[i])
}
this.vao.unbind()
}
function updateBounds(bounds, point) {
for(var i=0; i<3; ++i) {
bounds[0][i] = Math.min(bounds[0][i], point[i])
bounds[1][i] = Math.max(bounds[1][i], point[i])
}
}
var FACE_TABLE = (function(){
var table = new Array(3)
for(var d=0; d<3; ++d) {
var row = []
for(var j=1; j<=2; ++j) {
for(var s=-1; s<=1; s+=2) {
var u = (j+d) % 3
var y = [0,0,0]
y[u] = s
row.push(y)
}
}
table[d] = row
}
return table
})()
function emitFace(verts, x, c, d) {
var offsets = FACE_TABLE[d]
for(var i=0; i 0) {
var x = p.slice()
x[j] += e[1][j]
verts.push(p[0], p[1], p[2],
c[0], c[1], c[2], c[3],
0, 0, 0,
x[0], x[1], x[2],
c[0], c[1], c[2], c[3],
0, 0, 0)
updateBounds(this.bounds, x)
vertexCount += 2 + emitFace(verts, x, c, j)
}
}
this.lineCount[j] = vertexCount - this.lineOffset[j]
}
this.buffer.update(verts)
}
}
proto.dispose = function() {
this.shader.dispose()
this.buffer.dispose()
this.vao.dispose()
}
function createErrorBars(options) {
var gl = options.gl
var buffer = createBuffer(gl)
var vao = createVAO(gl, [
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 0,
stride: 40
},
{
buffer: buffer,
type: gl.FLOAT,
size: 4,
offset: 12,
stride: 40
},
{
buffer: buffer,
type: gl.FLOAT,
size: 3,
offset: 28,
stride: 40
}
])
var shader = createShader(gl)
shader.attributes.position.location = 0
shader.attributes.color.location = 1
shader.attributes.offset.location = 2
var result = new ErrorBars(gl, buffer, vao, shader)
result.update(options)
return result
}
},{"./shaders/index":158,"gl-buffer":152,"gl-vao":266}],158:[function(require,module,exports){
'use strict'
var createShader = require('gl-shader')
var vertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position, offset;\nattribute vec4 color;\nuniform mat4 model, view, projection;\nuniform float capSize;\nvarying vec4 fragColor;\nvarying vec3 fragPosition;\n\nvoid main() {\n vec4 worldPosition = model * vec4(position, 1.0);\n worldPosition = (worldPosition / worldPosition.w) + vec4(capSize * offset, 0.0);\n gl_Position = projection * view * worldPosition;\n fragColor = color;\n fragPosition = position;\n}"
var fragSrc = "precision mediump float;\n#define GLSLIFY 1\nuniform vec3 clipBounds[2];\nuniform float opacity;\nvarying vec3 fragPosition;\nvarying vec4 fragColor;\n\nvoid main() {\n if(any(lessThan(fragPosition, clipBounds[0])) || any(greaterThan(fragPosition, clipBounds[1]))) {\n discard;\n }\n gl_FragColor = opacity * fragColor;\n}"
module.exports = function(gl) {
return createShader(gl, vertSrc, fragSrc, null, [
{name: 'position', type: 'vec3'},
{name: 'offset', type: 'vec3'},
{name: 'color', type: 'vec4'}
])
}
},{"gl-shader":250}],159:[function(require,module,exports){
'use strict'
var createTexture = require('gl-texture2d')
module.exports = createFBO
var colorAttachmentArrays = null
var FRAMEBUFFER_UNSUPPORTED
var FRAMEBUFFER_INCOMPLETE_ATTACHMENT
var FRAMEBUFFER_INCOMPLETE_DIMENSIONS
var FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
function saveFBOState(gl) {
var fbo = gl.getParameter(gl.FRAMEBUFFER_BINDING)
var rbo = gl.getParameter(gl.RENDERBUFFER_BINDING)
var tex = gl.getParameter(gl.TEXTURE_BINDING_2D)
return [fbo, rbo, tex]
}
function restoreFBOState(gl, data) {
gl.bindFramebuffer(gl.FRAMEBUFFER, data[0])
gl.bindRenderbuffer(gl.RENDERBUFFER, data[1])
gl.bindTexture(gl.TEXTURE_2D, data[2])
}
function lazyInitColorAttachments(gl, ext) {
var maxColorAttachments = gl.getParameter(ext.MAX_COLOR_ATTACHMENTS_WEBGL)
colorAttachmentArrays = new Array(maxColorAttachments + 1)
for(var i=0; i<=maxColorAttachments; ++i) {
var x = new Array(maxColorAttachments)
for(var j=0; j 1) {
ext.drawBuffersWEBGL(colorAttachmentArrays[numColors])
}
//Allocate depth/stencil buffers
var WEBGL_depth_texture = gl.getExtension('WEBGL_depth_texture')
if(WEBGL_depth_texture) {
if(useStencil) {
fbo.depth = initTexture(gl, width, height,
WEBGL_depth_texture.UNSIGNED_INT_24_8_WEBGL,
gl.DEPTH_STENCIL,
gl.DEPTH_STENCIL_ATTACHMENT)
} else if(useDepth) {
fbo.depth = initTexture(gl, width, height,
gl.UNSIGNED_SHORT,
gl.DEPTH_COMPONENT,
gl.DEPTH_ATTACHMENT)
}
} else {
if(useDepth && useStencil) {
fbo._depth_rb = initRenderBuffer(gl, width, height, gl.DEPTH_STENCIL, gl.DEPTH_STENCIL_ATTACHMENT)
} else if(useDepth) {
fbo._depth_rb = initRenderBuffer(gl, width, height, gl.DEPTH_COMPONENT16, gl.DEPTH_ATTACHMENT)
} else if(useStencil) {
fbo._depth_rb = initRenderBuffer(gl, width, height, gl.STENCIL_INDEX, gl.STENCIL_ATTACHMENT)
}
}
//Check frame buffer state
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER)
if(status !== gl.FRAMEBUFFER_COMPLETE) {
//Release all partially allocated resources
fbo._destroyed = true
//Release all resources
gl.bindFramebuffer(gl.FRAMEBUFFER, null)
gl.deleteFramebuffer(fbo.handle)
fbo.handle = null
if(fbo.depth) {
fbo.depth.dispose()
fbo.depth = null
}
if(fbo._depth_rb) {
gl.deleteRenderbuffer(fbo._depth_rb)
fbo._depth_rb = null
}
for(var i=0; i maxFBOSize ||
h < 0 || h > maxFBOSize) {
throw new Error('gl-fbo: Can\'t resize FBO, invalid dimensions')
}
//Update shape
fbo._shape[0] = w
fbo._shape[1] = h
//Save framebuffer state
var state = saveFBOState(gl)
//Resize framebuffer attachments
for(var i=0; i maxFBOSize || height < 0 || height > maxFBOSize) {
throw new Error('gl-fbo: Parameters are too large for FBO')
}
//Handle each option type
options = options || {}
//Figure out number of color buffers to use
var numColors = 1
if('color' in options) {
numColors = Math.max(options.color|0, 0)
if(numColors < 0) {
throw new Error('gl-fbo: Must specify a nonnegative number of colors')
}
if(numColors > 1) {
//Check if multiple render targets supported
if(!WEBGL_draw_buffers) {
throw new Error('gl-fbo: Multiple draw buffer extension not supported')
} else if(numColors > gl.getParameter(WEBGL_draw_buffers.MAX_COLOR_ATTACHMENTS_WEBGL)) {
throw new Error('gl-fbo: Context does not support ' + numColors + ' draw buffers')
}
}
}
//Determine whether to use floating point textures
var colorType = gl.UNSIGNED_BYTE
var OES_texture_float = gl.getExtension('OES_texture_float')
if(options.float && numColors > 0) {
if(!OES_texture_float) {
throw new Error('gl-fbo: Context does not support floating point textures')
}
colorType = gl.FLOAT
} else if(options.preferFloat && numColors > 0) {
if(OES_texture_float) {
colorType = gl.FLOAT
}
}
//Check if we should use depth buffer
var useDepth = true
if('depth' in options) {
useDepth = !!options.depth
}
//Check if we should use a stencil buffer
var useStencil = false
if('stencil' in options) {
useStencil = !!options.stencil
}
return new Framebuffer(
gl,
width,
height,
colorType,
numColors,
useDepth,
useStencil,
WEBGL_draw_buffers)
}
},{"gl-texture2d":262}],160:[function(require,module,exports){
var sprintf = require('sprintf-js').sprintf;
var glConstants = require('gl-constants/lookup');
var shaderName = require('glsl-shader-name');
var addLineNumbers = require('add-line-numbers');
module.exports = formatCompilerError;
function formatCompilerError(errLog, src, type) {
"use strict";
var name = shaderName(src) || 'of unknown name (see npm glsl-shader-name)';
var typeName = 'unknown type';
if (type !== undefined) {
typeName = type === glConstants.FRAGMENT_SHADER ? 'fragment' : 'vertex'
}
var longForm = sprintf('Error compiling %s shader %s:\n', typeName, name);
var shortForm = sprintf("%s%s", longForm, errLog);
var errorStrings = errLog.split('\n');
var errors = {};
for (var i = 0; i < errorStrings.length; i++) {
var errorString = errorStrings[i];
if (errorString === '') continue;
var lineNo = parseInt(errorString.split(':')[2]);
if (isNaN(lineNo)) {
throw new Error(sprintf('Could not parse error: %s', errorString));
}
errors[lineNo] = errorString;
}
var lines = addLineNumbers(src).split('\n');
for (var i = 0; i < lines.length; i++) {
if (!errors[i+3] && !errors[i+2] && !errors[i+1]) continue;
var line = lines[i];
longForm += line + '\n';
if (errors[i+1]) {
var e = errors[i+1];
e = e.substr(e.split(':', 3).join(':').length + 1).trim();
longForm += sprintf('^^^ %s\n\n', e);
}
}
return {
long: longForm.trim(),
short: shortForm.trim()
};
}
},{"add-line-numbers":38,"gl-constants/lookup":154,"glsl-shader-name":274,"sprintf-js":519}],161:[function(require,module,exports){
'use strict'
module.exports = createHeatmap2D
var bsearch = require('binary-search-bounds')
var iota = require('iota-array')
var pool = require('typedarray-pool')
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var shaders = require('./lib/shaders')
function GLHeatmap2D (
plot,
shader,
pickShader,
positionBuffer,
weightBuffer,
colorBuffer,
idBuffer) {
this.plot = plot
this.shader = shader
this.pickShader = pickShader
this.positionBuffer = positionBuffer
this.weightBuffer = weightBuffer
this.colorBuffer = colorBuffer
this.idBuffer = idBuffer
this.xData = []
this.yData = []
this.shape = [0, 0]
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
this.pickOffset = 0
}
var proto = GLHeatmap2D.prototype
var WEIGHTS = [
0, 0,
1, 0,
0, 1,
1, 0,
1, 1,
0, 1
]
proto.draw = (function () {
var MATRIX = [
1, 0, 0,
0, 1, 0,
0, 0, 1
]
return function () {
var plot = this.plot
var shader = this.shader
var bounds = this.bounds
var numVertices = this.numVertices
if (numVertices <= 0) {
return
}
var gl = plot.gl
var dataBox = plot.dataBox
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
MATRIX[0] = 2.0 * boundX / dataX
MATRIX[4] = 2.0 * boundY / dataY
MATRIX[6] = 2.0 * (bounds[0] - dataBox[0]) / dataX - 1.0
MATRIX[7] = 2.0 * (bounds[1] - dataBox[1]) / dataY - 1.0
shader.bind()
var uniforms = shader.uniforms
uniforms.viewTransform = MATRIX
uniforms.shape = this.shape
var attributes = shader.attributes
this.positionBuffer.bind()
attributes.position.pointer()
this.weightBuffer.bind()
attributes.weight.pointer(gl.UNSIGNED_BYTE, false)
this.colorBuffer.bind()
attributes.color.pointer(gl.UNSIGNED_BYTE, true)
gl.drawArrays(gl.TRIANGLES, 0, numVertices)
}
})()
proto.drawPick = (function () {
var MATRIX = [
1, 0, 0,
0, 1, 0,
0, 0, 1
]
var PICK_VECTOR = [0, 0, 0, 0]
return function (pickOffset) {
var plot = this.plot
var shader = this.pickShader
var bounds = this.bounds
var numVertices = this.numVertices
if (numVertices <= 0) {
return
}
var gl = plot.gl
var dataBox = plot.dataBox
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
MATRIX[0] = 2.0 * boundX / dataX
MATRIX[4] = 2.0 * boundY / dataY
MATRIX[6] = 2.0 * (bounds[0] - dataBox[0]) / dataX - 1.0
MATRIX[7] = 2.0 * (bounds[1] - dataBox[1]) / dataY - 1.0
for (var i = 0; i < 4; ++i) {
PICK_VECTOR[i] = (pickOffset >> (i * 8)) & 0xff
}
this.pickOffset = pickOffset
shader.bind()
var uniforms = shader.uniforms
uniforms.viewTransform = MATRIX
uniforms.pickOffset = PICK_VECTOR
uniforms.shape = this.shape
var attributes = shader.attributes
this.positionBuffer.bind()
attributes.position.pointer()
this.weightBuffer.bind()
attributes.weight.pointer(gl.UNSIGNED_BYTE, false)
this.idBuffer.bind()
attributes.pickId.pointer(gl.UNSIGNED_BYTE, false)
gl.drawArrays(gl.TRIANGLES, 0, numVertices)
return pickOffset + this.shape[0] * this.shape[1]
}
})()
proto.pick = function (x, y, value) {
var pickOffset = this.pickOffset
var pointCount = this.shape[0] * this.shape[1]
if (value < pickOffset || value >= pickOffset + pointCount) {
return null
}
var pointId = value - pickOffset
var xData = this.xData
var yData = this.yData
return {
object: this,
pointId: pointId,
dataCoord: [
xData[pointId % this.shape[0]],
yData[(pointId / this.shape[0]) | 0]]
}
}
proto.update = function (options) {
options = options || {}
var shape = options.shape || [0, 0]
var x = options.x || iota(shape[0])
var y = options.y || iota(shape[1])
var z = options.z || new Float32Array(shape[0] * shape[1])
this.xData = x
this.yData = y
var colorLevels = options.colorLevels || [0]
var colorValues = options.colorValues || [0, 0, 0, 1]
var colorCount = colorLevels.length
var bounds = this.bounds
var lox = bounds[0] = x[0]
var loy = bounds[1] = y[0]
var hix = bounds[2] = x[x.length - 1]
var hiy = bounds[3] = y[y.length - 1]
var xs = 1.0 / (hix - lox)
var ys = 1.0 / (hiy - loy)
var numX = shape[0]
var numY = shape[1]
this.shape = [numX, numY]
var numVerts = (numX - 1) * (numY - 1) * (WEIGHTS.length >>> 1)
this.numVertices = numVerts
var colors = pool.mallocUint8(numVerts * 4)
var positions = pool.mallocFloat32(numVerts * 2)
var weights = pool.mallocUint8 (numVerts * 2)
var ids = pool.mallocUint32(numVerts)
var ptr = 0
for (var j = 0; j < numY - 1; ++j) {
var yc0 = ys * (y[j] - loy)
var yc1 = ys * (y[j + 1] - loy)
for (var i = 0; i < numX - 1; ++i) {
var xc0 = xs * (x[i] - lox)
var xc1 = xs * (x[i + 1] - lox)
for (var dd = 0; dd < WEIGHTS.length; dd += 2) {
var dx = WEIGHTS[dd]
var dy = WEIGHTS[dd + 1]
var offset = (j + dy) * numX + (i + dx)
var zc = z[offset]
var colorIdx = bsearch.le(colorLevels, zc)
var r, g, b, a
if (colorIdx < 0) {
r = colorValues[0]
g = colorValues[1]
b = colorValues[2]
a = colorValues[3]
} else if (colorIdx === colorCount - 1) {
r = colorValues[4 * colorCount - 4]
g = colorValues[4 * colorCount - 3]
b = colorValues[4 * colorCount - 2]
a = colorValues[4 * colorCount - 1]
} else {
var t = (zc - colorLevels[colorIdx]) /
(colorLevels[colorIdx + 1] - colorLevels[colorIdx])
var ti = 1.0 - t
var i0 = 4 * colorIdx
var i1 = 4 * (colorIdx + 1)
r = ti * colorValues[i0] + t * colorValues[i1]
g = ti * colorValues[i0 + 1] + t * colorValues[i1 + 1]
b = ti * colorValues[i0 + 2] + t * colorValues[i1 + 2]
a = ti * colorValues[i0 + 3] + t * colorValues[i1 + 3]
}
colors[4 * ptr] = 255 * r
colors[4 * ptr + 1] = 255 * g
colors[4 * ptr + 2] = 255 * b
colors[4 * ptr + 3] = 255 * a
positions[2*ptr] = xc0*.5 + xc1*.5;
positions[2*ptr+1] = yc0*.5 + yc1*.5;
weights[2*ptr] = dx;
weights[2*ptr+1] = dy;
ids[ptr] = j * numX + i
ptr += 1
}
}
}
this.positionBuffer.update(positions)
this.weightBuffer.update(weights)
this.colorBuffer.update(colors)
this.idBuffer.update(ids)
pool.free(positions)
pool.free(colors)
pool.free(weights)
pool.free(ids)
}
proto.dispose = function () {
this.shader.dispose()
this.pickShader.dispose()
this.positionBuffer.dispose()
this.weightBuffer.dispose()
this.colorBuffer.dispose()
this.idBuffer.dispose()
this.plot.removeObject(this)
}
function createHeatmap2D (plot, options) {
var gl = plot.gl
var shader = createShader(gl, shaders.vertex, shaders.fragment)
var pickShader = createShader(gl, shaders.pickVertex, shaders.pickFragment)
var positionBuffer = createBuffer(gl)
var weightBuffer = createBuffer(gl)
var colorBuffer = createBuffer(gl)
var idBuffer = createBuffer(gl)
var heatmap = new GLHeatmap2D(
plot,
shader,
pickShader,
positionBuffer,
weightBuffer,
colorBuffer,
idBuffer)
heatmap.update(options)
plot.addObject(heatmap)
return heatmap
}
},{"./lib/shaders":162,"binary-search-bounds":163,"gl-buffer":152,"gl-shader":250,"iota-array":287,"typedarray-pool":533}],162:[function(require,module,exports){
'use strict'
module.exports = {
fragment: "precision lowp float;\n#define GLSLIFY 1\nvarying vec4 fragColor;\nvoid main() {\n gl_FragColor = vec4(fragColor.rgb * fragColor.a, fragColor.a);\n}\n",
vertex: "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec2 position;\nattribute vec4 color;\nattribute vec2 weight;\n\nuniform vec2 shape;\nuniform mat3 viewTransform;\n\nvarying vec4 fragColor;\n\nvoid main() {\n vec3 vPosition = viewTransform * vec3( position + (weight-.5)/(shape-1.) , 1.0);\n fragColor = color;\n gl_Position = vec4(vPosition.xy, 0, vPosition.z);\n}\n",
pickFragment: "precision mediump float;\n#define GLSLIFY 1\n\nvarying vec4 fragId;\nvarying vec2 vWeight;\n\nuniform vec2 shape;\nuniform vec4 pickOffset;\n\nvoid main() {\n vec2 d = step(.5, vWeight);\n vec4 id = fragId + pickOffset;\n id.x += d.x + d.y*shape.x;\n\n id.y += floor(id.x / 256.0);\n id.x -= floor(id.x / 256.0) * 256.0;\n\n id.z += floor(id.y / 256.0);\n id.y -= floor(id.y / 256.0) * 256.0;\n\n id.w += floor(id.z / 256.0);\n id.z -= floor(id.z / 256.0) * 256.0;\n\n gl_FragColor = id/255.;\n}\n",
pickVertex: "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec2 position;\nattribute vec4 pickId;\nattribute vec2 weight;\n\nuniform vec2 shape;\nuniform mat3 viewTransform;\n\nvarying vec4 fragId;\nvarying vec2 vWeight;\n\nvoid main() {\n vWeight = weight;\n\n fragId = pickId;\n\n vec3 vPosition = viewTransform * vec3( position + (weight-.5)/(shape-1.) , 1.0);\n gl_Position = vec4(vPosition.xy, 0, vPosition.z);\n}\n"
}
},{}],163:[function(require,module,exports){
arguments[4][80][0].apply(exports,arguments)
},{"dup":80}],164:[function(require,module,exports){
exports.lineVertex = "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 aHi, aLo, dHi, dLo;\n\nuniform vec2 scaleHi, translateHi, scaleLo, translateLo, screenShape;\nuniform float width;\n\nvarying vec2 direction;\n\n\nvec2 project_1_0(vec2 scHi, vec2 trHi, vec2 scLo, vec2 trLo, vec2 posHi, vec2 posLo) {\n return (posHi + trHi) * scHi\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo;\n}\n\n\nvec2 project_2_1(vec2 scHi, vec2 scLo, vec2 posHi, vec2 posLo) {\n return scHi * posHi\n + scLo * posHi\n + scHi * posLo\n + scLo * posLo;\n}\n\nvoid main() {\n vec2 p = project_1_0(scaleHi, translateHi, scaleLo, translateLo, aHi, aLo);\n vec2 dir = project_2_1(scaleHi, scaleLo, dHi, dLo);\n vec2 n = 0.5 * width * normalize(screenShape.yx * vec2(dir.y, -dir.x)) / screenShape.xy;\n vec2 tangent = normalize(screenShape.xy * dir);\n if(dir.x < 0.0 || (dir.x == 0.0 && dir.y < 0.0)) {\n direction = -tangent;\n } else {\n direction = tangent;\n }\n gl_Position = vec4(p + n, 0.0, 1.0);\n}"
exports.lineFragment = "precision highp float;\n#define GLSLIFY 1\n\nuniform vec4 color;\nuniform vec2 screenShape;\nuniform sampler2D dashPattern;\nuniform float dashLength;\n\nvarying vec2 direction;\n\nvoid main() {\n float t = fract(dot(direction, gl_FragCoord.xy) / dashLength);\n vec4 pcolor = color * texture2D(dashPattern, vec2(t, 0.0)).r;\n gl_FragColor = vec4(pcolor.rgb * pcolor.a, pcolor.a);\n}"
exports.mitreVertex = "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 aHi, aLo;\n\nuniform vec2 scaleHi, translateHi, scaleLo, translateLo;\nuniform float radius;\n\n\nvec2 project_1_0(vec2 scHi, vec2 trHi, vec2 scLo, vec2 trLo, vec2 posHi, vec2 posLo) {\n return (posHi + trHi) * scHi\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo;\n}\n\n\nvoid main() {\n vec2 p = project_1_0(scaleHi, translateHi, scaleLo, translateLo, aHi, aLo);\n gl_Position = vec4(p, 0.0, 1.0);\n gl_PointSize = radius;\n}"
exports.mitreFragment = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec4 color;\n\nvoid main() {\n if(length(gl_PointCoord.xy - 0.5) > 0.25) {\n discard;\n }\n gl_FragColor = vec4(color.rgb, color.a);\n}"
exports.pickVertex = "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 aHi, aLo, dHi;\nattribute vec4 pick0, pick1;\n\nuniform vec2 scaleHi, translateHi, scaleLo, translateLo, screenShape;\nuniform float width;\n\nvarying vec4 pickA, pickB;\n\n\nvec2 project_1_0(vec2 scHi, vec2 trHi, vec2 scLo, vec2 trLo, vec2 posHi, vec2 posLo) {\n return (posHi + trHi) * scHi\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo;\n}\n\n\nvoid main() {\n vec2 p = project_1_0(scaleHi, translateHi, scaleLo, translateLo, aHi, aLo);\n vec2 n = width * normalize(screenShape.yx * vec2(dHi.y, -dHi.x)) / screenShape.xy;\n gl_Position = vec4(p + n, 0, 1);\n pickA = pick0;\n pickB = pick1;\n}"
exports.pickFragment = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec4 pickOffset;\n\nvarying vec4 pickA, pickB;\n\nvoid main() {\n vec4 fragId = vec4(pickA.xyz, 0.0);\n if(pickB.w > pickA.w) {\n fragId.xyz = pickB.xyz;\n }\n\n fragId += pickOffset;\n\n fragId.y += floor(fragId.x / 256.0);\n fragId.x -= floor(fragId.x / 256.0) * 256.0;\n\n fragId.z += floor(fragId.y / 256.0);\n fragId.y -= floor(fragId.y / 256.0) * 256.0;\n\n fragId.w += floor(fragId.z / 256.0);\n fragId.z -= floor(fragId.z / 256.0) * 256.0;\n\n gl_FragColor = fragId / 255.0;\n}"
exports.fillVertex = "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 aHi, aLo, dHi;\n\nuniform vec2 scaleHi, translateHi, scaleLo, translateLo, projectAxis;\nuniform float projectValue, depth;\n\n\nvec2 project_1_0(vec2 scHi, vec2 trHi, vec2 scLo, vec2 trLo, vec2 posHi, vec2 posLo) {\n return (posHi + trHi) * scHi\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo;\n}\n\n\nvoid main() {\n vec2 p = project_1_0(scaleHi, translateHi, scaleLo, translateLo, aHi, aLo);\n if(dHi.y < 0.0 || (dHi.y == 0.0 && dHi.x < 0.0)) {\n if(dot(p, projectAxis) < projectValue) {\n p = p * (1.0 - abs(projectAxis)) + projectAxis * projectValue;\n }\n }\n gl_Position = vec4(p, depth, 1);\n}"
exports.fillFragment = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec4 color;\n\nvoid main() {\n gl_FragColor = vec4(color.rgb * color.a, color.a);\n}"
},{}],165:[function(require,module,exports){
'use strict'
module.exports = createLinePlot
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var createTexture = require('gl-texture2d')
var ndarray = require('ndarray')
var pool = require('typedarray-pool')
var SHADERS = require('./lib/shaders')
function GLLine2D(
plot,
dashPattern,
lineBufferHi,
lineBufferLo,
pickBuffer,
lineShader,
mitreShader,
fillShader,
pickShader) {
this.plot = plot
this.dashPattern = dashPattern
this.lineBufferHi = lineBufferHi
this.lineBufferLo = lineBufferLo
this.pickBuffer = pickBuffer
this.lineShader = lineShader
this.mitreShader = mitreShader
this.fillShader = fillShader
this.pickShader = pickShader
this.usingDashes = false
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
this.width = 1
this.color = [0, 0, 1, 1]
//Fill to axes
this.fill = [false, false, false, false]
this.fillColor = [
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1]
]
this.data = null
this.numPoints = 0
this.vertCount = 0
this.pickOffset = 0
}
var proto = GLLine2D.prototype
proto.setProjectionModel = (function() {
var pm = {
scaleHi: new Float32Array([0, 0]),
scaleLo: new Float32Array([0, 0]),
translateHi: new Float32Array([0, 0]),
translateLo: new Float32Array([0, 0]),
screenShape: [0, 0]
}
return function() {
var bounds = this.bounds
var viewBox = this.plot.viewBox
var dataBox = this.plot.dataBox
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
var screenX = viewBox[2] - viewBox[0]
var screenY = viewBox[3] - viewBox[1]
var scaleX = 2 * boundX / dataX
var scaleY = 2 * boundY / dataY
var translateX = (bounds[0] - dataBox[0] - 0.5 * dataX) / boundX
var translateY = (bounds[1] - dataBox[1] - 0.5 * dataY) / boundY
pm.scaleHi[0] = scaleX
pm.scaleHi[1] = scaleY
pm.scaleLo[0] = scaleX - pm.scaleHi[0]
pm.scaleLo[1] = scaleY - pm.scaleHi[1]
pm.translateHi[0] = translateX
pm.translateHi[1] = translateY
pm.translateLo[0] = translateX - pm.translateHi[0]
pm.translateLo[1] = translateY - pm.translateHi[1]
pm.screenShape[0] = screenX
pm.screenShape[1] = screenY
return pm
}
})()
proto.setProjectionUniforms = function(uniforms, projectionModel) {
uniforms.scaleHi = projectionModel.scaleHi
uniforms.scaleLo = projectionModel.scaleLo
uniforms.translateHi = projectionModel.translateHi
uniforms.translateLo = projectionModel.translateLo
uniforms.screenShape = projectionModel.screenShape
}
proto.draw = (function() {
var PX_AXIS = [1, 0]
var NX_AXIS = [-1, 0]
var PY_AXIS = [0, 1]
var NY_AXIS = [0, -1]
return function() {
var count = this.vertCount
if(!count) {
return
}
var projectionModel = this.setProjectionModel()
var plot = this.plot
var width = this.width
var gl = plot.gl
var pixelRatio = plot.pixelRatio
var color = this.color
var fillAttributes = this.fillShader.attributes
this.lineBufferLo.bind()
fillAttributes.aLo.pointer(gl.FLOAT, false, 16, 0)
this.lineBufferHi.bind()
var fill = this.fill
if(fill[0] || fill[1] || fill[2] || fill[3]) {
var fillShader = this.fillShader
fillShader.bind()
var fillUniforms = fillShader.uniforms
this.setProjectionUniforms(fillUniforms, projectionModel)
fillUniforms.depth = plot.nextDepthValue()
fillAttributes.aHi.pointer(gl.FLOAT, false, 16, 0)
fillAttributes.dHi.pointer(gl.FLOAT, false, 16, 8)
gl.depthMask(true)
gl.enable(gl.DEPTH_TEST)
var fillColor = this.fillColor
if(fill[0]) {
fillUniforms.color = fillColor[0]
fillUniforms.projectAxis = NX_AXIS
fillUniforms.projectValue = 1
gl.drawArrays(gl.TRIANGLES, 0, count)
}
if(fill[1]) {
fillUniforms.color = fillColor[1]
fillUniforms.projectAxis = NY_AXIS
fillUniforms.projectValue = 1
gl.drawArrays(gl.TRIANGLES, 0, count)
}
if(fill[2]) {
fillUniforms.color = fillColor[2]
fillUniforms.projectAxis = PX_AXIS
fillUniforms.projectValue = 1
gl.drawArrays(gl.TRIANGLES, 0, count)
}
if(fill[3]) {
fillUniforms.color = fillColor[3]
fillUniforms.projectAxis = PY_AXIS
fillUniforms.projectValue = 1
gl.drawArrays(gl.TRIANGLES, 0, count)
}
gl.depthMask(false)
gl.disable(gl.DEPTH_TEST)
}
var shader = this.lineShader
shader.bind()
this.lineBufferLo.bind()
shader.attributes.aLo.pointer(gl.FLOAT, false, 16, 0)
shader.attributes.dLo.pointer(gl.FLOAT, false, 16, 8)
this.lineBufferHi.bind()
var uniforms = shader.uniforms
this.setProjectionUniforms(uniforms, projectionModel)
uniforms.color = color
uniforms.width = width * pixelRatio
uniforms.dashPattern = this.dashPattern.bind()
uniforms.dashLength = this.dashLength * pixelRatio
var attributes = shader.attributes
attributes.aHi.pointer(gl.FLOAT, false, 16, 0)
attributes.dHi.pointer(gl.FLOAT, false, 16, 8)
gl.drawArrays(gl.TRIANGLES, 0, count)
//Draw mitres
if(width > 2 && !this.usingDashes) {
var mshader = this.mitreShader
this.lineBufferLo.bind()
mshader.attributes.aLo.pointer(gl.FLOAT, false, 48, 0)
this.lineBufferHi.bind()
mshader.bind()
var muniforms = mshader.uniforms
this.setProjectionUniforms(muniforms, projectionModel)
muniforms.color = color
muniforms.radius = width * pixelRatio
mshader.attributes.aHi.pointer(gl.FLOAT, false, 48, 0)
gl.drawArrays(gl.POINTS, 0, (count / 3) | 0)
}
}
})()
proto.drawPick = (function() {
var PICK_OFFSET = [0, 0, 0, 0]
return function(pickOffset) {
var count = this.vertCount
var numPoints = this.numPoints
this.pickOffset = pickOffset
if(!count) {
return pickOffset + numPoints
}
var projectionModel = this.setProjectionModel()
var plot = this.plot
var width = this.width
var gl = plot.gl
var pixelRatio = plot.pickPixelRatio
var shader = this.pickShader
var pickBuffer = this.pickBuffer
PICK_OFFSET[0] = pickOffset & 0xff
PICK_OFFSET[1] = (pickOffset >>> 8) & 0xff
PICK_OFFSET[2] = (pickOffset >>> 16) & 0xff
PICK_OFFSET[3] = pickOffset >>> 24
shader.bind()
var uniforms = shader.uniforms
this.setProjectionUniforms(uniforms, projectionModel)
uniforms.width = width * pixelRatio
uniforms.pickOffset = PICK_OFFSET
var attributes = shader.attributes
this.lineBufferHi.bind()
attributes.aHi.pointer(gl.FLOAT, false, 16, 0)
attributes.dHi.pointer(gl.FLOAT, false, 16, 8)
this.lineBufferLo.bind()
attributes.aLo.pointer(gl.FLOAT, false, 16, 0)
//attributes.dLo.pointer(gl.FLOAT, false, 16, 8)
pickBuffer.bind()
attributes.pick0.pointer(gl.UNSIGNED_BYTE, false, 8, 0)
attributes.pick1.pointer(gl.UNSIGNED_BYTE, false, 8, 4)
gl.drawArrays(gl.TRIANGLES, 0, count)
return pickOffset + numPoints
}
})()
proto.pick = function(x, y, value) {
var pickOffset = this.pickOffset
var pointCount = this.numPoints
if(value < pickOffset || value >= pickOffset + pointCount) {
return null
}
var pointId = value - pickOffset
var points = this.data
return {
object: this,
pointId: pointId,
dataCoord: [points[2 * pointId], points[2 * pointId + 1]]
}
}
function deepCopy(arr) {
return arr.map(function(x) {
return x.slice()
})
}
proto.update = function(options) {
options = options || {}
var gl = this.plot.gl
var i, j, ptr, ax, ay
this.color = (options.color || [0, 0, 1, 1]).slice()
this.width = +(options.width || 1)
this.fill = (options.fill || [false, false, false, false]).slice()
this.fillColor = deepCopy(options.fillColor || [
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 1]
])
var dashes = options.dashes || [1]
var dashLength = 0
for(i = 0; i < dashes.length; ++i) {
dashLength += dashes[i]
}
var dashData = pool.mallocUint8(dashLength)
ptr = 0
var fillColor = 255
for(i = 0; i < dashes.length; ++i) {
for(j = 0; j < dashes[i]; ++j) {
dashData[ptr++] = fillColor
}
fillColor ^= 255
}
this.dashPattern.dispose()
this.usingDashes = dashes.length > 1
this.dashPattern = createTexture(gl, ndarray(dashData, [dashLength, 1, 4], [1, 0, 0]))
this.dashPattern.minFilter = gl.NEAREST
this.dashPattern.magFilter = gl.NEAREST
this.dashLength = dashLength
pool.free(dashData)
var data = options.positions
this.data = data
var bounds = this.bounds
bounds[0] = bounds[1] = Infinity
bounds[2] = bounds[3] = -Infinity
var numPoints = this.numPoints = data.length >>> 1
if(numPoints === 0) {
return
}
for(i = 0; i < numPoints; ++i) {
ax = data[2 * i]
ay = data[2 * i + 1]
if (isNaN(ax) || isNaN(ay)) {
continue
}
bounds[0] = Math.min(bounds[0], ax)
bounds[1] = Math.min(bounds[1], ay)
bounds[2] = Math.max(bounds[2], ax)
bounds[3] = Math.max(bounds[3], ay)
}
if(bounds[0] === bounds[2]) bounds[2] += 1
if(bounds[3] === bounds[1]) bounds[3] += 1
//Generate line data
var lineData = pool.mallocFloat64(24 * (numPoints - 1))
var lineDataHi = pool.mallocFloat32(24 * (numPoints - 1))
var lineDataLo = pool.mallocFloat32(24 * (numPoints - 1))
var pickData = pool.mallocUint32(12 * (numPoints - 1))
var lineDataPtr = lineDataHi.length
var pickDataPtr = pickData.length
ptr = numPoints
var count = 0
while(ptr > 1) {
var id = --ptr
ax = data[2 * ptr]
ay = data[2 * ptr + 1]
var next = id - 1
var bx = data[2 * next]
var by = data[2 * next + 1]
if (isNaN(ax) || isNaN(ay) || isNaN(bx) || isNaN(by)) {
continue
}
count += 1
ax = (ax - bounds[0]) / (bounds[2] - bounds[0])
ay = (ay - bounds[1]) / (bounds[3] - bounds[1])
bx = (bx - bounds[0]) / (bounds[2] - bounds[0])
by = (by - bounds[1]) / (bounds[3] - bounds[1])
var dx = bx - ax
var dy = by - ay
var akey0 = id | (1 << 24)
var akey1 = (id - 1)
var bkey0 = id
var bkey1 = (id - 1) | (1 << 24)
lineData[--lineDataPtr] = -dy
lineData[--lineDataPtr] = -dx
lineData[--lineDataPtr] = ay
lineData[--lineDataPtr] = ax
pickData[--pickDataPtr] = akey0
pickData[--pickDataPtr] = akey1
lineData[--lineDataPtr] = dy
lineData[--lineDataPtr] = dx
lineData[--lineDataPtr] = by
lineData[--lineDataPtr] = bx
pickData[--pickDataPtr] = bkey0
pickData[--pickDataPtr] = bkey1
lineData[--lineDataPtr] = -dy
lineData[--lineDataPtr] = -dx
lineData[--lineDataPtr] = by
lineData[--lineDataPtr] = bx
pickData[--pickDataPtr] = bkey0
pickData[--pickDataPtr] = bkey1
lineData[--lineDataPtr] = dy
lineData[--lineDataPtr] = dx
lineData[--lineDataPtr] = by
lineData[--lineDataPtr] = bx
pickData[--pickDataPtr] = bkey0
pickData[--pickDataPtr] = bkey1
lineData[--lineDataPtr] = -dy
lineData[--lineDataPtr] = -dx
lineData[--lineDataPtr] = ay
lineData[--lineDataPtr] = ax
pickData[--pickDataPtr] = akey0
pickData[--pickDataPtr] = akey1
lineData[--lineDataPtr] = dy
lineData[--lineDataPtr] = dx
lineData[--lineDataPtr] = ay
lineData[--lineDataPtr] = ax
pickData[--pickDataPtr] = akey0
pickData[--pickDataPtr] = akey1
}
for(i = 0; i < lineData.length; i++) {
lineDataHi[i] = lineData[i]
lineDataLo[i] = lineData[i] - lineDataHi[i]
}
this.vertCount = 6 * count
this.lineBufferHi.update(lineDataHi.subarray(lineDataPtr))
this.lineBufferLo.update(lineDataLo.subarray(lineDataPtr))
this.pickBuffer.update(pickData.subarray(pickDataPtr))
pool.free(lineData)
pool.free(lineDataHi)
pool.free(lineDataLo)
pool.free(pickData)
}
proto.dispose = function() {
this.plot.removeObject(this)
this.lineBufferLo.dispose()
this.lineBufferHi.dispose()
this.pickBuffer.dispose()
this.lineShader.dispose()
this.mitreShader.dispose()
this.fillShader.dispose()
this.pickShader.dispose()
this.dashPattern.dispose()
}
function createLinePlot(plot, options) {
var gl = plot.gl
var lineBufferHi = createBuffer(gl)
var lineBufferLo = createBuffer(gl)
var pickBuffer = createBuffer(gl)
var dashPattern = createTexture(gl, [1, 1])
var lineShader = createShader(gl, SHADERS.lineVertex, SHADERS.lineFragment)
var mitreShader = createShader(gl, SHADERS.mitreVertex, SHADERS.mitreFragment)
var fillShader = createShader(gl, SHADERS.fillVertex, SHADERS.fillFragment)
var pickShader = createShader(gl, SHADERS.pickVertex, SHADERS.pickFragment)
var linePlot = new GLLine2D(
plot,
dashPattern,
lineBufferHi,
lineBufferLo,
pickBuffer,
lineShader,
mitreShader,
fillShader,
pickShader)
plot.addObject(linePlot)
linePlot.update(options)
return linePlot
}
},{"./lib/shaders":164,"gl-buffer":152,"gl-shader":250,"gl-texture2d":262,"ndarray":460,"typedarray-pool":533}],166:[function(require,module,exports){
var createShader = require('gl-shader')
var vertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position, nextPosition;\nattribute float arcLength, lineWidth;\nattribute vec4 color;\n\nuniform vec2 screenShape;\nuniform float pixelRatio;\nuniform mat4 model, view, projection;\n\nvarying vec4 fragColor;\nvarying vec3 worldPosition;\nvarying float pixelArcLength;\n\nvoid main() {\n vec4 projected = projection * view * model * vec4(position, 1.0);\n vec4 tangentClip = projection * view * model * vec4(nextPosition - position, 0.0);\n vec2 tangent = normalize(screenShape * tangentClip.xy);\n vec2 offset = 0.5 * pixelRatio * lineWidth * vec2(tangent.y, -tangent.x) / screenShape;\n\n gl_Position = vec4(projected.xy + projected.w * offset, projected.zw);\n\n worldPosition = position;\n pixelArcLength = arcLength;\n fragColor = color;\n}\n"
var forwardFrag = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec3 clipBounds[2];\nuniform sampler2D dashTexture;\nuniform float dashScale;\nuniform float opacity;\n\nvarying vec3 worldPosition;\nvarying float pixelArcLength;\nvarying vec4 fragColor;\n\nvoid main() {\n if(any(lessThan(worldPosition, clipBounds[0])) || any(greaterThan(worldPosition, clipBounds[1]))) {\n discard;\n }\n float dashWeight = texture2D(dashTexture, vec2(dashScale * pixelArcLength, 0)).r;\n if(dashWeight < 0.5) {\n discard;\n }\n gl_FragColor = fragColor * opacity;\n}\n"
var pickFrag = "precision mediump float;\n#define GLSLIFY 1\n\n#define FLOAT_MAX 1.70141184e38\n#define FLOAT_MIN 1.17549435e-38\n\nlowp vec4 encode_float_1_0(highp float v) {\n highp float av = abs(v);\n\n //Handle special cases\n if(av < FLOAT_MIN) {\n return vec4(0.0, 0.0, 0.0, 0.0);\n } else if(v > FLOAT_MAX) {\n return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;\n } else if(v < -FLOAT_MAX) {\n return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;\n }\n\n highp vec4 c = vec4(0,0,0,0);\n\n //Compute exponent and mantissa\n highp float e = floor(log2(av));\n highp float m = av * pow(2.0, -e) - 1.0;\n \n //Unpack mantissa\n c[1] = floor(128.0 * m);\n m -= c[1] / 128.0;\n c[2] = floor(32768.0 * m);\n m -= c[2] / 32768.0;\n c[3] = floor(8388608.0 * m);\n \n //Unpack exponent\n highp float ebias = e + 127.0;\n c[0] = floor(ebias / 2.0);\n ebias -= c[0] * 2.0;\n c[1] += floor(ebias) * 128.0; \n\n //Unpack sign bit\n c[0] += 128.0 * step(0.0, -v);\n\n //Scale back to range\n return c / 255.0;\n}\n\n\n\nuniform float pickId;\nuniform vec3 clipBounds[2];\n\nvarying vec3 worldPosition;\nvarying float pixelArcLength;\nvarying vec4 fragColor;\n\nvoid main() {\n if(any(lessThan(worldPosition, clipBounds[0])) || any(greaterThan(worldPosition, clipBounds[1]))) {\n discard;\n }\n gl_FragColor = vec4(pickId/255.0, encode_float_1_0(pixelArcLength).xyz);\n}"
var ATTRIBUTES = [
{name: 'position', type: 'vec3'},
{name: 'nextPosition', type: 'vec3'},
{name: 'arcLength', type: 'float'},
{name: 'lineWidth', type: 'float'},
{name: 'color', type: 'vec4'}
]
exports.createShader = function(gl) {
return createShader(gl, vertSrc, forwardFrag, null, ATTRIBUTES)
}
exports.createPickShader = function(gl) {
return createShader(gl, vertSrc, pickFrag, null, ATTRIBUTES)
}
},{"gl-shader":250}],167:[function(require,module,exports){
'use strict'
module.exports = createLinePlot
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var createTexture = require('gl-texture2d')
var unpackFloat = require('glsl-read-float')
var bsearch = require('binary-search-bounds')
var ndarray = require('ndarray')
var shaders = require('./lib/shaders')
var createShader = shaders.createShader
var createPickShader = shaders.createPickShader
var identity = [1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]
function distance (a, b) {
var s = 0.0
for (var i = 0; i < 3; ++i) {
var d = a[i] - b[i]
s += d * d
}
return Math.sqrt(s)
}
function filterClipBounds (bounds) {
var result = [[-1e6, -1e6, -1e6], [1e6, 1e6, 1e6]]
for (var i = 0; i < 3; ++i) {
result[0][i] = Math.max(bounds[0][i], result[0][i])
result[1][i] = Math.min(bounds[1][i], result[1][i])
}
return result
}
function PickResult (tau, position, index, dataCoordinate) {
this.arcLength = tau
this.position = position
this.index = index
this.dataCoordinate = dataCoordinate
}
function LinePlot (gl, shader, pickShader, buffer, vao, texture) {
this.gl = gl
this.shader = shader
this.pickShader = pickShader
this.buffer = buffer
this.vao = vao
this.clipBounds = [
[ -Infinity, -Infinity, -Infinity ],
[ Infinity, Infinity, Infinity ]]
this.points = []
this.arcLength = []
this.vertexCount = 0
this.bounds = [[0, 0, 0], [0, 0, 0]]
this.pickId = 0
this.lineWidth = 1
this.texture = texture
this.dashScale = 1
this.opacity = 1
this.dirty = true
this.pixelRatio = 1
}
var proto = LinePlot.prototype
proto.isTransparent = function () {
return this.opacity < 1
}
proto.isOpaque = function () {
return this.opacity >= 1
}
proto.pickSlots = 1
proto.setPickBase = function (id) {
this.pickId = id
}
proto.drawTransparent = proto.draw = function (camera) {
var gl = this.gl
var shader = this.shader
var vao = this.vao
shader.bind()
shader.uniforms = {
model: camera.model || identity,
view: camera.view || identity,
projection: camera.projection || identity,
clipBounds: filterClipBounds(this.clipBounds),
dashTexture: this.texture.bind(),
dashScale: this.dashScale / this.arcLength[this.arcLength.length - 1],
opacity: this.opacity,
screenShape: [gl.drawingBufferWidth, gl.drawingBufferHeight],
pixelRatio: this.pixelRatio
}
vao.bind()
vao.draw(gl.TRIANGLE_STRIP, this.vertexCount)
}
proto.drawPick = function (camera) {
var gl = this.gl
var shader = this.pickShader
var vao = this.vao
shader.bind()
shader.uniforms = {
model: camera.model || identity,
view: camera.view || identity,
projection: camera.projection || identity,
pickId: this.pickId,
clipBounds: filterClipBounds(this.clipBounds),
screenShape: [gl.drawingBufferWidth, gl.drawingBufferHeight],
pixelRatio: this.pixelRatio
}
vao.bind()
vao.draw(gl.TRIANGLE_STRIP, this.vertexCount)
}
proto.update = function (options) {
var i, j
this.dirty = true
var connectGaps = !!options.connectGaps
if ('dashScale' in options) {
this.dashScale = options.dashScale
}
if ('opacity' in options) {
this.opacity = +options.opacity
}
var positions = options.position || options.positions
if (!positions) {
return
}
// Default color
var colors = options.color || options.colors || [0, 0, 0, 1]
var lineWidth = options.lineWidth || 1
// Recalculate buffer data
var buffer = []
var arcLengthArray = []
var pointArray = []
var arcLength = 0.0
var vertexCount = 0
var bounds = [
[ Infinity, Infinity, Infinity ],
[ -Infinity, -Infinity, -Infinity ]]
var hadGap = false
fill_loop:
for (i = 1; i < positions.length; ++i) {
var a = positions[i - 1]
var b = positions[i]
arcLengthArray.push(arcLength)
pointArray.push(a.slice())
for (j = 0; j < 3; ++j) {
if (isNaN(a[j]) || isNaN(b[j]) ||
!isFinite(a[j]) || !isFinite(b[j])) {
if (!connectGaps && buffer.length > 0) {
for (var k = 0; k < 24; ++k) {
buffer.push(buffer[buffer.length - 12])
}
vertexCount += 2
hadGap = true
}
continue fill_loop
}
bounds[0][j] = Math.min(bounds[0][j], a[j], b[j])
bounds[1][j] = Math.max(bounds[1][j], a[j], b[j])
}
var acolor, bcolor
if (Array.isArray(colors[0])) {
acolor = colors[i - 1]
bcolor = colors[i]
} else {
acolor = bcolor = colors
}
if (acolor.length === 3) {
acolor = [acolor[0], acolor[1], acolor[2], 1]
}
if (bcolor.length === 3) {
bcolor = [bcolor[0], bcolor[1], bcolor[2], 1]
}
var w0
if (Array.isArray(lineWidth)) {
w0 = lineWidth[i - 1]
} else {
w0 = lineWidth
}
var t0 = arcLength
arcLength += distance(a, b)
if (hadGap) {
for (j = 0; j < 2; ++j) {
buffer.push(
a[0], a[1], a[2], b[0], b[1], b[2], t0, w0, acolor[0], acolor[1], acolor[2], acolor[3])
}
vertexCount += 2
hadGap = false
}
buffer.push(
a[0], a[1], a[2], b[0], b[1], b[2], t0, w0, acolor[0], acolor[1], acolor[2], acolor[3],
a[0], a[1], a[2], b[0], b[1], b[2], t0, -w0, acolor[0], acolor[1], acolor[2], acolor[3],
b[0], b[1], b[2], a[0], a[1], a[2], arcLength, -w0, bcolor[0], bcolor[1], bcolor[2], bcolor[3],
b[0], b[1], b[2], a[0], a[1], a[2], arcLength, w0, bcolor[0], bcolor[1], bcolor[2], bcolor[3])
vertexCount += 4
}
this.buffer.update(buffer)
arcLengthArray.push(arcLength)
pointArray.push(positions[positions.length - 1].slice())
this.bounds = bounds
this.vertexCount = vertexCount
this.points = pointArray
this.arcLength = arcLengthArray
if ('dashes' in options) {
var dashArray = options.dashes
// Calculate prefix sum
var prefixSum = dashArray.slice()
prefixSum.unshift(0)
for (i = 1; i < prefixSum.length; ++i) {
prefixSum[i] = prefixSum[i - 1] + prefixSum[i]
}
var dashTexture = ndarray(new Array(256 * 4), [256, 1, 4])
for (i = 0; i < 256; ++i) {
for (j = 0; j < 4; ++j) {
dashTexture.set(i, 0, j, 0)
}
if (bsearch.le(prefixSum, prefixSum[prefixSum.length - 1] * i / 255.0) & 1) {
dashTexture.set(i, 0, 0, 0)
} else {
dashTexture.set(i, 0, 0, 255)
}
}
this.texture.setPixels(dashTexture)
}
}
proto.dispose = function () {
this.shader.dispose()
this.vao.dispose()
this.buffer.dispose()
}
proto.pick = function (selection) {
if (!selection) {
return null
}
if (selection.id !== this.pickId) {
return null
}
var tau = unpackFloat(
selection.value[0],
selection.value[1],
selection.value[2],
0)
var index = bsearch.le(this.arcLength, tau)
if (index < 0) {
return null
}
if (index === this.arcLength.length - 1) {
return new PickResult(
this.arcLength[this.arcLength.length - 1],
this.points[this.points.length - 1].slice(),
index)
}
var a = this.points[index]
var b = this.points[Math.min(index + 1, this.points.length - 1)]
var t = (tau - this.arcLength[index]) / (this.arcLength[index + 1] - this.arcLength[index])
var ti = 1.0 - t
var x = [0, 0, 0]
for (var i = 0; i < 3; ++i) {
x[i] = ti * a[i] + t * b[i]
}
var dataIndex = Math.min((t < 0.5) ? index : (index + 1), this.points.length - 1)
return new PickResult(
tau,
x,
dataIndex,
this.points[dataIndex])
}
function createLinePlot (options) {
var gl = options.gl || (options.scene && options.scene.gl)
var shader = createShader(gl)
shader.attributes.position.location = 0
shader.attributes.nextPosition.location = 1
shader.attributes.arcLength.location = 2
shader.attributes.lineWidth.location = 3
shader.attributes.color.location = 4
var pickShader = createPickShader(gl)
pickShader.attributes.position.location = 0
pickShader.attributes.nextPosition.location = 1
pickShader.attributes.arcLength.location = 2
pickShader.attributes.lineWidth.location = 3
pickShader.attributes.color.location = 4
var buffer = createBuffer(gl)
var vao = createVAO(gl, [
{
'buffer': buffer,
'size': 3,
'offset': 0,
'stride': 48
},
{
'buffer': buffer,
'size': 3,
'offset': 12,
'stride': 48
},
{
'buffer': buffer,
'size': 1,
'offset': 24,
'stride': 48
},
{
'buffer': buffer,
'size': 1,
'offset': 28,
'stride': 48
},
{
'buffer': buffer,
'size': 4,
'offset': 32,
'stride': 48
}
])
// Create texture for dash pattern
var defaultTexture = ndarray(new Array(256 * 4), [256, 1, 4])
for (var i = 0; i < 256 * 4; ++i) {
defaultTexture.data[i] = 255
}
var texture = createTexture(gl, defaultTexture)
texture.wrap = gl.REPEAT
var linePlot = new LinePlot(gl, shader, pickShader, buffer, vao, texture)
linePlot.update(options)
return linePlot
}
},{"./lib/shaders":166,"binary-search-bounds":62,"gl-buffer":152,"gl-texture2d":262,"gl-vao":266,"glsl-read-float":273,"ndarray":460}],168:[function(require,module,exports){
module.exports = invert
/**
* Inverts a mat2
*
* @alias mat2.invert
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
function invert(out, a) {
var a0 = a[0]
var a1 = a[1]
var a2 = a[2]
var a3 = a[3]
var det = a0 * a3 - a2 * a1
if (!det) return null
det = 1.0 / det
out[0] = a3 * det
out[1] = -a1 * det
out[2] = -a2 * det
out[3] = a0 * det
return out
}
},{}],169:[function(require,module,exports){
module.exports = invert
/**
* Inverts a mat3
*
* @alias mat3.invert
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
function invert(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2]
var a10 = a[3], a11 = a[4], a12 = a[5]
var a20 = a[6], a21 = a[7], a22 = a[8]
var b01 = a22 * a11 - a12 * a21
var b11 = -a22 * a10 + a12 * a20
var b21 = a21 * a10 - a11 * a20
// Calculate the determinant
var det = a00 * b01 + a01 * b11 + a02 * b21
if (!det) return null
det = 1.0 / det
out[0] = b01 * det
out[1] = (-a22 * a01 + a02 * a21) * det
out[2] = (a12 * a01 - a02 * a11) * det
out[3] = b11 * det
out[4] = (a22 * a00 - a02 * a20) * det
out[5] = (-a12 * a00 + a02 * a10) * det
out[6] = b21 * det
out[7] = (-a21 * a00 + a01 * a20) * det
out[8] = (a11 * a00 - a01 * a10) * det
return out
}
},{}],170:[function(require,module,exports){
module.exports = clone;
/**
* Creates a new mat4 initialized with values from an existing matrix
*
* @param {mat4} a matrix to clone
* @returns {mat4} a new 4x4 matrix
*/
function clone(a) {
var out = new Float32Array(16);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
},{}],171:[function(require,module,exports){
module.exports = create;
/**
* Creates a new identity mat4
*
* @returns {mat4} a new 4x4 matrix
*/
function create() {
var out = new Float32Array(16);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
},{}],172:[function(require,module,exports){
module.exports = determinant;
/**
* Calculates the determinant of a mat4
*
* @param {mat4} a the source matrix
* @returns {Number} determinant of a
*/
function determinant(a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32;
// Calculate the determinant
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
};
},{}],173:[function(require,module,exports){
module.exports = fromQuat;
/**
* Creates a matrix from a quaternion rotation.
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @returns {mat4} out
*/
function fromQuat(out, q) {
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
yx = y * x2,
yy = y * y2,
zx = z * x2,
zy = z * y2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - yy - zz;
out[1] = yx + wz;
out[2] = zx - wy;
out[3] = 0;
out[4] = yx - wz;
out[5] = 1 - xx - zz;
out[6] = zy + wx;
out[7] = 0;
out[8] = zx + wy;
out[9] = zy - wx;
out[10] = 1 - xx - yy;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
},{}],174:[function(require,module,exports){
module.exports = fromRotationTranslation;
/**
* Creates a matrix from a quaternion rotation and vector translation
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, vec);
* var quatMat = mat4.create();
* quat4.toMat4(quat, quatMat);
* mat4.multiply(dest, quatMat);
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @param {vec3} v Translation vector
* @returns {mat4} out
*/
function fromRotationTranslation(out, q, v) {
// Quaternion math
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[1] = xy + wz;
out[2] = xz - wy;
out[3] = 0;
out[4] = xy - wz;
out[5] = 1 - (xx + zz);
out[6] = yz + wx;
out[7] = 0;
out[8] = xz + wy;
out[9] = yz - wx;
out[10] = 1 - (xx + yy);
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
};
},{}],175:[function(require,module,exports){
module.exports = identity;
/**
* Set a mat4 to the identity matrix
*
* @param {mat4} out the receiving matrix
* @returns {mat4} out
*/
function identity(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
},{}],176:[function(require,module,exports){
module.exports = invert;
/**
* Inverts a mat4
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
function invert(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return out;
};
},{}],177:[function(require,module,exports){
var identity = require('./identity');
module.exports = lookAt;
/**
* Generates a look-at matrix with the given eye position, focal point, and up axis
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {vec3} eye Position of the viewer
* @param {vec3} center Point the viewer is looking at
* @param {vec3} up vec3 pointing up
* @returns {mat4} out
*/
function lookAt(out, eye, center, up) {
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
eyex = eye[0],
eyey = eye[1],
eyez = eye[2],
upx = up[0],
upy = up[1],
upz = up[2],
centerx = center[0],
centery = center[1],
centerz = center[2];
if (Math.abs(eyex - centerx) < 0.000001 &&
Math.abs(eyey - centery) < 0.000001 &&
Math.abs(eyez - centerz) < 0.000001) {
return identity(out);
}
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
x0 = upy * z2 - upz * z1;
x1 = upz * z0 - upx * z2;
x2 = upx * z1 - upy * z0;
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
y0 = z1 * x2 - z2 * x1;
y1 = z2 * x0 - z0 * x2;
y2 = z0 * x1 - z1 * x0;
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
out[0] = x0;
out[1] = y0;
out[2] = z0;
out[3] = 0;
out[4] = x1;
out[5] = y1;
out[6] = z1;
out[7] = 0;
out[8] = x2;
out[9] = y2;
out[10] = z2;
out[11] = 0;
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
out[15] = 1;
return out;
};
},{"./identity":175}],178:[function(require,module,exports){
module.exports = multiply;
/**
* Multiplies two mat4's
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
function multiply(out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
// Cache only the current line of the second matrix
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
return out;
};
},{}],179:[function(require,module,exports){
module.exports = perspective;
/**
* Generates a perspective projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} fovy Vertical field of view in radians
* @param {number} aspect Aspect ratio. typically viewport width/height
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
function perspective(out, fovy, aspect, near, far) {
var f = 1.0 / Math.tan(fovy / 2),
nf = 1 / (near - far);
out[0] = f / aspect;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = f;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (2 * far * near) * nf;
out[15] = 0;
return out;
};
},{}],180:[function(require,module,exports){
module.exports = rotate;
/**
* Rotates a mat4 by the given angle
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @param {vec3} axis the axis to rotate around
* @returns {mat4} out
*/
function rotate(out, a, rad, axis) {
var x = axis[0], y = axis[1], z = axis[2],
len = Math.sqrt(x * x + y * y + z * z),
s, c, t,
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23,
b00, b01, b02,
b10, b11, b12,
b20, b21, b22;
if (Math.abs(len) < 0.000001) { return null; }
len = 1 / len;
x *= len;
y *= len;
z *= len;
s = Math.sin(rad);
c = Math.cos(rad);
t = 1 - c;
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
// Construct the elements of the rotation matrix
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
// Perform rotation-specific matrix multiplication
out[0] = a00 * b00 + a10 * b01 + a20 * b02;
out[1] = a01 * b00 + a11 * b01 + a21 * b02;
out[2] = a02 * b00 + a12 * b01 + a22 * b02;
out[3] = a03 * b00 + a13 * b01 + a23 * b02;
out[4] = a00 * b10 + a10 * b11 + a20 * b12;
out[5] = a01 * b10 + a11 * b11 + a21 * b12;
out[6] = a02 * b10 + a12 * b11 + a22 * b12;
out[7] = a03 * b10 + a13 * b11 + a23 * b12;
out[8] = a00 * b20 + a10 * b21 + a20 * b22;
out[9] = a01 * b20 + a11 * b21 + a21 * b22;
out[10] = a02 * b20 + a12 * b21 + a22 * b22;
out[11] = a03 * b20 + a13 * b21 + a23 * b22;
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
return out;
};
},{}],181:[function(require,module,exports){
module.exports = rotateX;
/**
* Rotates a matrix by the given angle around the X axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
function rotateX(out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[4] = a10 * c + a20 * s;
out[5] = a11 * c + a21 * s;
out[6] = a12 * c + a22 * s;
out[7] = a13 * c + a23 * s;
out[8] = a20 * c - a10 * s;
out[9] = a21 * c - a11 * s;
out[10] = a22 * c - a12 * s;
out[11] = a23 * c - a13 * s;
return out;
};
},{}],182:[function(require,module,exports){
module.exports = rotateY;
/**
* Rotates a matrix by the given angle around the Y axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
function rotateY(out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c - a20 * s;
out[1] = a01 * c - a21 * s;
out[2] = a02 * c - a22 * s;
out[3] = a03 * c - a23 * s;
out[8] = a00 * s + a20 * c;
out[9] = a01 * s + a21 * c;
out[10] = a02 * s + a22 * c;
out[11] = a03 * s + a23 * c;
return out;
};
},{}],183:[function(require,module,exports){
module.exports = rotateZ;
/**
* Rotates a matrix by the given angle around the Z axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
function rotateZ(out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7];
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c + a10 * s;
out[1] = a01 * c + a11 * s;
out[2] = a02 * c + a12 * s;
out[3] = a03 * c + a13 * s;
out[4] = a10 * c - a00 * s;
out[5] = a11 * c - a01 * s;
out[6] = a12 * c - a02 * s;
out[7] = a13 * c - a03 * s;
return out;
};
},{}],184:[function(require,module,exports){
module.exports = scale;
/**
* Scales the mat4 by the dimensions in the given vec3
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {vec3} v the vec3 to scale the matrix by
* @returns {mat4} out
**/
function scale(out, a, v) {
var x = v[0], y = v[1], z = v[2];
out[0] = a[0] * x;
out[1] = a[1] * x;
out[2] = a[2] * x;
out[3] = a[3] * x;
out[4] = a[4] * y;
out[5] = a[5] * y;
out[6] = a[6] * y;
out[7] = a[7] * y;
out[8] = a[8] * z;
out[9] = a[9] * z;
out[10] = a[10] * z;
out[11] = a[11] * z;
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
},{}],185:[function(require,module,exports){
module.exports = translate;
/**
* Translate a mat4 by the given vector
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to translate
* @param {vec3} v vector to translate by
* @returns {mat4} out
*/
function translate(out, a, v) {
var x = v[0], y = v[1], z = v[2],
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23;
if (a === out) {
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
} else {
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
out[12] = a00 * x + a10 * y + a20 * z + a[12];
out[13] = a01 * x + a11 * y + a21 * z + a[13];
out[14] = a02 * x + a12 * y + a22 * z + a[14];
out[15] = a03 * x + a13 * y + a23 * z + a[15];
}
return out;
};
},{}],186:[function(require,module,exports){
module.exports = transpose;
/**
* Transpose the values of a mat4
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
function transpose(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a01 = a[1], a02 = a[2], a03 = a[3],
a12 = a[6], a13 = a[7],
a23 = a[11];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a01;
out[6] = a[9];
out[7] = a[13];
out[8] = a02;
out[9] = a12;
out[11] = a[14];
out[12] = a03;
out[13] = a13;
out[14] = a23;
} else {
out[0] = a[0];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a[1];
out[5] = a[5];
out[6] = a[9];
out[7] = a[13];
out[8] = a[2];
out[9] = a[6];
out[10] = a[10];
out[11] = a[14];
out[12] = a[3];
out[13] = a[7];
out[14] = a[11];
out[15] = a[15];
}
return out;
};
},{}],187:[function(require,module,exports){
'use strict'
module.exports = invert
var invert2 = require('gl-mat2/invert')
var invert3 = require('gl-mat3/invert')
var invert4 = require('gl-mat4/invert')
function invert(out, M) {
switch(M.length) {
case 0:
break
case 1:
out[0] = 1.0 / M[0]
break
case 4:
invert2(out, M)
break
case 9:
invert3(out, M)
break
case 16:
invert4(out, M)
break
default:
throw new Error('currently supports matrices up to 4x4')
break
}
return out
}
},{"gl-mat2/invert":168,"gl-mat3/invert":169,"gl-mat4/invert":176}],188:[function(require,module,exports){
/**
* @fileoverview gl-matrix - High performance matrix and vector operations
* @author Brandon Jones
* @author Colin MacKenzie IV
* @version 2.3.2
*/
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
// END HEADER
exports.glMatrix = require("./gl-matrix/common.js");
exports.mat2 = require("./gl-matrix/mat2.js");
exports.mat2d = require("./gl-matrix/mat2d.js");
exports.mat3 = require("./gl-matrix/mat3.js");
exports.mat4 = require("./gl-matrix/mat4.js");
exports.quat = require("./gl-matrix/quat.js");
exports.vec2 = require("./gl-matrix/vec2.js");
exports.vec3 = require("./gl-matrix/vec3.js");
exports.vec4 = require("./gl-matrix/vec4.js");
},{"./gl-matrix/common.js":189,"./gl-matrix/mat2.js":190,"./gl-matrix/mat2d.js":191,"./gl-matrix/mat3.js":192,"./gl-matrix/mat4.js":193,"./gl-matrix/quat.js":194,"./gl-matrix/vec2.js":195,"./gl-matrix/vec3.js":196,"./gl-matrix/vec4.js":197}],189:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
/**
* @class Common utilities
* @name glMatrix
*/
var glMatrix = {};
// Configuration Constants
glMatrix.EPSILON = 0.000001;
glMatrix.ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
glMatrix.RANDOM = Math.random;
glMatrix.ENABLE_SIMD = false;
// Capability detection
glMatrix.SIMD_AVAILABLE = (glMatrix.ARRAY_TYPE === Float32Array) && ('SIMD' in this);
glMatrix.USE_SIMD = glMatrix.ENABLE_SIMD && glMatrix.SIMD_AVAILABLE;
/**
* Sets the type of array used when creating new vectors and matrices
*
* @param {Type} type Array type, such as Float32Array or Array
*/
glMatrix.setMatrixArrayType = function(type) {
glMatrix.ARRAY_TYPE = type;
}
var degree = Math.PI / 180;
/**
* Convert Degree To Radian
*
* @param {Number} Angle in Degrees
*/
glMatrix.toRadian = function(a){
return a * degree;
}
/**
* Tests whether or not the arguments have approximately the same value, within an absolute
* or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less
* than or equal to 1.0, and a relative tolerance is used for larger values)
*
* @param {Number} a The first number to test.
* @param {Number} b The second number to test.
* @returns {Boolean} True if the numbers are approximately equal, false otherwise.
*/
glMatrix.equals = function(a, b) {
return Math.abs(a - b) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a), Math.abs(b));
}
module.exports = glMatrix;
},{}],190:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 2x2 Matrix
* @name mat2
*/
var mat2 = {};
/**
* Creates a new identity mat2
*
* @returns {mat2} a new 2x2 matrix
*/
mat2.create = function() {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Creates a new mat2 initialized with values from an existing matrix
*
* @param {mat2} a matrix to clone
* @returns {mat2} a new 2x2 matrix
*/
mat2.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Copy the values from one mat2 to another
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Set a mat2 to the identity matrix
*
* @param {mat2} out the receiving matrix
* @returns {mat2} out
*/
mat2.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Create a new mat2 with the given values
*
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m10 Component in column 1, row 0 position (index 2)
* @param {Number} m11 Component in column 1, row 1 position (index 3)
* @returns {mat2} out A new 2x2 matrix
*/
mat2.fromValues = function(m00, m01, m10, m11) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = m00;
out[1] = m01;
out[2] = m10;
out[3] = m11;
return out;
};
/**
* Set the components of a mat2 to the given values
*
* @param {mat2} out the receiving matrix
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m10 Component in column 1, row 0 position (index 2)
* @param {Number} m11 Component in column 1, row 1 position (index 3)
* @returns {mat2} out
*/
mat2.set = function(out, m00, m01, m10, m11) {
out[0] = m00;
out[1] = m01;
out[2] = m10;
out[3] = m11;
return out;
};
/**
* Transpose the values of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a1 = a[1];
out[1] = a[2];
out[2] = a1;
} else {
out[0] = a[0];
out[1] = a[2];
out[2] = a[1];
out[3] = a[3];
}
return out;
};
/**
* Inverts a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.invert = function(out, a) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
// Calculate the determinant
det = a0 * a3 - a2 * a1;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = a3 * det;
out[1] = -a1 * det;
out[2] = -a2 * det;
out[3] = a0 * det;
return out;
};
/**
* Calculates the adjugate of a mat2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the source matrix
* @returns {mat2} out
*/
mat2.adjoint = function(out, a) {
// Caching this value is nessecary if out == a
var a0 = a[0];
out[0] = a[3];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a0;
return out;
};
/**
* Calculates the determinant of a mat2
*
* @param {mat2} a the source matrix
* @returns {Number} determinant of a
*/
mat2.determinant = function (a) {
return a[0] * a[3] - a[2] * a[1];
};
/**
* Multiplies two mat2's
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
mat2.multiply = function (out, a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = a0 * b0 + a2 * b1;
out[1] = a1 * b0 + a3 * b1;
out[2] = a0 * b2 + a2 * b3;
out[3] = a1 * b2 + a3 * b3;
return out;
};
/**
* Alias for {@link mat2.multiply}
* @function
*/
mat2.mul = mat2.multiply;
/**
* Rotates a mat2 by the given angle
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2} out
*/
mat2.rotate = function (out, a, rad) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = a0 * c + a2 * s;
out[1] = a1 * c + a3 * s;
out[2] = a0 * -s + a2 * c;
out[3] = a1 * -s + a3 * c;
return out;
};
/**
* Scales the mat2 by the dimensions in the given vec2
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2} out
**/
mat2.scale = function(out, a, v) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
v0 = v[0], v1 = v[1];
out[0] = a0 * v0;
out[1] = a1 * v0;
out[2] = a2 * v1;
out[3] = a3 * v1;
return out;
};
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat2.identity(dest);
* mat2.rotate(dest, dest, rad);
*
* @param {mat2} out mat2 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2} out
*/
mat2.fromRotation = function(out, rad) {
var s = Math.sin(rad),
c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = -s;
out[3] = c;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat2.identity(dest);
* mat2.scale(dest, dest, vec);
*
* @param {mat2} out mat2 receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat2} out
*/
mat2.fromScaling = function(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = v[1];
return out;
}
/**
* Returns a string representation of a mat2
*
* @param {mat2} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat2.str = function (a) {
return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
/**
* Returns Frobenius norm of a mat2
*
* @param {mat2} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
mat2.frob = function (a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
};
/**
* Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
* @param {mat2} L the lower triangular matrix
* @param {mat2} D the diagonal matrix
* @param {mat2} U the upper triangular matrix
* @param {mat2} a the input matrix to factorize
*/
mat2.LDU = function (L, D, U, a) {
L[2] = a[2]/a[0];
U[0] = a[0];
U[1] = a[1];
U[3] = a[3] - L[2] * U[1];
return [L, D, U];
};
/**
* Adds two mat2's
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
mat2.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
};
/**
* Subtracts matrix b from matrix a
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @returns {mat2} out
*/
mat2.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
return out;
};
/**
* Alias for {@link mat2.subtract}
* @function
*/
mat2.sub = mat2.subtract;
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat2} a The first matrix.
* @param {mat2} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat2.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
};
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat2} a The first matrix.
* @param {mat2} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat2.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
};
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat2} out the receiving matrix
* @param {mat2} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat2} out
*/
mat2.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
};
/**
* Adds two mat2's after multiplying each element of the second operand by a scalar value.
*
* @param {mat2} out the receiving vector
* @param {mat2} a the first operand
* @param {mat2} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat2} out
*/
mat2.multiplyScalarAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
return out;
};
module.exports = mat2;
},{"./common.js":189}],191:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 2x3 Matrix
* @name mat2d
*
* @description
* A mat2d contains six elements defined as:
*
* [a, c, tx,
* b, d, ty]
*
* This is a short form for the 3x3 matrix:
*
* [a, c, tx,
* b, d, ty,
* 0, 0, 1]
*
* The last row is ignored so the array is shorter and operations are faster.
*/
var mat2d = {};
/**
* Creates a new identity mat2d
*
* @returns {mat2d} a new 2x3 matrix
*/
mat2d.create = function() {
var out = new glMatrix.ARRAY_TYPE(6);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
};
/**
* Creates a new mat2d initialized with values from an existing matrix
*
* @param {mat2d} a matrix to clone
* @returns {mat2d} a new 2x3 matrix
*/
mat2d.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(6);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
};
/**
* Copy the values from one mat2d to another
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
mat2d.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
return out;
};
/**
* Set a mat2d to the identity matrix
*
* @param {mat2d} out the receiving matrix
* @returns {mat2d} out
*/
mat2d.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = 0;
out[5] = 0;
return out;
};
/**
* Create a new mat2d with the given values
*
* @param {Number} a Component A (index 0)
* @param {Number} b Component B (index 1)
* @param {Number} c Component C (index 2)
* @param {Number} d Component D (index 3)
* @param {Number} tx Component TX (index 4)
* @param {Number} ty Component TY (index 5)
* @returns {mat2d} A new mat2d
*/
mat2d.fromValues = function(a, b, c, d, tx, ty) {
var out = new glMatrix.ARRAY_TYPE(6);
out[0] = a;
out[1] = b;
out[2] = c;
out[3] = d;
out[4] = tx;
out[5] = ty;
return out;
};
/**
* Set the components of a mat2d to the given values
*
* @param {mat2d} out the receiving matrix
* @param {Number} a Component A (index 0)
* @param {Number} b Component B (index 1)
* @param {Number} c Component C (index 2)
* @param {Number} d Component D (index 3)
* @param {Number} tx Component TX (index 4)
* @param {Number} ty Component TY (index 5)
* @returns {mat2d} out
*/
mat2d.set = function(out, a, b, c, d, tx, ty) {
out[0] = a;
out[1] = b;
out[2] = c;
out[3] = d;
out[4] = tx;
out[5] = ty;
return out;
};
/**
* Inverts a mat2d
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the source matrix
* @returns {mat2d} out
*/
mat2d.invert = function(out, a) {
var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
atx = a[4], aty = a[5];
var det = aa * ad - ab * ac;
if(!det){
return null;
}
det = 1.0 / det;
out[0] = ad * det;
out[1] = -ab * det;
out[2] = -ac * det;
out[3] = aa * det;
out[4] = (ac * aty - ad * atx) * det;
out[5] = (ab * atx - aa * aty) * det;
return out;
};
/**
* Calculates the determinant of a mat2d
*
* @param {mat2d} a the source matrix
* @returns {Number} determinant of a
*/
mat2d.determinant = function (a) {
return a[0] * a[3] - a[1] * a[2];
};
/**
* Multiplies two mat2d's
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
mat2d.multiply = function (out, a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
out[0] = a0 * b0 + a2 * b1;
out[1] = a1 * b0 + a3 * b1;
out[2] = a0 * b2 + a2 * b3;
out[3] = a1 * b2 + a3 * b3;
out[4] = a0 * b4 + a2 * b5 + a4;
out[5] = a1 * b4 + a3 * b5 + a5;
return out;
};
/**
* Alias for {@link mat2d.multiply}
* @function
*/
mat2d.mul = mat2d.multiply;
/**
* Rotates a mat2d by the given angle
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2d} out
*/
mat2d.rotate = function (out, a, rad) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = a0 * c + a2 * s;
out[1] = a1 * c + a3 * s;
out[2] = a0 * -s + a2 * c;
out[3] = a1 * -s + a3 * c;
out[4] = a4;
out[5] = a5;
return out;
};
/**
* Scales the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat2d} out
**/
mat2d.scale = function(out, a, v) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
v0 = v[0], v1 = v[1];
out[0] = a0 * v0;
out[1] = a1 * v0;
out[2] = a2 * v1;
out[3] = a3 * v1;
out[4] = a4;
out[5] = a5;
return out;
};
/**
* Translates the mat2d by the dimensions in the given vec2
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to translate
* @param {vec2} v the vec2 to translate the matrix by
* @returns {mat2d} out
**/
mat2d.translate = function(out, a, v) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
v0 = v[0], v1 = v[1];
out[0] = a0;
out[1] = a1;
out[2] = a2;
out[3] = a3;
out[4] = a0 * v0 + a2 * v1 + a4;
out[5] = a1 * v0 + a3 * v1 + a5;
return out;
};
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.rotate(dest, dest, rad);
*
* @param {mat2d} out mat2d receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat2d} out
*/
mat2d.fromRotation = function(out, rad) {
var s = Math.sin(rad), c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = -s;
out[3] = c;
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.scale(dest, dest, vec);
*
* @param {mat2d} out mat2d receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat2d} out
*/
mat2d.fromScaling = function(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = v[1];
out[4] = 0;
out[5] = 0;
return out;
}
/**
* Creates a matrix from a vector translation
* This is equivalent to (but much faster than):
*
* mat2d.identity(dest);
* mat2d.translate(dest, dest, vec);
*
* @param {mat2d} out mat2d receiving operation result
* @param {vec2} v Translation vector
* @returns {mat2d} out
*/
mat2d.fromTranslation = function(out, v) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 1;
out[4] = v[0];
out[5] = v[1];
return out;
}
/**
* Returns a string representation of a mat2d
*
* @param {mat2d} a matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat2d.str = function (a) {
return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ')';
};
/**
* Returns Frobenius norm of a mat2d
*
* @param {mat2d} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
mat2d.frob = function (a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))
};
/**
* Adds two mat2d's
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
mat2d.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
return out;
};
/**
* Subtracts matrix b from matrix a
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @returns {mat2d} out
*/
mat2d.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
return out;
};
/**
* Alias for {@link mat2d.subtract}
* @function
*/
mat2d.sub = mat2d.subtract;
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat2d} out the receiving matrix
* @param {mat2d} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat2d} out
*/
mat2d.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
return out;
};
/**
* Adds two mat2d's after multiplying each element of the second operand by a scalar value.
*
* @param {mat2d} out the receiving vector
* @param {mat2d} a the first operand
* @param {mat2d} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat2d} out
*/
mat2d.multiplyScalarAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
out[4] = a[4] + (b[4] * scale);
out[5] = a[5] + (b[5] * scale);
return out;
};
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat2d} a The first matrix.
* @param {mat2d} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat2d.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5];
};
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat2d} a The first matrix.
* @param {mat2d} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat2d.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)));
};
module.exports = mat2d;
},{"./common.js":189}],192:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 3x3 Matrix
* @name mat3
*/
var mat3 = {};
/**
* Creates a new identity mat3
*
* @returns {mat3} a new 3x3 matrix
*/
mat3.create = function() {
var out = new glMatrix.ARRAY_TYPE(9);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
};
/**
* Copies the upper-left 3x3 values into the given mat3.
*
* @param {mat3} out the receiving 3x3 matrix
* @param {mat4} a the source 4x4 matrix
* @returns {mat3} out
*/
mat3.fromMat4 = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[4];
out[4] = a[5];
out[5] = a[6];
out[6] = a[8];
out[7] = a[9];
out[8] = a[10];
return out;
};
/**
* Creates a new mat3 initialized with values from an existing matrix
*
* @param {mat3} a matrix to clone
* @returns {mat3} a new 3x3 matrix
*/
mat3.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(9);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Copy the values from one mat3 to another
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Create a new mat3 with the given values
*
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m10 Component in column 1, row 0 position (index 3)
* @param {Number} m11 Component in column 1, row 1 position (index 4)
* @param {Number} m12 Component in column 1, row 2 position (index 5)
* @param {Number} m20 Component in column 2, row 0 position (index 6)
* @param {Number} m21 Component in column 2, row 1 position (index 7)
* @param {Number} m22 Component in column 2, row 2 position (index 8)
* @returns {mat3} A new mat3
*/
mat3.fromValues = function(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
var out = new glMatrix.ARRAY_TYPE(9);
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m10;
out[4] = m11;
out[5] = m12;
out[6] = m20;
out[7] = m21;
out[8] = m22;
return out;
};
/**
* Set the components of a mat3 to the given values
*
* @param {mat3} out the receiving matrix
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m10 Component in column 1, row 0 position (index 3)
* @param {Number} m11 Component in column 1, row 1 position (index 4)
* @param {Number} m12 Component in column 1, row 2 position (index 5)
* @param {Number} m20 Component in column 2, row 0 position (index 6)
* @param {Number} m21 Component in column 2, row 1 position (index 7)
* @param {Number} m22 Component in column 2, row 2 position (index 8)
* @returns {mat3} out
*/
mat3.set = function(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m10;
out[4] = m11;
out[5] = m12;
out[6] = m20;
out[7] = m21;
out[8] = m22;
return out;
};
/**
* Set a mat3 to the identity matrix
*
* @param {mat3} out the receiving matrix
* @returns {mat3} out
*/
mat3.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
};
/**
* Transpose the values of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a01 = a[1], a02 = a[2], a12 = a[5];
out[1] = a[3];
out[2] = a[6];
out[3] = a01;
out[5] = a[7];
out[6] = a02;
out[7] = a12;
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[1];
out[4] = a[4];
out[5] = a[7];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
};
/**
* Inverts a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.invert = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
b01 = a22 * a11 - a12 * a21,
b11 = -a22 * a10 + a12 * a20,
b21 = a21 * a10 - a11 * a20,
// Calculate the determinant
det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = b01 * det;
out[1] = (-a22 * a01 + a02 * a21) * det;
out[2] = (a12 * a01 - a02 * a11) * det;
out[3] = b11 * det;
out[4] = (a22 * a00 - a02 * a20) * det;
out[5] = (-a12 * a00 + a02 * a10) * det;
out[6] = b21 * det;
out[7] = (-a21 * a00 + a01 * a20) * det;
out[8] = (a11 * a00 - a01 * a10) * det;
return out;
};
/**
* Calculates the adjugate of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
mat3.adjoint = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8];
out[0] = (a11 * a22 - a12 * a21);
out[1] = (a02 * a21 - a01 * a22);
out[2] = (a01 * a12 - a02 * a11);
out[3] = (a12 * a20 - a10 * a22);
out[4] = (a00 * a22 - a02 * a20);
out[5] = (a02 * a10 - a00 * a12);
out[6] = (a10 * a21 - a11 * a20);
out[7] = (a01 * a20 - a00 * a21);
out[8] = (a00 * a11 - a01 * a10);
return out;
};
/**
* Calculates the determinant of a mat3
*
* @param {mat3} a the source matrix
* @returns {Number} determinant of a
*/
mat3.determinant = function (a) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8];
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
};
/**
* Multiplies two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
mat3.multiply = function (out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
b00 = b[0], b01 = b[1], b02 = b[2],
b10 = b[3], b11 = b[4], b12 = b[5],
b20 = b[6], b21 = b[7], b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
};
/**
* Alias for {@link mat3.multiply}
* @function
*/
mat3.mul = mat3.multiply;
/**
* Translate a mat3 by the given vector
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to translate
* @param {vec2} v vector to translate by
* @returns {mat3} out
*/
mat3.translate = function(out, a, v) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
x = v[0], y = v[1];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a10;
out[4] = a11;
out[5] = a12;
out[6] = x * a00 + y * a10 + a20;
out[7] = x * a01 + y * a11 + a21;
out[8] = x * a02 + y * a12 + a22;
return out;
};
/**
* Rotates a mat3 by the given angle
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
mat3.rotate = function (out, a, rad) {
var a00 = a[0], a01 = a[1], a02 = a[2],
a10 = a[3], a11 = a[4], a12 = a[5],
a20 = a[6], a21 = a[7], a22 = a[8],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = c * a00 + s * a10;
out[1] = c * a01 + s * a11;
out[2] = c * a02 + s * a12;
out[3] = c * a10 - s * a00;
out[4] = c * a11 - s * a01;
out[5] = c * a12 - s * a02;
out[6] = a20;
out[7] = a21;
out[8] = a22;
return out;
};
/**
* Scales the mat3 by the dimensions in the given vec2
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat3} out
**/
mat3.scale = function(out, a, v) {
var x = v[0], y = v[1];
out[0] = x * a[0];
out[1] = x * a[1];
out[2] = x * a[2];
out[3] = y * a[3];
out[4] = y * a[4];
out[5] = y * a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
};
/**
* Creates a matrix from a vector translation
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.translate(dest, dest, vec);
*
* @param {mat3} out mat3 receiving operation result
* @param {vec2} v Translation vector
* @returns {mat3} out
*/
mat3.fromTranslation = function(out, v) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = v[0];
out[7] = v[1];
out[8] = 1;
return out;
}
/**
* Creates a matrix from a given angle
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.rotate(dest, dest, rad);
*
* @param {mat3} out mat3 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
mat3.fromRotation = function(out, rad) {
var s = Math.sin(rad), c = Math.cos(rad);
out[0] = c;
out[1] = s;
out[2] = 0;
out[3] = -s;
out[4] = c;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat3.identity(dest);
* mat3.scale(dest, dest, vec);
*
* @param {mat3} out mat3 receiving operation result
* @param {vec2} v Scaling vector
* @returns {mat3} out
*/
mat3.fromScaling = function(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = v[1];
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Copies the values from a mat2d into a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat2d} a the matrix to copy
* @returns {mat3} out
**/
mat3.fromMat2d = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = 0;
out[3] = a[2];
out[4] = a[3];
out[5] = 0;
out[6] = a[4];
out[7] = a[5];
out[8] = 1;
return out;
};
/**
* Calculates a 3x3 matrix from the given quaternion
*
* @param {mat3} out mat3 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat3} out
*/
mat3.fromQuat = function (out, q) {
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
yx = y * x2,
yy = y * y2,
zx = z * x2,
zy = z * y2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - yy - zz;
out[3] = yx - wz;
out[6] = zx + wy;
out[1] = yx + wz;
out[4] = 1 - xx - zz;
out[7] = zy - wx;
out[2] = zx - wy;
out[5] = zy + wx;
out[8] = 1 - xx - yy;
return out;
};
/**
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
*
* @param {mat3} out mat3 receiving operation result
* @param {mat4} a Mat4 to derive the normal matrix from
*
* @returns {mat3} out
*/
mat3.normalFromMat4 = function (out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
return out;
};
/**
* Returns a string representation of a mat3
*
* @param {mat3} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat3.str = function (a) {
return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
a[6] + ', ' + a[7] + ', ' + a[8] + ')';
};
/**
* Returns Frobenius norm of a mat3
*
* @param {mat3} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
mat3.frob = function (a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))
};
/**
* Adds two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
mat3.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
out[6] = a[6] + b[6];
out[7] = a[7] + b[7];
out[8] = a[8] + b[8];
return out;
};
/**
* Subtracts matrix b from matrix a
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
mat3.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
out[6] = a[6] - b[6];
out[7] = a[7] - b[7];
out[8] = a[8] - b[8];
return out;
};
/**
* Alias for {@link mat3.subtract}
* @function
*/
mat3.sub = mat3.subtract;
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat3} out
*/
mat3.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
out[6] = a[6] * b;
out[7] = a[7] * b;
out[8] = a[8] * b;
return out;
};
/**
* Adds two mat3's after multiplying each element of the second operand by a scalar value.
*
* @param {mat3} out the receiving vector
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat3} out
*/
mat3.multiplyScalarAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
out[4] = a[4] + (b[4] * scale);
out[5] = a[5] + (b[5] * scale);
out[6] = a[6] + (b[6] * scale);
out[7] = a[7] + (b[7] * scale);
out[8] = a[8] + (b[8] * scale);
return out;
};
/*
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat3} a The first matrix.
* @param {mat3} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat3.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] &&
a[3] === b[3] && a[4] === b[4] && a[5] === b[5] &&
a[6] === b[6] && a[7] === b[7] && a[8] === b[8];
};
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat3} a The first matrix.
* @param {mat3} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat3.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = a[6], b7 = b[7], b8 = b[8];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)));
};
module.exports = mat3;
},{"./common.js":189}],193:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 4x4 Matrix
* @name mat4
*/
var mat4 = {
scalar: {},
SIMD: {},
};
/**
* Creates a new identity mat4
*
* @returns {mat4} a new 4x4 matrix
*/
mat4.create = function() {
var out = new glMatrix.ARRAY_TYPE(16);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Creates a new mat4 initialized with values from an existing matrix
*
* @param {mat4} a matrix to clone
* @returns {mat4} a new 4x4 matrix
*/
mat4.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(16);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Copy the values from one mat4 to another
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Create a new mat4 with the given values
*
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m03 Component in column 0, row 3 position (index 3)
* @param {Number} m10 Component in column 1, row 0 position (index 4)
* @param {Number} m11 Component in column 1, row 1 position (index 5)
* @param {Number} m12 Component in column 1, row 2 position (index 6)
* @param {Number} m13 Component in column 1, row 3 position (index 7)
* @param {Number} m20 Component in column 2, row 0 position (index 8)
* @param {Number} m21 Component in column 2, row 1 position (index 9)
* @param {Number} m22 Component in column 2, row 2 position (index 10)
* @param {Number} m23 Component in column 2, row 3 position (index 11)
* @param {Number} m30 Component in column 3, row 0 position (index 12)
* @param {Number} m31 Component in column 3, row 1 position (index 13)
* @param {Number} m32 Component in column 3, row 2 position (index 14)
* @param {Number} m33 Component in column 3, row 3 position (index 15)
* @returns {mat4} A new mat4
*/
mat4.fromValues = function(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
var out = new glMatrix.ARRAY_TYPE(16);
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m03;
out[4] = m10;
out[5] = m11;
out[6] = m12;
out[7] = m13;
out[8] = m20;
out[9] = m21;
out[10] = m22;
out[11] = m23;
out[12] = m30;
out[13] = m31;
out[14] = m32;
out[15] = m33;
return out;
};
/**
* Set the components of a mat4 to the given values
*
* @param {mat4} out the receiving matrix
* @param {Number} m00 Component in column 0, row 0 position (index 0)
* @param {Number} m01 Component in column 0, row 1 position (index 1)
* @param {Number} m02 Component in column 0, row 2 position (index 2)
* @param {Number} m03 Component in column 0, row 3 position (index 3)
* @param {Number} m10 Component in column 1, row 0 position (index 4)
* @param {Number} m11 Component in column 1, row 1 position (index 5)
* @param {Number} m12 Component in column 1, row 2 position (index 6)
* @param {Number} m13 Component in column 1, row 3 position (index 7)
* @param {Number} m20 Component in column 2, row 0 position (index 8)
* @param {Number} m21 Component in column 2, row 1 position (index 9)
* @param {Number} m22 Component in column 2, row 2 position (index 10)
* @param {Number} m23 Component in column 2, row 3 position (index 11)
* @param {Number} m30 Component in column 3, row 0 position (index 12)
* @param {Number} m31 Component in column 3, row 1 position (index 13)
* @param {Number} m32 Component in column 3, row 2 position (index 14)
* @param {Number} m33 Component in column 3, row 3 position (index 15)
* @returns {mat4} out
*/
mat4.set = function(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m03;
out[4] = m10;
out[5] = m11;
out[6] = m12;
out[7] = m13;
out[8] = m20;
out[9] = m21;
out[10] = m22;
out[11] = m23;
out[12] = m30;
out[13] = m31;
out[14] = m32;
out[15] = m33;
return out;
};
/**
* Set a mat4 to the identity matrix
*
* @param {mat4} out the receiving matrix
* @returns {mat4} out
*/
mat4.identity = function(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Transpose the values of a mat4 not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.scalar.transpose = function(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
var a01 = a[1], a02 = a[2], a03 = a[3],
a12 = a[6], a13 = a[7],
a23 = a[11];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a01;
out[6] = a[9];
out[7] = a[13];
out[8] = a02;
out[9] = a12;
out[11] = a[14];
out[12] = a03;
out[13] = a13;
out[14] = a23;
} else {
out[0] = a[0];
out[1] = a[4];
out[2] = a[8];
out[3] = a[12];
out[4] = a[1];
out[5] = a[5];
out[6] = a[9];
out[7] = a[13];
out[8] = a[2];
out[9] = a[6];
out[10] = a[10];
out[11] = a[14];
out[12] = a[3];
out[13] = a[7];
out[14] = a[11];
out[15] = a[15];
}
return out;
};
/**
* Transpose the values of a mat4 using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.SIMD.transpose = function(out, a) {
var a0, a1, a2, a3,
tmp01, tmp23,
out0, out1, out2, out3;
a0 = SIMD.Float32x4.load(a, 0);
a1 = SIMD.Float32x4.load(a, 4);
a2 = SIMD.Float32x4.load(a, 8);
a3 = SIMD.Float32x4.load(a, 12);
tmp01 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);
tmp23 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);
out0 = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
out1 = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
SIMD.Float32x4.store(out, 0, out0);
SIMD.Float32x4.store(out, 4, out1);
tmp01 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);
tmp23 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);
out2 = SIMD.Float32x4.shuffle(tmp01, tmp23, 0, 2, 4, 6);
out3 = SIMD.Float32x4.shuffle(tmp01, tmp23, 1, 3, 5, 7);
SIMD.Float32x4.store(out, 8, out2);
SIMD.Float32x4.store(out, 12, out3);
return out;
};
/**
* Transpse a mat4 using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.transpose = glMatrix.USE_SIMD ? mat4.SIMD.transpose : mat4.scalar.transpose;
/**
* Inverts a mat4 not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.scalar.invert = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return out;
};
/**
* Inverts a mat4 using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.SIMD.invert = function(out, a) {
var row0, row1, row2, row3,
tmp1,
minor0, minor1, minor2, minor3,
det,
a0 = SIMD.Float32x4.load(a, 0),
a1 = SIMD.Float32x4.load(a, 4),
a2 = SIMD.Float32x4.load(a, 8),
a3 = SIMD.Float32x4.load(a, 12);
// Compute matrix adjugate
tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);
row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);
row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);
row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);
row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
tmp1 = SIMD.Float32x4.mul(row2, row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor0 = SIMD.Float32x4.mul(row1, tmp1);
minor1 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0);
minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1);
minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(row1, row2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0);
minor3 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1));
minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3);
minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
row2 = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0);
minor2 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1));
minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2);
minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(row0, row1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2);
minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2);
minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1));
tmp1 = SIMD.Float32x4.mul(row0, row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1));
minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1);
minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1));
tmp1 = SIMD.Float32x4.mul(row0, row2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1);
minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1));
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1));
minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3);
// Compute matrix determinant
det = SIMD.Float32x4.mul(row0, minor0);
det = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 2, 3, 0, 1), det);
det = SIMD.Float32x4.add(SIMD.Float32x4.swizzle(det, 1, 0, 3, 2), det);
tmp1 = SIMD.Float32x4.reciprocalApproximation(det);
det = SIMD.Float32x4.sub(
SIMD.Float32x4.add(tmp1, tmp1),
SIMD.Float32x4.mul(det, SIMD.Float32x4.mul(tmp1, tmp1)));
det = SIMD.Float32x4.swizzle(det, 0, 0, 0, 0);
if (!det) {
return null;
}
// Compute matrix inverse
SIMD.Float32x4.store(out, 0, SIMD.Float32x4.mul(det, minor0));
SIMD.Float32x4.store(out, 4, SIMD.Float32x4.mul(det, minor1));
SIMD.Float32x4.store(out, 8, SIMD.Float32x4.mul(det, minor2));
SIMD.Float32x4.store(out, 12, SIMD.Float32x4.mul(det, minor3));
return out;
}
/**
* Inverts a mat4 using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.invert = glMatrix.USE_SIMD ? mat4.SIMD.invert : mat4.scalar.invert;
/**
* Calculates the adjugate of a mat4 not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.scalar.adjoint = function(out, a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
return out;
};
/**
* Calculates the adjugate of a mat4 using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.SIMD.adjoint = function(out, a) {
var a0, a1, a2, a3;
var row0, row1, row2, row3;
var tmp1;
var minor0, minor1, minor2, minor3;
var a0 = SIMD.Float32x4.load(a, 0);
var a1 = SIMD.Float32x4.load(a, 4);
var a2 = SIMD.Float32x4.load(a, 8);
var a3 = SIMD.Float32x4.load(a, 12);
// Transpose the source matrix. Sort of. Not a true transpose operation
tmp1 = SIMD.Float32x4.shuffle(a0, a1, 0, 1, 4, 5);
row1 = SIMD.Float32x4.shuffle(a2, a3, 0, 1, 4, 5);
row0 = SIMD.Float32x4.shuffle(tmp1, row1, 0, 2, 4, 6);
row1 = SIMD.Float32x4.shuffle(row1, tmp1, 1, 3, 5, 7);
tmp1 = SIMD.Float32x4.shuffle(a0, a1, 2, 3, 6, 7);
row3 = SIMD.Float32x4.shuffle(a2, a3, 2, 3, 6, 7);
row2 = SIMD.Float32x4.shuffle(tmp1, row3, 0, 2, 4, 6);
row3 = SIMD.Float32x4.shuffle(row3, tmp1, 1, 3, 5, 7);
tmp1 = SIMD.Float32x4.mul(row2, row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor0 = SIMD.Float32x4.mul(row1, tmp1);
minor1 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row1, tmp1), minor0);
minor1 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor1);
minor1 = SIMD.Float32x4.swizzle(minor1, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(row1, row2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor0);
minor3 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row3, tmp1));
minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor3);
minor3 = SIMD.Float32x4.swizzle(minor3, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(row1, 2, 3, 0, 1), row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
row2 = SIMD.Float32x4.swizzle(row2, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor0);
minor2 = SIMD.Float32x4.mul(row0, tmp1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor0 = SIMD.Float32x4.sub(minor0, SIMD.Float32x4.mul(row2, tmp1));
minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row0, tmp1), minor2);
minor2 = SIMD.Float32x4.swizzle(minor2, 2, 3, 0, 1);
tmp1 = SIMD.Float32x4.mul(row0, row1);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor2);
minor3 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row2, tmp1), minor3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor2 = SIMD.Float32x4.sub(SIMD.Float32x4.mul(row3, tmp1), minor2);
minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row2, tmp1));
tmp1 = SIMD.Float32x4.mul(row0, row3);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row2, tmp1));
minor2 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row2, tmp1), minor1);
minor2 = SIMD.Float32x4.sub(minor2, SIMD.Float32x4.mul(row1, tmp1));
tmp1 = SIMD.Float32x4.mul(row0, row2);
tmp1 = SIMD.Float32x4.swizzle(tmp1, 1, 0, 3, 2);
minor1 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row3, tmp1), minor1);
minor3 = SIMD.Float32x4.sub(minor3, SIMD.Float32x4.mul(row1, tmp1));
tmp1 = SIMD.Float32x4.swizzle(tmp1, 2, 3, 0, 1);
minor1 = SIMD.Float32x4.sub(minor1, SIMD.Float32x4.mul(row3, tmp1));
minor3 = SIMD.Float32x4.add(SIMD.Float32x4.mul(row1, tmp1), minor3);
SIMD.Float32x4.store(out, 0, minor0);
SIMD.Float32x4.store(out, 4, minor1);
SIMD.Float32x4.store(out, 8, minor2);
SIMD.Float32x4.store(out, 12, minor3);
return out;
};
/**
* Calculates the adjugate of a mat4 using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the source matrix
* @returns {mat4} out
*/
mat4.adjoint = glMatrix.USE_SIMD ? mat4.SIMD.adjoint : mat4.scalar.adjoint;
/**
* Calculates the determinant of a mat4
*
* @param {mat4} a the source matrix
* @returns {Number} determinant of a
*/
mat4.determinant = function (a) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32;
// Calculate the determinant
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
};
/**
* Multiplies two mat4's explicitly using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand, must be a Float32Array
* @param {mat4} b the second operand, must be a Float32Array
* @returns {mat4} out
*/
mat4.SIMD.multiply = function (out, a, b) {
var a0 = SIMD.Float32x4.load(a, 0);
var a1 = SIMD.Float32x4.load(a, 4);
var a2 = SIMD.Float32x4.load(a, 8);
var a3 = SIMD.Float32x4.load(a, 12);
var b0 = SIMD.Float32x4.load(b, 0);
var out0 = SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 0, 0, 0, 0), a0),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 1, 1, 1, 1), a1),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 2, 2, 2, 2), a2),
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b0, 3, 3, 3, 3), a3))));
SIMD.Float32x4.store(out, 0, out0);
var b1 = SIMD.Float32x4.load(b, 4);
var out1 = SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 0, 0, 0, 0), a0),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 1, 1, 1, 1), a1),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 2, 2, 2, 2), a2),
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b1, 3, 3, 3, 3), a3))));
SIMD.Float32x4.store(out, 4, out1);
var b2 = SIMD.Float32x4.load(b, 8);
var out2 = SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 0, 0, 0, 0), a0),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 1, 1, 1, 1), a1),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 2, 2, 2, 2), a2),
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b2, 3, 3, 3, 3), a3))));
SIMD.Float32x4.store(out, 8, out2);
var b3 = SIMD.Float32x4.load(b, 12);
var out3 = SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 0, 0, 0, 0), a0),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 1, 1, 1, 1), a1),
SIMD.Float32x4.add(
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 2, 2, 2, 2), a2),
SIMD.Float32x4.mul(SIMD.Float32x4.swizzle(b3, 3, 3, 3, 3), a3))));
SIMD.Float32x4.store(out, 12, out3);
return out;
};
/**
* Multiplies two mat4's explicitly not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
mat4.scalar.multiply = function (out, a, b) {
var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
// Cache only the current line of the second matrix
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
return out;
};
/**
* Multiplies two mat4's using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
mat4.multiply = glMatrix.USE_SIMD ? mat4.SIMD.multiply : mat4.scalar.multiply;
/**
* Alias for {@link mat4.multiply}
* @function
*/
mat4.mul = mat4.multiply;
/**
* Translate a mat4 by the given vector not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to translate
* @param {vec3} v vector to translate by
* @returns {mat4} out
*/
mat4.scalar.translate = function (out, a, v) {
var x = v[0], y = v[1], z = v[2],
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23;
if (a === out) {
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
} else {
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03;
out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13;
out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23;
out[12] = a00 * x + a10 * y + a20 * z + a[12];
out[13] = a01 * x + a11 * y + a21 * z + a[13];
out[14] = a02 * x + a12 * y + a22 * z + a[14];
out[15] = a03 * x + a13 * y + a23 * z + a[15];
}
return out;
};
/**
* Translates a mat4 by the given vector using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to translate
* @param {vec3} v vector to translate by
* @returns {mat4} out
*/
mat4.SIMD.translate = function (out, a, v) {
var a0 = SIMD.Float32x4.load(a, 0),
a1 = SIMD.Float32x4.load(a, 4),
a2 = SIMD.Float32x4.load(a, 8),
a3 = SIMD.Float32x4.load(a, 12),
vec = SIMD.Float32x4(v[0], v[1], v[2] , 0);
if (a !== out) {
out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];
out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7];
out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11];
}
a0 = SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0));
a1 = SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1));
a2 = SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2));
var t0 = SIMD.Float32x4.add(a0, SIMD.Float32x4.add(a1, SIMD.Float32x4.add(a2, a3)));
SIMD.Float32x4.store(out, 12, t0);
return out;
};
/**
* Translates a mat4 by the given vector using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to translate
* @param {vec3} v vector to translate by
* @returns {mat4} out
*/
mat4.translate = glMatrix.USE_SIMD ? mat4.SIMD.translate : mat4.scalar.translate;
/**
* Scales the mat4 by the dimensions in the given vec3 not using vectorization
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {vec3} v the vec3 to scale the matrix by
* @returns {mat4} out
**/
mat4.scalar.scale = function(out, a, v) {
var x = v[0], y = v[1], z = v[2];
out[0] = a[0] * x;
out[1] = a[1] * x;
out[2] = a[2] * x;
out[3] = a[3] * x;
out[4] = a[4] * y;
out[5] = a[5] * y;
out[6] = a[6] * y;
out[7] = a[7] * y;
out[8] = a[8] * z;
out[9] = a[9] * z;
out[10] = a[10] * z;
out[11] = a[11] * z;
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Scales the mat4 by the dimensions in the given vec3 using vectorization
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {vec3} v the vec3 to scale the matrix by
* @returns {mat4} out
**/
mat4.SIMD.scale = function(out, a, v) {
var a0, a1, a2;
var vec = SIMD.Float32x4(v[0], v[1], v[2], 0);
a0 = SIMD.Float32x4.load(a, 0);
SIMD.Float32x4.store(
out, 0, SIMD.Float32x4.mul(a0, SIMD.Float32x4.swizzle(vec, 0, 0, 0, 0)));
a1 = SIMD.Float32x4.load(a, 4);
SIMD.Float32x4.store(
out, 4, SIMD.Float32x4.mul(a1, SIMD.Float32x4.swizzle(vec, 1, 1, 1, 1)));
a2 = SIMD.Float32x4.load(a, 8);
SIMD.Float32x4.store(
out, 8, SIMD.Float32x4.mul(a2, SIMD.Float32x4.swizzle(vec, 2, 2, 2, 2)));
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
return out;
};
/**
* Scales the mat4 by the dimensions in the given vec3 using SIMD if available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {vec3} v the vec3 to scale the matrix by
* @returns {mat4} out
*/
mat4.scale = glMatrix.USE_SIMD ? mat4.SIMD.scale : mat4.scalar.scale;
/**
* Rotates a mat4 by the given angle around the given axis
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @param {vec3} axis the axis to rotate around
* @returns {mat4} out
*/
mat4.rotate = function (out, a, rad, axis) {
var x = axis[0], y = axis[1], z = axis[2],
len = Math.sqrt(x * x + y * y + z * z),
s, c, t,
a00, a01, a02, a03,
a10, a11, a12, a13,
a20, a21, a22, a23,
b00, b01, b02,
b10, b11, b12,
b20, b21, b22;
if (Math.abs(len) < glMatrix.EPSILON) { return null; }
len = 1 / len;
x *= len;
y *= len;
z *= len;
s = Math.sin(rad);
c = Math.cos(rad);
t = 1 - c;
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
// Construct the elements of the rotation matrix
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
// Perform rotation-specific matrix multiplication
out[0] = a00 * b00 + a10 * b01 + a20 * b02;
out[1] = a01 * b00 + a11 * b01 + a21 * b02;
out[2] = a02 * b00 + a12 * b01 + a22 * b02;
out[3] = a03 * b00 + a13 * b01 + a23 * b02;
out[4] = a00 * b10 + a10 * b11 + a20 * b12;
out[5] = a01 * b10 + a11 * b11 + a21 * b12;
out[6] = a02 * b10 + a12 * b11 + a22 * b12;
out[7] = a03 * b10 + a13 * b11 + a23 * b12;
out[8] = a00 * b20 + a10 * b21 + a20 * b22;
out[9] = a01 * b20 + a11 * b21 + a21 * b22;
out[10] = a02 * b20 + a12 * b21 + a22 * b22;
out[11] = a03 * b20 + a13 * b21 + a23 * b22;
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
return out;
};
/**
* Rotates a matrix by the given angle around the X axis not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.scalar.rotateX = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[4] = a10 * c + a20 * s;
out[5] = a11 * c + a21 * s;
out[6] = a12 * c + a22 * s;
out[7] = a13 * c + a23 * s;
out[8] = a20 * c - a10 * s;
out[9] = a21 * c - a11 * s;
out[10] = a22 * c - a12 * s;
out[11] = a23 * c - a13 * s;
return out;
};
/**
* Rotates a matrix by the given angle around the X axis using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.SIMD.rotateX = function (out, a, rad) {
var s = SIMD.Float32x4.splat(Math.sin(rad)),
c = SIMD.Float32x4.splat(Math.cos(rad));
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
var a_1 = SIMD.Float32x4.load(a, 4);
var a_2 = SIMD.Float32x4.load(a, 8);
SIMD.Float32x4.store(out, 4,
SIMD.Float32x4.add(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_2, s)));
SIMD.Float32x4.store(out, 8,
SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_2, c), SIMD.Float32x4.mul(a_1, s)));
return out;
};
/**
* Rotates a matrix by the given angle around the X axis using SIMD if availabe and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateX = glMatrix.USE_SIMD ? mat4.SIMD.rotateX : mat4.scalar.rotateX;
/**
* Rotates a matrix by the given angle around the Y axis not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.scalar.rotateY = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c - a20 * s;
out[1] = a01 * c - a21 * s;
out[2] = a02 * c - a22 * s;
out[3] = a03 * c - a23 * s;
out[8] = a00 * s + a20 * c;
out[9] = a01 * s + a21 * c;
out[10] = a02 * s + a22 * c;
out[11] = a03 * s + a23 * c;
return out;
};
/**
* Rotates a matrix by the given angle around the Y axis using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.SIMD.rotateY = function (out, a, rad) {
var s = SIMD.Float32x4.splat(Math.sin(rad)),
c = SIMD.Float32x4.splat(Math.cos(rad));
if (a !== out) { // If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
var a_0 = SIMD.Float32x4.load(a, 0);
var a_2 = SIMD.Float32x4.load(a, 8);
SIMD.Float32x4.store(out, 0,
SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_2, s)));
SIMD.Float32x4.store(out, 8,
SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, s), SIMD.Float32x4.mul(a_2, c)));
return out;
};
/**
* Rotates a matrix by the given angle around the Y axis if SIMD available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateY = glMatrix.USE_SIMD ? mat4.SIMD.rotateY : mat4.scalar.rotateY;
/**
* Rotates a matrix by the given angle around the Z axis not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.scalar.rotateZ = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7];
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c + a10 * s;
out[1] = a01 * c + a11 * s;
out[2] = a02 * c + a12 * s;
out[3] = a03 * c + a13 * s;
out[4] = a10 * c - a00 * s;
out[5] = a11 * c - a01 * s;
out[6] = a12 * c - a02 * s;
out[7] = a13 * c - a03 * s;
return out;
};
/**
* Rotates a matrix by the given angle around the Z axis using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.SIMD.rotateZ = function (out, a, rad) {
var s = SIMD.Float32x4.splat(Math.sin(rad)),
c = SIMD.Float32x4.splat(Math.cos(rad));
if (a !== out) { // If the source and destination differ, copy the unchanged last row
out[8] = a[8];
out[9] = a[9];
out[10] = a[10];
out[11] = a[11];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
var a_0 = SIMD.Float32x4.load(a, 0);
var a_1 = SIMD.Float32x4.load(a, 4);
SIMD.Float32x4.store(out, 0,
SIMD.Float32x4.add(SIMD.Float32x4.mul(a_0, c), SIMD.Float32x4.mul(a_1, s)));
SIMD.Float32x4.store(out, 4,
SIMD.Float32x4.sub(SIMD.Float32x4.mul(a_1, c), SIMD.Float32x4.mul(a_0, s)));
return out;
};
/**
* Rotates a matrix by the given angle around the Z axis if SIMD available and enabled
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateZ = glMatrix.USE_SIMD ? mat4.SIMD.rotateZ : mat4.scalar.rotateZ;
/**
* Creates a matrix from a vector translation
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, dest, vec);
*
* @param {mat4} out mat4 receiving operation result
* @param {vec3} v Translation vector
* @returns {mat4} out
*/
mat4.fromTranslation = function(out, v) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
}
/**
* Creates a matrix from a vector scaling
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.scale(dest, dest, vec);
*
* @param {mat4} out mat4 receiving operation result
* @param {vec3} v Scaling vector
* @returns {mat4} out
*/
mat4.fromScaling = function(out, v) {
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = v[1];
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = v[2];
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Creates a matrix from a given angle around a given axis
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.rotate(dest, dest, rad, axis);
*
* @param {mat4} out mat4 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @param {vec3} axis the axis to rotate around
* @returns {mat4} out
*/
mat4.fromRotation = function(out, rad, axis) {
var x = axis[0], y = axis[1], z = axis[2],
len = Math.sqrt(x * x + y * y + z * z),
s, c, t;
if (Math.abs(len) < glMatrix.EPSILON) { return null; }
len = 1 / len;
x *= len;
y *= len;
z *= len;
s = Math.sin(rad);
c = Math.cos(rad);
t = 1 - c;
// Perform rotation-specific matrix multiplication
out[0] = x * x * t + c;
out[1] = y * x * t + z * s;
out[2] = z * x * t - y * s;
out[3] = 0;
out[4] = x * y * t - z * s;
out[5] = y * y * t + c;
out[6] = z * y * t + x * s;
out[7] = 0;
out[8] = x * z * t + y * s;
out[9] = y * z * t - x * s;
out[10] = z * z * t + c;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Creates a matrix from the given angle around the X axis
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.rotateX(dest, dest, rad);
*
* @param {mat4} out mat4 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.fromXRotation = function(out, rad) {
var s = Math.sin(rad),
c = Math.cos(rad);
// Perform axis-specific matrix multiplication
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = c;
out[6] = s;
out[7] = 0;
out[8] = 0;
out[9] = -s;
out[10] = c;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Creates a matrix from the given angle around the Y axis
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.rotateY(dest, dest, rad);
*
* @param {mat4} out mat4 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.fromYRotation = function(out, rad) {
var s = Math.sin(rad),
c = Math.cos(rad);
// Perform axis-specific matrix multiplication
out[0] = c;
out[1] = 0;
out[2] = -s;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = s;
out[9] = 0;
out[10] = c;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Creates a matrix from the given angle around the Z axis
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.rotateZ(dest, dest, rad);
*
* @param {mat4} out mat4 receiving operation result
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.fromZRotation = function(out, rad) {
var s = Math.sin(rad),
c = Math.cos(rad);
// Perform axis-specific matrix multiplication
out[0] = c;
out[1] = s;
out[2] = 0;
out[3] = 0;
out[4] = -s;
out[5] = c;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Creates a matrix from a quaternion rotation and vector translation
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, vec);
* var quatMat = mat4.create();
* quat4.toMat4(quat, quatMat);
* mat4.multiply(dest, quatMat);
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @param {vec3} v Translation vector
* @returns {mat4} out
*/
mat4.fromRotationTranslation = function (out, q, v) {
// Quaternion math
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[1] = xy + wz;
out[2] = xz - wy;
out[3] = 0;
out[4] = xy - wz;
out[5] = 1 - (xx + zz);
out[6] = yz + wx;
out[7] = 0;
out[8] = xz + wy;
out[9] = yz - wx;
out[10] = 1 - (xx + yy);
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
};
/**
* Returns the translation vector component of a transformation
* matrix. If a matrix is built with fromRotationTranslation,
* the returned vector will be the same as the translation vector
* originally supplied.
* @param {vec3} out Vector to receive translation component
* @param {mat4} mat Matrix to be decomposed (input)
* @return {vec3} out
*/
mat4.getTranslation = function (out, mat) {
out[0] = mat[12];
out[1] = mat[13];
out[2] = mat[14];
return out;
};
/**
* Returns a quaternion representing the rotational component
* of a transformation matrix. If a matrix is built with
* fromRotationTranslation, the returned quaternion will be the
* same as the quaternion originally supplied.
* @param {quat} out Quaternion to receive the rotation component
* @param {mat4} mat Matrix to be decomposed (input)
* @return {quat} out
*/
mat4.getRotation = function (out, mat) {
// Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
var trace = mat[0] + mat[5] + mat[10];
var S = 0;
if (trace > 0) {
S = Math.sqrt(trace + 1.0) * 2;
out[3] = 0.25 * S;
out[0] = (mat[6] - mat[9]) / S;
out[1] = (mat[8] - mat[2]) / S;
out[2] = (mat[1] - mat[4]) / S;
} else if ((mat[0] > mat[5])&(mat[0] > mat[10])) {
S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2;
out[3] = (mat[6] - mat[9]) / S;
out[0] = 0.25 * S;
out[1] = (mat[1] + mat[4]) / S;
out[2] = (mat[8] + mat[2]) / S;
} else if (mat[5] > mat[10]) {
S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2;
out[3] = (mat[8] - mat[2]) / S;
out[0] = (mat[1] + mat[4]) / S;
out[1] = 0.25 * S;
out[2] = (mat[6] + mat[9]) / S;
} else {
S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2;
out[3] = (mat[1] - mat[4]) / S;
out[0] = (mat[8] + mat[2]) / S;
out[1] = (mat[6] + mat[9]) / S;
out[2] = 0.25 * S;
}
return out;
};
/**
* Creates a matrix from a quaternion rotation, vector translation and vector scale
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, vec);
* var quatMat = mat4.create();
* quat4.toMat4(quat, quatMat);
* mat4.multiply(dest, quatMat);
* mat4.scale(dest, scale)
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @param {vec3} v Translation vector
* @param {vec3} s Scaling vector
* @returns {mat4} out
*/
mat4.fromRotationTranslationScale = function (out, q, v, s) {
// Quaternion math
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2,
sx = s[0],
sy = s[1],
sz = s[2];
out[0] = (1 - (yy + zz)) * sx;
out[1] = (xy + wz) * sx;
out[2] = (xz - wy) * sx;
out[3] = 0;
out[4] = (xy - wz) * sy;
out[5] = (1 - (xx + zz)) * sy;
out[6] = (yz + wx) * sy;
out[7] = 0;
out[8] = (xz + wy) * sz;
out[9] = (yz - wx) * sz;
out[10] = (1 - (xx + yy)) * sz;
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
};
/**
* Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin
* This is equivalent to (but much faster than):
*
* mat4.identity(dest);
* mat4.translate(dest, vec);
* mat4.translate(dest, origin);
* var quatMat = mat4.create();
* quat4.toMat4(quat, quatMat);
* mat4.multiply(dest, quatMat);
* mat4.scale(dest, scale)
* mat4.translate(dest, negativeOrigin);
*
* @param {mat4} out mat4 receiving operation result
* @param {quat4} q Rotation quaternion
* @param {vec3} v Translation vector
* @param {vec3} s Scaling vector
* @param {vec3} o The origin vector around which to scale and rotate
* @returns {mat4} out
*/
mat4.fromRotationTranslationScaleOrigin = function (out, q, v, s, o) {
// Quaternion math
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2,
sx = s[0],
sy = s[1],
sz = s[2],
ox = o[0],
oy = o[1],
oz = o[2];
out[0] = (1 - (yy + zz)) * sx;
out[1] = (xy + wz) * sx;
out[2] = (xz - wy) * sx;
out[3] = 0;
out[4] = (xy - wz) * sy;
out[5] = (1 - (xx + zz)) * sy;
out[6] = (yz + wx) * sy;
out[7] = 0;
out[8] = (xz + wy) * sz;
out[9] = (yz - wx) * sz;
out[10] = (1 - (xx + yy)) * sz;
out[11] = 0;
out[12] = v[0] + ox - (out[0] * ox + out[4] * oy + out[8] * oz);
out[13] = v[1] + oy - (out[1] * ox + out[5] * oy + out[9] * oz);
out[14] = v[2] + oz - (out[2] * ox + out[6] * oy + out[10] * oz);
out[15] = 1;
return out;
};
/**
* Calculates a 4x4 matrix from the given quaternion
*
* @param {mat4} out mat4 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat4} out
*/
mat4.fromQuat = function (out, q) {
var x = q[0], y = q[1], z = q[2], w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
yx = y * x2,
yy = y * y2,
zx = z * x2,
zy = z * y2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - yy - zz;
out[1] = yx + wz;
out[2] = zx - wy;
out[3] = 0;
out[4] = yx - wz;
out[5] = 1 - xx - zz;
out[6] = zy + wx;
out[7] = 0;
out[8] = zx + wy;
out[9] = zy - wx;
out[10] = 1 - xx - yy;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Generates a frustum matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {Number} left Left bound of the frustum
* @param {Number} right Right bound of the frustum
* @param {Number} bottom Bottom bound of the frustum
* @param {Number} top Top bound of the frustum
* @param {Number} near Near bound of the frustum
* @param {Number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.frustum = function (out, left, right, bottom, top, near, far) {
var rl = 1 / (right - left),
tb = 1 / (top - bottom),
nf = 1 / (near - far);
out[0] = (near * 2) * rl;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = (near * 2) * tb;
out[6] = 0;
out[7] = 0;
out[8] = (right + left) * rl;
out[9] = (top + bottom) * tb;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (far * near * 2) * nf;
out[15] = 0;
return out;
};
/**
* Generates a perspective projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} fovy Vertical field of view in radians
* @param {number} aspect Aspect ratio. typically viewport width/height
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.perspective = function (out, fovy, aspect, near, far) {
var f = 1.0 / Math.tan(fovy / 2),
nf = 1 / (near - far);
out[0] = f / aspect;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = f;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = (2 * far * near) * nf;
out[15] = 0;
return out;
};
/**
* Generates a perspective projection matrix with the given field of view.
* This is primarily useful for generating projection matrices to be used
* with the still experiemental WebVR API.
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.perspectiveFromFieldOfView = function (out, fov, near, far) {
var upTan = Math.tan(fov.upDegrees * Math.PI/180.0),
downTan = Math.tan(fov.downDegrees * Math.PI/180.0),
leftTan = Math.tan(fov.leftDegrees * Math.PI/180.0),
rightTan = Math.tan(fov.rightDegrees * Math.PI/180.0),
xScale = 2.0 / (leftTan + rightTan),
yScale = 2.0 / (upTan + downTan);
out[0] = xScale;
out[1] = 0.0;
out[2] = 0.0;
out[3] = 0.0;
out[4] = 0.0;
out[5] = yScale;
out[6] = 0.0;
out[7] = 0.0;
out[8] = -((leftTan - rightTan) * xScale * 0.5);
out[9] = ((upTan - downTan) * yScale * 0.5);
out[10] = far / (near - far);
out[11] = -1.0;
out[12] = 0.0;
out[13] = 0.0;
out[14] = (far * near) / (near - far);
out[15] = 0.0;
return out;
}
/**
* Generates a orthogonal projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} left Left bound of the frustum
* @param {number} right Right bound of the frustum
* @param {number} bottom Bottom bound of the frustum
* @param {number} top Top bound of the frustum
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.ortho = function (out, left, right, bottom, top, near, far) {
var lr = 1 / (left - right),
bt = 1 / (bottom - top),
nf = 1 / (near - far);
out[0] = -2 * lr;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = -2 * bt;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 2 * nf;
out[11] = 0;
out[12] = (left + right) * lr;
out[13] = (top + bottom) * bt;
out[14] = (far + near) * nf;
out[15] = 1;
return out;
};
/**
* Generates a look-at matrix with the given eye position, focal point, and up axis
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {vec3} eye Position of the viewer
* @param {vec3} center Point the viewer is looking at
* @param {vec3} up vec3 pointing up
* @returns {mat4} out
*/
mat4.lookAt = function (out, eye, center, up) {
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
eyex = eye[0],
eyey = eye[1],
eyez = eye[2],
upx = up[0],
upy = up[1],
upz = up[2],
centerx = center[0],
centery = center[1],
centerz = center[2];
if (Math.abs(eyex - centerx) < glMatrix.EPSILON &&
Math.abs(eyey - centery) < glMatrix.EPSILON &&
Math.abs(eyez - centerz) < glMatrix.EPSILON) {
return mat4.identity(out);
}
z0 = eyex - centerx;
z1 = eyey - centery;
z2 = eyez - centerz;
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
z0 *= len;
z1 *= len;
z2 *= len;
x0 = upy * z2 - upz * z1;
x1 = upz * z0 - upx * z2;
x2 = upx * z1 - upy * z0;
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
if (!len) {
x0 = 0;
x1 = 0;
x2 = 0;
} else {
len = 1 / len;
x0 *= len;
x1 *= len;
x2 *= len;
}
y0 = z1 * x2 - z2 * x1;
y1 = z2 * x0 - z0 * x2;
y2 = z0 * x1 - z1 * x0;
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
if (!len) {
y0 = 0;
y1 = 0;
y2 = 0;
} else {
len = 1 / len;
y0 *= len;
y1 *= len;
y2 *= len;
}
out[0] = x0;
out[1] = y0;
out[2] = z0;
out[3] = 0;
out[4] = x1;
out[5] = y1;
out[6] = z1;
out[7] = 0;
out[8] = x2;
out[9] = y2;
out[10] = z2;
out[11] = 0;
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
out[15] = 1;
return out;
};
/**
* Returns a string representation of a mat4
*
* @param {mat4} mat matrix to represent as a string
* @returns {String} string representation of the matrix
*/
mat4.str = function (a) {
return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
};
/**
* Returns Frobenius norm of a mat4
*
* @param {mat4} a the matrix to calculate Frobenius norm of
* @returns {Number} Frobenius norm
*/
mat4.frob = function (a) {
return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))
};
/**
* Adds two mat4's
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
mat4.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
out[6] = a[6] + b[6];
out[7] = a[7] + b[7];
out[8] = a[8] + b[8];
out[9] = a[9] + b[9];
out[10] = a[10] + b[10];
out[11] = a[11] + b[11];
out[12] = a[12] + b[12];
out[13] = a[13] + b[13];
out[14] = a[14] + b[14];
out[15] = a[15] + b[15];
return out;
};
/**
* Subtracts matrix b from matrix a
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @returns {mat4} out
*/
mat4.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
out[6] = a[6] - b[6];
out[7] = a[7] - b[7];
out[8] = a[8] - b[8];
out[9] = a[9] - b[9];
out[10] = a[10] - b[10];
out[11] = a[11] - b[11];
out[12] = a[12] - b[12];
out[13] = a[13] - b[13];
out[14] = a[14] - b[14];
out[15] = a[15] - b[15];
return out;
};
/**
* Alias for {@link mat4.subtract}
* @function
*/
mat4.sub = mat4.subtract;
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat4} out
*/
mat4.multiplyScalar = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
out[6] = a[6] * b;
out[7] = a[7] * b;
out[8] = a[8] * b;
out[9] = a[9] * b;
out[10] = a[10] * b;
out[11] = a[11] * b;
out[12] = a[12] * b;
out[13] = a[13] * b;
out[14] = a[14] * b;
out[15] = a[15] * b;
return out;
};
/**
* Adds two mat4's after multiplying each element of the second operand by a scalar value.
*
* @param {mat4} out the receiving vector
* @param {mat4} a the first operand
* @param {mat4} b the second operand
* @param {Number} scale the amount to scale b's elements by before adding
* @returns {mat4} out
*/
mat4.multiplyScalarAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
out[4] = a[4] + (b[4] * scale);
out[5] = a[5] + (b[5] * scale);
out[6] = a[6] + (b[6] * scale);
out[7] = a[7] + (b[7] * scale);
out[8] = a[8] + (b[8] * scale);
out[9] = a[9] + (b[9] * scale);
out[10] = a[10] + (b[10] * scale);
out[11] = a[11] + (b[11] * scale);
out[12] = a[12] + (b[12] * scale);
out[13] = a[13] + (b[13] * scale);
out[14] = a[14] + (b[14] * scale);
out[15] = a[15] + (b[15] * scale);
return out;
};
/**
* Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===)
*
* @param {mat4} a The first matrix.
* @param {mat4} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat4.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] &&
a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] &&
a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] &&
a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
};
/**
* Returns whether or not the matrices have approximately the same elements in the same position.
*
* @param {mat4} a The first matrix.
* @param {mat4} b The second matrix.
* @returns {Boolean} True if the matrices are equal, false otherwise.
*/
mat4.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7],
a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11],
a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3],
b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7],
b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11],
b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)) &&
Math.abs(a4 - b4) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a4), Math.abs(b4)) &&
Math.abs(a5 - b5) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a5), Math.abs(b5)) &&
Math.abs(a6 - b6) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a6), Math.abs(b6)) &&
Math.abs(a7 - b7) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a7), Math.abs(b7)) &&
Math.abs(a8 - b8) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a8), Math.abs(b8)) &&
Math.abs(a9 - b9) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a9), Math.abs(b9)) &&
Math.abs(a10 - b10) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a10), Math.abs(b10)) &&
Math.abs(a11 - b11) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a11), Math.abs(b11)) &&
Math.abs(a12 - b12) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a12), Math.abs(b12)) &&
Math.abs(a13 - b13) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a13), Math.abs(b13)) &&
Math.abs(a14 - b14) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a14), Math.abs(b14)) &&
Math.abs(a15 - b15) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a15), Math.abs(b15)));
};
module.exports = mat4;
},{"./common.js":189}],194:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
var mat3 = require("./mat3.js");
var vec3 = require("./vec3.js");
var vec4 = require("./vec4.js");
/**
* @class Quaternion
* @name quat
*/
var quat = {};
/**
* Creates a new identity quat
*
* @returns {quat} a new quaternion
*/
quat.create = function() {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Sets a quaternion to represent the shortest rotation from one
* vector to another.
*
* Both vectors are assumed to be unit length.
*
* @param {quat} out the receiving quaternion.
* @param {vec3} a the initial vector
* @param {vec3} b the destination vector
* @returns {quat} out
*/
quat.rotationTo = (function() {
var tmpvec3 = vec3.create();
var xUnitVec3 = vec3.fromValues(1,0,0);
var yUnitVec3 = vec3.fromValues(0,1,0);
return function(out, a, b) {
var dot = vec3.dot(a, b);
if (dot < -0.999999) {
vec3.cross(tmpvec3, xUnitVec3, a);
if (vec3.length(tmpvec3) < 0.000001)
vec3.cross(tmpvec3, yUnitVec3, a);
vec3.normalize(tmpvec3, tmpvec3);
quat.setAxisAngle(out, tmpvec3, Math.PI);
return out;
} else if (dot > 0.999999) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
} else {
vec3.cross(tmpvec3, a, b);
out[0] = tmpvec3[0];
out[1] = tmpvec3[1];
out[2] = tmpvec3[2];
out[3] = 1 + dot;
return quat.normalize(out, out);
}
};
})();
/**
* Sets the specified quaternion with values corresponding to the given
* axes. Each axis is a vec3 and is expected to be unit length and
* perpendicular to all other specified axes.
*
* @param {vec3} view the vector representing the viewing direction
* @param {vec3} right the vector representing the local "right" direction
* @param {vec3} up the vector representing the local "up" direction
* @returns {quat} out
*/
quat.setAxes = (function() {
var matr = mat3.create();
return function(out, view, right, up) {
matr[0] = right[0];
matr[3] = right[1];
matr[6] = right[2];
matr[1] = up[0];
matr[4] = up[1];
matr[7] = up[2];
matr[2] = -view[0];
matr[5] = -view[1];
matr[8] = -view[2];
return quat.normalize(out, quat.fromMat3(out, matr));
};
})();
/**
* Creates a new quat initialized with values from an existing quaternion
*
* @param {quat} a quaternion to clone
* @returns {quat} a new quaternion
* @function
*/
quat.clone = vec4.clone;
/**
* Creates a new quat initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} a new quaternion
* @function
*/
quat.fromValues = vec4.fromValues;
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
quat.copy = vec4.copy;
/**
* Set the components of a quat to the given values
*
* @param {quat} out the receiving quaternion
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} out
* @function
*/
quat.set = vec4.set;
/**
* Set a quat to the identity quaternion
*
* @param {quat} out the receiving quaternion
* @returns {quat} out
*/
quat.identity = function(out) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
quat.setAxisAngle = function(out, axis, rad) {
rad = rad * 0.5;
var s = Math.sin(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
};
/**
* Gets the rotation axis and angle for a given
* quaternion. If a quaternion is created with
* setAxisAngle, this method will return the same
* values as providied in the original parameter list
* OR functionally equivalent values.
* Example: The quaternion formed by axis [0, 0, 1] and
* angle -90 is the same as the quaternion formed by
* [0, 0, 1] and 270. This method favors the latter.
* @param {vec3} out_axis Vector receiving the axis of rotation
* @param {quat} q Quaternion to be decomposed
* @return {Number} Angle, in radians, of the rotation
*/
quat.getAxisAngle = function(out_axis, q) {
var rad = Math.acos(q[3]) * 2.0;
var s = Math.sin(rad / 2.0);
if (s != 0.0) {
out_axis[0] = q[0] / s;
out_axis[1] = q[1] / s;
out_axis[2] = q[2] / s;
} else {
// If s is zero, return any axis (no rotation - axis does not matter)
out_axis[0] = 1;
out_axis[1] = 0;
out_axis[2] = 0;
}
return rad;
};
/**
* Adds two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
* @function
*/
quat.add = vec4.add;
/**
* Multiplies two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
quat.multiply = function(out, a, b) {
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3];
out[0] = ax * bw + aw * bx + ay * bz - az * by;
out[1] = ay * bw + aw * by + az * bx - ax * bz;
out[2] = az * bw + aw * bz + ax * by - ay * bx;
out[3] = aw * bw - ax * bx - ay * by - az * bz;
return out;
};
/**
* Alias for {@link quat.multiply}
* @function
*/
quat.mul = quat.multiply;
/**
* Scales a quat by a scalar number
*
* @param {quat} out the receiving vector
* @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
*/
quat.scale = vec4.scale;
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateX = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + aw * bx;
out[1] = ay * bw + az * bx;
out[2] = az * bw - ay * bx;
out[3] = aw * bw - ax * bx;
return out;
};
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateY = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
by = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw - az * by;
out[1] = ay * bw + aw * by;
out[2] = az * bw + ax * by;
out[3] = aw * bw - ay * by;
return out;
};
/**
* Rotates a quaternion by the given angle about the Z axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateZ = function (out, a, rad) {
rad *= 0.5;
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bz = Math.sin(rad), bw = Math.cos(rad);
out[0] = ax * bw + ay * bz;
out[1] = ay * bw - ax * bz;
out[2] = az * bw + aw * bz;
out[3] = aw * bw - az * bz;
return out;
};
/**
* Calculates the W component of a quat from the X, Y, and Z components.
* Assumes that quaternion is 1 unit in length.
* Any existing W component will be ignored.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate W component of
* @returns {quat} out
*/
quat.calculateW = function (out, a) {
var x = a[0], y = a[1], z = a[2];
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
return out;
};
/**
* Calculates the dot product of two quat's
*
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {Number} dot product of a and b
* @function
*/
quat.dot = vec4.dot;
/**
* Performs a linear interpolation between two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
* @function
*/
quat.lerp = vec4.lerp;
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
quat.slerp = function (out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3];
var omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw;
// adjust signs (if necessary)
if ( cosom < 0.0 ) {
cosom = -cosom;
bx = - bx;
by = - by;
bz = - bz;
bw = - bw;
}
// calculate coefficients
if ( (1.0 - cosom) > 0.000001 ) {
// standard case (slerp)
omega = Math.acos(cosom);
sinom = Math.sin(omega);
scale0 = Math.sin((1.0 - t) * omega) / sinom;
scale1 = Math.sin(t * omega) / sinom;
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t;
scale1 = t;
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx;
out[1] = scale0 * ay + scale1 * by;
out[2] = scale0 * az + scale1 * bz;
out[3] = scale0 * aw + scale1 * bw;
return out;
};
/**
* Performs a spherical linear interpolation with two control points
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {quat} c the third operand
* @param {quat} d the fourth operand
* @param {Number} t interpolation amount
* @returns {quat} out
*/
quat.sqlerp = (function () {
var temp1 = quat.create();
var temp2 = quat.create();
return function (out, a, b, c, d, t) {
quat.slerp(temp1, a, d, t);
quat.slerp(temp2, b, c, t);
quat.slerp(out, temp1, temp2, 2 * t * (1 - t));
return out;
};
}());
/**
* Calculates the inverse of a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate inverse of
* @returns {quat} out
*/
quat.invert = function(out, a) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
invDot = dot ? 1.0/dot : 0;
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
out[0] = -a0*invDot;
out[1] = -a1*invDot;
out[2] = -a2*invDot;
out[3] = a3*invDot;
return out;
};
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
quat.conjugate = function (out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a[3];
return out;
};
/**
* Calculates the length of a quat
*
* @param {quat} a vector to calculate length of
* @returns {Number} length of a
* @function
*/
quat.length = vec4.length;
/**
* Alias for {@link quat.length}
* @function
*/
quat.len = quat.length;
/**
* Calculates the squared length of a quat
*
* @param {quat} a vector to calculate squared length of
* @returns {Number} squared length of a
* @function
*/
quat.squaredLength = vec4.squaredLength;
/**
* Alias for {@link quat.squaredLength}
* @function
*/
quat.sqrLen = quat.squaredLength;
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
quat.normalize = vec4.normalize;
/**
* Creates a quaternion from the given 3x3 rotation matrix.
*
* NOTE: The resultant quaternion is not normalized, so you should be sure
* to renormalize the quaternion yourself where necessary.
*
* @param {quat} out the receiving quaternion
* @param {mat3} m rotation matrix
* @returns {quat} out
* @function
*/
quat.fromMat3 = function(out, m) {
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
var fTrace = m[0] + m[4] + m[8];
var fRoot;
if ( fTrace > 0.0 ) {
// |w| > 1/2, may as well choose w > 1/2
fRoot = Math.sqrt(fTrace + 1.0); // 2w
out[3] = 0.5 * fRoot;
fRoot = 0.5/fRoot; // 1/(4w)
out[0] = (m[5]-m[7])*fRoot;
out[1] = (m[6]-m[2])*fRoot;
out[2] = (m[1]-m[3])*fRoot;
} else {
// |w| <= 1/2
var i = 0;
if ( m[4] > m[0] )
i = 1;
if ( m[8] > m[i*3+i] )
i = 2;
var j = (i+1)%3;
var k = (i+2)%3;
fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
out[i] = 0.5 * fRoot;
fRoot = 0.5 / fRoot;
out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;
out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
}
return out;
};
/**
* Returns a string representation of a quatenion
*
* @param {quat} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
quat.str = function (a) {
return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
/**
* Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
*
* @param {quat} a The first quaternion.
* @param {quat} b The second quaternion.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
quat.exactEquals = vec4.exactEquals;
/**
* Returns whether or not the quaternions have approximately the same elements in the same position.
*
* @param {quat} a The first vector.
* @param {quat} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
quat.equals = vec4.equals;
module.exports = quat;
},{"./common.js":189,"./mat3.js":192,"./vec3.js":196,"./vec4.js":197}],195:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 2 Dimensional Vector
* @name vec2
*/
var vec2 = {};
/**
* Creates a new, empty vec2
*
* @returns {vec2} a new 2D vector
*/
vec2.create = function() {
var out = new glMatrix.ARRAY_TYPE(2);
out[0] = 0;
out[1] = 0;
return out;
};
/**
* Creates a new vec2 initialized with values from an existing vector
*
* @param {vec2} a vector to clone
* @returns {vec2} a new 2D vector
*/
vec2.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(2);
out[0] = a[0];
out[1] = a[1];
return out;
};
/**
* Creates a new vec2 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} a new 2D vector
*/
vec2.fromValues = function(x, y) {
var out = new glMatrix.ARRAY_TYPE(2);
out[0] = x;
out[1] = y;
return out;
};
/**
* Copy the values from one vec2 to another
*
* @param {vec2} out the receiving vector
* @param {vec2} a the source vector
* @returns {vec2} out
*/
vec2.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
return out;
};
/**
* Set the components of a vec2 to the given values
*
* @param {vec2} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} out
*/
vec2.set = function(out, x, y) {
out[0] = x;
out[1] = y;
return out;
};
/**
* Adds two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
return out;
};
/**
* Alias for {@link vec2.subtract}
* @function
*/
vec2.sub = vec2.subtract;
/**
* Multiplies two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
return out;
};
/**
* Alias for {@link vec2.multiply}
* @function
*/
vec2.mul = vec2.multiply;
/**
* Divides two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
return out;
};
/**
* Alias for {@link vec2.divide}
* @function
*/
vec2.div = vec2.divide;
/**
* Math.ceil the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to ceil
* @returns {vec2} out
*/
vec2.ceil = function (out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
return out;
};
/**
* Math.floor the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to floor
* @returns {vec2} out
*/
vec2.floor = function (out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
return out;
};
/**
* Returns the minimum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
return out;
};
/**
* Returns the maximum of two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
vec2.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
return out;
};
/**
* Math.round the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to round
* @returns {vec2} out
*/
vec2.round = function (out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
return out;
};
/**
* Scales a vec2 by a scalar number
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec2} out
*/
vec2.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
return out;
};
/**
* Adds two vec2's after scaling the second operand by a scalar value
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec2} out
*/
vec2.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} distance between a and b
*/
vec2.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Alias for {@link vec2.distance}
* @function
*/
vec2.dist = vec2.distance;
/**
* Calculates the squared euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} squared distance between a and b
*/
vec2.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return x*x + y*y;
};
/**
* Alias for {@link vec2.squaredDistance}
* @function
*/
vec2.sqrDist = vec2.squaredDistance;
/**
* Calculates the length of a vec2
*
* @param {vec2} a vector to calculate length of
* @returns {Number} length of a
*/
vec2.length = function (a) {
var x = a[0],
y = a[1];
return Math.sqrt(x*x + y*y);
};
/**
* Alias for {@link vec2.length}
* @function
*/
vec2.len = vec2.length;
/**
* Calculates the squared length of a vec2
*
* @param {vec2} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec2.squaredLength = function (a) {
var x = a[0],
y = a[1];
return x*x + y*y;
};
/**
* Alias for {@link vec2.squaredLength}
* @function
*/
vec2.sqrLen = vec2.squaredLength;
/**
* Negates the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to negate
* @returns {vec2} out
*/
vec2.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
return out;
};
/**
* Returns the inverse of the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to invert
* @returns {vec2} out
*/
vec2.inverse = function(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
return out;
};
/**
* Normalize a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to normalize
* @returns {vec2} out
*/
vec2.normalize = function(out, a) {
var x = a[0],
y = a[1];
var len = x*x + y*y;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
}
return out;
};
/**
* Calculates the dot product of two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} dot product of a and b
*/
vec2.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1];
};
/**
* Computes the cross product of two vec2's
* Note that the cross product must by definition produce a 3D vector
*
* @param {vec3} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec3} out
*/
vec2.cross = function(out, a, b) {
var z = a[0] * b[1] - a[1] * b[0];
out[0] = out[1] = 0;
out[2] = z;
return out;
};
/**
* Performs a linear interpolation between two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec2} out
*/
vec2.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec2} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec2} out
*/
vec2.random = function (out, scale) {
scale = scale || 1.0;
var r = glMatrix.RANDOM() * 2.0 * Math.PI;
out[0] = Math.cos(r) * scale;
out[1] = Math.sin(r) * scale;
return out;
};
/**
* Transforms the vec2 with a mat2
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat2 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
return out;
};
/**
* Transforms the vec2 with a mat2d
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2d} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat2d = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y + m[4];
out[1] = m[1] * x + m[3] * y + m[5];
return out;
};
/**
* Transforms the vec2 with a mat3
* 3rd vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat3} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat3 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[3] * y + m[6];
out[1] = m[1] * x + m[4] * y + m[7];
return out;
};
/**
* Transforms the vec2 with a mat4
* 3rd vector component is implicitly '0'
* 4th vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec2} out
*/
vec2.transformMat4 = function(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[4] * y + m[12];
out[1] = m[1] * x + m[5] * y + m[13];
return out;
};
/**
* Perform some operation over an array of vec2s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec2.forEach = (function() {
var vec = vec2.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 2;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1];
}
return a;
};
})();
/**
* Returns a string representation of a vector
*
* @param {vec2} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec2.str = function (a) {
return 'vec2(' + a[0] + ', ' + a[1] + ')';
};
/**
* Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
*
* @param {vec2} a The first vector.
* @param {vec2} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec2.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1];
};
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec2} a The first vector.
* @param {vec2} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec2.equals = function (a, b) {
var a0 = a[0], a1 = a[1];
var b0 = b[0], b1 = b[1];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)));
};
module.exports = vec2;
},{"./common.js":189}],196:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 3 Dimensional Vector
* @name vec3
*/
var vec3 = {};
/**
* Creates a new, empty vec3
*
* @returns {vec3} a new 3D vector
*/
vec3.create = function() {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = 0;
out[1] = 0;
out[2] = 0;
return out;
};
/**
* Creates a new vec3 initialized with values from an existing vector
*
* @param {vec3} a vector to clone
* @returns {vec3} a new 3D vector
*/
vec3.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
};
/**
* Creates a new vec3 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} a new 3D vector
*/
vec3.fromValues = function(x, y, z) {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
/**
* Copy the values from one vec3 to another
*
* @param {vec3} out the receiving vector
* @param {vec3} a the source vector
* @returns {vec3} out
*/
vec3.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
};
/**
* Set the components of a vec3 to the given values
*
* @param {vec3} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} out
*/
vec3.set = function(out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
/**
* Adds two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
return out;
};
/**
* Alias for {@link vec3.subtract}
* @function
*/
vec3.sub = vec3.subtract;
/**
* Multiplies two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
return out;
};
/**
* Alias for {@link vec3.multiply}
* @function
*/
vec3.mul = vec3.multiply;
/**
* Divides two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
return out;
};
/**
* Alias for {@link vec3.divide}
* @function
*/
vec3.div = vec3.divide;
/**
* Math.ceil the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to ceil
* @returns {vec3} out
*/
vec3.ceil = function (out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
out[2] = Math.ceil(a[2]);
return out;
};
/**
* Math.floor the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to floor
* @returns {vec3} out
*/
vec3.floor = function (out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
out[2] = Math.floor(a[2]);
return out;
};
/**
* Returns the minimum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
return out;
};
/**
* Returns the maximum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
return out;
};
/**
* Math.round the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to round
* @returns {vec3} out
*/
vec3.round = function (out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
out[2] = Math.round(a[2]);
return out;
};
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
vec3.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
};
/**
* Adds two vec3's after scaling the second operand by a scalar value
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec3} out
*/
vec3.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} distance between a and b
*/
vec3.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2];
return Math.sqrt(x*x + y*y + z*z);
};
/**
* Alias for {@link vec3.distance}
* @function
*/
vec3.dist = vec3.distance;
/**
* Calculates the squared euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} squared distance between a and b
*/
vec3.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2];
return x*x + y*y + z*z;
};
/**
* Alias for {@link vec3.squaredDistance}
* @function
*/
vec3.sqrDist = vec3.squaredDistance;
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
vec3.length = function (a) {
var x = a[0],
y = a[1],
z = a[2];
return Math.sqrt(x*x + y*y + z*z);
};
/**
* Alias for {@link vec3.length}
* @function
*/
vec3.len = vec3.length;
/**
* Calculates the squared length of a vec3
*
* @param {vec3} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec3.squaredLength = function (a) {
var x = a[0],
y = a[1],
z = a[2];
return x*x + y*y + z*z;
};
/**
* Alias for {@link vec3.squaredLength}
* @function
*/
vec3.sqrLen = vec3.squaredLength;
/**
* Negates the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to negate
* @returns {vec3} out
*/
vec3.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
return out;
};
/**
* Returns the inverse of the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to invert
* @returns {vec3} out
*/
vec3.inverse = function(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
out[2] = 1.0 / a[2];
return out;
};
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
vec3.normalize = function(out, a) {
var x = a[0],
y = a[1],
z = a[2];
var len = x*x + y*y + z*z;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
}
return out;
};
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
vec3.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
};
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.cross = function(out, a, b) {
var ax = a[0], ay = a[1], az = a[2],
bx = b[0], by = b[1], bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
};
/**
* Performs a linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
vec3.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1],
az = a[2];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
return out;
};
/**
* Performs a hermite interpolation with two control points
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {vec3} c the third operand
* @param {vec3} d the fourth operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
vec3.hermite = function (out, a, b, c, d, t) {
var factorTimes2 = t * t,
factor1 = factorTimes2 * (2 * t - 3) + 1,
factor2 = factorTimes2 * (t - 2) + t,
factor3 = factorTimes2 * (t - 1),
factor4 = factorTimes2 * (3 - 2 * t);
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
return out;
};
/**
* Performs a bezier interpolation with two control points
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {vec3} c the third operand
* @param {vec3} d the fourth operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
vec3.bezier = function (out, a, b, c, d, t) {
var inverseFactor = 1 - t,
inverseFactorTimesTwo = inverseFactor * inverseFactor,
factorTimes2 = t * t,
factor1 = inverseFactorTimesTwo * inverseFactor,
factor2 = 3 * t * inverseFactorTimesTwo,
factor3 = 3 * factorTimes2 * inverseFactor,
factor4 = factorTimes2 * t;
out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec3} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec3} out
*/
vec3.random = function (out, scale) {
scale = scale || 1.0;
var r = glMatrix.RANDOM() * 2.0 * Math.PI;
var z = (glMatrix.RANDOM() * 2.0) - 1.0;
var zScale = Math.sqrt(1.0-z*z) * scale;
out[0] = Math.cos(r) * zScale;
out[1] = Math.sin(r) * zScale;
out[2] = z * scale;
return out;
};
/**
* Transforms the vec3 with a mat4.
* 4th vector component is implicitly '1'
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec3} out
*/
vec3.transformMat4 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2],
w = m[3] * x + m[7] * y + m[11] * z + m[15];
w = w || 1.0;
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
return out;
};
/**
* Transforms the vec3 with a mat3.
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m the 3x3 matrix to transform with
* @returns {vec3} out
*/
vec3.transformMat3 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2];
out[0] = x * m[0] + y * m[3] + z * m[6];
out[1] = x * m[1] + y * m[4] + z * m[7];
out[2] = x * m[2] + y * m[5] + z * m[8];
return out;
};
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
vec3.transformQuat = function(out, a, q) {
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
var x = a[0], y = a[1], z = a[2],
qx = q[0], qy = q[1], qz = q[2], qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return out;
};
/**
* Rotate a 3D vector around the x-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
vec3.rotateX = function(out, a, b, c){
var p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[0];
r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);
r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
};
/**
* Rotate a 3D vector around the y-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
vec3.rotateY = function(out, a, b, c){
var p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);
r[1] = p[1];
r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
};
/**
* Rotate a 3D vector around the z-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
vec3.rotateZ = function(out, a, b, c){
var p = [], r=[];
//Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
//perform rotation
r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);
r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
r[2] = p[2];
//translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
};
/**
* Perform some operation over an array of vec3s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec3.forEach = (function() {
var vec = vec3.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 3;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
}
return a;
};
})();
/**
* Get the angle between two 3D vectors
* @param {vec3} a The first operand
* @param {vec3} b The second operand
* @returns {Number} The angle in radians
*/
vec3.angle = function(a, b) {
var tempA = vec3.fromValues(a[0], a[1], a[2]);
var tempB = vec3.fromValues(b[0], b[1], b[2]);
vec3.normalize(tempA, tempA);
vec3.normalize(tempB, tempB);
var cosine = vec3.dot(tempA, tempB);
if(cosine > 1.0){
return 0;
} else {
return Math.acos(cosine);
}
};
/**
* Returns a string representation of a vector
*
* @param {vec3} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec3.str = function (a) {
return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
};
/**
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
*
* @param {vec3} a The first vector.
* @param {vec3} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec3.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
};
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec3} a The first vector.
* @param {vec3} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec3.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2];
var b0 = b[0], b1 = b[1], b2 = b[2];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)));
};
module.exports = vec3;
},{"./common.js":189}],197:[function(require,module,exports){
/* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */
var glMatrix = require("./common.js");
/**
* @class 4 Dimensional Vector
* @name vec4
*/
var vec4 = {};
/**
* Creates a new, empty vec4
*
* @returns {vec4} a new 4D vector
*/
vec4.create = function() {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 0;
return out;
};
/**
* Creates a new vec4 initialized with values from an existing vector
*
* @param {vec4} a vector to clone
* @returns {vec4} a new 4D vector
*/
vec4.clone = function(a) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Creates a new vec4 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} a new 4D vector
*/
vec4.fromValues = function(x, y, z, w) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
};
/**
* Copy the values from one vec4 to another
*
* @param {vec4} out the receiving vector
* @param {vec4} a the source vector
* @returns {vec4} out
*/
vec4.copy = function(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Set the components of a vec4 to the given values
*
* @param {vec4} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} out
*/
vec4.set = function(out, x, y, z, w) {
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
};
/**
* Adds two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.add = function(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.subtract = function(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
return out;
};
/**
* Alias for {@link vec4.subtract}
* @function
*/
vec4.sub = vec4.subtract;
/**
* Multiplies two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.multiply = function(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
out[3] = a[3] * b[3];
return out;
};
/**
* Alias for {@link vec4.multiply}
* @function
*/
vec4.mul = vec4.multiply;
/**
* Divides two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.divide = function(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
out[3] = a[3] / b[3];
return out;
};
/**
* Alias for {@link vec4.divide}
* @function
*/
vec4.div = vec4.divide;
/**
* Math.ceil the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to ceil
* @returns {vec4} out
*/
vec4.ceil = function (out, a) {
out[0] = Math.ceil(a[0]);
out[1] = Math.ceil(a[1]);
out[2] = Math.ceil(a[2]);
out[3] = Math.ceil(a[3]);
return out;
};
/**
* Math.floor the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to floor
* @returns {vec4} out
*/
vec4.floor = function (out, a) {
out[0] = Math.floor(a[0]);
out[1] = Math.floor(a[1]);
out[2] = Math.floor(a[2]);
out[3] = Math.floor(a[3]);
return out;
};
/**
* Returns the minimum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.min = function(out, a, b) {
out[0] = Math.min(a[0], b[0]);
out[1] = Math.min(a[1], b[1]);
out[2] = Math.min(a[2], b[2]);
out[3] = Math.min(a[3], b[3]);
return out;
};
/**
* Returns the maximum of two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
vec4.max = function(out, a, b) {
out[0] = Math.max(a[0], b[0]);
out[1] = Math.max(a[1], b[1]);
out[2] = Math.max(a[2], b[2]);
out[3] = Math.max(a[3], b[3]);
return out;
};
/**
* Math.round the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to round
* @returns {vec4} out
*/
vec4.round = function (out, a) {
out[0] = Math.round(a[0]);
out[1] = Math.round(a[1]);
out[2] = Math.round(a[2]);
out[3] = Math.round(a[3]);
return out;
};
/**
* Scales a vec4 by a scalar number
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec4} out
*/
vec4.scale = function(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
};
/**
* Adds two vec4's after scaling the second operand by a scalar value
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec4} out
*/
vec4.scaleAndAdd = function(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale);
out[1] = a[1] + (b[1] * scale);
out[2] = a[2] + (b[2] * scale);
out[3] = a[3] + (b[3] * scale);
return out;
};
/**
* Calculates the euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} distance between a and b
*/
vec4.distance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2],
w = b[3] - a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
};
/**
* Alias for {@link vec4.distance}
* @function
*/
vec4.dist = vec4.distance;
/**
* Calculates the squared euclidian distance between two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} squared distance between a and b
*/
vec4.squaredDistance = function(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2],
w = b[3] - a[3];
return x*x + y*y + z*z + w*w;
};
/**
* Alias for {@link vec4.squaredDistance}
* @function
*/
vec4.sqrDist = vec4.squaredDistance;
/**
* Calculates the length of a vec4
*
* @param {vec4} a vector to calculate length of
* @returns {Number} length of a
*/
vec4.length = function (a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
return Math.sqrt(x*x + y*y + z*z + w*w);
};
/**
* Alias for {@link vec4.length}
* @function
*/
vec4.len = vec4.length;
/**
* Calculates the squared length of a vec4
*
* @param {vec4} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
vec4.squaredLength = function (a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
return x*x + y*y + z*z + w*w;
};
/**
* Alias for {@link vec4.squaredLength}
* @function
*/
vec4.sqrLen = vec4.squaredLength;
/**
* Negates the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to negate
* @returns {vec4} out
*/
vec4.negate = function(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = -a[3];
return out;
};
/**
* Returns the inverse of the components of a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to invert
* @returns {vec4} out
*/
vec4.inverse = function(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
out[2] = 1.0 / a[2];
out[3] = 1.0 / a[3];
return out;
};
/**
* Normalize a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to normalize
* @returns {vec4} out
*/
vec4.normalize = function(out, a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
var len = x*x + y*y + z*z + w*w;
if (len > 0) {
len = 1 / Math.sqrt(len);
out[0] = x * len;
out[1] = y * len;
out[2] = z * len;
out[3] = w * len;
}
return out;
};
/**
* Calculates the dot product of two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} dot product of a and b
*/
vec4.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
};
/**
* Performs a linear interpolation between two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec4} out
*/
vec4.lerp = function (out, a, b, t) {
var ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
out[3] = aw + t * (b[3] - aw);
return out;
};
/**
* Generates a random vector with the given scale
*
* @param {vec4} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec4} out
*/
vec4.random = function (out, scale) {
scale = scale || 1.0;
//TODO: This is a pretty awful way of doing this. Find something better.
out[0] = glMatrix.RANDOM();
out[1] = glMatrix.RANDOM();
out[2] = glMatrix.RANDOM();
out[3] = glMatrix.RANDOM();
vec4.normalize(out, out);
vec4.scale(out, out, scale);
return out;
};
/**
* Transforms the vec4 with a mat4.
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec4} out
*/
vec4.transformMat4 = function(out, a, m) {
var x = a[0], y = a[1], z = a[2], w = a[3];
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
return out;
};
/**
* Transforms the vec4 with a quat
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec4} out
*/
vec4.transformQuat = function(out, a, q) {
var x = a[0], y = a[1], z = a[2],
qx = q[0], qy = q[1], qz = q[2], qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
out[3] = a[3];
return out;
};
/**
* Perform some operation over an array of vec4s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
vec4.forEach = (function() {
var vec = vec4.create();
return function(a, stride, offset, count, fn, arg) {
var i, l;
if(!stride) {
stride = 4;
}
if(!offset) {
offset = 0;
}
if(count) {
l = Math.min((count * stride) + offset, a.length);
} else {
l = a.length;
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
fn(vec, vec, arg);
a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
}
return a;
};
})();
/**
* Returns a string representation of a vector
*
* @param {vec4} vec vector to represent as a string
* @returns {String} string representation of the vector
*/
vec4.str = function (a) {
return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
};
/**
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
*
* @param {vec4} a The first vector.
* @param {vec4} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec4.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
};
/**
* Returns whether or not the vectors have approximately the same elements in the same position.
*
* @param {vec4} a The first vector.
* @param {vec4} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
vec4.equals = function (a, b) {
var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
return (Math.abs(a0 - b0) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a0), Math.abs(b0)) &&
Math.abs(a1 - b1) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a1), Math.abs(b1)) &&
Math.abs(a2 - b2) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a2), Math.abs(b2)) &&
Math.abs(a3 - b3) <= glMatrix.EPSILON*Math.max(1.0, Math.abs(a3), Math.abs(b3)));
};
module.exports = vec4;
},{"./common.js":189}],198:[function(require,module,exports){
'use strict'
var barycentric = require('barycentric')
var closestPointToTriangle = require('polytope-closest-point/lib/closest_point_2d.js')
module.exports = closestPointToPickLocation
function xformMatrix(m, v) {
var out = [0,0,0,0]
for(var i=0; i<4; ++i) {
for(var j=0; j<4; ++j) {
out[j] += m[4*i + j] * v[i]
}
}
return out
}
function projectVertex(v, model, view, projection, resolution) {
var p = xformMatrix(projection,
xformMatrix(view,
xformMatrix(model, [v[0], v[1], v[2], 1])))
for(var i=0; i<3; ++i) {
p[i] /= p[3]
}
return [ 0.5 * resolution[0] * (1.0+p[0]), 0.5 * resolution[1] * (1.0-p[1]) ]
}
function barycentricCoord(simplex, point) {
if(simplex.length === 2) {
var d0 = 0.0
var d1 = 0.0
for(var i=0; i<2; ++i) {
d0 += Math.pow(point[i] - simplex[0][i], 2)
d1 += Math.pow(point[i] - simplex[1][i], 2)
}
d0 = Math.sqrt(d0)
d1 = Math.sqrt(d1)
if(d0+d1 < 1e-6) {
return [1,0]
}
return [d1/(d0+d1),d0/(d1+d0)]
} else if(simplex.length === 3) {
var closestPoint = [0,0]
closestPointToTriangle(simplex[0], simplex[1], simplex[2], point, closestPoint)
return barycentric(simplex, closestPoint)
}
return []
}
function interpolate(simplex, weights) {
var result = [0,0,0]
for(var i=0; i 1.0001) {
return null
}
s += weights[i]
}
if(Math.abs(s - 1.0) > 0.001) {
return null
}
return [closestIndex, interpolate(simplex, weights), weights]
}
},{"barycentric":45,"polytope-closest-point/lib/closest_point_2d.js":478}],199:[function(require,module,exports){
var triVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position, normal;\nattribute vec4 color;\nattribute vec2 uv;\n\nuniform mat4 model\n , view\n , projection;\nuniform vec3 eyePosition\n , lightPosition;\n\nvarying vec3 f_normal\n , f_lightDirection\n , f_eyeDirection\n , f_data;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n vec4 m_position = model * vec4(position, 1.0);\n vec4 t_position = view * m_position;\n gl_Position = projection * t_position;\n f_color = color;\n f_normal = normal;\n f_data = position;\n f_eyeDirection = eyePosition - position;\n f_lightDirection = lightPosition - position;\n f_uv = uv;\n}"
var triFragSrc = "precision mediump float;\n#define GLSLIFY 1\n\nfloat beckmannDistribution_2_0(float x, float roughness) {\n float NdotH = max(x, 0.0001);\n float cos2Alpha = NdotH * NdotH;\n float tan2Alpha = (cos2Alpha - 1.0) / cos2Alpha;\n float roughness2 = roughness * roughness;\n float denom = 3.141592653589793 * roughness2 * cos2Alpha * cos2Alpha;\n return exp(tan2Alpha / roughness2) / denom;\n}\n\n\n\nfloat cookTorranceSpecular_1_1(\n vec3 lightDirection,\n vec3 viewDirection,\n vec3 surfaceNormal,\n float roughness,\n float fresnel) {\n\n float VdotN = max(dot(viewDirection, surfaceNormal), 0.0);\n float LdotN = max(dot(lightDirection, surfaceNormal), 0.0);\n\n //Half angle vector\n vec3 H = normalize(lightDirection + viewDirection);\n\n //Geometric term\n float NdotH = max(dot(surfaceNormal, H), 0.0);\n float VdotH = max(dot(viewDirection, H), 0.000001);\n float LdotH = max(dot(lightDirection, H), 0.000001);\n float G1 = (2.0 * NdotH * VdotN) / VdotH;\n float G2 = (2.0 * NdotH * LdotN) / LdotH;\n float G = min(1.0, min(G1, G2));\n \n //Distribution term\n float D = beckmannDistribution_2_0(NdotH, roughness);\n\n //Fresnel term\n float F = pow(1.0 - VdotN, fresnel);\n\n //Multiply terms and done\n return G * F * D / max(3.14159265 * VdotN, 0.000001);\n}\n\n\n\nuniform vec3 clipBounds[2];\nuniform float roughness\n , fresnel\n , kambient\n , kdiffuse\n , kspecular\n , opacity;\nuniform sampler2D texture;\n\nvarying vec3 f_normal\n , f_lightDirection\n , f_eyeDirection\n , f_data;\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n if(any(lessThan(f_data, clipBounds[0])) || \n any(greaterThan(f_data, clipBounds[1]))) {\n discard;\n }\n\n vec3 N = normalize(f_normal);\n vec3 L = normalize(f_lightDirection);\n vec3 V = normalize(f_eyeDirection);\n \n if(!gl_FrontFacing) {\n N = -N;\n }\n\n float specular = cookTorranceSpecular_1_1(L, V, N, roughness, fresnel);\n float diffuse = min(kambient + kdiffuse * max(dot(N, L), 0.0), 1.0);\n\n vec4 surfaceColor = f_color * texture2D(texture, f_uv);\n vec4 litColor = surfaceColor.a * vec4(diffuse * surfaceColor.rgb + kspecular * vec3(1,1,1) * specular, 1.0);\n\n gl_FragColor = litColor * opacity;\n}"
var edgeVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec4 color;\nattribute vec2 uv;\n\nuniform mat4 model, view, projection;\n\nvarying vec4 f_color;\nvarying vec3 f_data;\nvarying vec2 f_uv;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n f_color = color;\n f_data = position;\n f_uv = uv;\n}"
var edgeFragSrc = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec3 clipBounds[2];\nuniform sampler2D texture;\nuniform float opacity;\n\nvarying vec4 f_color;\nvarying vec3 f_data;\nvarying vec2 f_uv;\n\nvoid main() {\n if(any(lessThan(f_data, clipBounds[0])) || \n any(greaterThan(f_data, clipBounds[1]))) {\n discard;\n }\n\n gl_FragColor = f_color * texture2D(texture, f_uv) * opacity;\n}"
var pointVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec4 color;\nattribute vec2 uv;\nattribute float pointSize;\n\nuniform mat4 model, view, projection;\nuniform vec3 clipBounds[2];\n\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n if(any(lessThan(position, clipBounds[0])) || \n any(greaterThan(position, clipBounds[1]))) {\n gl_Position = vec4(0,0,0,0);\n } else {\n gl_Position = projection * view * model * vec4(position, 1.0);\n }\n gl_PointSize = pointSize;\n f_color = color;\n f_uv = uv;\n}"
var pointFragSrc = "precision mediump float;\n#define GLSLIFY 1\n\nuniform sampler2D texture;\nuniform float opacity;\n\nvarying vec4 f_color;\nvarying vec2 f_uv;\n\nvoid main() {\n vec2 pointR = gl_PointCoord.xy - vec2(0.5,0.5);\n if(dot(pointR, pointR) > 0.25) {\n discard;\n }\n gl_FragColor = f_color * texture2D(texture, f_uv) * opacity;\n}"
var pickVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute vec4 id;\n\nuniform mat4 model, view, projection;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n f_id = id;\n f_position = position;\n}"
var pickFragSrc = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec3 clipBounds[2];\nuniform float pickId;\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n if(any(lessThan(f_position, clipBounds[0])) || \n any(greaterThan(f_position, clipBounds[1]))) {\n discard;\n }\n gl_FragColor = vec4(pickId, f_id.xyz);\n}"
var pickPointVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position;\nattribute float pointSize;\nattribute vec4 id;\n\nuniform mat4 model, view, projection;\nuniform vec3 clipBounds[2];\n\nvarying vec3 f_position;\nvarying vec4 f_id;\n\nvoid main() {\n if(any(lessThan(position, clipBounds[0])) || \n any(greaterThan(position, clipBounds[1]))) {\n gl_Position = vec4(0,0,0,0);\n } else {\n gl_Position = projection * view * model * vec4(position, 1.0);\n gl_PointSize = pointSize;\n }\n f_id = id;\n f_position = position;\n}"
var contourVertSrc = "precision mediump float;\n#define GLSLIFY 1\n\nattribute vec3 position;\n\nuniform mat4 model, view, projection;\n\nvoid main() {\n gl_Position = projection * view * model * vec4(position, 1.0);\n}"
var contourFragSrc = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec3 contourColor;\n\nvoid main() {\n gl_FragColor = vec4(contourColor,1);\n}\n"
exports.meshShader = {
vertex: triVertSrc,
fragment: triFragSrc,
attributes: [
{name: 'position', type: 'vec3'},
{name: 'normal', type: 'vec3'},
{name: 'color', type: 'vec4'},
{name: 'uv', type: 'vec2'}
]
}
exports.wireShader = {
vertex: edgeVertSrc,
fragment: edgeFragSrc,
attributes: [
{name: 'position', type: 'vec3'},
{name: 'color', type: 'vec4'},
{name: 'uv', type: 'vec2'}
]
}
exports.pointShader = {
vertex: pointVertSrc,
fragment: pointFragSrc,
attributes: [
{name: 'position', type: 'vec3'},
{name: 'color', type: 'vec4'},
{name: 'uv', type: 'vec2'},
{name: 'pointSize', type: 'float'}
]
}
exports.pickShader = {
vertex: pickVertSrc,
fragment: pickFragSrc,
attributes: [
{name: 'position', type: 'vec3'},
{name: 'id', type: 'vec4'}
]
}
exports.pointPickShader = {
vertex: pickPointVertSrc,
fragment: pickFragSrc,
attributes: [
{name: 'position', type: 'vec3'},
{name: 'pointSize', type: 'float'},
{name: 'id', type: 'vec4'}
]
}
exports.contourShader = {
vertex: contourVertSrc,
fragment: contourFragSrc,
attributes: [
{name: 'position', type: 'vec3'}
]
}
},{}],200:[function(require,module,exports){
'use strict'
var DEFAULT_VERTEX_NORMALS_EPSILON = 1e-6; // may be too large if triangles are very small
var DEFAULT_FACE_NORMALS_EPSILON = 1e-6;
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var createVAO = require('gl-vao')
var createTexture = require('gl-texture2d')
var normals = require('normals')
var multiply = require('gl-mat4/multiply')
var invert = require('gl-mat4/invert')
var ndarray = require('ndarray')
var colormap = require('colormap')
var getContour = require('simplicial-complex-contour')
var pool = require('typedarray-pool')
var shaders = require('./lib/shaders')
var closestPoint = require('./lib/closest-point')
var meshShader = shaders.meshShader
var wireShader = shaders.wireShader
var pointShader = shaders.pointShader
var pickShader = shaders.pickShader
var pointPickShader = shaders.pointPickShader
var contourShader = shaders.contourShader
var identityMatrix = [
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1]
function SimplicialMesh(gl
, texture
, triShader
, lineShader
, pointShader
, pickShader
, pointPickShader
, contourShader
, trianglePositions
, triangleIds
, triangleColors
, triangleUVs
, triangleNormals
, triangleVAO
, edgePositions
, edgeIds
, edgeColors
, edgeUVs
, edgeVAO
, pointPositions
, pointIds
, pointColors
, pointUVs
, pointSizes
, pointVAO
, contourPositions
, contourVAO) {
this.gl = gl
this.cells = []
this.positions = []
this.intensity = []
this.texture = texture
this.dirty = true
this.triShader = triShader
this.lineShader = lineShader
this.pointShader = pointShader
this.pickShader = pickShader
this.pointPickShader = pointPickShader
this.contourShader = contourShader
this.trianglePositions = trianglePositions
this.triangleColors = triangleColors
this.triangleNormals = triangleNormals
this.triangleUVs = triangleUVs
this.triangleIds = triangleIds
this.triangleVAO = triangleVAO
this.triangleCount = 0
this.lineWidth = 1
this.edgePositions = edgePositions
this.edgeColors = edgeColors
this.edgeUVs = edgeUVs
this.edgeIds = edgeIds
this.edgeVAO = edgeVAO
this.edgeCount = 0
this.pointPositions = pointPositions
this.pointColors = pointColors
this.pointUVs = pointUVs
this.pointSizes = pointSizes
this.pointIds = pointIds
this.pointVAO = pointVAO
this.pointCount = 0
this.contourLineWidth = 1
this.contourPositions = contourPositions
this.contourVAO = contourVAO
this.contourCount = 0
this.contourColor = [0,0,0]
this.contourEnable = true
this.pickId = 1
this.bounds = [
[ Infinity, Infinity, Infinity],
[-Infinity,-Infinity,-Infinity] ]
this.clipBounds = [
[-Infinity,-Infinity,-Infinity],
[ Infinity, Infinity, Infinity] ]
this.lightPosition = [1e5, 1e5, 0]
this.ambientLight = 0.8
this.diffuseLight = 0.8
this.specularLight = 2.0
this.roughness = 0.5
this.fresnel = 1.5
this.opacity = 1.0
this._model = identityMatrix
this._view = identityMatrix
this._projection = identityMatrix
this._resolution = [1,1]
}
var proto = SimplicialMesh.prototype
proto.isOpaque = function() {
return this.opacity >= 1
}
proto.isTransparent = function() {
return this.opacity < 1
}
proto.pickSlots = 1
proto.setPickBase = function(id) {
this.pickId = id
}
function genColormap(param) {
var colors = colormap({
colormap: param
, nshades: 256
, format: 'rgba'
})
var result = new Uint8Array(256*4)
for(var i=0; i<256; ++i) {
var c = colors[i]
for(var j=0; j<3; ++j) {
result[4*i+j] = c[j]
}
result[4*i+3] = c[3]*255
}
return ndarray(result, [256,256,4], [4,0,1])
}
function unpackIntensity(cells, numVerts, cellIntensity) {
var result = new Array(numVerts)
for(var i=0; i 0) {
var shader = this.triShader
shader.bind()
shader.uniforms = uniforms
this.triangleVAO.bind()
gl.drawArrays(gl.TRIANGLES, 0, this.triangleCount*3)
this.triangleVAO.unbind()
}
if(this.edgeCount > 0 && this.lineWidth > 0) {
var shader = this.lineShader
shader.bind()
shader.uniforms = uniforms
this.edgeVAO.bind()
gl.lineWidth(this.lineWidth)
gl.drawArrays(gl.LINES, 0, this.edgeCount*2)
this.edgeVAO.unbind()
}
if(this.pointCount > 0) {
var shader = this.pointShader
shader.bind()
shader.uniforms = uniforms
this.pointVAO.bind()
gl.drawArrays(gl.POINTS, 0, this.pointCount)
this.pointVAO.unbind()
}
if(this.contourEnable && this.contourCount > 0 && this.contourLineWidth > 0) {
var shader = this.contourShader
shader.bind()
shader.uniforms = uniforms
this.contourVAO.bind()
gl.drawArrays(gl.LINES, 0, this.contourCount)
this.contourVAO.unbind()
}
}
proto.drawPick = function(params) {
params = params || {}
var gl = this.gl
var model = params.model || identityMatrix
var view = params.view || identityMatrix
var projection = params.projection || identityMatrix
var clipBounds = [[-1e6,-1e6,-1e6],[1e6,1e6,1e6]]
for(var i=0; i<3; ++i) {
clipBounds[0][i] = Math.max(clipBounds[0][i], this.clipBounds[0][i])
clipBounds[1][i] = Math.min(clipBounds[1][i], this.clipBounds[1][i])
}
//Save camera parameters
this._model = [].slice.call(model)
this._view = [].slice.call(view)
this._projection = [].slice.call(projection)
this._resolution = [gl.drawingBufferWidth, gl.drawingBufferHeight]
var uniforms = {
model: model,
view: view,
projection: projection,
clipBounds: clipBounds,
pickId: this.pickId / 255.0,
}
var shader = this.pickShader
shader.bind()
shader.uniforms = uniforms
if(this.triangleCount > 0) {
this.triangleVAO.bind()
gl.drawArrays(gl.TRIANGLES, 0, this.triangleCount*3)
this.triangleVAO.unbind()
}
if(this.edgeCount > 0) {
this.edgeVAO.bind()
gl.lineWidth(this.lineWidth)
gl.drawArrays(gl.LINES, 0, this.edgeCount*2)
this.edgeVAO.unbind()
}
if(this.pointCount > 0) {
var shader = this.pointPickShader
shader.bind()
shader.uniforms = uniforms
this.pointVAO.bind()
gl.drawArrays(gl.POINTS, 0, this.pointCount)
this.pointVAO.unbind()
}
}
proto.pick = function(pickData) {
if(!pickData) {
return null
}
if(pickData.id !== this.pickId) {
return null
}
var cellId = pickData.value[0] + 256*pickData.value[1] + 65536*pickData.value[2]
var cell = this.cells[cellId]
var positions = this.positions
var simplex = new Array(cell.length)
for(var i=0; i tickOffset[start]) {
shader.uniforms.dataAxis = DATA_AXIS
shader.uniforms.screenOffset = SCREEN_OFFSET
shader.uniforms.color = textColor[axis]
shader.uniforms.angle = textAngle[axis]
gl.drawArrays(
gl.TRIANGLES,
tickOffset[start],
tickOffset[end] - tickOffset[start])
}
}
if(labelEnable[axis] && labelCount) {
SCREEN_OFFSET[axis^1] -= screenScale * pixelRatio * labelPad[axis]
shader.uniforms.dataAxis = ZERO_2
shader.uniforms.screenOffset = SCREEN_OFFSET
shader.uniforms.color = labelColor[axis]
shader.uniforms.angle = labelAngle[axis]
gl.drawArrays(
gl.TRIANGLES,
labelOffset,
labelCount)
}
SCREEN_OFFSET[axis^1] = screenScale * viewBox[2+(axis^1)] - 1.0
if(tickEnable[axis+2]) {
SCREEN_OFFSET[axis^1] += screenScale * pixelRatio * tickPad[axis+2]
if(start < end && tickOffset[end] > tickOffset[start]) {
shader.uniforms.dataAxis = DATA_AXIS
shader.uniforms.screenOffset = SCREEN_OFFSET
shader.uniforms.color = textColor[axis+2]
shader.uniforms.angle = textAngle[axis+2]
gl.drawArrays(
gl.TRIANGLES,
tickOffset[start],
tickOffset[end] - tickOffset[start])
}
}
if(labelEnable[axis+2] && labelCount) {
SCREEN_OFFSET[axis^1] += screenScale * pixelRatio * labelPad[axis+2]
shader.uniforms.dataAxis = ZERO_2
shader.uniforms.screenOffset = SCREEN_OFFSET
shader.uniforms.color = labelColor[axis+2]
shader.uniforms.angle = labelAngle[axis+2]
gl.drawArrays(
gl.TRIANGLES,
labelOffset,
labelCount)
}
}
})()
proto.drawTitle = (function() {
var DATA_AXIS = [0,0]
var SCREEN_OFFSET = [0,0]
return function() {
var plot = this.plot
var shader = this.shader
var gl = plot.gl
var screenBox = plot.screenBox
var titleCenter = plot.titleCenter
var titleAngle = plot.titleAngle
var titleColor = plot.titleColor
var pixelRatio = plot.pixelRatio
if(!this.titleCount) {
return
}
for(var i=0; i<2; ++i) {
SCREEN_OFFSET[i] = 2.0 * (titleCenter[i]*pixelRatio - screenBox[i]) /
(screenBox[2+i] - screenBox[i]) - 1
}
shader.bind()
shader.uniforms.dataAxis = DATA_AXIS
shader.uniforms.screenOffset = SCREEN_OFFSET
shader.uniforms.angle = titleAngle
shader.uniforms.color = titleColor
gl.drawArrays(gl.TRIANGLES, this.titleOffset, this.titleCount)
}
})()
proto.bind = (function() {
var DATA_SHIFT = [0,0]
var DATA_SCALE = [0,0]
var TEXT_SCALE = [0,0]
return function() {
var plot = this.plot
var shader = this.shader
var bounds = plot._tickBounds
var dataBox = plot.dataBox
var screenBox = plot.screenBox
var viewBox = plot.viewBox
shader.bind()
//Set up coordinate scaling uniforms
for(var i=0; i<2; ++i) {
var lo = bounds[i]
var hi = bounds[i+2]
var boundScale = hi - lo
var dataCenter = 0.5 * (dataBox[i+2] + dataBox[i])
var dataWidth = (dataBox[i+2] - dataBox[i])
var viewLo = viewBox[i]
var viewHi = viewBox[i+2]
var viewScale = viewHi - viewLo
var screenLo = screenBox[i]
var screenHi = screenBox[i+2]
var screenScale = screenHi - screenLo
DATA_SCALE[i] = 2.0 * boundScale / dataWidth * viewScale / screenScale
DATA_SHIFT[i] = 2.0 * (lo - dataCenter) / dataWidth * viewScale / screenScale
}
TEXT_SCALE[1] = 2.0 * plot.pixelRatio / (screenBox[3] - screenBox[1])
TEXT_SCALE[0] = TEXT_SCALE[1] * (screenBox[3] - screenBox[1]) / (screenBox[2] - screenBox[0])
shader.uniforms.dataScale = DATA_SCALE
shader.uniforms.dataShift = DATA_SHIFT
shader.uniforms.textScale = TEXT_SCALE
//Set attributes
this.vbo.bind()
shader.attributes.textCoordinate.pointer()
}
})()
proto.update = function(options) {
var vertices = []
var axesTicks = options.ticks
var bounds = options.bounds
var i, j, k, data, scale, dimension
for(dimension=0; dimension<2; ++dimension) {
var offsets = [Math.floor(vertices.length/3)], tickX = [-Infinity]
//Copy vertices over to buffer
var ticks = axesTicks[dimension]
for(i=0; i oldAttribCount) {
for(i = oldAttribCount; i < newAttribCount; i++) {
this.gl.enableVertexAttribArray(i)
}
} else if(oldAttribCount > newAttribCount) {
for(i = newAttribCount; i < oldAttribCount; i++) {
this.gl.disableVertexAttribArray(i)
}
}
this.gl.lastAttribCount = newAttribCount
this.gl.useProgram(this.program)
}
proto.dispose = function() {
// disabling vertex attributes so new shader starts with zero
// and it's also useful if all shaders are disposed but the
// gl context is reused for subsequent replotting
var oldAttribCount = this.gl.lastAttribCount
for (var i = 0; i < oldAttribCount; i++) {
this.gl.disableVertexAttribArray(i)
}
this.gl.lastAttribCount = 0
if(this._fref) {
this._fref.dispose()
}
if(this._vref) {
this._vref.dispose()
}
this.attributes =
this.types =
this.vertShader =
this.fragShader =
this.program =
this._relink =
this._fref =
this._vref = null
}
function compareAttributes(a, b) {
if(a.name < b.name) {
return -1
}
return 1
}
//Update export hook for glslify-live
proto.update = function(
vertSource
, fragSource
, uniforms
, attributes) {
//If only one object passed, assume glslify style output
if(!fragSource || arguments.length === 1) {
var obj = vertSource
vertSource = obj.vertex
fragSource = obj.fragment
uniforms = obj.uniforms
attributes = obj.attributes
}
var wrapper = this
var gl = wrapper.gl
//Compile vertex and fragment shaders
var pvref = wrapper._vref
wrapper._vref = shaderCache.shader(gl, gl.VERTEX_SHADER, vertSource)
if(pvref) {
pvref.dispose()
}
wrapper.vertShader = wrapper._vref.shader
var pfref = this._fref
wrapper._fref = shaderCache.shader(gl, gl.FRAGMENT_SHADER, fragSource)
if(pfref) {
pfref.dispose()
}
wrapper.fragShader = wrapper._fref.shader
//If uniforms/attributes is not specified, use RT reflection
if(!uniforms || !attributes) {
//Create initial test program
var testProgram = gl.createProgram()
gl.attachShader(testProgram, wrapper.fragShader)
gl.attachShader(testProgram, wrapper.vertShader)
gl.linkProgram(testProgram)
if(!gl.getProgramParameter(testProgram, gl.LINK_STATUS)) {
var errLog = gl.getProgramInfoLog(testProgram)
throw new GLError(errLog, 'Error linking program:' + errLog)
}
//Load data from runtime
uniforms = uniforms || runtime.uniforms(gl, testProgram)
attributes = attributes || runtime.attributes(gl, testProgram)
//Release test program
gl.deleteProgram(testProgram)
}
//Sort attributes lexicographically
// overrides undefined WebGL behavior for attribute locations
attributes = attributes.slice()
attributes.sort(compareAttributes)
//Convert attribute types, read out locations
var attributeUnpacked = []
var attributeNames = []
var attributeLocations = []
var i
for(i=0; i= 0) {
var size = attr.type.charAt(attr.type.length-1)|0
var locVector = new Array(size)
for(var j=0; j= 0) {
curLocation += 1
}
attributeLocations[i] = curLocation
}
}
//Rebuild program and recompute all uniform locations
var uniformLocations = new Array(uniforms.length)
function relink() {
wrapper.program = shaderCache.program(
gl
, wrapper._vref
, wrapper._fref
, attributeNames
, attributeLocations)
for(var i=0; i= 0) {
var d = type.charCodeAt(type.length-1) - 48
if(d < 2 || d > 4) {
throw new GLError('', 'Invalid data type for attribute ' + name + ': ' + type)
}
addVectorAttribute(
gl
, wrapper
, locs[0]
, locations
, d
, obj
, name)
} else if(type.indexOf('mat') >= 0) {
var d = type.charCodeAt(type.length-1) - 48
if(d < 2 || d > 4) {
throw new GLError('', 'Invalid data type for attribute ' + name + ': ' + type)
}
addMatrixAttribute(
gl
, wrapper
, locs
, locations
, d
, obj
, name)
} else {
throw new GLError('', 'Unknown data type for attribute ' + name + ': ' + type)
}
break
}
}
return obj
}
},{"./GLError":208}],210:[function(require,module,exports){
'use strict'
var coallesceUniforms = require('./reflect')
var GLError = require("./GLError")
module.exports = createUniformWrapper
//Binds a function and returns a value
function identity(x) {
var c = new Function('y', 'return function(){return y}')
return c(x)
}
function makeVector(length, fill) {
var result = new Array(length)
for(var i=0; i 4) {
throw new GLError('', 'Invalid data type')
}
switch(type.charAt(0)) {
case 'b':
case 'i':
return 'gl.uniform' + d + 'iv(locations[' + index + '],obj' + path + ')'
case 'v':
return 'gl.uniform' + d + 'fv(locations[' + index + '],obj' + path + ')'
default:
throw new GLError('', 'Unrecognized data type for vector ' + name + ': ' + type)
}
} else if(type.indexOf('mat') === 0 && type.length === 4) {
var d = type.charCodeAt(type.length-1) - 48
if(d < 2 || d > 4) {
throw new GLError('', 'Invalid uniform dimension type for matrix ' + name + ': ' + type)
}
return 'gl.uniformMatrix' + d + 'fv(locations[' + index + '],false,obj' + path + ')'
} else {
throw new GLError('', 'Unknown uniform data type for ' + name + ': ' + type)
}
break
}
}
function enumerateIndices(prefix, type) {
if(typeof type !== 'object') {
return [ [prefix, type] ]
}
var indices = []
for(var id in type) {
var prop = type[id]
var tprefix = prefix
if(parseInt(id) + '' === id) {
tprefix += '[' + id + ']'
} else {
tprefix += '.' + id
}
if(typeof prop === 'object') {
indices.push.apply(indices, enumerateIndices(tprefix, prop))
} else {
indices.push([tprefix, prop])
}
}
return indices
}
function makeSetter(type) {
var code = [ 'return function updateProperty(obj){' ]
var indices = enumerateIndices('', type)
for(var i=0; i 4) {
throw new GLError('', 'Invalid data type')
}
if(type.charAt(0) === 'b') {
return makeVector(d, false)
}
return makeVector(d, 0)
} else if(type.indexOf('mat') === 0 && type.length === 4) {
var d = type.charCodeAt(type.length-1) - 48
if(d < 2 || d > 4) {
throw new GLError('', 'Invalid uniform dimension type for matrix ' + name + ': ' + type)
}
return makeVector(d*d, 0)
} else {
throw new GLError('', 'Unknown uniform data type for ' + name + ': ' + type)
}
break
}
}
function storeProperty(obj, prop, type) {
if(typeof type === 'object') {
var child = processObject(type)
Object.defineProperty(obj, prop, {
get: identity(child),
set: makeSetter(type),
enumerable: true,
configurable: false
})
} else {
if(locations[type]) {
Object.defineProperty(obj, prop, {
get: makeGetter(type),
set: makeSetter(type),
enumerable: true,
configurable: false
})
} else {
obj[prop] = defaultValue(uniforms[type].type)
}
}
}
function processObject(obj) {
var result
if(Array.isArray(obj)) {
result = new Array(obj.length)
for(var i=0; i 1) {
if(!(x[0] in o)) {
o[x[0]] = []
}
o = o[x[0]]
for(var k=1; k 1) {
for(var j=0; j= 0)) {
continue
}
var zeroIntercept = screenBox[i] -
dataBox[i] * (screenBox[i+2] - screenBox[i]) / (dataBox[i+2] - dataBox[i])
if(i === 0) {
line.drawLine(
zeroIntercept, screenBox[1], zeroIntercept, screenBox[3],
zeroLineWidth[i],
zeroLineColor[i])
} else {
line.drawLine(
screenBox[0], zeroIntercept, screenBox[2], zeroIntercept,
zeroLineWidth[i],
zeroLineColor[i])
}
}
}
//Draw traces
for(var i=0; i=0; --i) {
this.objects[i].dispose()
}
this.objects.length = 0
for(var i=this.overlays.length-1; i>=0; --i) {
this.overlays[i].dispose()
}
this.overlays.length = 0
this.gl = null
}
proto.addObject = function(object) {
if(this.objects.indexOf(object) < 0) {
this.objects.push(object)
this.setDirty()
}
}
proto.removeObject = function(object) {
var objects = this.objects
for(var i=0; i 0) {
var base = Math.round(Math.pow(10, y))
return Math.ceil(x/base) * base
}
return Math.ceil(x)
}
function defaultBool(x) {
if(typeof x === 'boolean') {
return x
}
return true
}
function createScene(options) {
options = options || {}
var stopped = false
var pixelRatio = options.pixelRatio || parseFloat(window.devicePixelRatio)
var canvas = options.canvas
if(!canvas) {
canvas = document.createElement('canvas')
if(options.container) {
var container = options.container
container.appendChild(canvas)
} else {
document.body.appendChild(canvas)
}
}
var gl = options.gl
if(!gl) {
gl = getContext(canvas,
options.glOptions || {
premultipliedAlpha: true,
antialias: true
})
}
if(!gl) {
throw new Error('webgl not supported')
}
//Initial bounds
var bounds = options.bounds || [[-10,-10,-10], [10,10,10]]
//Create selection
var selection = new MouseSelect()
//Accumulation buffer
var accumBuffer = createFBO(gl,
[gl.drawingBufferWidth, gl.drawingBufferHeight], {
preferFloat: !isMobile
})
var accumShader = createShader(gl)
//Create a camera
var cameraOptions = options.camera || {
eye: [2,0,0],
center: [0,0,0],
up: [0,1,0],
zoomMin: 0.1,
zoomMax: 100,
mode: 'turntable'
}
//Create axes
var axesOptions = options.axes || {}
var axes = createAxes(gl, axesOptions)
axes.enable = !axesOptions.disable
//Create spikes
var spikeOptions = options.spikes || {}
var spikes = createSpikes(gl, spikeOptions)
//Object list is empty initially
var objects = []
var pickBufferIds = []
var pickBufferCount = []
var pickBuffers = []
//Dirty flag, skip redraw if scene static
var dirty = true
var pickDirty = true
var projection = new Array(16)
var model = new Array(16)
var cameraParams = {
view: null,
projection: projection,
model: model
}
var pickDirty = true
var viewShape = [ gl.drawingBufferWidth, gl.drawingBufferHeight ]
//Create scene object
var scene = {
gl: gl,
contextLost: false,
pixelRatio: options.pixelRatio || parseFloat(window.devicePixelRatio),
canvas: canvas,
selection: selection,
camera: createCamera(canvas, cameraOptions),
axes: axes,
axesPixels: null,
spikes: spikes,
bounds: bounds,
objects: objects,
shape: viewShape,
aspect: options.aspectRatio || [1,1,1],
pickRadius: options.pickRadius || 10,
zNear: options.zNear || 0.01,
zFar: options.zFar || 1000,
fovy: options.fovy || Math.PI/4,
clearColor: options.clearColor || [0,0,0,0],
autoResize: defaultBool(options.autoResize),
autoBounds: defaultBool(options.autoBounds),
autoScale: !!options.autoScale,
autoCenter: defaultBool(options.autoCenter),
clipToBounds: defaultBool(options.clipToBounds),
snapToData: !!options.snapToData,
onselect: options.onselect || null,
onrender: options.onrender || null,
onclick: options.onclick || null,
cameraParams: cameraParams,
oncontextloss: null,
mouseListener: null
}
var pickShape = [ (gl.drawingBufferWidth/scene.pixelRatio)|0, (gl.drawingBufferHeight/scene.pixelRatio)|0 ]
function resizeListener() {
if(stopped) {
return
}
if(!scene.autoResize) {
return
}
var parent = canvas.parentNode
var width = 1
var height = 1
if(parent && parent !== document.body) {
width = parent.clientWidth
height = parent.clientHeight
} else {
width = window.innerWidth
height = window.innerHeight
}
var nextWidth = Math.ceil(width * scene.pixelRatio)|0
var nextHeight = Math.ceil(height * scene.pixelRatio)|0
if(nextWidth !== canvas.width || nextHeight !== canvas.height) {
canvas.width = nextWidth
canvas.height = nextHeight
var style = canvas.style
style.position = style.position || 'absolute'
style.left = '0px'
style.top = '0px'
style.width = width + 'px'
style.height = height + 'px'
dirty = true
}
}
if(scene.autoResize) {
resizeListener()
}
window.addEventListener('resize', resizeListener)
function reallocPickIds() {
var numObjs = objects.length
var numPick = pickBuffers.length
for(var i=0; i 0 && pickBufferCount[numPick-1] === 0) {
pickBufferCount.pop()
pickBuffers.pop().dispose()
}
}
scene.update = function(options) {
if(stopped) {
return
}
options = options || {}
dirty = true
pickDirty = true
}
scene.add = function(obj) {
if(stopped) {
return
}
obj.axes = axes
objects.push(obj)
pickBufferIds.push(-1)
dirty = true
pickDirty = true
reallocPickIds()
}
scene.remove = function(obj) {
if(stopped) {
return
}
var idx = objects.indexOf(obj)
if(idx < 0) {
return
}
objects.splice(idx, 1)
pickBufferIds.pop()
dirty = true
pickDirty = true
reallocPickIds()
}
scene.dispose = function() {
if(stopped) {
return
}
stopped = true
window.removeEventListener('resize', resizeListener)
canvas.removeEventListener('webglcontextlost', checkContextLoss)
scene.mouseListener.enabled = false
if(scene.contextLost) {
return
}
//Destroy objects
axes.dispose()
spikes.dispose()
for(var i=0; i selection.distance) {
continue
}
for(var j=0; j>> 1
var dataStraightThrough = options.positions instanceof Float32Array
var idStraightThrough = options.idToIndex instanceof Int32Array && options.idToIndex.length >= pointCount // permit larger to help reuse
var data = options.positions
var packed = dataStraightThrough ? data : pool.mallocFloat32(data.length)
var packedId = idStraightThrough ? options.idToIndex : pool.mallocInt32(pointCount)
if(!dataStraightThrough) {
packed.set(data)
}
if(!idStraightThrough) {
packed.set(data)
for(i = 0; i < pointCount; i++) {
packedId[i] = i
}
}
this.points = data
this.offsetBuffer.update(packed)
this.pickBuffer.update(packedId)
if(!dataStraightThrough) {
pool.free(packed)
}
if(!idStraightThrough) {
pool.free(packedId)
}
this.pointCount = pointCount
this.pickOffset = 0
}
function count(points, dataBox) {
var visiblePointCountEstimate = 0
var length = points.length >>> 1
var i
for(i = 0; i < length; i++) {
var x = points[i * 2]
var y = points[i * 2 + 1]
if(x >= dataBox[0] && x <= dataBox[2] && y >= dataBox[1] && y <= dataBox[3])
visiblePointCountEstimate++
}
return visiblePointCountEstimate
}
proto.unifiedDraw = (function() {
var MATRIX = [1, 0, 0,
0, 1, 0,
0, 0, 1]
var PICK_VEC4 = [0, 0, 0, 0]
return function(pickOffset) {
var pick = pickOffset !== void(0)
var shader = pick ? this.pickShader : this.shader
var gl = this.plot.gl
var dataBox = this.plot.dataBox
if(this.pointCount === 0) {
return pickOffset
}
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
var visiblePointCountEstimate = count(this.points, dataBox)
var basicPointSize = this.plot.pickPixelRatio * Math.max(Math.min(this.sizeMinCap, this.sizeMin), Math.min(this.sizeMax, this.sizeMax / Math.pow(visiblePointCountEstimate, 0.33333)))
MATRIX[0] = 2.0 / dataX
MATRIX[4] = 2.0 / dataY
MATRIX[6] = -2.0 * dataBox[0] / dataX - 1.0
MATRIX[7] = -2.0 * dataBox[1] / dataY - 1.0
this.offsetBuffer.bind()
shader.bind()
shader.attributes.position.pointer()
shader.uniforms.matrix = MATRIX
shader.uniforms.color = this.color
shader.uniforms.borderColor = this.borderColor
shader.uniforms.pointCloud = basicPointSize < 5
shader.uniforms.pointSize = basicPointSize
shader.uniforms.centerFraction = Math.min(1, Math.max(0, Math.sqrt(1 - this.areaRatio)))
if(pick) {
PICK_VEC4[0] = ( pickOffset & 0xff)
PICK_VEC4[1] = ((pickOffset >> 8) & 0xff)
PICK_VEC4[2] = ((pickOffset >> 16) & 0xff)
PICK_VEC4[3] = ((pickOffset >> 24) & 0xff)
this.pickBuffer.bind()
shader.attributes.pickId.pointer(gl.UNSIGNED_BYTE)
shader.uniforms.pickOffset = PICK_VEC4
this.pickOffset = pickOffset
}
// Worth switching these off, but we can't make assumptions about other
// renderers, so let's restore it after each draw
var blend = gl.getParameter(gl.BLEND)
var dither = gl.getParameter(gl.DITHER)
if(blend && !this.blend)
gl.disable(gl.BLEND)
if(dither)
gl.disable(gl.DITHER)
gl.drawArrays(gl.POINTS, 0, this.pointCount)
if(blend && !this.blend)
gl.enable(gl.BLEND)
if(dither)
gl.enable(gl.DITHER)
return pickOffset + this.pointCount
}
})()
proto.draw = proto.unifiedDraw
proto.drawPick = proto.unifiedDraw
proto.pick = function(x, y, value) {
var pickOffset = this.pickOffset
var pointCount = this.pointCount
if(value < pickOffset || value >= pickOffset + pointCount) {
return null
}
var pointId = value - pickOffset
var points = this.points
return {
object: this,
pointId: pointId,
dataCoord: [points[2 * pointId], points[2 * pointId + 1] ]
}
}
function createPointcloud2D(plot, options) {
var gl = plot.gl
var buffer = createBuffer(gl)
var pickBuffer = createBuffer(gl)
var shader = createShader(gl, SHADERS.pointVertex, SHADERS.pointFragment)
var pickShader = createShader(gl, SHADERS.pickVertex, SHADERS.pickFragment)
var result = new Pointcloud2D(plot, buffer, pickBuffer, shader, pickShader)
result.update(options)
//Register with plot
plot.addObject(result)
return result
}
},{"./lib/shader":217,"gl-buffer":152,"gl-shader":218,"typedarray-pool":533}],226:[function(require,module,exports){
module.exports = slerp
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
function slerp (out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations
var ax = a[0], ay = a[1], az = a[2], aw = a[3],
bx = b[0], by = b[1], bz = b[2], bw = b[3]
var omega, cosom, sinom, scale0, scale1
// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw
// adjust signs (if necessary)
if (cosom < 0.0) {
cosom = -cosom
bx = -bx
by = -by
bz = -bz
bw = -bw
}
// calculate coefficients
if ((1.0 - cosom) > 0.000001) {
// standard case (slerp)
omega = Math.acos(cosom)
sinom = Math.sin(omega)
scale0 = Math.sin((1.0 - t) * omega) / sinom
scale1 = Math.sin(t * omega) / sinom
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t
scale1 = t
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx
out[1] = scale0 * ay + scale1 * by
out[2] = scale0 * az + scale1 * bz
out[3] = scale0 * aw + scale1 * bw
return out
}
},{}],227:[function(require,module,exports){
'use strict'
module.exports = {
vertex: "precision highp float;\n#define GLSLIFY 1\n\n\nvec4 computePosition_1_0(vec2 posHi, vec2 posLo, vec2 scHi, vec2 scLo, vec2 trHi, vec2 trLo) {\n return vec4((posHi + trHi) * scHi\n \t\t\t//FIXME: this thingy does not give noticeable precision gain, need test\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo\n , 0, 1);\n}\n\n\nattribute vec2 positionHi, positionLo;\nattribute float size, border;\nattribute vec2 char, color;\n\n//this is 64-bit form of scale and translate\nuniform vec2 scaleHi, scaleLo, translateHi, translateLo;\nuniform float pixelRatio;\nuniform vec4 viewBox;\nuniform sampler2D palette;\n\nvarying vec4 charColor, borderColor;\nvarying vec2 charId;\nvarying vec2 pointCoord;\nvarying float pointSize;\nvarying float borderWidth;\n\n\nvoid main() {\n charColor = texture2D(palette, vec2(color.x / 255., 0));\n borderColor = texture2D(palette, vec2(color.y / 255., 0));\n\n gl_PointSize = size * pixelRatio;\n pointSize = size * pixelRatio;\n\n charId = char;\n borderWidth = border;\n\n gl_Position = computePosition_1_0(\n positionHi, positionLo,\n scaleHi, scaleLo,\n translateHi, translateLo);\n\n pointCoord = viewBox.xy + (viewBox.zw - viewBox.xy) * (gl_Position.xy * .5 + .5);\n}\n",
fragment: "precision highp float;\n#define GLSLIFY 1\n\nuniform sampler2D chars;\nuniform vec2 charsShape;\nuniform float charsStep, pixelRatio, charOffset;\n\nvarying vec4 borderColor;\nvarying vec4 charColor;\nvarying vec2 charId;\nvarying vec2 pointCoord;\nvarying float pointSize;\nvarying float borderWidth;\n\nvoid main() {\n\tvec2 pointUV = (pointCoord - gl_FragCoord.xy + pointSize * .5) / pointSize;\n\tpointUV.x = 1. - pointUV.x;\n\tvec2 texCoord = ((charId + pointUV) * charsStep) / charsShape;\n\tfloat dist = texture2D(chars, texCoord).r;\n\n\t//max-distance alpha\n\tif (dist < 1e-2)\n\t\tdiscard;\n\n\tfloat gamma = .0045 * charsStep / pointSize;\n\n //null-border case\n \tif (borderWidth * borderColor.a == 0.) {\n\t\tfloat charAmt = smoothstep(.748 - gamma, .748 + gamma, dist);\n\t\tgl_FragColor = vec4(charColor.rgb, charAmt*charColor.a);\n\t\treturn;\n\t}\n\n\tfloat dif = 5. * pixelRatio * borderWidth / pointSize;\n\tfloat borderLevel = .748 - dif * .5;\n\tfloat charLevel = .748 + dif * .5;\n\n\tfloat borderAmt = smoothstep(borderLevel - gamma, borderLevel + gamma, dist);\n\tfloat charAmt = smoothstep(charLevel - gamma, charLevel + gamma, dist);\n\n\tvec4 color = borderColor;\n\tcolor.a *= borderAmt;\n\n\tgl_FragColor = mix(color, charColor, charAmt);\n}\n",
pickVertex: "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 positionHi, positionLo;\nattribute vec4 id;\nattribute float size;\n\nuniform vec2 scaleHi, scaleLo, translateHi, translateLo;\nuniform vec4 pickOffset;\nuniform float pixelRatio;\n\nvarying vec4 fragColor;\n\n\nvec4 computePosition_1_0(vec2 posHi, vec2 posLo, vec2 scHi, vec2 scLo, vec2 trHi, vec2 trLo) {\n return vec4((posHi + trHi) * scHi\n \t\t\t//FIXME: this thingy does not give noticeable precision gain, need test\n + (posLo + trLo) * scHi\n + (posHi + trHi) * scLo\n + (posLo + trLo) * scLo\n , 0, 1);\n}\n\n\nvoid main() {\n vec4 fragId = id + pickOffset;\n\n fragId.y += floor(fragId.x / 256.0);\n fragId.x -= floor(fragId.x / 256.0) * 256.0;\n\n fragId.z += floor(fragId.y / 256.0);\n fragId.y -= floor(fragId.y / 256.0) * 256.0;\n\n fragId.w += floor(fragId.z / 256.0);\n fragId.z -= floor(fragId.z / 256.0) * 256.0;\n\n fragColor = fragId / 255.0;\n\n gl_PointSize = size * .25 * pixelRatio;\n\n gl_Position = computePosition_1_0(\n positionHi, positionLo,\n scaleHi, scaleLo,\n translateHi, translateLo);\n}\n",
pickFragment: "precision lowp float;\n#define GLSLIFY 1\nvarying vec4 fragColor;\nvoid main() {\n gl_FragColor = fragColor;\n}\n"
}
},{}],228:[function(require,module,exports){
arguments[4][80][0].apply(exports,arguments)
},{"dup":80}],229:[function(require,module,exports){
arguments[4][207][0].apply(exports,arguments)
},{"./lib/GLError":230,"./lib/create-attributes":231,"./lib/create-uniforms":232,"./lib/reflect":233,"./lib/runtime-reflect":234,"./lib/shader-cache":235,"dup":207}],230:[function(require,module,exports){
arguments[4][208][0].apply(exports,arguments)
},{"dup":208}],231:[function(require,module,exports){
arguments[4][209][0].apply(exports,arguments)
},{"./GLError":230,"dup":209}],232:[function(require,module,exports){
arguments[4][210][0].apply(exports,arguments)
},{"./GLError":230,"./reflect":233,"dup":210}],233:[function(require,module,exports){
arguments[4][211][0].apply(exports,arguments)
},{"dup":211}],234:[function(require,module,exports){
arguments[4][212][0].apply(exports,arguments)
},{"dup":212}],235:[function(require,module,exports){
arguments[4][213][0].apply(exports,arguments)
},{"./GLError":230,"dup":213,"gl-format-compiler-error":160,"weakmap-shim":554}],236:[function(require,module,exports){
'use strict'
module.exports = sortLevels
var INSERT_SORT_CUTOFF = 32
function sortLevels(data_levels, data_points, data_ids, data_weights, n0) {
if (n0 <= 4*INSERT_SORT_CUTOFF) {
insertionSort(0, n0 - 1, data_levels, data_points, data_ids, data_weights)
} else {
quickSort(0, n0 - 1, data_levels, data_points, data_ids, data_weights)
}
}
function insertionSort(left, right, data_levels, data_points, data_ids, data_weights) {
for(var i=left+1; i<=right; ++i) {
var a_level = data_levels[i]
var a_x = data_points[2*i]
var a_y = data_points[2*i+1]
var a_id = data_ids[i]
var a_weight = data_weights[i]
var j = i
while(j > left) {
var b_level = data_levels[j-1]
var b_x = data_points[2*(j-1)]
if(((b_level - a_level) || (a_x - b_x)) >= 0) {
break
}
data_levels[j] = b_level
data_points[2*j] = b_x
data_points[2*j+1] = data_points[2*j-1]
data_ids[j] = data_ids[j-1]
data_weights[j] = data_weights[j-1]
j -= 1
}
data_levels[j] = a_level
data_points[2*j] = a_x
data_points[2*j+1] = a_y
data_ids[j] = a_id
data_weights[j] = a_weight
}
}
function swap(i, j, data_levels, data_points, data_ids, data_weights) {
var a_level = data_levels[i]
var a_x = data_points[2*i]
var a_y = data_points[2*i+1]
var a_id = data_ids[i]
var a_weight = data_weights[i]
data_levels[i] = data_levels[j]
data_points[2*i] = data_points[2*j]
data_points[2*i+1] = data_points[2*j+1]
data_ids[i] = data_ids[j]
data_weights[i] = data_weights[j]
data_levels[j] = a_level
data_points[2*j] = a_x
data_points[2*j+1] = a_y
data_ids[j] = a_id
data_weights[j] = a_weight
}
function move(i, j, data_levels, data_points, data_ids, data_weights) {
data_levels[i] = data_levels[j]
data_points[2*i] = data_points[2*j]
data_points[2*i+1] = data_points[2*j+1]
data_ids[i] = data_ids[j]
data_weights[i] = data_weights[j]
}
function rotate(i, j, k, data_levels, data_points, data_ids, data_weights) {
var a_level = data_levels[i]
var a_x = data_points[2*i]
var a_y = data_points[2*i+1]
var a_id = data_ids[i]
var a_weight = data_weights[i]
data_levels[i] = data_levels[j]
data_points[2*i] = data_points[2*j]
data_points[2*i+1] = data_points[2*j+1]
data_ids[i] = data_ids[j]
data_weights[i] = data_weights[j]
data_levels[j] = data_levels[k]
data_points[2*j] = data_points[2*k]
data_points[2*j+1] = data_points[2*k+1]
data_ids[j] = data_ids[k]
data_weights[j] = data_weights[k]
data_levels[k] = a_level
data_points[2*k] = a_x
data_points[2*k+1] = a_y
data_ids[k] = a_id
data_weights[k] = a_weight
}
function shufflePivot(
i, j,
a_level, a_x, a_y, a_id, a_weight,
data_levels, data_points, data_ids, data_weights) {
data_levels[i] = data_levels[j]
data_points[2*i] = data_points[2*j]
data_points[2*i+1] = data_points[2*j+1]
data_ids[i] = data_ids[j]
data_weights[i] = data_weights[j]
data_levels[j] = a_level
data_points[2*j] = a_x
data_points[2*j+1] = a_y
data_ids[j] = a_id
data_weights[j] = a_weight
}
function compare(i, j, data_levels, data_points, data_ids) {
return ((data_levels[i] - data_levels[j]) ||
(data_points[2*j] - data_points[2*i]) ||
(data_ids[i] - data_ids[j])) < 0
}
function comparePivot(i, level, x, y, id, data_levels, data_points, data_ids) {
return ((level - data_levels[i]) ||
(data_points[2*i] - x) ||
(id - data_ids[i])) < 0
}
function quickSort(left, right, data_levels, data_points, data_ids, data_weights) {
var sixth = (right - left + 1) / 6 | 0,
index1 = left + sixth,
index5 = right - sixth,
index3 = left + right >> 1,
index2 = index3 - sixth,
index4 = index3 + sixth,
el1 = index1,
el2 = index2,
el3 = index3,
el4 = index4,
el5 = index5,
less = left + 1,
great = right - 1,
tmp = 0
if(compare(el1, el2, data_levels, data_points, data_ids, data_weights)) {
tmp = el1
el1 = el2
el2 = tmp
}
if(compare(el4, el5, data_levels, data_points, data_ids, data_weights)) {
tmp = el4
el4 = el5
el5 = tmp
}
if(compare(el1, el3, data_levels, data_points, data_ids, data_weights)) {
tmp = el1
el1 = el3
el3 = tmp
}
if(compare(el2, el3, data_levels, data_points, data_ids, data_weights)) {
tmp = el2
el2 = el3
el3 = tmp
}
if(compare(el1, el4, data_levels, data_points, data_ids, data_weights)) {
tmp = el1
el1 = el4
el4 = tmp
}
if(compare(el3, el4, data_levels, data_points, data_ids, data_weights)) {
tmp = el3
el3 = el4
el4 = tmp
}
if(compare(el2, el5, data_levels, data_points, data_ids, data_weights)) {
tmp = el2
el2 = el5
el5 = tmp
}
if(compare(el2, el3, data_levels, data_points, data_ids, data_weights)) {
tmp = el2
el2 = el3
el3 = tmp
}
if(compare(el4, el5, data_levels, data_points, data_ids, data_weights)) {
tmp = el4
el4 = el5
el5 = tmp
}
var pivot1_level = data_levels[el2]
var pivot1_x = data_points[2*el2]
var pivot1_y = data_points[2*el2+1]
var pivot1_id = data_ids[el2]
var pivot1_weight = data_weights[el2]
var pivot2_level = data_levels[el4]
var pivot2_x = data_points[2*el4]
var pivot2_y = data_points[2*el4+1]
var pivot2_id = data_ids[el4]
var pivot2_weight = data_weights[el4]
var ptr0 = el1
var ptr2 = el3
var ptr4 = el5
var ptr5 = index1
var ptr6 = index3
var ptr7 = index5
var level_x = data_levels[ptr0]
var level_y = data_levels[ptr2]
var level_z = data_levels[ptr4]
data_levels[ptr5] = level_x
data_levels[ptr6] = level_y
data_levels[ptr7] = level_z
for (var i1 = 0; i1 < 2; ++i1) {
var x = data_points[2*ptr0+i1]
var y = data_points[2*ptr2+i1]
var z = data_points[2*ptr4+i1]
data_points[2*ptr5+i1] = x
data_points[2*ptr6+i1] = y
data_points[2*ptr7+i1] = z
}
var id_x = data_ids[ptr0]
var id_y = data_ids[ptr2]
var id_z = data_ids[ptr4]
data_ids[ptr5] = id_x
data_ids[ptr6] = id_y
data_ids[ptr7] = id_z
var weight_x = data_weights[ptr0]
var weight_y = data_weights[ptr2]
var weight_z = data_weights[ptr4]
data_weights[ptr5] = weight_x
data_weights[ptr6] = weight_y
data_weights[ptr7] = weight_z
move(index2, left, data_levels, data_points, data_ids, data_weights)
move(index4, right, data_levels, data_points, data_ids, data_weights)
for (var k = less; k <= great; ++k) {
if (comparePivot(k,
pivot1_level, pivot1_x, pivot1_y, pivot1_id,
data_levels, data_points, data_ids)) {
if (k !== less) {
swap(k, less, data_levels, data_points, data_ids, data_weights)
}
++less;
} else {
if (!comparePivot(k,
pivot2_level, pivot2_x, pivot2_y, pivot2_id,
data_levels, data_points, data_ids)) {
while (true) {
if (!comparePivot(great,
pivot2_level, pivot2_x, pivot2_y, pivot2_id,
data_levels, data_points, data_ids)) {
if (--great < k) {
break;
}
continue;
} else {
if (comparePivot(great,
pivot1_level, pivot1_x, pivot1_y, pivot1_id,
data_levels, data_points, data_ids)) {
rotate(k, less, great, data_levels, data_points, data_ids, data_weights)
++less;
--great;
} else {
swap(k, great, data_levels, data_points, data_ids, data_weights)
--great;
}
break;
}
}
}
}
}
shufflePivot(left, less-1, pivot1_level, pivot1_x, pivot1_y, pivot1_id, pivot1_weight, data_levels, data_points, data_ids, data_weights)
shufflePivot(right, great+1, pivot2_level, pivot2_x, pivot2_y, pivot2_id, pivot2_weight, data_levels, data_points, data_ids, data_weights)
if (less - 2 - left <= INSERT_SORT_CUTOFF) {
insertionSort(left, less - 2, data_levels, data_points, data_ids, data_weights)
} else {
quickSort(left, less - 2, data_levels, data_points, data_ids, data_weights)
}
if (right - (great + 2) <= INSERT_SORT_CUTOFF) {
insertionSort(great + 2, right, data_levels, data_points, data_ids, data_weights)
} else {
quickSort(great + 2, right, data_levels, data_points, data_ids, data_weights)
}
if (great - less <= INSERT_SORT_CUTOFF) {
insertionSort(less, great, data_levels, data_points, data_ids, data_weights)
} else {
quickSort(less, great, data_levels, data_points, data_ids, data_weights)
}
}
},{}],237:[function(require,module,exports){
'use strict'
var pool = require('typedarray-pool')
var sortLevels = require('./lib/sort')
module.exports = snapPoints
function partition(points, ids, start, end, lox, loy, hix, hiy) {
var mid = start
for(var i=start; i>> 1
if(n < 1) {
return []
}
var lox = Infinity, loy = Infinity
var hix = -Infinity, hiy = -Infinity
for(var i=0; i= Math.max(0.9 * count, 32)) {
var mid = (end + start)>>>1
snapRec(nx, ny, diam_2, offset, mid, level+1)
offset = mid
}
snapRec(nx, ny, diam_2, offset, nextOffset, level+1)
offset = nextOffset
}
}
}
snapRec(lox, loy, diam, 0, n, 0)
sortLevels(levels, points, ids, weights, n)
var lod = []
var lastLevel = 0
var prevOffset = n
for(var ptr=n-1; ptr>=0; --ptr) {
points[2*ptr] = (points[2*ptr] - lox) * scaleX
points[2*ptr+1] = (points[2*ptr+1] - loy) * scaleY
var level = levels[ptr]
if(level === lastLevel) {
continue
}
lod.push(new SnapInterval(
diam * Math.pow(0.5, level),
ptr+1,
prevOffset - (ptr+1)
))
prevOffset = ptr+1
lastLevel = level
}
lod.push(new SnapInterval(diam * Math.pow(0.5, level+1), 0, prevOffset))
pool.free(levels)
return lod
}
},{"./lib/sort":236,"typedarray-pool":533}],238:[function(require,module,exports){
'use strict'
module.exports = createFancyScatter2D
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var pool = require('typedarray-pool')
var shaders = require('./lib/shaders')
var snapPoints = require('snap-points-2d')
var atlas = require('font-atlas-sdf')
var createTexture = require('gl-texture2d')
var colorId = require('color-id')
var ndarray = require('ndarray')
var clamp = require('clamp')
var search = require('binary-search-bounds')
function GLScatterFancy(
plot,
shader,
pickShader,
positionBuffer,
sizeBuffer,
colorBuffer,
idBuffer,
charBuffer) {
this.plot = plot
this.shader = shader
this.pickShader = pickShader
//buffers
this.positionBuffer = positionBuffer
this.sizeBuffer = sizeBuffer
this.colorBuffer = colorBuffer
this.idBuffer = idBuffer
this.charBuffer = charBuffer
this.pointCount = 0
this.pickOffset = 0
//positions data
this.points = null
//lod scales
this.scales = []
this.xCoords = []
//font atlas texture
this.charCanvas = document.createElement('canvas')
this.charTexture = createTexture(this.plot.gl, this.charCanvas)
this.charStep = 400
//snapping loses points sorting, so disable snapping on small number of points
this.snapThreshold = 1e4
//border/char colors texture
this.paletteTexture = createTexture(this.plot.gl, [256, 1])
}
var proto = GLScatterFancy.prototype
;(function() {
var SCALE_HI = new Float32Array([0, 0])
var SCALE_LO = new Float32Array([0, 0])
var TRANSLATE_HI = new Float32Array([0, 0])
var TRANSLATE_LO = new Float32Array([0, 0])
var PIXEL_SCALE = [0, 0]
var pixelSize, xStart, xEnd
function calcScales() {
var plot = this.plot
var viewBox = plot.viewBox
var dataBox = plot.dataBox
var pixelRatio = plot.pixelRatio
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
var scaleX = 2 / dataX
var scaleY = 2 / dataY
var translateX = (- dataBox[0] - 0.5 * dataX)
var translateY = (- dataBox[1] - 0.5 * dataY)
SCALE_HI[0] = scaleX
SCALE_LO[0] = scaleX - SCALE_HI[0]
SCALE_HI[1] = scaleY
SCALE_LO[1] = scaleY - SCALE_HI[1]
TRANSLATE_HI[0] = translateX
TRANSLATE_LO[0] = translateX - TRANSLATE_HI[0]
TRANSLATE_HI[1] = translateY
TRANSLATE_LO[1] = translateY - TRANSLATE_HI[1]
var screenX = viewBox[2] - viewBox[0]
var screenY = viewBox[3] - viewBox[1]
pixelSize = Math.min(dataX / screenX, dataY / screenY)
//FIXME: why twice?
PIXEL_SCALE[0] = 2 * pixelRatio / screenX
PIXEL_SCALE[1] = 2 * pixelRatio / screenY
xStart = dataBox[0]
xEnd = dataBox[2]
}
var PICK_OFFSET = [0, 0, 0, 0]
proto.drawPick = function(offset) {
var pick = offset !== undefined
var plot = this.plot
var pointCount = this.pointCount
var snap = pointCount > this.snapThreshold
if(!pointCount) {
return offset
}
calcScales.call(this)
var gl = plot.gl
var shader = pick ? this.pickShader : this.shader
var blend = gl.isEnabled(gl.BLEND)
shader.bind()
if(pick) {
this.pickOffset = offset
for (var i = 0; i < 4; ++i) {
PICK_OFFSET[i] = (offset >> (i * 8)) & 0xff
}
shader.uniforms.pickOffset = PICK_OFFSET
this.idBuffer.bind()
shader.attributes.id.pointer(gl.UNSIGNED_BYTE, false)
} else {
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.blendColor(0,0,0,1);
if (!blend) gl.enable(gl.BLEND)
this.colorBuffer.bind()
shader.attributes.color.pointer(gl.UNSIGNED_BYTE, false)
this.charBuffer.bind()
shader.attributes.char.pointer(gl.UNSIGNED_BYTE, false)
shader.uniforms.chars = this.charTexture.bind(0)
shader.uniforms.charsShape = [this.charCanvas.width, this.charCanvas.height]
shader.uniforms.charsStep = this.charStep
shader.uniforms.palette = this.paletteTexture.bind(1)
}
this.sizeBuffer.bind()
shader.attributes.size.pointer(gl.FLOAT, false, 8, 0)
if (!pick) shader.attributes.border.pointer(gl.FLOAT, false, 8, 4)
this.positionBuffer.bind()
shader.attributes.positionHi.pointer(gl.FLOAT, false, 16, 0)
shader.attributes.positionLo.pointer(gl.FLOAT, false, 16, 8)
shader.uniforms.pixelRatio = plot.pixelRatio
shader.uniforms.scaleHi = SCALE_HI
shader.uniforms.scaleLo = SCALE_LO
shader.uniforms.translateHi = TRANSLATE_HI
shader.uniforms.translateLo = TRANSLATE_LO
shader.uniforms.viewBox = plot.viewBox
var scales = this.scales
if (snap) {
for (var scaleNum = scales.length - 1; scaleNum >= 0; scaleNum--) {
var lod = scales[scaleNum]
if(lod.pixelSize && (lod.pixelSize < pixelSize * 1.25) && scaleNum > 1) {
continue
}
var intervalStart = lod.offset
var intervalEnd = lod.count + intervalStart
var startOffset = search.ge(this.xCoords, xStart, intervalStart, intervalEnd - 1)
var endOffset = search.lt(this.xCoords, xEnd, startOffset, intervalEnd - 1) + 1
if (endOffset > startOffset) {
gl.drawArrays(gl.POINTS, startOffset, (endOffset - startOffset))
}
}
}
else {
gl.drawArrays(gl.POINTS, 0, pointCount)
}
if (pick) return offset + pointCount
else {
if (!blend) gl.disable(gl.BLEND)
else {
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
}
}
}
})()
proto.draw = proto.drawPick
proto.pick = function(x, y, value) {
var pickOffset = this.pickOffset
var pointCount = this.pointCount
if(value < pickOffset || value >= pickOffset + pointCount) {
return null
}
var pointId = value - pickOffset
var points = this.points
return {
object: this,
pointId: pointId,
dataCoord: [points[2 * pointId], points[2 * pointId + 1]]
}
}
proto.update = function(options) {
options = options || {}
var positions = options.positions || []
var colors = options.colors || []
var glyphs = options.glyphs || []
var sizes = options.sizes || []
var borderWidths = options.borderWidths || []
var borderColors = options.borderColors || []
var gl = this.plot.gl
this.points = positions
//create packed positions here
var pointCount = this.points.length / 2
var packedId = pool.mallocInt32(pointCount)
var packedW = pool.mallocFloat32(2 * pointCount)
var packed = pool.mallocFloat64(2 * pointCount)
packed.set(this.points)
this.pointCount = pointCount
var snap = pointCount > this.snapThreshold
if (snap) {
this.scales = snapPoints(packed, packedId, packedW)
}
//v_position contains normalized positions to the available range of positions
var v_position = pool.mallocFloat32(4 * pointCount)
var v_sizeWidth = pool.mallocFloat32(2 * pointCount)
var v_color = pool.mallocUint8(2 * pointCount)
var v_ids = pool.mallocUint32(pointCount)
var v_chars = pool.mallocUint8(2 * pointCount)
//aggregate colors
var paletteIds = {}, colorIds = [], paletteColors = [], bColorIds = []
for (var i = 0, l = pointCount, k = 0; i < l; ++i) {
var channels = [colors[4 * i] * 255, colors[4 * i + 1] * 255, colors[4 * i + 2] * 255, colors[4 * i + 3] * 255]
var cId = colorId(channels, false)
if (paletteIds[cId] == null) {
paletteIds[cId] = k++
paletteColors.push(channels[0])
paletteColors.push(channels[1])
paletteColors.push(channels[2])
paletteColors.push(channels[3])
}
colorIds.push(cId)
if (borderColors && borderColors.length) {
channels = [borderColors[4 * i] * 255, borderColors[4 * i + 1] * 255, borderColors[4 * i + 2] * 255, borderColors[4 * i + 3] * 255]
cId = colorId(channels, false)
if (paletteIds[cId] == null) {
paletteIds[cId] = k++
paletteColors.push(channels[0])
paletteColors.push(channels[1])
paletteColors.push(channels[2])
paletteColors.push(channels[3])
}
bColorIds.push(cId)
}
}
//aggregate glyphs
var glyphChars = {}
for (var i = 0, l = pointCount, k = 0; i < l; i++) {
var char = glyphs[i]
if (glyphChars[char] == null) {
glyphChars[char] = k++
}
}
//generate font atlas
var maxSize = 0
for (var i = 0, l = sizes.length; i < l; ++i) {
if (sizes[i] > maxSize) maxSize = sizes[i]
}
var oldStep = this.charStep
this.charStep = clamp(Math.ceil(maxSize*4), 128, 768)
var chars = Object.keys(glyphChars)
var step = this.charStep
var charSize = Math.floor(step / 2)
var maxW = gl.getParameter(gl.MAX_TEXTURE_SIZE)
var maxChars = (maxW / step) * (maxW / step)
var atlasW = Math.min(maxW, step*chars.length)
var atlasH = Math.min(maxW, step*Math.ceil(step*chars.length/maxW))
var cols = Math.floor(atlasW / step)
if (chars.length > maxChars) {
console.warn('gl-scatter2d-fancy: number of characters is more than maximum texture size. Try reducing it.')
}
//do not overupdate atlas
if (!this.chars || (this.chars+'' !== chars+'') || this.charStep != oldStep) {
this.charCanvas = atlas({
canvas: this.charCanvas,
family: 'sans-serif',
size: charSize,
shape: [atlasW, atlasH],
step: [step, step],
chars: chars,
align: true
})
this.chars = chars
}
//collect buffers data
for(var i = 0; i < pointCount; ++i) {
var id = snap ? packedId[i] : i
var x = positions[2 * id]
var y = positions[2 * id + 1]
var s = sizes[id]
var w = borderWidths[id]
//write hi- and lo- position parts
v_position[4 * i] = x
v_position[4 * i + 1] = y
v_position[4 * i + 2] = x - v_position[4 * i]
v_position[4 * i + 3] = y - v_position[4 * i + 1]
this.xCoords[i] = x
//size is doubled bc character SDF is twice less than character step
v_sizeWidth[2 * i] = s*2
v_sizeWidth[2 * i + 1] = w
v_ids[i] = id
//color/bufferColor indexes
var cId = colorIds[id]
var pcId = paletteIds[cId]
v_color[2 * i] = pcId
var bcId = bColorIds[id]
var pbcId = paletteIds[bcId]
v_color[2 * i + 1] = pbcId
//char indexes
var char = glyphs[id]
var charId = glyphChars[char]
v_chars[2 * i + 1] = Math.floor(charId / cols)
v_chars[2 * i] = charId % cols
}
// if (!v_color.length) return
//fill buffes
this.positionBuffer.update(v_position)
this.sizeBuffer.update(v_sizeWidth)
this.colorBuffer.update(v_color)
this.idBuffer.update(v_ids)
this.charBuffer.update(v_chars)
//update char/color textures
this.charTexture.shape = [this.charCanvas.width, this.charCanvas.height]
if (this.charCanvas && this.charCanvas.width) {
this.charTexture.setPixels(this.charCanvas)
}
this.paletteTexture.setPixels(ndarray(paletteColors.slice(0, 256*4), [256, 1, 4]))
pool.free(v_position)
pool.free(v_sizeWidth)
pool.free(v_color)
pool.free(v_ids)
pool.free(v_chars)
pool.free(packed)
pool.free(packedId)
pool.free(packedW)
}
proto.dispose = function() {
this.shader.dispose()
this.pickShader.dispose()
this.positionBuffer.dispose()
this.sizeBuffer.dispose()
this.colorBuffer.dispose()
this.idBuffer.dispose()
this.charBuffer.dispose()
this.plot.removeObject(this)
}
function createFancyScatter2D(plot, options) {
var gl = plot.gl
var shader = createShader(gl, shaders.vertex, shaders.fragment)
var pickShader = createShader(gl, shaders.pickVertex, shaders.pickFragment)
var positionBuffer = createBuffer(gl)
var sizeBuffer = createBuffer(gl)
var colorBuffer = createBuffer(gl)
var idBuffer = createBuffer(gl)
var charBuffer = createBuffer(gl)
var scatter = new GLScatterFancy(
plot,
shader,
pickShader,
positionBuffer,
sizeBuffer,
colorBuffer,
idBuffer,
charBuffer)
scatter.update(options)
plot.addObject(scatter)
return scatter
}
},{"./lib/shaders":227,"binary-search-bounds":228,"clamp":84,"color-id":88,"font-atlas-sdf":130,"gl-buffer":152,"gl-shader":229,"gl-texture2d":262,"ndarray":460,"snap-points-2d":237,"typedarray-pool":533}],239:[function(require,module,exports){
exports.pointVertex = "precision highp float;\n#define GLSLIFY 1\n\nattribute vec2 positionHi, positionLo;\nattribute float weight;\n\nuniform vec2 scaleHi, scaleLo, translateHi, translateLo;\nuniform float pointSize, useWeight;\n\nvarying float fragWeight;\n\n\nvec4 pfx_1_0(vec2 scaleHi, vec2 scaleLo, vec2 translateHi, vec2 translateLo, vec2 positionHi, vec2 positionLo) {\n return vec4((positionHi + translateHi) * scaleHi\n + (positionLo + translateLo) * scaleHi\n + (positionHi + translateHi) * scaleLo\n + (positionLo + translateLo) * scaleLo, 0.0, 1.0);\n}\n\nvoid main() {\n gl_Position = pfx_1_0(scaleHi, scaleLo, translateHi, translateLo, positionHi, positionLo);\n gl_PointSize = pointSize;\n fragWeight = mix(1.0, weight, useWeight);\n}"
exports.pointFragment = "precision mediump float;\n#define GLSLIFY 1\n\nuniform vec4 color, borderColor;\nuniform float centerFraction;\n\nvarying float fragWeight;\n\nfloat smoothStep(float x, float y) {\n return 1.0 / (1.0 + exp(50.0*(x - y)));\n}\n\nvoid main() {\n float radius = length(2.0*gl_PointCoord.xy-1.0);\n if(radius > 1.0) {\n discard;\n }\n vec4 baseColor = mix(borderColor, color, smoothStep(radius, centerFraction));\n float alpha = 1.0 - pow(1.0 - baseColor.a, fragWeight);\n gl_FragColor = vec4(baseColor.rgb * alpha, alpha);\n}"
exports.pickVertex = "precision highp float;\n#define GLSLIFY 1\n\nvec4 pfx_1_0(vec2 scaleHi, vec2 scaleLo, vec2 translateHi, vec2 translateLo, vec2 positionHi, vec2 positionLo) {\n return vec4((positionHi + translateHi) * scaleHi\n + (positionLo + translateLo) * scaleHi\n + (positionHi + translateHi) * scaleLo\n + (positionLo + translateLo) * scaleLo, 0.0, 1.0);\n}\n\nattribute vec2 positionHi, positionLo;\nattribute vec4 pickId;\n\nuniform vec2 scaleHi, scaleLo, translateHi, translateLo;\nuniform float pointSize;\nuniform vec4 pickOffset;\n\nvarying vec4 fragId;\n\nvoid main() {\n\n vec4 id = pickId + pickOffset;\n id.y += floor(id.x / 256.0);\n id.x -= floor(id.x / 256.0) * 256.0;\n\n id.z += floor(id.y / 256.0);\n id.y -= floor(id.y / 256.0) * 256.0;\n\n id.w += floor(id.z / 256.0);\n id.z -= floor(id.z / 256.0) * 256.0;\n\n gl_Position = pfx_1_0(scaleHi, scaleLo, translateHi, translateLo, positionHi, positionLo);\n gl_PointSize = pointSize;\n fragId = id;\n}"
exports.pickFragment = "precision mediump float;\n#define GLSLIFY 1\n\nvarying vec4 fragId;\n\nvoid main() {\n float radius = length(2.0 * gl_PointCoord.xy - 1.0);\n if(radius > 1.0) {\n discard;\n }\n gl_FragColor = fragId / 255.0;\n}"
},{}],240:[function(require,module,exports){
arguments[4][80][0].apply(exports,arguments)
},{"dup":80}],241:[function(require,module,exports){
arguments[4][236][0].apply(exports,arguments)
},{"dup":236}],242:[function(require,module,exports){
arguments[4][237][0].apply(exports,arguments)
},{"./lib/sort":241,"dup":237,"typedarray-pool":533}],243:[function(require,module,exports){
'use strict'
var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')
var search = require('binary-search-bounds')
var snapPoints = require('snap-points-2d')
var pool = require('typedarray-pool')
var SHADERS = require('./lib/shader')
module.exports = createScatter2D
function Scatter2D(plot, positionBufferHi, positionBufferLo, pickBuffer, weightBuffer, shader, pickShader) {
this.plot = plot
this.positionBufferHi = positionBufferHi
this.positionBufferLo = positionBufferLo
this.pickBuffer = pickBuffer
this.weightBuffer = weightBuffer
this.shader = shader
this.pickShader = pickShader
this.scales = []
this.size = 12.0
this.borderSize = 1.0
this.pointCount = 0
this.color = [1, 0, 0, 1]
this.borderColor = [0, 0, 0, 1]
this.bounds = [Infinity, Infinity, -Infinity, -Infinity]
this.pickOffset = 0
this.points = null
this.xCoords = null
}
var proto = Scatter2D.prototype
var scaleHi = new Float32Array(2)
var scaleLo = new Float32Array(2)
var translateHi = new Float32Array(2)
var translateLo = new Float32Array(2)
var PICK_VEC4 = [0, 0, 0, 0]
proto.dispose = function() {
this.shader.dispose()
this.pickShader.dispose()
this.positionBufferHi.dispose()
this.positionBufferLo.dispose()
this.pickBuffer.dispose()
if(this.xCoords) pool.free(this.xCoords)
this.plot.removeObject(this)
}
proto.update = function(options) {
options = options || {}
function dflt(opt, value) {
return opt in options ? options[opt] : value
}
this.size = dflt('size', 12)
this.color = dflt('color', [1, 0, 0, 1]).slice()
this.borderSize = dflt('borderSize', 1)
this.borderColor = dflt('borderColor', [0, 0, 0, 1]).slice()
if(this.xCoords) pool.free(this.xCoords)
this.points = options.positions
var pointCount = this.points.length >>> 1
var packedId = pool.mallocInt32(pointCount)
var packedW = pool.mallocFloat32(2 * pointCount)
var packed = pool.mallocFloat64(2 * pointCount)
packed.set(this.points)
this.scales = snapPoints(packed, packedId, packedW, this.bounds)
var xCoords = pool.mallocFloat64(pointCount)
var packedHi = pool.mallocFloat32(2 * pointCount)
var packedLo = pool.mallocFloat32(2 * pointCount)
packedHi.set(packed)
for(var i = 0, j = 0; i < pointCount; i++, j += 2) {
packedLo[j] = packed[j] - packedHi[j]
packedLo[j + 1] = packed[j + 1] - packedHi[j + 1]
xCoords[i] = packed[j]
}
this.positionBufferHi.update(packedHi)
this.positionBufferLo.update(packedLo)
this.pickBuffer.update(packedId)
this.weightBuffer.update(packedW)
pool.free(packedId)
pool.free(packed)
pool.free(packedHi)
pool.free(packedLo)
pool.free(packedW)
this.xCoords = xCoords
this.pointCount = pointCount
this.pickOffset = 0
}
proto.draw = function(pickOffset) {
var pick = pickOffset !== void(0)
var plot = this.plot
var shader = pick ? this.pickShader : this.shader
var scales = this.scales
var positionBufferHi = this.positionBufferHi
var positionBufferLo = this.positionBufferLo
var pickBuffer = this.pickBuffer
var bounds = this.bounds
var size = this.size
var borderSize = this.borderSize
var gl = plot.gl
var pixelRatio = pick ? plot.pickPixelRatio : plot.pixelRatio
var viewBox = plot.viewBox
var dataBox = plot.dataBox
if(this.pointCount === 0)
return pickOffset
var boundX = bounds[2] - bounds[0]
var boundY = bounds[3] - bounds[1]
var dataX = dataBox[2] - dataBox[0]
var dataY = dataBox[3] - dataBox[1]
var screenX = (viewBox[2] - viewBox[0]) * pixelRatio / plot.pixelRatio
var screenY = (viewBox[3] - viewBox[1]) * pixelRatio / plot.pixelRatio
var pixelSize = Math.min(dataX / screenX, dataY / screenY)
var scaleX = 2 * boundX / dataX
var scaleY = 2 * boundY / dataY
scaleHi[0] = scaleX
scaleHi[1] = scaleY
scaleLo[0] = scaleX - scaleHi[0]
scaleLo[1] = scaleY - scaleHi[1]
var translateX = (bounds[0] - dataBox[0] - 0.5 * dataX) / boundX
var translateY = (bounds[1] - dataBox[1] - 0.5 * dataY) / boundY
translateHi[0] = translateX
translateHi[1] = translateY
translateLo[0] = translateX - translateHi[0]
translateLo[1] = translateY - translateHi[1]
shader.bind()
shader.uniforms.scaleHi = scaleHi
shader.uniforms.scaleLo = scaleLo
shader.uniforms.translateHi = translateHi
shader.uniforms.translateLo = translateLo
shader.uniforms.color = this.color
shader.uniforms.borderColor = this.borderColor
shader.uniforms.pointSize = pixelRatio * (size + borderSize)
shader.uniforms.centerFraction = this.borderSize === 0 ? 2 : size / (size + borderSize + 1.25)
positionBufferHi.bind()
shader.attributes.positionHi.pointer()
positionBufferLo.bind()
shader.attributes.positionLo.pointer()
if(pick) {
this.pickOffset = pickOffset
PICK_VEC4[0] = ( pickOffset & 0xff)
PICK_VEC4[1] = ((pickOffset >> 8) & 0xff)
PICK_VEC4[2] = ((pickOffset >> 16) & 0xff)
PICK_VEC4[3] = ((pickOffset >> 24) & 0xff)
shader.uniforms.pickOffset = PICK_VEC4
pickBuffer.bind()
shader.attributes.pickId.pointer(gl.UNSIGNED_BYTE)
} else {
shader.uniforms.useWeight = 1
this.weightBuffer.bind()
shader.attributes.weight.pointer()
}
var xCoords = this.xCoords
var xStart = (dataBox[0] - bounds[0] - pixelSize * size * pixelRatio) / boundX
var xEnd = (dataBox[2] - bounds[0] + pixelSize * size * pixelRatio) / boundX
var firstLevel = true
for(var scaleNum = scales.length - 1; scaleNum >= 0; scaleNum--) {
var lod = scales[scaleNum]
if(lod.pixelSize < pixelSize && scaleNum > 1)
continue
var intervalStart = lod.offset
var intervalEnd = lod.count + intervalStart
var startOffset = search.ge(xCoords, xStart, intervalStart, intervalEnd - 1)
var endOffset = search.lt(xCoords, xEnd, startOffset, intervalEnd - 1) + 1
if(endOffset > startOffset)
gl.drawArrays(gl.POINTS, startOffset, endOffset - startOffset)
if(!pick && firstLevel) {
firstLevel = false
shader.uniforms.useWeight = 0
}
}
return pickOffset + this.pointCount
}
proto.drawPick = proto.draw
proto.pick = function(x, y, value) {
var pointId = value - this.pickOffset
return pointId < 0 || pointId >= this.pointCount
? null : {
object: this,
pointId: pointId,
dataCoord: [ this.points[2 * pointId], this.points[2 * pointId + 1] ]
}
}
function createScatter2D(plot, options) {
var gl = plot.gl
var positionBufferHi = createBuffer(gl)
var positionBufferLo = createBuffer(gl)
var pickBuffer = createBuffer(gl)
var weightBuffer = createBuffer(gl)
var shader = createShader(gl, SHADERS.pointVertex, SHADERS.pointFragment)
var pickShader = createShader(gl, SHADERS.pickVertex, SHADERS.pickFragment)
var result = new Scatter2D(plot, positionBufferHi, positionBufferLo, pickBuffer, weightBuffer, shader, pickShader)
result.update(options)
plot.addObject(result) // register with plot
return result
}
},{"./lib/shader":239,"binary-search-bounds":240,"gl-buffer":152,"gl-shader":250,"snap-points-2d":242,"typedarray-pool":533}],244:[function(require,module,exports){
"use strict"
var vectorizeText = require("vectorize-text")
module.exports = getGlyph
var GLYPH_CACHE = {}
function getGlyph(symbol, font) {
var fontCache = GLYPH_CACHE[font]
if(!fontCache) {
fontCache = GLYPH_CACHE[font] = {}
}
if(symbol in fontCache) {
return fontCache[symbol]
}
//Get line and triangle meshes for glyph
var lineSymbol = vectorizeText(symbol, {
textAlign: "center",
textBaseline: "middle",
lineHeight: 1.0,
font: font
})
var triSymbol = vectorizeText(symbol, {
triangles: true,
textAlign: "center",
textBaseline: "middle",
lineHeight: 1.0,
font: font
})
//Calculate bounding box
var bounds = [[Infinity,Infinity], [-Infinity,-Infinity]]
for(var i=0; i= 1) {
return true
}
for(var i=0; i<3; ++i) {
if(this.axesProject[i] && this.projectOpacity[i] >= 1) {
return true
}
}
return false
}
var VIEW_SHAPE = [0,0]
var U_VEC = [0,0,0]
var V_VEC = [0,0,0]
var MU_VEC = [0,0,0,1]
var MV_VEC = [0,0,0,1]
var SCRATCH_MATRIX = IDENTITY.slice()
var SCRATCH_VEC = [0,0,0]
var CLIP_BOUNDS = [[0,0,0], [0,0,0]]
function zeroVec(a) {
a[0] = a[1] = a[2] = 0
return a
}
function augment(hg, af) {
hg[0] = af[0]
hg[1] = af[1]
hg[2] = af[2]
hg[3] = 1
return hg
}
function setComponent(out, v, i, x) {
out[0] = v[0]
out[1] = v[1]
out[2] = v[2]
out[i] = x
return out
}
function getClipBounds(bounds) {
var result = CLIP_BOUNDS
for(var i=0; i<2; ++i) {
for(var j=0; j<3; ++j) {
result[i][j] = Math.max(Math.min(bounds[i][j], 1e8), -1e8)
}
}
return result
}
function drawProject(shader, points, camera, transparent, forceDraw) {
var axesProject = points.axesProject
var gl = points.gl
var uniforms = shader.uniforms
var model = camera.model || IDENTITY
var view = camera.view || IDENTITY
var projection = camera.projection || IDENTITY
var bounds = points.axesBounds
var clipBounds = getClipBounds(points.clipBounds)
var cubeAxis
if(points.axes) {
cubeAxis = points.axes.lastCubeProps.axis
} else {
cubeAxis = [1,1,1]
}
VIEW_SHAPE[0] = 2.0/gl.drawingBufferWidth
VIEW_SHAPE[1] = 2.0/gl.drawingBufferHeight
shader.bind()
uniforms.view = view
uniforms.projection = projection
uniforms.screenSize = VIEW_SHAPE
uniforms.highlightId = points.highlightId
uniforms.highlightScale = points.highlightScale
uniforms.clipBounds = clipBounds
uniforms.pickGroup = points.pickId / 255.0
uniforms.pixelRatio = points.pixelRatio
for(var i=0; i<3; ++i) {
if(!axesProject[i]) {
continue
}
if((points.projectOpacity[i] < 1) !== transparent) {
continue
}
uniforms.scale = points.projectScale[i]
uniforms.opacity = points.projectOpacity[i]
//Project model matrix
var pmodel = SCRATCH_MATRIX
for(var j=0; j<16; ++j) {
pmodel[j] = 0
}
for(var j=0; j<4; ++j) {
pmodel[5*j] = 1
}
pmodel[5*i] = 0
if(cubeAxis[i] < 0) {
pmodel[12+i] = bounds[0][i]
} else {
pmodel[12+i] = bounds[1][i]
}
mat4mult(pmodel, model, pmodel)
uniforms.model = pmodel
//Compute initial axes
var u = (i+1)%3
var v = (i+2)%3
var du = zeroVec(U_VEC)
var dv = zeroVec(V_VEC)
du[u] = 1
dv[v] = 1
//Align orientation relative to viewer
var mdu = project(projection, view, model, augment(MU_VEC, du))
var mdv = project(projection, view, model, augment(MV_VEC, dv))
if(Math.abs(mdu[1]) > Math.abs(mdv[1])) {
var tmp = mdu
mdu = mdv
mdv = tmp
tmp = du
du = dv
dv = tmp
var t = u
u = v
v = t
}
if(mdu[0] < 0) {
du[u] = -1
}
if(mdv[1] > 0) {
dv[v] = -1
}
var su = 0.0
var sv = 0.0
for(var j=0; j<4; ++j) {
su += Math.pow(model[4*u+j], 2)
sv += Math.pow(model[4*v+j], 2)
}
du[u] /= Math.sqrt(su)
dv[v] /= Math.sqrt(sv)
uniforms.axes[0] = du
uniforms.axes[1] = dv
//Update fragment clip bounds
uniforms.fragClipBounds[0] = setComponent(SCRATCH_VEC, clipBounds[0], i, -1e8)
uniforms.fragClipBounds[1] = setComponent(SCRATCH_VEC, clipBounds[1], i, 1e8)
//Draw interior
points.vao.draw(gl.TRIANGLES, points.vertexCount)
//Draw edges
if(points.lineWidth > 0) {
gl.lineWidth(points.lineWidth)
points.vao.draw(gl.LINES, points.lineVertexCount, points.vertexCount)
}
}
}
var NEG_INFINITY3 = [-1e8, -1e8, -1e8]
var POS_INFINITY3 = [1e8, 1e8, 1e8]
var CLIP_GROUP = [NEG_INFINITY3, POS_INFINITY3]
function drawFull(shader, pshader, points, camera, transparent, forceDraw) {
var gl = points.gl
points.vao.bind()
if(transparent === (points.opacity < 1) || forceDraw) {
shader.bind()
var uniforms = shader.uniforms
uniforms.model = camera.model || IDENTITY
uniforms.view = camera.view || IDENTITY
uniforms.projection = camera.projection || IDENTITY
VIEW_SHAPE[0] = 2.0/gl.drawingBufferWidth
VIEW_SHAPE[1] = 2.0/gl.drawingBufferHeight
uniforms.screenSize = VIEW_SHAPE
uniforms.highlightId = points.highlightId
uniforms.highlightScale = points.highlightScale
uniforms.fragClipBounds = CLIP_GROUP
uniforms.clipBounds = points.axes.bounds
uniforms.opacity = points.opacity
uniforms.pickGroup = points.pickId / 255.0
uniforms.pixelRatio = points.pixelRatio
//Draw interior
points.vao.draw(gl.TRIANGLES, points.vertexCount)
//Draw edges
if(points.lineWidth > 0) {
gl.lineWidth(points.lineWidth)
points.vao.draw(gl.LINES, points.lineVertexCount, points.vertexCount)
}
}
drawProject(pshader, points, camera, transparent, forceDraw)
points.vao.unbind()
}
proto.draw = function(camera) {
var shader = this.useOrtho ? this.orthoShader : this.shader
drawFull(shader, this.projectShader, this, camera, false, false)
}
proto.drawTransparent = function(camera) {
var shader = this.useOrtho ? this.orthoShader : this.shader
drawFull(shader, this.projectShader, this, camera, true, false)
}
proto.drawPick = function(camera) {
var shader = this.useOrtho ? this.pickOrthoShader : this.pickPerspectiveShader
drawFull(shader, this.pickProjectShader, this, camera, false, true)
}
proto.pick = function(selected) {
if(!selected) {
return null
}
if(selected.id !== this.pickId) {
return null
}
var x = selected.value[2] + (selected.value[1]<<8) + (selected.value[0]<<16)
if(x >= this.pointCount || x < 0) {
return null
}
//Unpack result
var coord = this.points[x]
var result = this._selectResult
result.index = x
for(var i=0; i<3; ++i) {
result.position[i] = result.dataCoordinate[i] = coord[i]
}
return result
}
proto.highlight = function(selection) {
if(!selection) {
this.highlightId = [1,1,1,1]
} else {
var pointId = selection.index
var a0 = pointId &0xff
var a1 = (pointId>>8) &0xff
var a2 = (pointId>>16)&0xff
this.highlightId = [a0/255.0, a1/255.0, a2/255.0, 0]
}
}
proto.update = function(options) {
options = options || {}
if('perspective' in options) {
this.useOrtho = !options.perspective
}
if('orthographic' in options) {
this.useOrtho = !!options.orthographic
}
if('lineWidth' in options) {
this.lineWidth = options.lineWidth
}
if('project' in options) {
if(Array.isArray(options.project)) {
this.axesProject = options.project
} else {
var v = !!options.project
this.axesProject = [v,v,v]
}
}
if('projectScale' in options) {
if(Array.isArray(options.projectScale)) {
this.projectScale = options.projectScale.slice()
} else {
var s = +options.projectScale
this.projectScale = [s,s,s]
}
}
if('projectOpacity' in options) {
if(Array.isArray(options.projectOpacity)) {
this.projectOpacity = options.projectOpacity.slice()
} else {
var s = +options.projectOpacity
this.projectOpacity = [s,s,s]
}
}
if('opacity' in options) {
this.opacity = options.opacity
}
//Set dirty flag
this.dirty = true
//Create new buffers
var points = options.position
if(!points) {
return
}
//Text font
var font = options.font || 'normal'
var alignment = options.alignment || [0,0]
//Bounds
var lowerBound = [ Infinity, Infinity, Infinity]
var upperBound = [-Infinity,-Infinity,-Infinity]
//Unpack options
var glyphs = options.glyph
var colors = options.color
var sizes = options.size
var angles = options.angle
var lineColors = options.lineColor
//Picking geometry
var pickCounter = 0
//First do pass to compute buffer sizes
var triVertexCount = 0
var lineVertexCount = 0
//Count number of points and buffer size
var numPoints = points.length
count_loop:
for(var i=0; i 0) {
textOffset[0] = -alignment[0] * (1+glyphBounds[0][0])
}
//Write out inner marker
var cells = glyphMesh.cells
var verts = glyphMesh.positions
for(var j=0; j 0) {
//Draw border
var w = lineWidth * pixelRatio
boxes.drawBox(loX-w, loY-w, hiX+w, loY+w, borderColor)
boxes.drawBox(loX-w, hiY-w, hiX+w, hiY+w, borderColor)
boxes.drawBox(loX-w, loY-w, loX+w, hiY+w, borderColor)
boxes.drawBox(hiX-w, loY-w, hiX+w, hiY+w, borderColor)
}
}
proto.update = function(options) {
options = options || {}
this.innerFill = !!options.innerFill
this.outerFill = !!options.outerFill
this.innerColor = (options.innerColor || [0,0,0,0.5]).slice()
this.outerColor = (options.outerColor || [0,0,0,0.5]).slice()
this.borderColor = (options.borderColor || [0,0,0,1]).slice()
this.borderWidth = options.borderWidth || 0
this.selectBox = (options.selectBox || this.selectBox).slice()
}
proto.dispose = function() {
this.boxBuffer.dispose()
this.boxShader.dispose()
this.plot.removeOverlay(this)
}
function createSelectBox(plot, options) {
var gl = plot.gl
var buffer = createBuffer(gl, [
0, 0,
0, 1,
1, 0,
1, 1 ])
var shader = createShader(gl, SHADERS.boxVertex, SHADERS.boxFragment)
var selectBox = new SelectBox(plot, buffer, shader)
selectBox.update(options)
plot.addOverlay(selectBox)
return selectBox
}
},{"./lib/shaders":247,"gl-buffer":152,"gl-shader":250}],249:[function(require,module,exports){
'use strict'
module.exports = createSelectBuffer
var createFBO = require('gl-fbo')
var pool = require('typedarray-pool')
var ndarray = require('ndarray')
var nextPow2 = require('bit-twiddle').nextPow2
var selectRange = require('cwise/lib/wrapper')({"args":["array",{"offset":[0,0,1],"array":0},{"offset":[0,0,2],"array":0},{"offset":[0,0,3],"array":0},"scalar","scalar","index"],"pre":{"body":"{this_closestD2=1e8,this_closestX=-1,this_closestY=-1}","args":[],"thisVars":["this_closestD2","this_closestX","this_closestY"],"localVars":[]},"body":{"body":"{if(_inline_46_arg0_<255||_inline_46_arg1_<255||_inline_46_arg2_<255||_inline_46_arg3_<255){var _inline_46_l=_inline_46_arg4_-_inline_46_arg6_[0],_inline_46_a=_inline_46_arg5_-_inline_46_arg6_[1],_inline_46_f=_inline_46_l*_inline_46_l+_inline_46_a*_inline_46_a;_inline_46_f this.buffer.length) {
pool.free(this.buffer)
var buffer = this.buffer = pool.mallocUint8(nextPow2(r*c*4))
for(var i=0; i= 0) {
var size = attr.type.charAt(attr.type.length-1)|0
var locVector = new Array(size)
for(var j=0; j= 0) {
curLocation += 1
}
attributeLocations[i] = curLocation
}
}
//Rebuild program and recompute all uniform locations
var uniformLocations = new Array(uniforms.length)
function relink() {
wrapper.program = shaderCache.program(
gl
, wrapper._vref
, wrapper._fref
, attributeNames
, attributeLocations)
for(var i=0; i= 1) {
return true
}
for (var i = 0; i < 3; ++i) {
if (this._contourCounts[i].length > 0 || this._dynamicCounts[i] > 0) {
return true
}
}
return false
}
proto.pickSlots = 1
proto.setPickBase = function (id) {
this.pickId = id
}
var ZERO_VEC = [0, 0, 0]
var PROJECT_DATA = {
showSurface: false,
showContour: false,
projections: [IDENTITY.slice(), IDENTITY.slice(), IDENTITY.slice()],
clipBounds: [
[[0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0]]]
}
function computeProjectionData (camera, obj) {
var i, j, k
// Compute cube properties
var cubeAxis = (obj.axes && obj.axes.lastCubeProps.axis) || ZERO_VEC
var showSurface = obj.showSurface
var showContour = obj.showContour
for (i = 0; i < 3; ++i) {
showSurface = showSurface || obj.surfaceProject[i]
for (j = 0; j < 3; ++j) {
showContour = showContour || obj.contourProject[i][j]
}
}
for (i = 0; i < 3; ++i) {
// Construct projection onto axis
var axisSquish = PROJECT_DATA.projections[i]
for (j = 0; j < 16; ++j) {
axisSquish[j] = 0
}
for (j = 0; j < 4; ++j) {
axisSquish[5 * j] = 1
}
axisSquish[5 * i] = 0
axisSquish[12 + i] = obj.axesBounds[+(cubeAxis[i] > 0)][i]
multiply(axisSquish, camera.model, axisSquish)
var nclipBounds = PROJECT_DATA.clipBounds[i]
for (k = 0; k < 2; ++k) {
for (j = 0; j < 3; ++j) {
nclipBounds[k][j] = camera.clipBounds[k][j]
}
}
nclipBounds[0][i] = -1e8
nclipBounds[1][i] = 1e8
}
PROJECT_DATA.showSurface = showSurface
PROJECT_DATA.showContour = showContour
return PROJECT_DATA
}
var UNIFORMS = {
model: IDENTITY,
view: IDENTITY,
projection: IDENTITY,
inverseModel: IDENTITY.slice(),
lowerBound: [0, 0, 0],
upperBound: [0, 0, 0],
colorMap: 0,
clipBounds: [[0, 0, 0], [0, 0, 0]],
height: 0.0,
contourTint: 0,
contourColor: [0, 0, 0, 1],
permutation: [1, 0, 0, 0, 1, 0, 0, 0, 1],
zOffset: -1e-4,
kambient: 1,
kdiffuse: 1,
kspecular: 1,
lightPosition: [1000, 1000, 1000],
eyePosition: [0, 0, 0],
roughness: 1,
fresnel: 1,
opacity: 1,
vertexColor: 0
}
var MATRIX_INVERSE = IDENTITY.slice()
var DEFAULT_PERM = [1, 0, 0, 0, 1, 0, 0, 0, 1]
function drawCore (params, transparent) {
params = params || {}
var gl = this.gl
gl.disable(gl.CULL_FACE)
this._colorMap.bind(0)
var uniforms = UNIFORMS
uniforms.model = params.model || IDENTITY
uniforms.view = params.view || IDENTITY
uniforms.projection = params.projection || IDENTITY
uniforms.lowerBound = [this.bounds[0][0], this.bounds[0][1], this.colorBounds[0] || this.bounds[0][2]]
uniforms.upperBound = [this.bounds[1][0], this.bounds[1][1], this.colorBounds[1] || this.bounds[1][2]]
uniforms.contourColor = this.contourColor[0]
uniforms.inverseModel = invert(uniforms.inverseModel, uniforms.model)
for (var i = 0; i < 2; ++i) {
var clipClamped = uniforms.clipBounds[i]
for (var j = 0; j < 3; ++j) {
clipClamped[j] = Math.min(Math.max(this.clipBounds[i][j], -1e8), 1e8)
}
}
uniforms.kambient = this.ambientLight
uniforms.kdiffuse = this.diffuseLight
uniforms.kspecular = this.specularLight
uniforms.roughness = this.roughness
uniforms.fresnel = this.fresnel
uniforms.opacity = this.opacity
uniforms.height = 0.0
uniforms.permutation = DEFAULT_PERM
uniforms.vertexColor = this.vertexColor
// Compute camera matrix inverse
var invCameraMatrix = MATRIX_INVERSE
multiply(invCameraMatrix, uniforms.view, uniforms.model)
multiply(invCameraMatrix, uniforms.projection, invCameraMatrix)
invert(invCameraMatrix, invCameraMatrix)
for (i = 0; i < 3; ++i) {
uniforms.eyePosition[i] = invCameraMatrix[12 + i] / invCameraMatrix[15]
}
var w = invCameraMatrix[15]
for (i = 0; i < 3; ++i) {
w += this.lightPosition[i] * invCameraMatrix[4 * i + 3]
}
for (i = 0; i < 3; ++i) {
var s = invCameraMatrix[12 + i]
for (j = 0; j < 3; ++j) {
s += invCameraMatrix[4 * j + i] * this.lightPosition[j]
}
uniforms.lightPosition[i] = s / w
}
var projectData = computeProjectionData(uniforms, this)
if (projectData.showSurface && (transparent === (this.opacity < 1))) {
// Set up uniforms
this._shader.bind()
this._shader.uniforms = uniforms
// Draw it
this._vao.bind()
if (this.showSurface && this._vertexCount) {
this._vao.draw(gl.TRIANGLES, this._vertexCount)
}
// Draw projections of surface
for (i = 0; i < 3; ++i) {
if (!this.surfaceProject[i] || !this.vertexCount) {
continue
}
this._shader.uniforms.model = projectData.projections[i]
this._shader.uniforms.clipBounds = projectData.clipBounds[i]
this._vao.draw(gl.TRIANGLES, this._vertexCount)
}
this._vao.unbind()
}
if (projectData.showContour && !transparent) {
var shader = this._contourShader
// Don't apply lighting to contours
uniforms.kambient = 1.0
uniforms.kdiffuse = 0.0
uniforms.kspecular = 0.0
uniforms.opacity = 1.0
shader.bind()
shader.uniforms = uniforms
// Draw contour lines
var vao = this._contourVAO
vao.bind()
// Draw contour levels
for (i = 0; i < 3; ++i) {
shader.uniforms.permutation = PERMUTATIONS[i]
gl.lineWidth(this.contourWidth[i])
for (j = 0; j < this.contourLevels[i].length; ++j) {
if (!this._contourCounts[i][j]) {
continue
}
if (j === this.highlightLevel[i]) {
shader.uniforms.contourColor = this.highlightColor[i]
shader.uniforms.contourTint = this.highlightTint[i]
} else if (j === 0 || (j - 1) === this.highlightLevel[i]) {
shader.uniforms.contourColor = this.contourColor[i]
shader.uniforms.contourTint = this.contourTint[i]
}
shader.uniforms.height = this.contourLevels[i][j]
vao.draw(gl.LINES, this._contourCounts[i][j], this._contourOffsets[i][j])
}
}
// Draw projections of surface
for (i = 0; i < 3; ++i) {
shader.uniforms.model = projectData.projections[i]
shader.uniforms.clipBounds = projectData.clipBounds[i]
for (j = 0; j < 3; ++j) {
if (!this.contourProject[i][j]) {
continue
}
shader.uniforms.permutation = PERMUTATIONS[j]
gl.lineWidth(this.contourWidth[j])
for (var k = 0; k < this.contourLevels[j].length; ++k) {
if (k === this.highlightLevel[j]) {
shader.uniforms.contourColor = this.highlightColor[j]
shader.uniforms.contourTint = this.highlightTint[j]
} else if (k === 0 || (k - 1) === this.highlightLevel[j]) {
shader.uniforms.contourColor = this.contourColor[j]
shader.uniforms.contourTint = this.contourTint[j]
}
shader.uniforms.height = this.contourLevels[j][k]
vao.draw(gl.LINES, this._contourCounts[j][k], this._contourOffsets[j][k])
}
}
}
// Draw dynamic contours
vao = this._dynamicVAO
vao.bind()
// Draw contour levels
for (i = 0; i < 3; ++i) {
if (this._dynamicCounts[i] === 0) {
continue
}
shader.uniforms.model = uniforms.model
shader.uniforms.clipBounds = uniforms.clipBounds
shader.uniforms.permutation = PERMUTATIONS[i]
gl.lineWidth(this.dynamicWidth[i])
shader.uniforms.contourColor = this.dynamicColor[i]
shader.uniforms.contourTint = this.dynamicTint[i]
shader.uniforms.height = this.dynamicLevel[i]
vao.draw(gl.LINES, this._dynamicCounts[i], this._dynamicOffsets[i])
for (j = 0; j < 3; ++j) {
if (!this.contourProject[j][i]) {
continue
}
shader.uniforms.model = projectData.projections[j]
shader.uniforms.clipBounds = projectData.clipBounds[j]
vao.draw(gl.LINES, this._dynamicCounts[i], this._dynamicOffsets[i])
}
}
vao.unbind()
}
}
proto.draw = function (params) {
return drawCore.call(this, params, false)
}
proto.drawTransparent = function (params) {
return drawCore.call(this, params, true)
}
var PICK_UNIFORMS = {
model: IDENTITY,
view: IDENTITY,
projection: IDENTITY,
inverseModel: IDENTITY,
clipBounds: [[0, 0, 0], [0, 0, 0]],
height: 0.0,
shape: [0, 0],
pickId: 0,
lowerBound: [0, 0, 0],
upperBound: [0, 0, 0],
zOffset: 0.0,
permutation: [1, 0, 0, 0, 1, 0, 0, 0, 1],
lightPosition: [0, 0, 0],
eyePosition: [0, 0, 0]
}
proto.drawPick = function (params) {
params = params || {}
var gl = this.gl
gl.disable(gl.CULL_FACE)
var uniforms = PICK_UNIFORMS
uniforms.model = params.model || IDENTITY
uniforms.view = params.view || IDENTITY
uniforms.projection = params.projection || IDENTITY
uniforms.shape = this._field[2].shape
uniforms.pickId = this.pickId / 255.0
uniforms.lowerBound = this.bounds[0]
uniforms.upperBound = this.bounds[1]
uniforms.permutation = DEFAULT_PERM
for (var i = 0; i < 2; ++i) {
var clipClamped = uniforms.clipBounds[i]
for (var j = 0; j < 3; ++j) {
clipClamped[j] = Math.min(Math.max(this.clipBounds[i][j], -1e8), 1e8)
}
}
var projectData = computeProjectionData(uniforms, this)
if (projectData.showSurface) {
// Set up uniforms
this._pickShader.bind()
this._pickShader.uniforms = uniforms
// Draw it
this._vao.bind()
this._vao.draw(gl.TRIANGLES, this._vertexCount)
// Draw projections of surface
for (i = 0; i < 3; ++i) {
if (!this.surfaceProject[i]) {
continue
}
this._pickShader.uniforms.model = projectData.projections[i]
this._pickShader.uniforms.clipBounds = projectData.clipBounds[i]
this._vao.draw(gl.TRIANGLES, this._vertexCount)
}
this._vao.unbind()
}
if (projectData.showContour) {
var shader = this._contourPickShader
shader.bind()
shader.uniforms = uniforms
var vao = this._contourVAO
vao.bind()
for (j = 0; j < 3; ++j) {
gl.lineWidth(this.contourWidth[j])
shader.uniforms.permutation = PERMUTATIONS[j]
for (i = 0; i < this.contourLevels[j].length; ++i) {
if (this._contourCounts[j][i]) {
shader.uniforms.height = this.contourLevels[j][i]
vao.draw(gl.LINES, this._contourCounts[j][i], this._contourOffsets[j][i])
}
}
}
// Draw projections of surface
for (i = 0; i < 3; ++i) {
shader.uniforms.model = projectData.projections[i]
shader.uniforms.clipBounds = projectData.clipBounds[i]
for (j = 0; j < 3; ++j) {
if (!this.contourProject[i][j]) {
continue
}
shader.uniforms.permutation = PERMUTATIONS[j]
gl.lineWidth(this.contourWidth[j])
for (var k = 0; k < this.contourLevels[j].length; ++k) {
if (this._contourCounts[j][k]) {
shader.uniforms.height = this.contourLevels[j][k]
vao.draw(gl.LINES, this._contourCounts[j][k], this._contourOffsets[j][k])
}
}
}
}
vao.unbind()
}
}
proto.pick = function (selection) {
if (!selection) {
return null
}
if (selection.id !== this.pickId) {
return null
}
var shape = this._field[2].shape
var result = this._pickResult
// Compute uv coordinate
var x = shape[0] * (selection.value[0] + (selection.value[2] >> 4) / 16.0) / 255.0
var ix = Math.floor(x)
var fx = x - ix
var y = shape[1] * (selection.value[1] + (selection.value[2] & 15) / 16.0) / 255.0
var iy = Math.floor(y)
var fy = y - iy
ix += 1
iy += 1
// Compute xyz coordinate
var pos = result.position
pos[0] = pos[1] = pos[2] = 0
for (var dx = 0; dx < 2; ++dx) {
var s = dx ? fx : 1.0 - fx
for (var dy = 0; dy < 2; ++dy) {
var t = dy ? fy : 1.0 - fy
var r = ix + dx
var c = iy + dy
var w = s * t
for (var i = 0; i < 3; ++i) {
pos[i] += this._field[i].get(r, c) * w
}
}
}
// Find closest level
var levelIndex = this._pickResult.level
for (var j = 0; j < 3; ++j) {
levelIndex[j] = bsearch.le(this.contourLevels[j], pos[j])
if (levelIndex[j] < 0) {
if (this.contourLevels[j].length > 0) {
levelIndex[j] = 0
}
} else if (levelIndex[j] < this.contourLevels[j].length - 1) {
var a = this.contourLevels[j][levelIndex[j]]
var b = this.contourLevels[j][levelIndex[j] + 1]
if (Math.abs(a - pos[j]) > Math.abs(b - pos[j])) {
levelIndex[j] += 1
}
}
}
result.index[0] = fx < 0.5 ? ix : (ix + 1)
result.index[1] = fy < 0.5 ? iy : (iy + 1)
result.uv[0] = x / shape[0]
result.uv[1] = y / shape[1]
for (i = 0; i < 3; ++i) {
result.dataCoordinate[i] = this._field[i].get(result.index[0], result.index[1])
}
return result
}
function padField (nfield, field) {
var shape = field.shape.slice()
var nshape = nfield.shape.slice()
// Center
ops.assign(nfield.lo(1, 1).hi(shape[0], shape[1]), field)
// Edges
ops.assign(nfield.lo(1).hi(shape[0], 1),
field.hi(shape[0], 1))
ops.assign(nfield.lo(1, nshape[1] - 1).hi(shape[0], 1),
field.lo(0, shape[1] - 1).hi(shape[0], 1))
ops.assign(nfield.lo(0, 1).hi(1, shape[1]),
field.hi(1))
ops.assign(nfield.lo(nshape[0] - 1, 1).hi(1, shape[1]),
field.lo(shape[0] - 1))
// Corners
nfield.set(0, 0, field.get(0, 0))
nfield.set(0, nshape[1] - 1, field.get(0, shape[1] - 1))
nfield.set(nshape[0] - 1, 0, field.get(shape[0] - 1, 0))
nfield.set(nshape[0] - 1, nshape[1] - 1, field.get(shape[0] - 1, shape[1] - 1))
}
function handleArray (param, ctor) {
if (Array.isArray(param)) {
return [ ctor(param[0]), ctor(param[1]), ctor(param[2]) ]
}
return [ ctor(param), ctor(param), ctor(param) ]
}
function toColor (x) {
if (Array.isArray(x)) {
if (x.length === 3) {
return [x[0], x[1], x[2], 1]
}
return [x[0], x[1], x[2], x[3]]
}
return [0, 0, 0, 1]
}
function handleColor (param) {
if (Array.isArray(param)) {
if (Array.isArray(param)) {
return [
toColor(param[0]),
toColor(param[1]),
toColor(param[2]) ]
} else {
var c = toColor(param)
return [
c.slice(),
c.slice(),
c.slice() ]
}
}
}
proto.update = function (params) {
params = params || {}
this.dirty = true
if ('contourWidth' in params) {
this.contourWidth = handleArray(params.contourWidth, Number)
}
if ('showContour' in params) {
this.showContour = handleArray(params.showContour, Boolean)
}
if ('showSurface' in params) {
this.showSurface = !!params.showSurface
}
if ('contourTint' in params) {
this.contourTint = handleArray(params.contourTint, Boolean)
}
if ('contourColor' in params) {
this.contourColor = handleColor(params.contourColor)
}
if ('contourProject' in params) {
this.contourProject = handleArray(params.contourProject, function (x) {
return handleArray(x, Boolean)
})
}
if ('surfaceProject' in params) {
this.surfaceProject = params.surfaceProject
}
if ('dynamicColor' in params) {
this.dynamicColor = handleColor(params.dynamicColor)
}
if ('dynamicTint' in params) {
this.dynamicTint = handleArray(params.dynamicTint, Number)
}
if ('dynamicWidth' in params) {
this.dynamicWidth = handleArray(params.dynamicWidth, Number)
}
if ('opacity' in params) {
this.opacity = params.opacity
}
if ('colorBounds' in params) {
this.colorBounds = params.colorBounds
}
if ('vertexColor' in params) {
this.vertexColor = params.vertexColor ? 1 : 0;
}
var field = params.field || (params.coords && params.coords[2]) || null
var levelsChanged = false
if (!field) {
if (this._field[2].shape[0] || this._field[2].shape[2]) {
field = this._field[2].lo(1, 1).hi(this._field[2].shape[0] - 2, this._field[2].shape[1] - 2)
} else {
field = this._field[2].hi(0, 0)
}
}
// Update field
if ('field' in params || 'coords' in params) {
var fsize = (field.shape[0] + 2) * (field.shape[1] + 2)
// Resize if necessary
if (fsize > this._field[2].data.length) {
pool.freeFloat(this._field[2].data)
this._field[2].data = pool.mallocFloat(bits.nextPow2(fsize))
}
// Pad field
this._field[2] = ndarray(this._field[2].data, [field.shape[0] + 2, field.shape[1] + 2])
padField(this._field[2], field)
// Save shape of field
this.shape = field.shape.slice()
var shape = this.shape
// Resize coordinate fields if necessary
for (var i = 0; i < 2; ++i) {
if (this._field[2].size > this._field[i].data.length) {
pool.freeFloat(this._field[i].data)
this._field[i].data = pool.mallocFloat(this._field[2].size)
}
this._field[i] = ndarray(this._field[i].data, [shape[0] + 2, shape[1] + 2])
}
// Generate x/y coordinates
if (params.coords) {
var coords = params.coords
if (!Array.isArray(coords) || coords.length !== 3) {
throw new Error('gl-surface: invalid coordinates for x/y')
}
for (i = 0; i < 2; ++i) {
var coord = coords[i]
for (j = 0; j < 2; ++j) {
if (coord.shape[j] !== shape[j]) {
throw new Error('gl-surface: coords have incorrect shape')
}
}
padField(this._field[i], coord)
}
} else if (params.ticks) {
var ticks = params.ticks
if (!Array.isArray(ticks) || ticks.length !== 2) {
throw new Error('gl-surface: invalid ticks')
}
for (i = 0; i < 2; ++i) {
var tick = ticks[i]
if (Array.isArray(tick) || tick.length) {
tick = ndarray(tick)
}
if (tick.shape[0] !== shape[i]) {
throw new Error('gl-surface: invalid tick length')
}
// Make a copy view of the tick array
var tick2 = ndarray(tick.data, shape)
tick2.stride[i] = tick.stride[0]
tick2.stride[i ^ 1] = 0
// Fill in field array
padField(this._field[i], tick2)
}
} else {
for (i = 0; i < 2; ++i) {
var offset = [0, 0]
offset[i] = 1
this._field[i] = ndarray(this._field[i].data, [shape[0] + 2, shape[1] + 2], offset, 0)
}
this._field[0].set(0, 0, 0)
for (var j = 0; j < shape[0]; ++j) {
this._field[0].set(j + 1, 0, j)
}
this._field[0].set(shape[0] + 1, 0, shape[0] - 1)
this._field[1].set(0, 0, 0)
for (j = 0; j < shape[1]; ++j) {
this._field[1].set(0, j + 1, j)
}
this._field[1].set(0, shape[1] + 1, shape[1] - 1)
}
// Save shape
var fields = this._field
// Compute surface normals
var dfields = ndarray(pool.mallocFloat(fields[2].size * 3 * 2), [3, shape[0] + 2, shape[1] + 2, 2])
for (i = 0; i < 3; ++i) {
gradient(dfields.pick(i), fields[i], 'mirror')
}
var normals = ndarray(pool.mallocFloat(fields[2].size * 3), [shape[0] + 2, shape[1] + 2, 3])
for (i = 0; i < shape[0] + 2; ++i) {
for (j = 0; j < shape[1] + 2; ++j) {
var dxdu = dfields.get(0, i, j, 0)
var dxdv = dfields.get(0, i, j, 1)
var dydu = dfields.get(1, i, j, 0)
var dydv = dfields.get(1, i, j, 1)
var dzdu = dfields.get(2, i, j, 0)
var dzdv = dfields.get(2, i, j, 1)
var nx = dydu * dzdv - dydv * dzdu
var ny = dzdu * dxdv - dzdv * dxdu
var nz = dxdu * dydv - dxdv * dydu
var nl = Math.sqrt(nx * nx + ny * ny + nz * nz)
if (nl < 1e-8) {
nl = Math.max(Math.abs(nx), Math.abs(ny), Math.abs(nz))
if (nl < 1e-8) {
nz = 1.0
ny = nx = 0.0
nl = 1.0
} else {
nl = 1.0 / nl
}
} else {
nl = 1.0 / Math.sqrt(nl)
}
normals.set(i, j, 0, nx * nl)
normals.set(i, j, 1, ny * nl)
normals.set(i, j, 2, nz * nl)
}
}
pool.free(dfields.data)
// Initialize surface
var lo = [ Infinity, Infinity, Infinity ]
var hi = [ -Infinity, -Infinity, -Infinity ]
var lo_intensity = Infinity
var hi_intensity = -Infinity
var count = (shape[0] - 1) * (shape[1] - 1) * 6
var tverts = pool.mallocFloat(bits.nextPow2(10 * count))
var tptr = 0
var vertexCount = 0
for (i = 0; i < shape[0] - 1; ++i) {
j_loop:
for (j = 0; j < shape[1] - 1; ++j) {
// Test for NaNs
for (var dx = 0; dx < 2; ++dx) {
for (var dy = 0; dy < 2; ++dy) {
for (var k = 0; k < 3; ++k) {
var f = this._field[k].get(1 + i + dx, 1 + j + dy)
if (isNaN(f) || !isFinite(f)) {
continue j_loop
}
}
}
}
for (k = 0; k < 6; ++k) {
var r = i + QUAD[k][0]
var c = j + QUAD[k][1]
var tx = this._field[0].get(r + 1, c + 1)
var ty = this._field[1].get(r + 1, c + 1)
f = this._field[2].get(r + 1, c + 1)
var vf = f
nx = normals.get(r + 1, c + 1, 0)
ny = normals.get(r + 1, c + 1, 1)
nz = normals.get(r + 1, c + 1, 2)
if (params.intensity) {
vf = params.intensity.get(r, c)
}
tverts[tptr++] = r
tverts[tptr++] = c
tverts[tptr++] = tx
tverts[tptr++] = ty
tverts[tptr++] = f
tverts[tptr++] = 0
tverts[tptr++] = vf
tverts[tptr++] = nx
tverts[tptr++] = ny
tverts[tptr++] = nz
lo[0] = Math.min(lo[0], tx)
lo[1] = Math.min(lo[1], ty)
lo[2] = Math.min(lo[2], f)
lo_intensity = Math.min(lo_intensity, vf)
hi[0] = Math.max(hi[0], tx)
hi[1] = Math.max(hi[1], ty)
hi[2] = Math.max(hi[2], f)
hi_intensity = Math.max(hi_intensity, vf)
vertexCount += 1
}
}
}
if (params.intensityBounds) {
lo_intensity = +params.intensityBounds[0]
hi_intensity = +params.intensityBounds[1]
}
// Scale all vertex intensities
for (i = 6; i < tptr; i += 10) {
tverts[i] = (tverts[i] - lo_intensity) / (hi_intensity - lo_intensity)
}
this._vertexCount = vertexCount
this._coordinateBuffer.update(tverts.subarray(0, tptr))
pool.freeFloat(tverts)
pool.free(normals.data)
// Update bounds
this.bounds = [lo, hi]
// Save intensity
this.intensity = params.intensity || this._field[2]
if(this.intensityBounds[0] !== lo_intensity || this.intensityBounds[1] !== hi_intensity) {
levelsChanged = true
}
// Save intensity bound
this.intensityBounds = [lo_intensity, hi_intensity]
}
// Update level crossings
if ('levels' in params) {
var levels = params.levels
if (!Array.isArray(levels[0])) {
levels = [ [], [], levels ]
} else {
levels = levels.slice()
}
for (i = 0; i < 3; ++i) {
levels[i] = levels[i].slice()
levels.sort(function (a, b) {
return a - b
})
}
change_test:
for (i = 0; i < 3; ++i) {
if (levels[i].length !== this.contourLevels[i].length) {
levelsChanged = true
break
}
for (j = 0; j < levels[i].length; ++j) {
if (levels[i][j] !== this.contourLevels[i][j]) {
levelsChanged = true
break change_test
}
}
}
this.contourLevels = levels
}
if (levelsChanged) {
fields = this._field
shape = this.shape
// Update contour lines
var contourVerts = []
for (var dim = 0; dim < 3; ++dim) {
levels = this.contourLevels[dim]
var levelOffsets = []
var levelCounts = []
var parts = [0, 0, 0]
for (i = 0; i < levels.length; ++i) {
var graph = surfaceNets(this._field[dim], levels[i])
levelOffsets.push((contourVerts.length / 5) | 0)
vertexCount = 0
edge_loop:
for (j = 0; j < graph.cells.length; ++j) {
var e = graph.cells[j]
for (k = 0; k < 2; ++k) {
var p = graph.positions[e[k]]
var x = p[0]
var ix = Math.floor(x) | 0
var fx = x - ix
var y = p[1]
var iy = Math.floor(y) | 0
var fy = y - iy
var hole = false
dd_loop:
for (var dd = 0; dd < 3; ++dd) {
parts[dd] = 0.0
var iu = (dim + dd + 1) % 3
for (dx = 0; dx < 2; ++dx) {
var s = dx ? fx : 1.0 - fx
r = Math.min(Math.max(ix + dx, 0), shape[0]) | 0
for (dy = 0; dy < 2; ++dy) {
var t = dy ? fy : 1.0 - fy
c = Math.min(Math.max(iy + dy, 0), shape[1]) | 0
if (dd < 2) {
f = this._field[iu].get(r, c)
} else {
f = (this.intensity.get(r, c) - this.intensityBounds[0]) / (this.intensityBounds[1] - this.intensityBounds[0])
}
if (!isFinite(f) || isNaN(f)) {
hole = true
break dd_loop
}
var w = s * t
parts[dd] += w * f
}
}
}
if (!hole) {
contourVerts.push(parts[0], parts[1], p[0], p[1], parts[2])
vertexCount += 1
} else {
if (k > 0) {
// If we already added first edge, pop off verts
for (var l = 0; l < 5; ++l) {
contourVerts.pop()
}
vertexCount -= 1
}
continue edge_loop
}
}
}
levelCounts.push(vertexCount)
}
// Store results
this._contourOffsets[dim] = levelOffsets
this._contourCounts[dim] = levelCounts
}
var floatBuffer = pool.mallocFloat(contourVerts.length)
for (i = 0; i < contourVerts.length; ++i) {
floatBuffer[i] = contourVerts[i]
}
this._contourBuffer.update(floatBuffer)
pool.freeFloat(floatBuffer)
}
if (params.colormap) {
this._colorMap.setPixels(genColormap(params.colormap))
}
}
proto.dispose = function () {
this._shader.dispose()
this._vao.dispose()
this._coordinateBuffer.dispose()
this._colorMap.dispose()
this._contourBuffer.dispose()
this._contourVAO.dispose()
this._contourShader.dispose()
this._contourPickShader.dispose()
this._dynamicBuffer.dispose()
this._dynamicVAO.dispose()
for (var i = 0; i < 3; ++i) {
pool.freeFloat(this._field[i].data)
}
}
proto.highlight = function (selection) {
if (!selection) {
this._dynamicCounts = [0, 0, 0]
this.dyanamicLevel = [NaN, NaN, NaN]
this.highlightLevel = [-1, -1, -1]
return
}
for (var i = 0; i < 3; ++i) {
if (this.enableHighlight[i]) {
this.highlightLevel[i] = selection.level[i]
} else {
this.highlightLevel[i] = -1
}
}
var levels
if (this.snapToData) {
levels = selection.dataCoordinate
} else {
levels = selection.position
}
if ((!this.enableDynamic[0] || levels[0] === this.dynamicLevel[0]) &&
(!this.enableDynamic[1] || levels[1] === this.dynamicLevel[1]) &&
(!this.enableDynamic[2] || levels[2] === this.dynamicLevel[2])) {
return
}
var vertexCount = 0
var shape = this.shape
var scratchBuffer = pool.mallocFloat(12 * shape[0] * shape[1])
for (var d = 0; d < 3; ++d) {
if (!this.enableDynamic[d]) {
this.dynamicLevel[d] = NaN
this._dynamicCounts[d] = 0
continue
}
this.dynamicLevel[d] = levels[d]
var u = (d + 1) % 3
var v = (d + 2) % 3
var f = this._field[d]
var g = this._field[u]
var h = this._field[v]
var intensity = this.intensity
var graph = surfaceNets(f, levels[d])
var edges = graph.cells
var positions = graph.positions
this._dynamicOffsets[d] = vertexCount
for (i = 0; i < edges.length; ++i) {
var e = edges[i]
for (var j = 0; j < 2; ++j) {
var p = positions[e[j]]
var x = +p[0]
var ix = x | 0
var jx = Math.min(ix + 1, shape[0]) | 0
var fx = x - ix
var hx = 1.0 - fx
var y = +p[1]
var iy = y | 0
var jy = Math.min(iy + 1, shape[1]) | 0
var fy = y - iy
var hy = 1.0 - fy
var w00 = hx * hy
var w01 = hx * fy
var w10 = fx * hy
var w11 = fx * fy
var cu = w00 * g.get(ix, iy) +
w01 * g.get(ix, jy) +
w10 * g.get(jx, iy) +
w11 * g.get(jx, jy)
var cv = w00 * h.get(ix, iy) +
w01 * h.get(ix, jy) +
w10 * h.get(jx, iy) +
w11 * h.get(jx, jy)
if (isNaN(cu) || isNaN(cv)) {
if (j) {
vertexCount -= 1
}
break
}
scratchBuffer[2 * vertexCount + 0] = cu
scratchBuffer[2 * vertexCount + 1] = cv
vertexCount += 1
}
}
this._dynamicCounts[d] = vertexCount - this._dynamicOffsets[d]
}
this._dynamicBuffer.update(scratchBuffer.subarray(0, 2 * vertexCount))
pool.freeFloat(scratchBuffer)
}
function createSurfacePlot (params) {
var gl = params.gl
var shader = createShader(gl)
var pickShader = createPickShader(gl)
var contourShader = createContourShader(gl)
var contourPickShader = createPickContourShader(gl)
var coordinateBuffer = createBuffer(gl)
var vao = createVAO(gl, [
{ buffer: coordinateBuffer,
size: 4,
stride: SURFACE_VERTEX_SIZE,
offset: 0
},
{ buffer: coordinateBuffer,
size: 3,
stride: SURFACE_VERTEX_SIZE,
offset: 16
},
{
buffer: coordinateBuffer,
size: 3,
stride: SURFACE_VERTEX_SIZE,
offset: 28
}
])
var contourBuffer = createBuffer(gl)
var contourVAO = createVAO(gl, [
{
buffer: contourBuffer,
size: 4,
stride: 20,
offset: 0
},
{
buffer: contourBuffer,
size: 1,
stride: 20,
offset: 16
}
])
var dynamicBuffer = createBuffer(gl)
var dynamicVAO = createVAO(gl, [
{
buffer: dynamicBuffer,
size: 2,
type: gl.FLOAT
}])
var cmap = createTexture(gl, 1, N_COLORS, gl.RGBA, gl.UNSIGNED_BYTE)
cmap.minFilter = gl.LINEAR
cmap.magFilter = gl.LINEAR
var surface = new SurfacePlot(
gl,
[0, 0],
[[0, 0, 0], [0, 0, 0]],
shader,
pickShader,
coordinateBuffer,
vao,
cmap,
contourShader,
contourPickShader,
contourBuffer,
contourVAO,
dynamicBuffer,
dynamicVAO
)
var nparams = {
levels: [[], [], []]
}
for (var id in params) {
nparams[id] = params[id]
}
nparams.colormap = nparams.colormap || 'jet'
surface.update(nparams)
return surface
}
},{"./lib/shaders":260,"binary-search-bounds":62,"bit-twiddle":63,"colormap":95,"gl-buffer":152,"gl-mat4/invert":176,"gl-mat4/multiply":178,"gl-texture2d":262,"gl-vao":266,"ndarray":460,"ndarray-gradient":451,"ndarray-ops":454,"ndarray-pack":455,"surface-nets":523,"typedarray-pool":533}],262:[function(require,module,exports){
'use strict'
var ndarray = require('ndarray')
var ops = require('ndarray-ops')
var pool = require('typedarray-pool')
module.exports = createTexture2D
var linearTypes = null
var filterTypes = null
var wrapTypes = null
function lazyInitLinearTypes(gl) {
linearTypes = [
gl.LINEAR,
gl.NEAREST_MIPMAP_LINEAR,
gl.LINEAR_MIPMAP_NEAREST,
gl.LINEAR_MIPMAP_NEAREST
]
filterTypes = [
gl.NEAREST,
gl.LINEAR,
gl.NEAREST_MIPMAP_NEAREST,
gl.NEAREST_MIPMAP_LINEAR,
gl.LINEAR_MIPMAP_NEAREST,
gl.LINEAR_MIPMAP_LINEAR
]
wrapTypes = [
gl.REPEAT,
gl.CLAMP_TO_EDGE,
gl.MIRRORED_REPEAT
]
}
function acceptTextureDOM (obj) {
return (
('undefined' != typeof HTMLCanvasElement && obj instanceof HTMLCanvasElement) ||
('undefined' != typeof HTMLImageElement && obj instanceof HTMLImageElement) ||
('undefined' != typeof HTMLVideoElement && obj instanceof HTMLVideoElement) ||
('undefined' != typeof ImageData && obj instanceof ImageData))
}
var convertFloatToUint8 = function(out, inp) {
ops.muls(out, inp, 255.0)
}
function reshapeTexture(tex, w, h) {
var gl = tex.gl
var maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE)
if(w < 0 || w > maxSize || h < 0 || h > maxSize) {
throw new Error('gl-texture2d: Invalid texture size')
}
tex._shape = [w, h]
tex.bind()
gl.texImage2D(gl.TEXTURE_2D, 0, tex.format, w, h, 0, tex.format, tex.type, null)
tex._mipLevels = [0]
return tex
}
function Texture2D(gl, handle, width, height, format, type) {
this.gl = gl
this.handle = handle
this.format = format
this.type = type
this._shape = [width, height]
this._mipLevels = [0]
this._magFilter = gl.NEAREST
this._minFilter = gl.NEAREST
this._wrapS = gl.CLAMP_TO_EDGE
this._wrapT = gl.CLAMP_TO_EDGE
this._anisoSamples = 1
var parent = this
var wrapVector = [this._wrapS, this._wrapT]
Object.defineProperties(wrapVector, [
{
get: function() {
return parent._wrapS
},
set: function(v) {
return parent.wrapS = v
}
},
{
get: function() {
return parent._wrapT
},
set: function(v) {
return parent.wrapT = v
}
}
])
this._wrapVector = wrapVector
var shapeVector = [this._shape[0], this._shape[1]]
Object.defineProperties(shapeVector, [
{
get: function() {
return parent._shape[0]
},
set: function(v) {
return parent.width = v
}
},
{
get: function() {
return parent._shape[1]
},
set: function(v) {
return parent.height = v
}
}
])
this._shapeVector = shapeVector
}
var proto = Texture2D.prototype
Object.defineProperties(proto, {
minFilter: {
get: function() {
return this._minFilter
},
set: function(v) {
this.bind()
var gl = this.gl
if(this.type === gl.FLOAT && linearTypes.indexOf(v) >= 0) {
if(!gl.getExtension('OES_texture_float_linear')) {
v = gl.NEAREST
}
}
if(filterTypes.indexOf(v) < 0) {
throw new Error('gl-texture2d: Unknown filter mode ' + v)
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, v)
return this._minFilter = v
}
},
magFilter: {
get: function() {
return this._magFilter
},
set: function(v) {
this.bind()
var gl = this.gl
if(this.type === gl.FLOAT && linearTypes.indexOf(v) >= 0) {
if(!gl.getExtension('OES_texture_float_linear')) {
v = gl.NEAREST
}
}
if(filterTypes.indexOf(v) < 0) {
throw new Error('gl-texture2d: Unknown filter mode ' + v)
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, v)
return this._magFilter = v
}
},
mipSamples: {
get: function() {
return this._anisoSamples
},
set: function(i) {
var psamples = this._anisoSamples
this._anisoSamples = Math.max(i, 1)|0
if(psamples !== this._anisoSamples) {
var ext = this.gl.getExtension('EXT_texture_filter_anisotropic')
if(ext) {
this.gl.texParameterf(this.gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, this._anisoSamples)
}
}
return this._anisoSamples
}
},
wrapS: {
get: function() {
return this._wrapS
},
set: function(v) {
this.bind()
if(wrapTypes.indexOf(v) < 0) {
throw new Error('gl-texture2d: Unknown wrap mode ' + v)
}
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, v)
return this._wrapS = v
}
},
wrapT: {
get: function() {
return this._wrapT
},
set: function(v) {
this.bind()
if(wrapTypes.indexOf(v) < 0) {
throw new Error('gl-texture2d: Unknown wrap mode ' + v)
}
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, v)
return this._wrapT = v
}
},
wrap: {
get: function() {
return this._wrapVector
},
set: function(v) {
if(!Array.isArray(v)) {
v = [v,v]
}
if(v.length !== 2) {
throw new Error('gl-texture2d: Must specify wrap mode for rows and columns')
}
for(var i=0; i<2; ++i) {
if(wrapTypes.indexOf(v[i]) < 0) {
throw new Error('gl-texture2d: Unknown wrap mode ' + v)
}
}
this._wrapS = v[0]
this._wrapT = v[1]
var gl = this.gl
this.bind()
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this._wrapS)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this._wrapT)
return v
}
},
shape: {
get: function() {
return this._shapeVector
},
set: function(x) {
if(!Array.isArray(x)) {
x = [x|0,x|0]
} else {
if(x.length !== 2) {
throw new Error('gl-texture2d: Invalid texture shape')
}
}
reshapeTexture(this, x[0]|0, x[1]|0)
return [x[0]|0, x[1]|0]
}
},
width: {
get: function() {
return this._shape[0]
},
set: function(w) {
w = w|0
reshapeTexture(this, w, this._shape[1])
return w
}
},
height: {
get: function() {
return this._shape[1]
},
set: function(h) {
h = h|0
reshapeTexture(this, this._shape[0], h)
return h
}
}
})
proto.bind = function(unit) {
var gl = this.gl
if(unit !== undefined) {
gl.activeTexture(gl.TEXTURE0 + (unit|0))
}
gl.bindTexture(gl.TEXTURE_2D, this.handle)
if(unit !== undefined) {
return (unit|0)
}
return gl.getParameter(gl.ACTIVE_TEXTURE) - gl.TEXTURE0
}
proto.dispose = function() {
this.gl.deleteTexture(this.handle)
}
proto.generateMipmap = function() {
this.bind()
this.gl.generateMipmap(this.gl.TEXTURE_2D)
//Update mip levels
var l = Math.min(this._shape[0], this._shape[1])
for(var i=0; l>0; ++i, l>>>=1) {
if(this._mipLevels.indexOf(i) < 0) {
this._mipLevels.push(i)
}
}
}
proto.setPixels = function(data, x_off, y_off, mip_level) {
var gl = this.gl
this.bind()
if(Array.isArray(x_off)) {
mip_level = y_off
y_off = x_off[1]|0
x_off = x_off[0]|0
} else {
x_off = x_off || 0
y_off = y_off || 0
}
mip_level = mip_level || 0
var directData = acceptTextureDOM(data) ? data : data.raw
if(directData) {
var needsMip = this._mipLevels.indexOf(mip_level) < 0
if(needsMip) {
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, this.type, directData)
this._mipLevels.push(mip_level)
} else {
gl.texSubImage2D(gl.TEXTURE_2D, mip_level, x_off, y_off, this.format, this.type, directData)
}
} else if(data.shape && data.stride && data.data) {
if(data.shape.length < 2 ||
x_off + data.shape[1] > this._shape[1]>>>mip_level ||
y_off + data.shape[0] > this._shape[0]>>>mip_level ||
x_off < 0 ||
y_off < 0) {
throw new Error('gl-texture2d: Texture dimensions are out of bounds')
}
texSubImageArray(gl, x_off, y_off, mip_level, this.format, this.type, this._mipLevels, data)
} else {
throw new Error('gl-texture2d: Unsupported data type')
}
}
function isPacked(shape, stride) {
if(shape.length === 3) {
return (stride[2] === 1) &&
(stride[1] === shape[0]*shape[2]) &&
(stride[0] === shape[2])
}
return (stride[0] === 1) &&
(stride[1] === shape[0])
}
function texSubImageArray(gl, x_off, y_off, mip_level, cformat, ctype, mipLevels, array) {
var dtype = array.dtype
var shape = array.shape.slice()
if(shape.length < 2 || shape.length > 3) {
throw new Error('gl-texture2d: Invalid ndarray, must be 2d or 3d')
}
var type = 0, format = 0
var packed = isPacked(shape, array.stride.slice())
if(dtype === 'float32') {
type = gl.FLOAT
} else if(dtype === 'float64') {
type = gl.FLOAT
packed = false
dtype = 'float32'
} else if(dtype === 'uint8') {
type = gl.UNSIGNED_BYTE
} else {
type = gl.UNSIGNED_BYTE
packed = false
dtype = 'uint8'
}
var channels = 1
if(shape.length === 2) {
format = gl.LUMINANCE
shape = [shape[0], shape[1], 1]
array = ndarray(array.data, shape, [array.stride[0], array.stride[1], 1], array.offset)
} else if(shape.length === 3) {
if(shape[2] === 1) {
format = gl.ALPHA
} else if(shape[2] === 2) {
format = gl.LUMINANCE_ALPHA
} else if(shape[2] === 3) {
format = gl.RGB
} else if(shape[2] === 4) {
format = gl.RGBA
} else {
throw new Error('gl-texture2d: Invalid shape for pixel coords')
}
channels = shape[2]
} else {
throw new Error('gl-texture2d: Invalid shape for texture')
}
//For 1-channel textures allow conversion between formats
if((format === gl.LUMINANCE || format === gl.ALPHA) &&
(cformat === gl.LUMINANCE || cformat === gl.ALPHA)) {
format = cformat
}
if(format !== cformat) {
throw new Error('gl-texture2d: Incompatible texture format for setPixels')
}
var size = array.size
var needsMip = mipLevels.indexOf(mip_level) < 0
if(needsMip) {
mipLevels.push(mip_level)
}
if(type === ctype && packed) {
//Array data types are compatible, can directly copy into texture
if(array.offset === 0 && array.data.length === size) {
if(needsMip) {
gl.texImage2D(gl.TEXTURE_2D, mip_level, cformat, shape[0], shape[1], 0, cformat, ctype, array.data)
} else {
gl.texSubImage2D(gl.TEXTURE_2D, mip_level, x_off, y_off, shape[0], shape[1], cformat, ctype, array.data)
}
} else {
if(needsMip) {
gl.texImage2D(gl.TEXTURE_2D, mip_level, cformat, shape[0], shape[1], 0, cformat, ctype, array.data.subarray(array.offset, array.offset+size))
} else {
gl.texSubImage2D(gl.TEXTURE_2D, mip_level, x_off, y_off, shape[0], shape[1], cformat, ctype, array.data.subarray(array.offset, array.offset+size))
}
}
} else {
//Need to do type conversion to pack data into buffer
var pack_buffer
if(ctype === gl.FLOAT) {
pack_buffer = pool.mallocFloat32(size)
} else {
pack_buffer = pool.mallocUint8(size)
}
var pack_view = ndarray(pack_buffer, shape, [shape[2], shape[2]*shape[0], 1])
if(type === gl.FLOAT && ctype === gl.UNSIGNED_BYTE) {
convertFloatToUint8(pack_view, array)
} else {
ops.assign(pack_view, array)
}
if(needsMip) {
gl.texImage2D(gl.TEXTURE_2D, mip_level, cformat, shape[0], shape[1], 0, cformat, ctype, pack_buffer.subarray(0, size))
} else {
gl.texSubImage2D(gl.TEXTURE_2D, mip_level, x_off, y_off, shape[0], shape[1], cformat, ctype, pack_buffer.subarray(0, size))
}
if(ctype === gl.FLOAT) {
pool.freeFloat32(pack_buffer)
} else {
pool.freeUint8(pack_buffer)
}
}
}
function initTexture(gl) {
var tex = gl.createTexture()
gl.bindTexture(gl.TEXTURE_2D, tex)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
return tex
}
function createTextureShape(gl, width, height, format, type) {
var maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE)
if(width < 0 || width > maxTextureSize || height < 0 || height > maxTextureSize) {
throw new Error('gl-texture2d: Invalid texture shape')
}
if(type === gl.FLOAT && !gl.getExtension('OES_texture_float')) {
throw new Error('gl-texture2d: Floating point textures not supported on this platform')
}
var tex = initTexture(gl)
gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, format, type, null)
return new Texture2D(gl, tex, width, height, format, type)
}
function createTextureDOM(gl, directData, width, height, format, type) {
var tex = initTexture(gl)
gl.texImage2D(gl.TEXTURE_2D, 0, format, format, type, directData)
return new Texture2D(gl, tex, width, height, format, type)
}
//Creates a texture from an ndarray
function createTextureArray(gl, array) {
var dtype = array.dtype
var shape = array.shape.slice()
var maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE)
if(shape[0] < 0 || shape[0] > maxSize || shape[1] < 0 || shape[1] > maxSize) {
throw new Error('gl-texture2d: Invalid texture size')
}
var packed = isPacked(shape, array.stride.slice())
var type = 0
if(dtype === 'float32') {
type = gl.FLOAT
} else if(dtype === 'float64') {
type = gl.FLOAT
packed = false
dtype = 'float32'
} else if(dtype === 'uint8') {
type = gl.UNSIGNED_BYTE
} else {
type = gl.UNSIGNED_BYTE
packed = false
dtype = 'uint8'
}
var format = 0
if(shape.length === 2) {
format = gl.LUMINANCE
shape = [shape[0], shape[1], 1]
array = ndarray(array.data, shape, [array.stride[0], array.stride[1], 1], array.offset)
} else if(shape.length === 3) {
if(shape[2] === 1) {
format = gl.ALPHA
} else if(shape[2] === 2) {
format = gl.LUMINANCE_ALPHA
} else if(shape[2] === 3) {
format = gl.RGB
} else if(shape[2] === 4) {
format = gl.RGBA
} else {
throw new Error('gl-texture2d: Invalid shape for pixel coords')
}
} else {
throw new Error('gl-texture2d: Invalid shape for texture')
}
if(type === gl.FLOAT && !gl.getExtension('OES_texture_float')) {
type = gl.UNSIGNED_BYTE
packed = false
}
var buffer, buf_store
var size = array.size
if(!packed) {
var stride = [shape[2], shape[2]*shape[0], 1]
buf_store = pool.malloc(size, dtype)
var buf_array = ndarray(buf_store, shape, stride, 0)
if((dtype === 'float32' || dtype === 'float64') && type === gl.UNSIGNED_BYTE) {
convertFloatToUint8(buf_array, array)
} else {
ops.assign(buf_array, array)
}
buffer = buf_store.subarray(0, size)
} else if (array.offset === 0 && array.data.length === size) {
buffer = array.data
} else {
buffer = array.data.subarray(array.offset, array.offset + size)
}
var tex = initTexture(gl)
gl.texImage2D(gl.TEXTURE_2D, 0, format, shape[0], shape[1], 0, format, type, buffer)
if(!packed) {
pool.free(buf_store)
}
return new Texture2D(gl, tex, shape[0], shape[1], format, type)
}
function createTexture2D(gl) {
if(arguments.length <= 1) {
throw new Error('gl-texture2d: Missing arguments for texture2d constructor')
}
if(!linearTypes) {
lazyInitLinearTypes(gl)
}
if(typeof arguments[1] === 'number') {
return createTextureShape(gl, arguments[1], arguments[2], arguments[3]||gl.RGBA, arguments[4]||gl.UNSIGNED_BYTE)
}
if(Array.isArray(arguments[1])) {
return createTextureShape(gl, arguments[1][0]|0, arguments[1][1]|0, arguments[2]||gl.RGBA, arguments[3]||gl.UNSIGNED_BYTE)
}
if(typeof arguments[1] === 'object') {
var obj = arguments[1]
var directData = acceptTextureDOM(obj) ? obj : obj.raw
if (directData) {
return createTextureDOM(gl, directData, obj.width|0, obj.height|0, arguments[2]||gl.RGBA, arguments[3]||gl.UNSIGNED_BYTE)
} else if(obj.shape && obj.data && obj.stride) {
return createTextureArray(gl, obj)
}
}
throw new Error('gl-texture2d: Invalid arguments for texture2d constructor')
}
},{"ndarray":460,"ndarray-ops":454,"typedarray-pool":533}],263:[function(require,module,exports){
"use strict"
function doBind(gl, elements, attributes) {
if(elements) {
elements.bind()
} else {
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null)
}
var nattribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS)|0
if(attributes) {
if(attributes.length > nattribs) {
throw new Error("gl-vao: Too many vertex attributes")
}
for(var i=0; i 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len)
out[0] = a[0] * len
out[1] = a[1] * len
out[2] = a[2] * len
}
return out
}
},{}],272:[function(require,module,exports){
module.exports = transformMat4
/**
* Transforms the vec4 with a mat4.
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec4} out
*/
function transformMat4 (out, a, m) {
var x = a[0], y = a[1], z = a[2], w = a[3]
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w
return out
}
},{}],273:[function(require,module,exports){
module.exports = decodeFloat
var UINT8_VIEW = new Uint8Array(4)
var FLOAT_VIEW = new Float32Array(UINT8_VIEW.buffer)
function decodeFloat(x, y, z, w) {
UINT8_VIEW[0] = w
UINT8_VIEW[1] = z
UINT8_VIEW[2] = y
UINT8_VIEW[3] = x
return FLOAT_VIEW[0]
}
},{}],274:[function(require,module,exports){
var tokenize = require('glsl-tokenizer')
var atob = require('atob-lite')
module.exports = getName
function getName(src) {
var tokens = Array.isArray(src)
? src
: tokenize(src)
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i]
if (token.type !== 'preprocessor') continue
var match = token.data.match(/\#define\s+SHADER_NAME(_B64)?\s+(.+)$/)
if (!match) continue
if (!match[2]) continue
var b64 = match[1]
var name = match[2]
return (b64 ? atob(name) : name).trim()
}
}
},{"atob-lite":44,"glsl-tokenizer":281}],275:[function(require,module,exports){
module.exports = tokenize
var literals100 = require('./lib/literals')
, operators = require('./lib/operators')
, builtins100 = require('./lib/builtins')
, literals300es = require('./lib/literals-300es')
, builtins300es = require('./lib/builtins-300es')
var NORMAL = 999 // <-- never emitted
, TOKEN = 9999 // <-- never emitted
, BLOCK_COMMENT = 0
, LINE_COMMENT = 1
, PREPROCESSOR = 2
, OPERATOR = 3
, INTEGER = 4
, FLOAT = 5
, IDENT = 6
, BUILTIN = 7
, KEYWORD = 8
, WHITESPACE = 9
, EOF = 10
, HEX = 11
var map = [
'block-comment'
, 'line-comment'
, 'preprocessor'
, 'operator'
, 'integer'
, 'float'
, 'ident'
, 'builtin'
, 'keyword'
, 'whitespace'
, 'eof'
, 'integer'
]
function tokenize(opt) {
var i = 0
, total = 0
, mode = NORMAL
, c
, last
, content = []
, tokens = []
, token_idx = 0
, token_offs = 0
, line = 1
, col = 0
, start = 0
, isnum = false
, isoperator = false
, input = ''
, len
opt = opt || {}
var allBuiltins = builtins100
var allLiterals = literals100
if (opt.version === '300 es') {
allBuiltins = builtins300es
allLiterals = literals300es
}
return function(data) {
tokens = []
if (data !== null) return write(data.replace ? data.replace(/\r\n/g, '\n') : data)
return end()
}
function token(data) {
if (data.length) {
tokens.push({
type: map[mode]
, data: data
, position: start
, line: line
, column: col
})
}
}
function write(chunk) {
i = 0
input += chunk
len = input.length
var last
while(c = input[i], i < len) {
last = i
switch(mode) {
case BLOCK_COMMENT: i = block_comment(); break
case LINE_COMMENT: i = line_comment(); break
case PREPROCESSOR: i = preprocessor(); break
case OPERATOR: i = operator(); break
case INTEGER: i = integer(); break
case HEX: i = hex(); break
case FLOAT: i = decimal(); break
case TOKEN: i = readtoken(); break
case WHITESPACE: i = whitespace(); break
case NORMAL: i = normal(); break
}
if(last !== i) {
switch(input[last]) {
case '\n': col = 0; ++line; break
default: ++col; break
}
}
}
total += i
input = input.slice(i)
return tokens
}
function end(chunk) {
if(content.length) {
token(content.join(''))
}
mode = EOF
token('(eof)')
return tokens
}
function normal() {
content = content.length ? [] : content
if(last === '/' && c === '*') {
start = total + i - 1
mode = BLOCK_COMMENT
last = c
return i + 1
}
if(last === '/' && c === '/') {
start = total + i - 1
mode = LINE_COMMENT
last = c
return i + 1
}
if(c === '#') {
mode = PREPROCESSOR
start = total + i
return i
}
if(/\s/.test(c)) {
mode = WHITESPACE
start = total + i
return i
}
isnum = /\d/.test(c)
isoperator = /[^\w_]/.test(c)
start = total + i
mode = isnum ? INTEGER : isoperator ? OPERATOR : TOKEN
return i
}
function whitespace() {
if(/[^\s]/g.test(c)) {
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function preprocessor() {
if((c === '\r' || c === '\n') && last !== '\\') {
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function line_comment() {
return preprocessor()
}
function block_comment() {
if(c === '/' && last === '*') {
content.push(c)
token(content.join(''))
mode = NORMAL
return i + 1
}
content.push(c)
last = c
return i + 1
}
function operator() {
if(last === '.' && /\d/.test(c)) {
mode = FLOAT
return i
}
if(last === '/' && c === '*') {
mode = BLOCK_COMMENT
return i
}
if(last === '/' && c === '/') {
mode = LINE_COMMENT
return i
}
if(c === '.' && content.length) {
while(determine_operator(content));
mode = FLOAT
return i
}
if(c === ';' || c === ')' || c === '(') {
if(content.length) while(determine_operator(content));
token(c)
mode = NORMAL
return i + 1
}
var is_composite_operator = content.length === 2 && c !== '='
if(/[\w_\d\s]/.test(c) || is_composite_operator) {
while(determine_operator(content));
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function determine_operator(buf) {
var j = 0
, idx
, res
do {
idx = operators.indexOf(buf.slice(0, buf.length + j).join(''))
res = operators[idx]
if(idx === -1) {
if(j-- + buf.length > 0) continue
res = buf.slice(0, 1).join('')
}
token(res)
start += res.length
content = content.slice(res.length)
return content.length
} while(1)
}
function hex() {
if(/[^a-fA-F0-9]/.test(c)) {
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function integer() {
if(c === '.') {
content.push(c)
mode = FLOAT
last = c
return i + 1
}
if(/[eE]/.test(c)) {
content.push(c)
mode = FLOAT
last = c
return i + 1
}
if(c === 'x' && content.length === 1 && content[0] === '0') {
mode = HEX
content.push(c)
last = c
return i + 1
}
if(/[^\d]/.test(c)) {
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function decimal() {
if(c === 'f') {
content.push(c)
last = c
i += 1
}
if(/[eE]/.test(c)) {
content.push(c)
last = c
return i + 1
}
if (c === '-' && /[eE]/.test(last)) {
content.push(c)
last = c
return i + 1
}
if(/[^\d]/.test(c)) {
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
function readtoken() {
if(/[^\d\w_]/.test(c)) {
var contentstr = content.join('')
if(allLiterals.indexOf(contentstr) > -1) {
mode = KEYWORD
} else if(allBuiltins.indexOf(contentstr) > -1) {
mode = BUILTIN
} else {
mode = IDENT
}
token(content.join(''))
mode = NORMAL
return i
}
content.push(c)
last = c
return i + 1
}
}
},{"./lib/builtins":277,"./lib/builtins-300es":276,"./lib/literals":279,"./lib/literals-300es":278,"./lib/operators":280}],276:[function(require,module,exports){
// 300es builtins/reserved words that were previously valid in v100
var v100 = require('./builtins')
// The texture2D|Cube functions have been removed
// And the gl_ features are updated
v100 = v100.slice().filter(function (b) {
return !/^(gl\_|texture)/.test(b)
})
module.exports = v100.concat([
// the updated gl_ constants
'gl_VertexID'
, 'gl_InstanceID'
, 'gl_Position'
, 'gl_PointSize'
, 'gl_FragCoord'
, 'gl_FrontFacing'
, 'gl_FragDepth'
, 'gl_PointCoord'
, 'gl_MaxVertexAttribs'
, 'gl_MaxVertexUniformVectors'
, 'gl_MaxVertexOutputVectors'
, 'gl_MaxFragmentInputVectors'
, 'gl_MaxVertexTextureImageUnits'
, 'gl_MaxCombinedTextureImageUnits'
, 'gl_MaxTextureImageUnits'
, 'gl_MaxFragmentUniformVectors'
, 'gl_MaxDrawBuffers'
, 'gl_MinProgramTexelOffset'
, 'gl_MaxProgramTexelOffset'
, 'gl_DepthRangeParameters'
, 'gl_DepthRange'
// other builtins
, 'trunc'
, 'round'
, 'roundEven'
, 'isnan'
, 'isinf'
, 'floatBitsToInt'
, 'floatBitsToUint'
, 'intBitsToFloat'
, 'uintBitsToFloat'
, 'packSnorm2x16'
, 'unpackSnorm2x16'
, 'packUnorm2x16'
, 'unpackUnorm2x16'
, 'packHalf2x16'
, 'unpackHalf2x16'
, 'outerProduct'
, 'transpose'
, 'determinant'
, 'inverse'
, 'texture'
, 'textureSize'
, 'textureProj'
, 'textureLod'
, 'textureOffset'
, 'texelFetch'
, 'texelFetchOffset'
, 'textureProjOffset'
, 'textureLodOffset'
, 'textureProjLod'
, 'textureProjLodOffset'
, 'textureGrad'
, 'textureGradOffset'
, 'textureProjGrad'
, 'textureProjGradOffset'
])
},{"./builtins":277}],277:[function(require,module,exports){
module.exports = [
// Keep this list sorted
'abs'
, 'acos'
, 'all'
, 'any'
, 'asin'
, 'atan'
, 'ceil'
, 'clamp'
, 'cos'
, 'cross'
, 'dFdx'
, 'dFdy'
, 'degrees'
, 'distance'
, 'dot'
, 'equal'
, 'exp'
, 'exp2'
, 'faceforward'
, 'floor'
, 'fract'
, 'gl_BackColor'
, 'gl_BackLightModelProduct'
, 'gl_BackLightProduct'
, 'gl_BackMaterial'
, 'gl_BackSecondaryColor'
, 'gl_ClipPlane'
, 'gl_ClipVertex'
, 'gl_Color'
, 'gl_DepthRange'
, 'gl_DepthRangeParameters'
, 'gl_EyePlaneQ'
, 'gl_EyePlaneR'
, 'gl_EyePlaneS'
, 'gl_EyePlaneT'
, 'gl_Fog'
, 'gl_FogCoord'
, 'gl_FogFragCoord'
, 'gl_FogParameters'
, 'gl_FragColor'
, 'gl_FragCoord'
, 'gl_FragData'
, 'gl_FragDepth'
, 'gl_FragDepthEXT'
, 'gl_FrontColor'
, 'gl_FrontFacing'
, 'gl_FrontLightModelProduct'
, 'gl_FrontLightProduct'
, 'gl_FrontMaterial'
, 'gl_FrontSecondaryColor'
, 'gl_LightModel'
, 'gl_LightModelParameters'
, 'gl_LightModelProducts'
, 'gl_LightProducts'
, 'gl_LightSource'
, 'gl_LightSourceParameters'
, 'gl_MaterialParameters'
, 'gl_MaxClipPlanes'
, 'gl_MaxCombinedTextureImageUnits'
, 'gl_MaxDrawBuffers'
, 'gl_MaxFragmentUniformComponents'
, 'gl_MaxLights'
, 'gl_MaxTextureCoords'
, 'gl_MaxTextureImageUnits'
, 'gl_MaxTextureUnits'
, 'gl_MaxVaryingFloats'
, 'gl_MaxVertexAttribs'
, 'gl_MaxVertexTextureImageUnits'
, 'gl_MaxVertexUniformComponents'
, 'gl_ModelViewMatrix'
, 'gl_ModelViewMatrixInverse'
, 'gl_ModelViewMatrixInverseTranspose'
, 'gl_ModelViewMatrixTranspose'
, 'gl_ModelViewProjectionMatrix'
, 'gl_ModelViewProjectionMatrixInverse'
, 'gl_ModelViewProjectionMatrixInverseTranspose'
, 'gl_ModelViewProjectionMatrixTranspose'
, 'gl_MultiTexCoord0'
, 'gl_MultiTexCoord1'
, 'gl_MultiTexCoord2'
, 'gl_MultiTexCoord3'
, 'gl_MultiTexCoord4'
, 'gl_MultiTexCoord5'
, 'gl_MultiTexCoord6'
, 'gl_MultiTexCoord7'
, 'gl_Normal'
, 'gl_NormalMatrix'
, 'gl_NormalScale'
, 'gl_ObjectPlaneQ'
, 'gl_ObjectPlaneR'
, 'gl_ObjectPlaneS'
, 'gl_ObjectPlaneT'
, 'gl_Point'
, 'gl_PointCoord'
, 'gl_PointParameters'
, 'gl_PointSize'
, 'gl_Position'
, 'gl_ProjectionMatrix'
, 'gl_ProjectionMatrixInverse'
, 'gl_ProjectionMatrixInverseTranspose'
, 'gl_ProjectionMatrixTranspose'
, 'gl_SecondaryColor'
, 'gl_TexCoord'
, 'gl_TextureEnvColor'
, 'gl_TextureMatrix'
, 'gl_TextureMatrixInverse'
, 'gl_TextureMatrixInverseTranspose'
, 'gl_TextureMatrixTranspose'
, 'gl_Vertex'
, 'greaterThan'
, 'greaterThanEqual'
, 'inversesqrt'
, 'length'
, 'lessThan'
, 'lessThanEqual'
, 'log'
, 'log2'
, 'matrixCompMult'
, 'max'
, 'min'
, 'mix'
, 'mod'
, 'normalize'
, 'not'
, 'notEqual'
, 'pow'
, 'radians'
, 'reflect'
, 'refract'
, 'sign'
, 'sin'
, 'smoothstep'
, 'sqrt'
, 'step'
, 'tan'
, 'texture2D'
, 'texture2DLod'
, 'texture2DProj'
, 'texture2DProjLod'
, 'textureCube'
, 'textureCubeLod'
, 'texture2DLodEXT'
, 'texture2DProjLodEXT'
, 'textureCubeLodEXT'
, 'texture2DGradEXT'
, 'texture2DProjGradEXT'
, 'textureCubeGradEXT'
]
},{}],278:[function(require,module,exports){
var v100 = require('./literals')
module.exports = v100.slice().concat([
'layout'
, 'centroid'
, 'smooth'
, 'case'
, 'mat2x2'
, 'mat2x3'
, 'mat2x4'
, 'mat3x2'
, 'mat3x3'
, 'mat3x4'
, 'mat4x2'
, 'mat4x3'
, 'mat4x4'
, 'uint'
, 'uvec2'
, 'uvec3'
, 'uvec4'
, 'samplerCubeShadow'
, 'sampler2DArray'
, 'sampler2DArrayShadow'
, 'isampler2D'
, 'isampler3D'
, 'isamplerCube'
, 'isampler2DArray'
, 'usampler2D'
, 'usampler3D'
, 'usamplerCube'
, 'usampler2DArray'
, 'coherent'
, 'restrict'
, 'readonly'
, 'writeonly'
, 'resource'
, 'atomic_uint'
, 'noperspective'
, 'patch'
, 'sample'
, 'subroutine'
, 'common'
, 'partition'
, 'active'
, 'filter'
, 'image1D'
, 'image2D'
, 'image3D'
, 'imageCube'
, 'iimage1D'
, 'iimage2D'
, 'iimage3D'
, 'iimageCube'
, 'uimage1D'
, 'uimage2D'
, 'uimage3D'
, 'uimageCube'
, 'image1DArray'
, 'image2DArray'
, 'iimage1DArray'
, 'iimage2DArray'
, 'uimage1DArray'
, 'uimage2DArray'
, 'image1DShadow'
, 'image2DShadow'
, 'image1DArrayShadow'
, 'image2DArrayShadow'
, 'imageBuffer'
, 'iimageBuffer'
, 'uimageBuffer'
, 'sampler1DArray'
, 'sampler1DArrayShadow'
, 'isampler1D'
, 'isampler1DArray'
, 'usampler1D'
, 'usampler1DArray'
, 'isampler2DRect'
, 'usampler2DRect'
, 'samplerBuffer'
, 'isamplerBuffer'
, 'usamplerBuffer'
, 'sampler2DMS'
, 'isampler2DMS'
, 'usampler2DMS'
, 'sampler2DMSArray'
, 'isampler2DMSArray'
, 'usampler2DMSArray'
])
},{"./literals":279}],279:[function(require,module,exports){
module.exports = [
// current
'precision'
, 'highp'
, 'mediump'
, 'lowp'
, 'attribute'
, 'const'
, 'uniform'
, 'varying'
, 'break'
, 'continue'
, 'do'
, 'for'
, 'while'
, 'if'
, 'else'
, 'in'
, 'out'
, 'inout'
, 'float'
, 'int'
, 'void'
, 'bool'
, 'true'
, 'false'
, 'discard'
, 'return'
, 'mat2'
, 'mat3'
, 'mat4'
, 'vec2'
, 'vec3'
, 'vec4'
, 'ivec2'
, 'ivec3'
, 'ivec4'
, 'bvec2'
, 'bvec3'
, 'bvec4'
, 'sampler1D'
, 'sampler2D'
, 'sampler3D'
, 'samplerCube'
, 'sampler1DShadow'
, 'sampler2DShadow'
, 'struct'
// future
, 'asm'
, 'class'
, 'union'
, 'enum'
, 'typedef'
, 'template'
, 'this'
, 'packed'
, 'goto'
, 'switch'
, 'default'
, 'inline'
, 'noinline'
, 'volatile'
, 'public'
, 'static'
, 'extern'
, 'external'
, 'interface'
, 'long'
, 'short'
, 'double'
, 'half'
, 'fixed'
, 'unsigned'
, 'input'
, 'output'
, 'hvec2'
, 'hvec3'
, 'hvec4'
, 'dvec2'
, 'dvec3'
, 'dvec4'
, 'fvec2'
, 'fvec3'
, 'fvec4'
, 'sampler2DRect'
, 'sampler3DRect'
, 'sampler2DRectShadow'
, 'sizeof'
, 'cast'
, 'namespace'
, 'using'
]
},{}],280:[function(require,module,exports){
module.exports = [
'<<='
, '>>='
, '++'
, '--'
, '<<'
, '>>'
, '<='
, '>='
, '=='
, '!='
, '&&'
, '||'
, '+='
, '-='
, '*='
, '/='
, '%='
, '&='
, '^^'
, '^='
, '|='
, '('
, ')'
, '['
, ']'
, '.'
, '!'
, '~'
, '*'
, '/'
, '%'
, '+'
, '-'
, '<'
, '>'
, '&'
, '^'
, '|'
, '?'
, ':'
, '='
, ','
, ';'
, '{'
, '}'
]
},{}],281:[function(require,module,exports){
var tokenize = require('./index')
module.exports = tokenizeString
function tokenizeString(str, opt) {
var generator = tokenize(opt)
var tokens = []
tokens = tokens.concat(generator(str))
tokens = tokens.concat(generator(null))
return tokens
}
},{"./index":275}],282:[function(require,module,exports){
'use strict';
module.exports = GridIndex;
var NUM_PARAMS = 3;
function GridIndex(extent, n, padding) {
var cells = this.cells = [];
if (extent instanceof ArrayBuffer) {
this.arrayBuffer = extent;
var array = new Int32Array(this.arrayBuffer);
extent = array[0];
n = array[1];
padding = array[2];
this.d = n + 2 * padding;
for (var k = 0; k < this.d * this.d; k++) {
var start = array[NUM_PARAMS + k];
var end = array[NUM_PARAMS + k + 1];
cells.push(start === end ?
null :
array.subarray(start, end));
}
var keysOffset = array[NUM_PARAMS + cells.length];
var bboxesOffset = array[NUM_PARAMS + cells.length + 1];
this.keys = array.subarray(keysOffset, bboxesOffset);
this.bboxes = array.subarray(bboxesOffset);
this.insert = this._insertReadonly;
} else {
this.d = n + 2 * padding;
for (var i = 0; i < this.d * this.d; i++) {
cells.push([]);
}
this.keys = [];
this.bboxes = [];
}
this.n = n;
this.extent = extent;
this.padding = padding;
this.scale = n / extent;
this.uid = 0;
var p = (padding / n) * extent;
this.min = -p;
this.max = extent + p;
}
GridIndex.prototype.insert = function(key, x1, y1, x2, y2) {
this._forEachCell(x1, y1, x2, y2, this._insertCell, this.uid++);
this.keys.push(key);
this.bboxes.push(x1);
this.bboxes.push(y1);
this.bboxes.push(x2);
this.bboxes.push(y2);
};
GridIndex.prototype._insertReadonly = function() {
throw 'Cannot insert into a GridIndex created from an ArrayBuffer.';
};
GridIndex.prototype._insertCell = function(x1, y1, x2, y2, cellIndex, uid) {
this.cells[cellIndex].push(uid);
};
GridIndex.prototype.query = function(x1, y1, x2, y2) {
var min = this.min;
var max = this.max;
if (x1 <= min && y1 <= min && max <= x2 && max <= y2) {
// We use `Array#slice` because `this.keys` may be a `Int32Array` and
// some browsers (Safari and IE) do not support `TypedArray#slice`
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice#Browser_compatibility
return Array.prototype.slice.call(this.keys);
} else {
var result = [];
var seenUids = {};
this._forEachCell(x1, y1, x2, y2, this._queryCell, result, seenUids);
return result;
}
};
GridIndex.prototype._queryCell = function(x1, y1, x2, y2, cellIndex, result, seenUids) {
var cell = this.cells[cellIndex];
if (cell !== null) {
var keys = this.keys;
var bboxes = this.bboxes;
for (var u = 0; u < cell.length; u++) {
var uid = cell[u];
if (seenUids[uid] === undefined) {
var offset = uid * 4;
if ((x1 <= bboxes[offset + 2]) &&
(y1 <= bboxes[offset + 3]) &&
(x2 >= bboxes[offset + 0]) &&
(y2 >= bboxes[offset + 1])) {
seenUids[uid] = true;
result.push(keys[uid]);
} else {
seenUids[uid] = false;
}
}
}
}
};
GridIndex.prototype._forEachCell = function(x1, y1, x2, y2, fn, arg1, arg2) {
var cx1 = this._convertToCellCoord(x1);
var cy1 = this._convertToCellCoord(y1);
var cx2 = this._convertToCellCoord(x2);
var cy2 = this._convertToCellCoord(y2);
for (var x = cx1; x <= cx2; x++) {
for (var y = cy1; y <= cy2; y++) {
var cellIndex = this.d * y + x;
if (fn.call(this, x1, y1, x2, y2, cellIndex, arg1, arg2)) return;
}
}
};
GridIndex.prototype._convertToCellCoord = function(x) {
return Math.max(0, Math.min(this.d - 1, Math.floor(x * this.scale) + this.padding));
};
GridIndex.prototype.toArrayBuffer = function() {
if (this.arrayBuffer) return this.arrayBuffer;
var cells = this.cells;
var metadataLength = NUM_PARAMS + this.cells.length + 1 + 1;
var totalCellLength = 0;
for (var i = 0; i < this.cells.length; i++) {
totalCellLength += this.cells[i].length;
}
var array = new Int32Array(metadataLength + totalCellLength + this.keys.length + this.bboxes.length);
array[0] = this.extent;
array[1] = this.n;
array[2] = this.padding;
var offset = metadataLength;
for (var k = 0; k < cells.length; k++) {
var cell = cells[k];
array[NUM_PARAMS + k] = offset;
array.set(cell, offset);
offset += cell.length;
}
array[NUM_PARAMS + cells.length] = offset;
array.set(this.keys, offset);
offset += this.keys.length;
array[NUM_PARAMS + cells.length + 1] = offset;
array.set(this.bboxes, offset);
offset += this.bboxes.length;
return array.buffer;
};
},{}],283:[function(require,module,exports){
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
var e, m
var eLen = nBytes * 8 - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var nBits = -7
var i = isLE ? (nBytes - 1) : 0
var d = isLE ? -1 : 1
var s = buffer[offset + i]
i += d
e = s & ((1 << (-nBits)) - 1)
s >>= (-nBits)
nBits += eLen
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
m = e & ((1 << (-nBits)) - 1)
e >>= (-nBits)
nBits += mLen
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
if (e === 0) {
e = 1 - eBias
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity)
} else {
m = m + Math.pow(2, mLen)
e = e - eBias
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
}
exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
var e, m, c
var eLen = nBytes * 8 - mLen - 1
var eMax = (1 << eLen) - 1
var eBias = eMax >> 1
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
var i = isLE ? 0 : (nBytes - 1)
var d = isLE ? 1 : -1
var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
value = Math.abs(value)
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0
e = eMax
} else {
e = Math.floor(Math.log(value) / Math.LN2)
if (value * (c = Math.pow(2, -e)) < 1) {
e--
c *= 2
}
if (e + eBias >= 1) {
value += rt / c
} else {
value += rt * Math.pow(2, 1 - eBias)
}
if (value * c >= 2) {
e++
c /= 2
}
if (e + eBias >= eMax) {
m = 0
e = eMax
} else if (e + eBias >= 1) {
m = (value * c - 1) * Math.pow(2, mLen)
e = e + eBias
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
e = 0
}
}
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
e = (e << mLen) | m
eLen += mLen
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
buffer[offset + i - d] |= s * 128
}
},{}],284:[function(require,module,exports){
"use strict"
//High level idea:
// 1. Use Clarkson's incremental construction to find convex hull
// 2. Point location in triangulation by jump and walk
module.exports = incrementalConvexHull
var orient = require("robust-orientation")
var compareCell = require("simplicial-complex").compareCells
function compareInt(a, b) {
return a - b
}
function Simplex(vertices, adjacent, boundary) {
this.vertices = vertices
this.adjacent = adjacent
this.boundary = boundary
this.lastVisited = -1
}
Simplex.prototype.flip = function() {
var t = this.vertices[0]
this.vertices[0] = this.vertices[1]
this.vertices[1] = t
var u = this.adjacent[0]
this.adjacent[0] = this.adjacent[1]
this.adjacent[1] = u
}
function GlueFacet(vertices, cell, index) {
this.vertices = vertices
this.cell = cell
this.index = index
}
function compareGlue(a, b) {
return compareCell(a.vertices, b.vertices)
}
function bakeOrient(d) {
var code = ["function orient(){var tuple=this.tuple;return test("]
for(var i=0; i<=d; ++i) {
if(i > 0) {
code.push(",")
}
code.push("tuple[", i, "]")
}
code.push(")}return orient")
var proc = new Function("test", code.join(""))
var test = orient[d+1]
if(!test) {
test = orient
}
return proc(test)
}
var BAKED = []
function Triangulation(dimension, vertices, simplices) {
this.dimension = dimension
this.vertices = vertices
this.simplices = simplices
this.interior = simplices.filter(function(c) {
return !c.boundary
})
this.tuple = new Array(dimension+1)
for(var i=0; i<=dimension; ++i) {
this.tuple[i] = this.vertices[i]
}
var o = BAKED[dimension]
if(!o) {
o = BAKED[dimension] = bakeOrient(dimension)
}
this.orient = o
}
var proto = Triangulation.prototype
//Degenerate situation where we are on boundary, but coplanar to face
proto.handleBoundaryDegeneracy = function(cell, point) {
var d = this.dimension
var n = this.vertices.length - 1
var tuple = this.tuple
var verts = this.vertices
//Dumb solution: Just do dfs from boundary cell until we find any peak, or terminate
var toVisit = [ cell ]
cell.lastVisited = -n
while(toVisit.length > 0) {
cell = toVisit.pop()
var cellVerts = cell.vertices
var cellAdj = cell.adjacent
for(var i=0; i<=d; ++i) {
var neighbor = cellAdj[i]
if(!neighbor.boundary || neighbor.lastVisited <= -n) {
continue
}
var nv = neighbor.vertices
for(var j=0; j<=d; ++j) {
var vv = nv[j]
if(vv < 0) {
tuple[j] = point
} else {
tuple[j] = verts[vv]
}
}
var o = this.orient()
if(o > 0) {
return neighbor
}
neighbor.lastVisited = -n
if(o === 0) {
toVisit.push(neighbor)
}
}
}
return null
}
proto.walk = function(point, random) {
//Alias local properties
var n = this.vertices.length - 1
var d = this.dimension
var verts = this.vertices
var tuple = this.tuple
//Compute initial jump cell
var initIndex = random ? (this.interior.length * Math.random())|0 : (this.interior.length-1)
var cell = this.interior[ initIndex ]
//Start walking
outerLoop:
while(!cell.boundary) {
var cellVerts = cell.vertices
var cellAdj = cell.adjacent
for(var i=0; i<=d; ++i) {
tuple[i] = verts[cellVerts[i]]
}
cell.lastVisited = n
//Find farthest adjacent cell
for(var i=0; i<=d; ++i) {
var neighbor = cellAdj[i]
if(neighbor.lastVisited >= n) {
continue
}
var prev = tuple[i]
tuple[i] = point
var o = this.orient()
tuple[i] = prev
if(o < 0) {
cell = neighbor
continue outerLoop
} else {
if(!neighbor.boundary) {
neighbor.lastVisited = n
} else {
neighbor.lastVisited = -n
}
}
}
return
}
return cell
}
proto.addPeaks = function(point, cell) {
var n = this.vertices.length - 1
var d = this.dimension
var verts = this.vertices
var tuple = this.tuple
var interior = this.interior
var simplices = this.simplices
//Walking finished at boundary, time to add peaks
var tovisit = [ cell ]
//Stretch initial boundary cell into a peak
cell.lastVisited = n
cell.vertices[cell.vertices.indexOf(-1)] = n
cell.boundary = false
interior.push(cell)
//Record a list of all new boundaries created by added peaks so we can glue them together when we are all done
var glueFacets = []
//Do a traversal of the boundary walking outward from starting peak
while(tovisit.length > 0) {
//Pop off peak and walk over adjacent cells
var cell = tovisit.pop()
var cellVerts = cell.vertices
var cellAdj = cell.adjacent
var indexOfN = cellVerts.indexOf(n)
if(indexOfN < 0) {
continue
}
for(var i=0; i<=d; ++i) {
if(i === indexOfN) {
continue
}
//For each boundary neighbor of the cell
var neighbor = cellAdj[i]
if(!neighbor.boundary || neighbor.lastVisited >= n) {
continue
}
var nv = neighbor.vertices
//Test if neighbor is a peak
if(neighbor.lastVisited !== -n) {
//Compute orientation of p relative to each boundary peak
var indexOfNeg1 = 0
for(var j=0; j<=d; ++j) {
if(nv[j] < 0) {
indexOfNeg1 = j
tuple[j] = point
} else {
tuple[j] = verts[nv[j]]
}
}
var o = this.orient()
//Test if neighbor cell is also a peak
if(o > 0) {
nv[indexOfNeg1] = n
neighbor.boundary = false
interior.push(neighbor)
tovisit.push(neighbor)
neighbor.lastVisited = n
continue
} else {
neighbor.lastVisited = -n
}
}
var na = neighbor.adjacent
//Otherwise, replace neighbor with new face
var vverts = cellVerts.slice()
var vadj = cellAdj.slice()
var ncell = new Simplex(vverts, vadj, true)
simplices.push(ncell)
//Connect to neighbor
var opposite = na.indexOf(cell)
if(opposite < 0) {
continue
}
na[opposite] = ncell
vadj[indexOfN] = neighbor
//Connect to cell
vverts[i] = -1
vadj[i] = cell
cellAdj[i] = ncell
//Flip facet
ncell.flip()
//Add to glue list
for(var j=0; j<=d; ++j) {
var uu = vverts[j]
if(uu < 0 || uu === n) {
continue
}
var nface = new Array(d-1)
var nptr = 0
for(var k=0; k<=d; ++k) {
var vv = vverts[k]
if(vv < 0 || k === j) {
continue
}
nface[nptr++] = vv
}
glueFacets.push(new GlueFacet(nface, ncell, j))
}
}
}
//Glue boundary facets together
glueFacets.sort(compareGlue)
for(var i=0; i+1= 0) {
bcell[ptr++] = cv[j]
} else {
parity = j&1
}
}
if(parity === (d&1)) {
var t = bcell[0]
bcell[0] = bcell[1]
bcell[1] = t
}
boundary.push(bcell)
}
}
return boundary
}
function incrementalConvexHull(points, randomSearch) {
var n = points.length
if(n === 0) {
throw new Error("Must have at least d+1 points")
}
var d = points[0].length
if(n <= d) {
throw new Error("Must input at least d+1 points")
}
//FIXME: This could be degenerate, but need to select d+1 non-coplanar points to bootstrap process
var initialSimplex = points.slice(0, d+1)
//Make sure initial simplex is positively oriented
var o = orient.apply(void 0, initialSimplex)
if(o === 0) {
throw new Error("Input not in general position")
}
var initialCoords = new Array(d+1)
for(var i=0; i<=d; ++i) {
initialCoords[i] = i
}
if(o < 0) {
initialCoords[0] = 1
initialCoords[1] = 0
}
//Create initial topological index, glue pointers together (kind of messy)
var initialCell = new Simplex(initialCoords, new Array(d+1), false)
var boundary = initialCell.adjacent
var list = new Array(d+2)
for(var i=0; i<=d; ++i) {
var verts = initialCoords.slice()
for(var j=0; j<=d; ++j) {
if(j === i) {
verts[j] = -1
}
}
var t = verts[0]
verts[0] = verts[1]
verts[1] = t
var cell = new Simplex(verts, new Array(d+1), true)
boundary[i] = cell
list[i] = cell
}
list[d+1] = initialCell
for(var i=0; i<=d; ++i) {
var verts = boundary[i].vertices
var adj = boundary[i].adjacent
for(var j=0; j<=d; ++j) {
var v = verts[j]
if(v < 0) {
adj[j] = initialCell
continue
}
for(var k=0; k<=d; ++k) {
if(boundary[k].vertices.indexOf(v) < 0) {
adj[j] = boundary[k]
}
}
}
}
//Initialize triangles
var triangles = new Triangulation(d, initialSimplex, list)
//Insert remaining points
var useRandom = !!randomSearch
for(var i=d+1; i 3*(weight+1)) {
rebuildWithInterval(this, interval)
} else {
this.left.insert(interval)
}
} else {
this.left = createIntervalTree([interval])
}
} else if(interval[0] > this.mid) {
if(this.right) {
if(4*(this.right.count+1) > 3*(weight+1)) {
rebuildWithInterval(this, interval)
} else {
this.right.insert(interval)
}
} else {
this.right = createIntervalTree([interval])
}
} else {
var l = bounds.ge(this.leftPoints, interval, compareBegin)
var r = bounds.ge(this.rightPoints, interval, compareEnd)
this.leftPoints.splice(l, 0, interval)
this.rightPoints.splice(r, 0, interval)
}
}
proto.remove = function(interval) {
var weight = this.count - this.leftPoints
if(interval[1] < this.mid) {
if(!this.left) {
return NOT_FOUND
}
var rw = this.right ? this.right.count : 0
if(4 * rw > 3 * (weight-1)) {
return rebuildWithoutInterval(this, interval)
}
var r = this.left.remove(interval)
if(r === EMPTY) {
this.left = null
this.count -= 1
return SUCCESS
} else if(r === SUCCESS) {
this.count -= 1
}
return r
} else if(interval[0] > this.mid) {
if(!this.right) {
return NOT_FOUND
}
var lw = this.left ? this.left.count : 0
if(4 * lw > 3 * (weight-1)) {
return rebuildWithoutInterval(this, interval)
}
var r = this.right.remove(interval)
if(r === EMPTY) {
this.right = null
this.count -= 1
return SUCCESS
} else if(r === SUCCESS) {
this.count -= 1
}
return r
} else {
if(this.count === 1) {
if(this.leftPoints[0] === interval) {
return EMPTY
} else {
return NOT_FOUND
}
}
if(this.leftPoints.length === 1 && this.leftPoints[0] === interval) {
if(this.left && this.right) {
var p = this
var n = this.left
while(n.right) {
p = n
n = n.right
}
if(p === this) {
n.right = this.right
} else {
var l = this.left
var r = this.right
p.count -= n.count
p.right = n.left
n.left = l
n.right = r
}
copy(this, n)
this.count = (this.left?this.left.count:0) + (this.right?this.right.count:0) + this.leftPoints.length
} else if(this.left) {
copy(this, this.left)
} else {
copy(this, this.right)
}
return SUCCESS
}
for(var l = bounds.ge(this.leftPoints, interval, compareBegin); l=0 && arr[i][1] >= lo; --i) {
var r = cb(arr[i])
if(r) { return r }
}
}
function reportRange(arr, cb) {
for(var i=0; i this.mid) {
if(this.right) {
var r = this.right.queryPoint(x, cb)
if(r) { return r }
}
return reportRightRange(this.rightPoints, x, cb)
} else {
return reportRange(this.leftPoints, cb)
}
}
proto.queryInterval = function(lo, hi, cb) {
if(lo < this.mid && this.left) {
var r = this.left.queryInterval(lo, hi, cb)
if(r) { return r }
}
if(hi > this.mid && this.right) {
var r = this.right.queryInterval(lo, hi, cb)
if(r) { return r }
}
if(hi < this.mid) {
return reportLeftRange(this.leftPoints, hi, cb)
} else if(lo > this.mid) {
return reportRightRange(this.rightPoints, lo, cb)
} else {
return reportRange(this.leftPoints, cb)
}
}
function compareNumbers(a, b) {
return a - b
}
function compareBegin(a, b) {
var d = a[0] - b[0]
if(d) { return d }
return a[1] - b[1]
}
function compareEnd(a, b) {
var d = a[1] - b[1]
if(d) { return d }
return a[0] - b[0]
}
function createIntervalTree(intervals) {
if(intervals.length === 0) {
return null
}
var pts = []
for(var i=0; i>1]
var leftIntervals = []
var rightIntervals = []
var centerIntervals = []
for(var i=0; i
* @license MIT
*/
// The _isBuffer check is for Safari 5-7 support, because it's missing
// Object.prototype.constructor. Remove this eventually
module.exports = function (obj) {
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer)
}
function isBuffer (obj) {
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj)
}
// For Node v0.10 support. Remove this eventually.
function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
},{}],289:[function(require,module,exports){
module.exports = isMobile;
function isMobile (ua) {
if (!ua && typeof navigator != 'undefined') ua = navigator.userAgent;
if (ua && ua.headers && typeof ua.headers['user-agent'] == 'string') {
ua = ua.headers['user-agent'];
}
if (typeof ua != 'string') return false;
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(ua) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0,4));
}
},{}],290:[function(require,module,exports){
'use strict';
var toString = Object.prototype.toString;
module.exports = function (x) {
var prototype;
return toString.call(x) === '[object Object]' && (prototype = Object.getPrototypeOf(x), prototype === null || prototype === Object.getPrototypeOf({}));
};
},{}],291:[function(require,module,exports){
'use strict';
var sort = require('./sort');
var range = require('./range');
var within = require('./within');
module.exports = kdbush;
function kdbush(points, getX, getY, nodeSize, ArrayType) {
return new KDBush(points, getX, getY, nodeSize, ArrayType);
}
function KDBush(points, getX, getY, nodeSize, ArrayType) {
getX = getX || defaultGetX;
getY = getY || defaultGetY;
ArrayType = ArrayType || Array;
this.nodeSize = nodeSize || 64;
this.points = points;
this.ids = new ArrayType(points.length);
this.coords = new ArrayType(points.length * 2);
for (var i = 0; i < points.length; i++) {
this.ids[i] = i;
this.coords[2 * i] = getX(points[i]);
this.coords[2 * i + 1] = getY(points[i]);
}
sort(this.ids, this.coords, this.nodeSize, 0, this.ids.length - 1, 0);
}
KDBush.prototype = {
range: function (minX, minY, maxX, maxY) {
return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize);
},
within: function (x, y, r) {
return within(this.ids, this.coords, x, y, r, this.nodeSize);
}
};
function defaultGetX(p) { return p[0]; }
function defaultGetY(p) { return p[1]; }
},{"./range":292,"./sort":293,"./within":294}],292:[function(require,module,exports){
'use strict';
module.exports = range;
function range(ids, coords, minX, minY, maxX, maxY, nodeSize) {
var stack = [0, ids.length - 1, 0];
var result = [];
var x, y;
while (stack.length) {
var axis = stack.pop();
var right = stack.pop();
var left = stack.pop();
if (right - left <= nodeSize) {
for (var i = left; i <= right; i++) {
x = coords[2 * i];
y = coords[2 * i + 1];
if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[i]);
}
continue;
}
var m = Math.floor((left + right) / 2);
x = coords[2 * m];
y = coords[2 * m + 1];
if (x >= minX && x <= maxX && y >= minY && y <= maxY) result.push(ids[m]);
var nextAxis = (axis + 1) % 2;
if (axis === 0 ? minX <= x : minY <= y) {
stack.push(left);
stack.push(m - 1);
stack.push(nextAxis);
}
if (axis === 0 ? maxX >= x : maxY >= y) {
stack.push(m + 1);
stack.push(right);
stack.push(nextAxis);
}
}
return result;
}
},{}],293:[function(require,module,exports){
'use strict';
module.exports = sortKD;
function sortKD(ids, coords, nodeSize, left, right, depth) {
if (right - left <= nodeSize) return;
var m = Math.floor((left + right) / 2);
select(ids, coords, m, left, right, depth % 2);
sortKD(ids, coords, nodeSize, left, m - 1, depth + 1);
sortKD(ids, coords, nodeSize, m + 1, right, depth + 1);
}
function select(ids, coords, k, left, right, inc) {
while (right > left) {
if (right - left > 600) {
var n = right - left + 1;
var m = k - left + 1;
var z = Math.log(n);
var s = 0.5 * Math.exp(2 * z / 3);
var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
select(ids, coords, k, newLeft, newRight, inc);
}
var t = coords[2 * k + inc];
var i = left;
var j = right;
swapItem(ids, coords, left, k);
if (coords[2 * right + inc] > t) swapItem(ids, coords, left, right);
while (i < j) {
swapItem(ids, coords, i, j);
i++;
j--;
while (coords[2 * i + inc] < t) i++;
while (coords[2 * j + inc] > t) j--;
}
if (coords[2 * left + inc] === t) swapItem(ids, coords, left, j);
else {
j++;
swapItem(ids, coords, j, right);
}
if (j <= k) left = j + 1;
if (k <= j) right = j - 1;
}
}
function swapItem(ids, coords, i, j) {
swap(ids, i, j);
swap(coords, 2 * i, 2 * j);
swap(coords, 2 * i + 1, 2 * j + 1);
}
function swap(arr, i, j) {
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
},{}],294:[function(require,module,exports){
'use strict';
module.exports = within;
function within(ids, coords, qx, qy, r, nodeSize) {
var stack = [0, ids.length - 1, 0];
var result = [];
var r2 = r * r;
while (stack.length) {
var axis = stack.pop();
var right = stack.pop();
var left = stack.pop();
if (right - left <= nodeSize) {
for (var i = left; i <= right; i++) {
if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2) result.push(ids[i]);
}
continue;
}
var m = Math.floor((left + right) / 2);
var x = coords[2 * m];
var y = coords[2 * m + 1];
if (sqDist(x, y, qx, qy) <= r2) result.push(ids[m]);
var nextAxis = (axis + 1) % 2;
if (axis === 0 ? qx - r <= x : qy - r <= y) {
stack.push(left);
stack.push(m - 1);
stack.push(nextAxis);
}
if (axis === 0 ? qx + r >= x : qy + r >= y) {
stack.push(m + 1);
stack.push(right);
stack.push(nextAxis);
}
}
return result;
}
function sqDist(ax, ay, bx, by) {
var dx = ax - bx;
var dy = ay - by;
return dx * dx + dy * dy;
}
},{}],295:[function(require,module,exports){
'use strict';
function createFunction(parameters, defaultType) {
var fun;
if (!isFunctionDefinition(parameters)) {
fun = function() { return parameters; };
fun.isFeatureConstant = true;
fun.isZoomConstant = true;
} else {
var zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
var featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
var zoomDependent = zoomAndFeatureDependent || !featureDependent;
var type = parameters.type || defaultType || 'exponential';
var innerFun;
if (type === 'exponential') {
innerFun = evaluateExponentialFunction;
} else if (type === 'interval') {
innerFun = evaluateIntervalFunction;
} else if (type === 'categorical') {
innerFun = evaluateCategoricalFunction;
} else if (type === 'identity') {
innerFun = evaluateIdentityFunction;
} else {
throw new Error('Unknown function type "' + type + '"');
}
if (zoomAndFeatureDependent) {
var featureFunctions = {};
var featureFunctionStops = [];
for (var s = 0; s < parameters.stops.length; s++) {
var stop = parameters.stops[s];
if (featureFunctions[stop[0].zoom] === undefined) {
featureFunctions[stop[0].zoom] = {
zoom: stop[0].zoom,
type: parameters.type,
property: parameters.property,
stops: []
};
}
featureFunctions[stop[0].zoom].stops.push([stop[0].value, stop[1]]);
}
for (var z in featureFunctions) {
featureFunctionStops.push([featureFunctions[z].zoom, createFunction(featureFunctions[z])]);
}
fun = function(zoom, feature) {
return evaluateExponentialFunction({ stops: featureFunctionStops, base: parameters.base }, zoom)(zoom, feature);
};
fun.isFeatureConstant = false;
fun.isZoomConstant = false;
} else if (zoomDependent) {
fun = function(zoom) {
return innerFun(parameters, zoom);
};
fun.isFeatureConstant = true;
fun.isZoomConstant = false;
} else {
fun = function(zoom, feature) {
return innerFun(parameters, feature[parameters.property]);
};
fun.isFeatureConstant = false;
fun.isZoomConstant = true;
}
}
return fun;
}
function evaluateCategoricalFunction(parameters, input) {
for (var i = 0; i < parameters.stops.length; i++) {
if (input === parameters.stops[i][0]) {
return parameters.stops[i][1];
}
}
return parameters.stops[0][1];
}
function evaluateIntervalFunction(parameters, input) {
for (var i = 0; i < parameters.stops.length; i++) {
if (input < parameters.stops[i][0]) break;
}
return parameters.stops[Math.max(i - 1, 0)][1];
}
function evaluateExponentialFunction(parameters, input) {
var base = parameters.base !== undefined ? parameters.base : 1;
var i = 0;
while (true) {
if (i >= parameters.stops.length) break;
else if (input <= parameters.stops[i][0]) break;
else i++;
}
if (i === 0) {
return parameters.stops[i][1];
} else if (i === parameters.stops.length) {
return parameters.stops[i - 1][1];
} else {
return interpolate(
input,
base,
parameters.stops[i - 1][0],
parameters.stops[i][0],
parameters.stops[i - 1][1],
parameters.stops[i][1]
);
}
}
function evaluateIdentityFunction(parameters, input) {
return input;
}
function interpolate(input, base, inputLower, inputUpper, outputLower, outputUpper) {
if (typeof outputLower === 'function') {
return function() {
var evaluatedLower = outputLower.apply(undefined, arguments);
var evaluatedUpper = outputUpper.apply(undefined, arguments);
return interpolate(input, base, inputLower, inputUpper, evaluatedLower, evaluatedUpper);
};
} else if (outputLower.length) {
return interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper);
} else {
return interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper);
}
}
function interpolateNumber(input, base, inputLower, inputUpper, outputLower, outputUpper) {
var difference = inputUpper - inputLower;
var progress = input - inputLower;
var ratio;
if (base === 1) {
ratio = progress / difference;
} else {
ratio = (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
}
return (outputLower * (1 - ratio)) + (outputUpper * ratio);
}
function interpolateArray(input, base, inputLower, inputUpper, outputLower, outputUpper) {
var output = [];
for (var i = 0; i < outputLower.length; i++) {
output[i] = interpolateNumber(input, base, inputLower, inputUpper, outputLower[i], outputUpper[i]);
}
return output;
}
function isFunctionDefinition(value) {
return typeof value === 'object' && (value.stops || value.type === 'identity');
}
module.exports.isFunctionDefinition = isFunctionDefinition;
module.exports.interpolated = function(parameters) {
return createFunction(parameters, 'exponential');
};
module.exports['piecewise-constant'] = function(parameters) {
return createFunction(parameters, 'interval');
};
},{}],296:[function(require,module,exports){
var path = require('path');
// readFileSync calls must be written out long-form for brfs.
module.exports = {
debug: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform lowp vec4 u_color;\n\nvoid main() {\n gl_FragColor = u_color;\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1);\n}\n"
},
fill: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n#pragma mapbox: define lowp vec4 color\n#pragma mapbox: define lowp float opacity\n\nvoid main() {\n #pragma mapbox: initialize lowp vec4 color\n #pragma mapbox: initialize lowp float opacity\n\n gl_FragColor = color * opacity;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\n\n#pragma mapbox: define lowp vec4 color\n#pragma mapbox: define lowp float opacity\n\nvoid main() {\n #pragma mapbox: initialize lowp vec4 color\n #pragma mapbox: initialize lowp float opacity\n\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n}\n"
},
circle: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n#pragma mapbox: define lowp vec4 color\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n\nvarying vec2 v_extrude;\nvarying lowp float v_antialiasblur;\n\nvoid main() {\n #pragma mapbox: initialize lowp vec4 color\n #pragma mapbox: initialize lowp float blur\n #pragma mapbox: initialize lowp float opacity\n\n float t = smoothstep(1.0 - max(blur, v_antialiasblur), 1.0, length(v_extrude));\n gl_FragColor = color * (1.0 - t) * opacity;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform mat4 u_matrix;\nuniform bool u_scale_with_map;\nuniform vec2 u_extrude_scale;\nuniform float u_devicepixelratio;\n\nattribute vec2 a_pos;\n\n#pragma mapbox: define lowp vec4 color\n#pragma mapbox: define mediump float radius\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n\nvarying vec2 v_extrude;\nvarying lowp float v_antialiasblur;\n\nvoid main(void) {\n #pragma mapbox: initialize lowp vec4 color\n #pragma mapbox: initialize mediump float radius\n #pragma mapbox: initialize lowp float blur\n #pragma mapbox: initialize lowp float opacity\n\n // unencode the extrusion vector that we snuck into the a_pos vector\n v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);\n\n vec2 extrude = v_extrude * radius * u_extrude_scale;\n // multiply a_pos by 0.5, since we had it * 2 in order to sneak\n // in extrusion data\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1);\n\n if (u_scale_with_map) {\n gl_Position.xy += extrude;\n } else {\n gl_Position.xy += extrude * gl_Position.w;\n }\n\n // This is a minimum blur distance that serves as a faux-antialiasing for\n // the circle. since blur is a ratio of the circle's size and the intent is\n // to keep the blur at roughly 1px, the two are inversely related.\n v_antialiasblur = 1.0 / u_devicepixelratio / radius;\n}\n"
},
line: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform lowp vec4 u_color;\nuniform lowp float u_opacity;\nuniform float u_blur;\n\nvarying vec2 v_linewidth;\nvarying vec2 v_normal;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * v_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\n\n gl_FragColor = u_color * (alpha * u_opacity);\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform mat4 u_matrix;\nuniform mediump float u_ratio;\nuniform mediump float u_linewidth;\nuniform mediump float u_gapwidth;\nuniform mediump float u_antialiasing;\nuniform mediump float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform mediump float u_offset;\nuniform mediump float u_blur;\n\nvarying vec2 v_normal;\nvarying vec2 v_linewidth;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy - 128.0;\n float a_direction = mod(a_data.z, 4.0) - 1.0;\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n mediump vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n mediump vec2 dist = outset * a_extrude * scale;\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n mediump float u = 0.5 * a_direction;\n mediump float t = 1.0 - abs(u);\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_linewidth = vec2(outset, inset);\n v_gamma_scale = perspective_scale * squish_scale;\n}\n"
},
linepattern: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform float u_blur;\n\nuniform vec2 u_pattern_size_a;\nuniform vec2 u_pattern_size_b;\nuniform vec2 u_pattern_tl_a;\nuniform vec2 u_pattern_br_a;\nuniform vec2 u_pattern_tl_b;\nuniform vec2 u_pattern_br_b;\nuniform float u_fade;\nuniform float u_opacity;\n\nuniform sampler2D u_image;\n\nvarying vec2 v_normal;\nvarying vec2 v_linewidth;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * v_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\n\n float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0);\n float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0);\n float y_a = 0.5 + (v_normal.y * v_linewidth.s / u_pattern_size_a.y);\n float y_b = 0.5 + (v_normal.y * v_linewidth.s / u_pattern_size_b.y);\n vec2 pos_a = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a));\n vec2 pos_b = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b));\n\n vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade);\n\n alpha *= u_opacity;\n\n gl_FragColor = color * alpha;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\n// We scale the distance before adding it to the buffers so that we can store\n// long distances for long segments. Use this value to unscale the distance.\n#define LINE_DISTANCE_SCALE 2.0\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform mat4 u_matrix;\nuniform mediump float u_ratio;\nuniform mediump float u_linewidth;\nuniform mediump float u_gapwidth;\nuniform mediump float u_antialiasing;\nuniform mediump float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform mediump float u_offset;\n\nvarying vec2 v_normal;\nvarying vec2 v_linewidth;\nvarying float v_linesofar;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy - 128.0;\n float a_direction = mod(a_data.z, 4.0) - 1.0;\n float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n mediump vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n mediump vec2 dist = outset * a_extrude * scale;\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n mediump float u = 0.5 * a_direction;\n mediump float t = 1.0 - abs(u);\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\n v_linesofar = a_linesofar;\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_linewidth = vec2(outset, inset);\n v_gamma_scale = perspective_scale * squish_scale;\n}\n"
},
linesdfpattern: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform lowp vec4 u_color;\nuniform lowp float u_opacity;\n\nuniform float u_blur;\nuniform sampler2D u_image;\nuniform float u_sdfgamma;\nuniform float u_mix;\n\nvarying vec2 v_normal;\nvarying vec2 v_linewidth;\nvarying vec2 v_tex_a;\nvarying vec2 v_tex_b;\nvarying float v_gamma_scale;\n\nvoid main() {\n // Calculate the distance of the pixel from the line in pixels.\n float dist = length(v_normal) * v_linewidth.s;\n\n // Calculate the antialiasing fade factor. This is either when fading in\n // the line in case of an offset line (v_linewidth.t) or when fading out\n // (v_linewidth.s)\n float blur = u_blur * v_gamma_scale;\n float alpha = clamp(min(dist - (v_linewidth.t - blur), v_linewidth.s - dist) / blur, 0.0, 1.0);\n\n float sdfdist_a = texture2D(u_image, v_tex_a).a;\n float sdfdist_b = texture2D(u_image, v_tex_b).a;\n float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);\n alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);\n\n gl_FragColor = u_color * (alpha * u_opacity);\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n// floor(127 / 2) == 63.0\n// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is\n// stored in a byte (-128..127). we scale regular normals up to length 63, but\n// there are also \"special\" normals that have a bigger length (of up to 126 in\n// this case).\n// #define scale 63.0\n#define scale 0.015873016\n\n// We scale the distance before adding it to the buffers so that we can store\n// long distances for long segments. Use this value to unscale the distance.\n#define LINE_DISTANCE_SCALE 2.0\n\nattribute vec2 a_pos;\nattribute vec4 a_data;\n\nuniform mat4 u_matrix;\nuniform mediump float u_ratio;\nuniform mediump float u_linewidth;\nuniform mediump float u_gapwidth;\nuniform mediump float u_antialiasing;\nuniform vec2 u_patternscale_a;\nuniform float u_tex_y_a;\nuniform vec2 u_patternscale_b;\nuniform float u_tex_y_b;\nuniform float u_extra;\nuniform mat2 u_antialiasingmatrix;\nuniform mediump float u_offset;\n\nvarying vec2 v_normal;\nvarying vec2 v_linewidth;\nvarying vec2 v_tex_a;\nvarying vec2 v_tex_b;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_extrude = a_data.xy - 128.0;\n float a_direction = mod(a_data.z, 4.0) - 1.0;\n float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;\n\n // We store the texture normals in the most insignificant bit\n // transform y so that 0 => -1 and 1 => 1\n // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap\n // y is 1 if the normal points up, and -1 if it points down\n mediump vec2 normal = mod(a_pos, 2.0);\n normal.y = sign(normal.y - 0.5);\n v_normal = normal;\n\n float inset = u_gapwidth + (u_gapwidth > 0.0 ? u_antialiasing : 0.0);\n float outset = u_gapwidth + u_linewidth * (u_gapwidth > 0.0 ? 2.0 : 1.0) + u_antialiasing;\n\n // Scale the extrusion vector down to a normal and then up by the line width\n // of this vertex.\n mediump vec2 dist = outset * a_extrude * scale;\n\n // Calculate the offset when drawing a line that is to the side of the actual line.\n // We do this by creating a vector that points towards the extrude, but rotate\n // it when we're drawing round end points (a_direction = -1 or 1) since their\n // extrude vector points in another direction.\n mediump float u = 0.5 * a_direction;\n mediump float t = 1.0 - abs(u);\n mediump vec2 offset = u_offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);\n\n // Remove the texture normal bit of the position before scaling it with the\n // model/view matrix.\n gl_Position = u_matrix * vec4(floor(a_pos * 0.5) + (offset + dist) / u_ratio, 0.0, 1.0);\n\n v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);\n v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);\n\n // position of y on the screen\n float y = gl_Position.y / gl_Position.w;\n\n // how much features are squished in the y direction by the tilt\n float squish_scale = length(a_extrude) / length(u_antialiasingmatrix * a_extrude);\n\n // how much features are squished in all directions by the perspectiveness\n float perspective_scale = 1.0 / (1.0 - min(y * u_extra, 0.9));\n\n v_linewidth = vec2(outset, inset);\n v_gamma_scale = perspective_scale * squish_scale;\n}\n"
},
outline: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\n#pragma mapbox: define lowp vec4 outline_color\n#pragma mapbox: define lowp float opacity\n\nvarying vec2 v_pos;\n\nvoid main() {\n #pragma mapbox: initialize lowp vec4 outline_color\n #pragma mapbox: initialize lowp float opacity\n\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n gl_FragColor = outline_color * (alpha * opacity);\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos;\n\n#pragma mapbox: define lowp vec4 outline_color\n#pragma mapbox: define lowp float opacity\n\nvoid main() {\n #pragma mapbox: initialize lowp vec4 outline_color\n #pragma mapbox: initialize lowp float opacity\n\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;\n}\n"
},
outlinepattern: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform float u_opacity;\nuniform vec2 u_pattern_tl_a;\nuniform vec2 u_pattern_br_a;\nuniform vec2 u_pattern_tl_b;\nuniform vec2 u_pattern_br_b;\nuniform float u_mix;\n\nuniform sampler2D u_image;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\nvarying vec2 v_pos;\n\nvoid main() {\n vec2 imagecoord = mod(v_pos_a, 1.0);\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);\n vec4 color1 = texture2D(u_image, pos);\n\n vec2 imagecoord_b = mod(v_pos_b, 1.0);\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);\n vec4 color2 = texture2D(u_image, pos2);\n\n // find distance to outline for alpha interpolation\n\n float dist = length(v_pos - gl_FragCoord.xy);\n float alpha = smoothstep(1.0, 0.0, dist);\n \n\n gl_FragColor = mix(color1, color2, u_mix) * alpha * u_opacity;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform vec2 u_pattern_size_a;\nuniform vec2 u_pattern_size_b;\nuniform vec2 u_pixel_coord_upper;\nuniform vec2 u_pixel_coord_lower;\nuniform float u_scale_a;\nuniform float u_scale_b;\nuniform float u_tile_units_to_pixels;\n\nattribute vec2 a_pos;\n\nuniform mat4 u_matrix;\nuniform vec2 u_world;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\nvarying vec2 v_pos;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n vec2 scaled_size_a = u_scale_a * u_pattern_size_a;\n vec2 scaled_size_b = u_scale_b * u_pattern_size_b;\n\n // the correct offset needs to be calculated.\n //\n // The offset depends on how many pixels are between the world origin and\n // the edge of the tile:\n // vec2 offset = mod(pixel_coord, size)\n //\n // At high zoom levels there are a ton of pixels between the world origin\n // and the edge of the tile. The glsl spec only guarantees 16 bits of\n // precision for highp floats. We need more than that.\n //\n // The pixel_coord is passed in as two 16 bit values:\n // pixel_coord_upper = floor(pixel_coord / 2^16)\n // pixel_coord_lower = mod(pixel_coord, 2^16)\n //\n // The offset is calculated in a series of steps that should preserve this precision:\n vec2 offset_a = mod(mod(mod(u_pixel_coord_upper, scaled_size_a) * 256.0, scaled_size_a) * 256.0 + u_pixel_coord_lower, scaled_size_a);\n vec2 offset_b = mod(mod(mod(u_pixel_coord_upper, scaled_size_b) * 256.0, scaled_size_b) * 256.0 + u_pixel_coord_lower, scaled_size_b);\n\n v_pos_a = (u_tile_units_to_pixels * a_pos + offset_a) / scaled_size_a;\n v_pos_b = (u_tile_units_to_pixels * a_pos + offset_b) / scaled_size_b;\n\n v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;\n}\n"
},
pattern: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform float u_opacity;\nuniform vec2 u_pattern_tl_a;\nuniform vec2 u_pattern_br_a;\nuniform vec2 u_pattern_tl_b;\nuniform vec2 u_pattern_br_b;\nuniform float u_mix;\n\nuniform sampler2D u_image;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\n\nvoid main() {\n\n vec2 imagecoord = mod(v_pos_a, 1.0);\n vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);\n vec4 color1 = texture2D(u_image, pos);\n\n vec2 imagecoord_b = mod(v_pos_b, 1.0);\n vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);\n vec4 color2 = texture2D(u_image, pos2);\n\n gl_FragColor = mix(color1, color2, u_mix) * u_opacity;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform mat4 u_matrix;\nuniform vec2 u_pattern_size_a;\nuniform vec2 u_pattern_size_b;\nuniform vec2 u_pixel_coord_upper;\nuniform vec2 u_pixel_coord_lower;\nuniform float u_scale_a;\nuniform float u_scale_b;\nuniform float u_tile_units_to_pixels;\n\nattribute vec2 a_pos;\n\nvarying vec2 v_pos_a;\nvarying vec2 v_pos_b;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n vec2 scaled_size_a = u_scale_a * u_pattern_size_a;\n vec2 scaled_size_b = u_scale_b * u_pattern_size_b;\n\n // the correct offset needs to be calculated.\n //\n // The offset depends on how many pixels are between the world origin and\n // the edge of the tile:\n // vec2 offset = mod(pixel_coord, size)\n //\n // At high zoom levels there are a ton of pixels between the world origin\n // and the edge of the tile. The glsl spec only guarantees 16 bits of\n // precision for highp floats. We need more than that.\n //\n // The pixel_coord is passed in as two 16 bit values:\n // pixel_coord_upper = floor(pixel_coord / 2^16)\n // pixel_coord_lower = mod(pixel_coord, 2^16)\n //\n // The offset is calculated in a series of steps that should preserve this precision:\n vec2 offset_a = mod(mod(mod(u_pixel_coord_upper, scaled_size_a) * 256.0, scaled_size_a) * 256.0 + u_pixel_coord_lower, scaled_size_a);\n vec2 offset_b = mod(mod(mod(u_pixel_coord_upper, scaled_size_b) * 256.0, scaled_size_b) * 256.0 + u_pixel_coord_lower, scaled_size_b);\n\n v_pos_a = (u_tile_units_to_pixels * a_pos + offset_a) / scaled_size_a;\n v_pos_b = (u_tile_units_to_pixels * a_pos + offset_b) / scaled_size_b;\n}\n"
},
raster: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform float u_opacity0;\nuniform float u_opacity1;\nuniform sampler2D u_image0;\nuniform sampler2D u_image1;\nvarying vec2 v_pos0;\nvarying vec2 v_pos1;\n\nuniform float u_brightness_low;\nuniform float u_brightness_high;\n\nuniform float u_saturation_factor;\nuniform float u_contrast_factor;\nuniform vec3 u_spin_weights;\n\nvoid main() {\n\n // read and cross-fade colors from the main and parent tiles\n vec4 color0 = texture2D(u_image0, v_pos0);\n vec4 color1 = texture2D(u_image1, v_pos1);\n vec4 color = color0 * u_opacity0 + color1 * u_opacity1;\n vec3 rgb = color.rgb;\n\n // spin\n rgb = vec3(\n dot(rgb, u_spin_weights.xyz),\n dot(rgb, u_spin_weights.zxy),\n dot(rgb, u_spin_weights.yzx));\n\n // saturation\n float average = (color.r + color.g + color.b) / 3.0;\n rgb += (average - rgb) * u_saturation_factor;\n\n // contrast\n rgb = (rgb - 0.5) * u_contrast_factor + 0.5;\n\n // brightness\n vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low);\n vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high);\n\n gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb), color.a);\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform mat4 u_matrix;\nuniform vec2 u_tl_parent;\nuniform float u_scale_parent;\nuniform float u_buffer_scale;\n\nattribute vec2 a_pos;\nattribute vec2 a_texture_pos;\n\nvarying vec2 v_pos0;\nvarying vec2 v_pos1;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos, 0, 1);\n v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5;\n v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent;\n}\n"
},
icon: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform sampler2D u_texture;\nuniform sampler2D u_fadetexture;\nuniform lowp float u_opacity;\n\nvarying vec2 v_tex;\nvarying vec2 v_fade_tex;\n\nvoid main() {\n lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * u_opacity;\n gl_FragColor = texture2D(u_texture, v_tex) * alpha;\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec2 a_texture_pos;\nattribute vec4 a_data;\n\n\n// matrix is for the vertex position.\nuniform mat4 u_matrix;\n\nuniform mediump float u_zoom;\nuniform bool u_rotate_with_map;\nuniform vec2 u_extrude_scale;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying vec2 v_fade_tex;\n\nvoid main() {\n vec2 a_tex = a_texture_pos.xy;\n mediump float a_labelminzoom = a_data[0];\n mediump vec2 a_zoom = a_data.pq;\n mediump float a_minzoom = a_zoom[0];\n mediump float a_maxzoom = a_zoom[1];\n\n // u_zoom is the current zoom level adjusted for the change in font size\n mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\n\n vec2 extrude = u_extrude_scale * (a_offset / 64.0);\n if (u_rotate_with_map) {\n gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);\n gl_Position.z += z * gl_Position.w;\n } else {\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\n }\n\n v_tex = a_tex / u_texsize;\n v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);\n}\n"
},
sdf: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform sampler2D u_texture;\nuniform sampler2D u_fadetexture;\nuniform lowp vec4 u_color;\nuniform lowp float u_opacity;\nuniform lowp float u_buffer;\nuniform lowp float u_gamma;\n\nvarying vec2 v_tex;\nvarying vec2 v_fade_tex;\nvarying float v_gamma_scale;\n\nvoid main() {\n lowp float dist = texture2D(u_texture, v_tex).a;\n lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;\n lowp float gamma = u_gamma * v_gamma_scale;\n lowp float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * fade_alpha;\n\n gl_FragColor = u_color * (alpha * u_opacity);\n\n#ifdef OVERDRAW_INSPECTOR\n gl_FragColor = vec4(1.0);\n#endif\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nconst float PI = 3.141592653589793;\n\nattribute vec2 a_pos;\nattribute vec2 a_offset;\nattribute vec2 a_texture_pos;\nattribute vec4 a_data;\n\n\n// matrix is for the vertex position.\nuniform mat4 u_matrix;\n\nuniform mediump float u_zoom;\nuniform bool u_rotate_with_map;\nuniform bool u_pitch_with_map;\nuniform mediump float u_pitch;\nuniform mediump float u_bearing;\nuniform mediump float u_aspect_ratio;\nuniform vec2 u_extrude_scale;\n\nuniform vec2 u_texsize;\n\nvarying vec2 v_tex;\nvarying vec2 v_fade_tex;\nvarying float v_gamma_scale;\n\nvoid main() {\n vec2 a_tex = a_texture_pos.xy;\n mediump float a_labelminzoom = a_data[0];\n mediump vec2 a_zoom = a_data.pq;\n mediump float a_minzoom = a_zoom[0];\n mediump float a_maxzoom = a_zoom[1];\n\n // u_zoom is the current zoom level adjusted for the change in font size\n mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));\n\n // pitch-alignment: map\n // rotation-alignment: map | viewport\n if (u_pitch_with_map) {\n lowp float angle = u_rotate_with_map ? (a_data[1] / 256.0 * 2.0 * PI) : u_bearing;\n lowp float asin = sin(angle);\n lowp float acos = cos(angle);\n mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);\n vec2 offset = RotationMatrix * a_offset;\n vec2 extrude = u_extrude_scale * (offset / 64.0);\n gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);\n gl_Position.z += z * gl_Position.w;\n // pitch-alignment: viewport\n // rotation-alignment: map\n } else if (u_rotate_with_map) {\n // foreshortening factor to apply on pitched maps\n // as a label goes from horizontal <=> vertical in angle\n // it goes from 0% foreshortening to up to around 70% foreshortening\n lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));\n\n lowp float lineangle = a_data[1] / 256.0 * 2.0 * PI;\n\n // use the lineangle to position points a,b along the line\n // project the points and calculate the label angle in projected space\n // this calculation allows labels to be rendered unskewed on pitched maps\n vec4 a = u_matrix * vec4(a_pos, 0, 1);\n vec4 b = u_matrix * vec4(a_pos + vec2(cos(lineangle),sin(lineangle)), 0, 1);\n lowp float angle = atan((b[1]/b[3] - a[1]/a[3])/u_aspect_ratio, b[0]/b[3] - a[0]/a[3]);\n lowp float asin = sin(angle);\n lowp float acos = cos(angle);\n mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);\n\n vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset);\n vec2 extrude = u_extrude_scale * (offset / 64.0);\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\n gl_Position.z += z * gl_Position.w;\n // pitch-alignment: viewport\n // rotation-alignment: viewport\n } else {\n vec2 extrude = u_extrude_scale * (a_offset / 64.0);\n gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);\n }\n\n v_gamma_scale = (gl_Position.w - 0.5);\n\n v_tex = a_tex / u_texsize;\n v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);\n}\n"
},
collisionbox: {
fragmentSource: "#ifdef GL_ES\nprecision mediump float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nuniform float u_zoom;\nuniform float u_maxzoom;\n\nvarying float v_max_zoom;\nvarying float v_placement_zoom;\n\nvoid main() {\n\n float alpha = 0.5;\n\n gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha;\n\n if (v_placement_zoom > u_zoom) {\n gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;\n }\n\n if (u_zoom >= v_max_zoom) {\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25;\n }\n\n if (v_placement_zoom >= u_maxzoom) {\n gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2;\n }\n}\n",
vertexSource: "#ifdef GL_ES\nprecision highp float;\n#else\n#define lowp\n#define mediump\n#define highp\n#endif\n\nattribute vec2 a_pos;\nattribute vec2 a_extrude;\nattribute vec2 a_data;\n\nuniform mat4 u_matrix;\nuniform float u_scale;\n\nvarying float v_max_zoom;\nvarying float v_placement_zoom;\n\nvoid main() {\n gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0);\n\n v_max_zoom = a_data.x;\n v_placement_zoom = a_data.y;\n}\n"
}
};
module.exports.util = "float evaluate_zoom_function_1(const vec4 values, const float t) {\n if (t < 1.0) {\n return mix(values[0], values[1], t);\n } else if (t < 2.0) {\n return mix(values[1], values[2], t - 1.0);\n } else {\n return mix(values[2], values[3], t - 2.0);\n }\n}\nvec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {\n if (t < 1.0) {\n return mix(value0, value1, t);\n } else if (t < 2.0) {\n return mix(value1, value2, t - 1.0);\n } else {\n return mix(value2, value3, t - 2.0);\n }\n}\n";
},{"path":468}],297:[function(require,module,exports){
'use strict';
var format = require('util').format;
function ValidationError(key, value /*, message, ...*/) {
this.message = (
(key ? key + ': ' : '') +
format.apply(format, Array.prototype.slice.call(arguments, 2))
);
if (value !== null && value !== undefined && value.__line__) {
this.line = value.__line__;
}
}
module.exports = ValidationError;
},{"util":541}],298:[function(require,module,exports){
'use strict';
module.exports = function (output) {
for (var i = 1; i < arguments.length; i++) {
var input = arguments[i];
for (var k in input) {
output[k] = input[k];
}
}
return output;
};
},{}],299:[function(require,module,exports){
'use strict';
module.exports = function getType(val) {
if (val instanceof Number) {
return 'number';
} else if (val instanceof String) {
return 'string';
} else if (val instanceof Boolean) {
return 'boolean';
} else if (Array.isArray(val)) {
return 'array';
} else if (val === null) {
return 'null';
} else {
return typeof val;
}
};
},{}],300:[function(require,module,exports){
'use strict';
// Turn jsonlint-lines-primitives objects into primitive objects
module.exports = function unbundle(value) {
if (value instanceof Number || value instanceof String || value instanceof Boolean) {
return value.valueOf();
} else {
return value;
}
};
},{}],301:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var getType = require('../util/get_type');
var extend = require('../util/extend');
// Main recursive validation function. Tracks:
//
// - key: string representing location of validation in style tree. Used only
// for more informative error reporting.
// - value: current value from style being evaluated. May be anything from a
// high level object that needs to be descended into deeper or a simple
// scalar value.
// - valueSpec: current spec being evaluated. Tracks value.
module.exports = function validate(options) {
var validateFunction = require('./validate_function');
var validateObject = require('./validate_object');
var VALIDATORS = {
'*': function() {
return [];
},
'array': require('./validate_array'),
'boolean': require('./validate_boolean'),
'number': require('./validate_number'),
'color': require('./validate_color'),
'constants': require('./validate_constants'),
'enum': require('./validate_enum'),
'filter': require('./validate_filter'),
'function': require('./validate_function'),
'layer': require('./validate_layer'),
'object': require('./validate_object'),
'source': require('./validate_source'),
'string': require('./validate_string')
};
var value = options.value;
var valueSpec = options.valueSpec;
var key = options.key;
var styleSpec = options.styleSpec;
var style = options.style;
if (getType(value) === 'string' && value[0] === '@') {
if (styleSpec.$version > 7) {
return [new ValidationError(key, value, 'constants have been deprecated as of v8')];
}
if (!(value in style.constants)) {
return [new ValidationError(key, value, 'constant "%s" not found', value)];
}
options = extend({}, options, { value: style.constants[value] });
}
if (valueSpec.function && getType(value) === 'object') {
return validateFunction(options);
} else if (valueSpec.type && VALIDATORS[valueSpec.type]) {
return VALIDATORS[valueSpec.type](options);
} else {
return validateObject(extend({}, options, {
valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec
}));
}
};
},{"../error/validation_error":297,"../util/extend":298,"../util/get_type":299,"./validate_array":302,"./validate_boolean":303,"./validate_color":304,"./validate_constants":305,"./validate_enum":306,"./validate_filter":307,"./validate_function":308,"./validate_layer":310,"./validate_number":312,"./validate_object":313,"./validate_source":315,"./validate_string":316}],302:[function(require,module,exports){
'use strict';
var getType = require('../util/get_type');
var validate = require('./validate');
var ValidationError = require('../error/validation_error');
module.exports = function validateArray(options) {
var array = options.value;
var arraySpec = options.valueSpec;
var style = options.style;
var styleSpec = options.styleSpec;
var key = options.key;
var validateArrayElement = options.arrayElementValidator || validate;
if (getType(array) !== 'array') {
return [new ValidationError(key, array, 'array expected, %s found', getType(array))];
}
if (arraySpec.length && array.length !== arraySpec.length) {
return [new ValidationError(key, array, 'array length %d expected, length %d found', arraySpec.length, array.length)];
}
if (arraySpec['min-length'] && array.length < arraySpec['min-length']) {
return [new ValidationError(key, array, 'array length at least %d expected, length %d found', arraySpec['min-length'], array.length)];
}
var arrayElementSpec = {
"type": arraySpec.value
};
if (styleSpec.$version < 7) {
arrayElementSpec.function = arraySpec.function;
}
if (getType(arraySpec.value) === 'object') {
arrayElementSpec = arraySpec.value;
}
var errors = [];
for (var i = 0; i < array.length; i++) {
errors = errors.concat(validateArrayElement({
array: array,
arrayIndex: i,
value: array[i],
valueSpec: arrayElementSpec,
style: style,
styleSpec: styleSpec,
key: key + '[' + i + ']'
}));
}
return errors;
};
},{"../error/validation_error":297,"../util/get_type":299,"./validate":301}],303:[function(require,module,exports){
'use strict';
var getType = require('../util/get_type');
var ValidationError = require('../error/validation_error');
module.exports = function validateBoolean(options) {
var value = options.value;
var key = options.key;
var type = getType(value);
if (type !== 'boolean') {
return [new ValidationError(key, value, 'boolean expected, %s found', type)];
}
return [];
};
},{"../error/validation_error":297,"../util/get_type":299}],304:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var getType = require('../util/get_type');
var parseCSSColor = require('csscolorparser').parseCSSColor;
module.exports = function validateColor(options) {
var key = options.key;
var value = options.value;
var type = getType(value);
if (type !== 'string') {
return [new ValidationError(key, value, 'color expected, %s found', type)];
}
if (parseCSSColor(value) === null) {
return [new ValidationError(key, value, 'color expected, "%s" found', value)];
}
return [];
};
},{"../error/validation_error":297,"../util/get_type":299,"csscolorparser":104}],305:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var getType = require('../util/get_type');
module.exports = function validateConstants(options) {
var key = options.key;
var constants = options.value;
var styleSpec = options.styleSpec;
if (styleSpec.$version > 7) {
if (constants) {
return [new ValidationError(key, constants, 'constants have been deprecated as of v8')];
} else {
return [];
}
} else {
var type = getType(constants);
if (type !== 'object') {
return [new ValidationError(key, constants, 'object expected, %s found', type)];
}
var errors = [];
for (var constantName in constants) {
if (constantName[0] !== '@') {
errors.push(new ValidationError(key + '.' + constantName, constants[constantName], 'constants must start with "@"'));
}
}
return errors;
}
};
},{"../error/validation_error":297,"../util/get_type":299}],306:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var unbundle = require('../util/unbundle_jsonlint');
module.exports = function validateEnum(options) {
var key = options.key;
var value = options.value;
var valueSpec = options.valueSpec;
var errors = [];
if (valueSpec.values.indexOf(unbundle(value)) === -1) {
errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', valueSpec.values.join(', '), value));
}
return errors;
};
},{"../error/validation_error":297,"../util/unbundle_jsonlint":300}],307:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var validateEnum = require('./validate_enum');
var getType = require('../util/get_type');
var unbundle = require('../util/unbundle_jsonlint');
module.exports = function validateFilter(options) {
var value = options.value;
var key = options.key;
var styleSpec = options.styleSpec;
var type;
var errors = [];
if (getType(value) !== 'array') {
return [new ValidationError(key, value, 'array expected, %s found', getType(value))];
}
if (value.length < 1) {
return [new ValidationError(key, value, 'filter array must have at least 1 element')];
}
errors = errors.concat(validateEnum({
key: key + '[0]',
value: value[0],
valueSpec: styleSpec.filter_operator,
style: options.style,
styleSpec: options.styleSpec
}));
switch (unbundle(value[0])) {
case '<':
case '<=':
case '>':
case '>=':
if (value.length >= 2 && value[1] == '$type') {
errors.push(new ValidationError(key, value, '"$type" cannot be use with operator "%s"', value[0]));
}
/* falls through */
case '==':
case '!=':
if (value.length != 3) {
errors.push(new ValidationError(key, value, 'filter array for operator "%s" must have 3 elements', value[0]));
}
/* falls through */
case 'in':
case '!in':
if (value.length >= 2) {
type = getType(value[1]);
if (type !== 'string') {
errors.push(new ValidationError(key + '[1]', value[1], 'string expected, %s found', type));
} else if (value[1][0] === '@') {
errors.push(new ValidationError(key + '[1]', value[1], 'filter key cannot be a constant'));
}
}
for (var i = 2; i < value.length; i++) {
type = getType(value[i]);
if (value[1] == '$type') {
errors = errors.concat(validateEnum({
key: key + '[' + i + ']',
value: value[i],
valueSpec: styleSpec.geometry_type,
style: options.style,
styleSpec: options.styleSpec
}));
} else if (type === 'string' && value[i][0] === '@') {
errors.push(new ValidationError(key + '[' + i + ']', value[i], 'filter value cannot be a constant'));
} else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
errors.push(new ValidationError(key + '[' + i + ']', value[i], 'string, number, or boolean expected, %s found', type));
}
}
break;
case 'any':
case 'all':
case 'none':
for (i = 1; i < value.length; i++) {
errors = errors.concat(validateFilter({
key: key + '[' + i + ']',
value: value[i],
style: options.style,
styleSpec: options.styleSpec
}));
}
break;
case 'has':
case '!has':
type = getType(value[1]);
if (value.length !== 2) {
errors.push(new ValidationError(key, value, 'filter array for "%s" operator must have 2 elements', value[0]));
} else if (type !== 'string') {
errors.push(new ValidationError(key + '[1]', value[1], 'string expected, %s found', type));
} else if (value[1][0] === '@') {
errors.push(new ValidationError(key + '[1]', value[1], 'filter key cannot be a constant'));
}
break;
}
return errors;
};
},{"../error/validation_error":297,"../util/get_type":299,"../util/unbundle_jsonlint":300,"./validate_enum":306}],308:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var getType = require('../util/get_type');
var validate = require('./validate');
var validateObject = require('./validate_object');
var validateArray = require('./validate_array');
var validateNumber = require('./validate_number');
module.exports = function validateFunction(options) {
var functionValueSpec = options.valueSpec;
var stopKeyType;
var isPropertyFunction = options.value.property !== undefined || stopKeyType === 'object';
var isZoomFunction = options.value.property === undefined || stopKeyType === 'object';
var errors = validateObject({
key: options.key,
value: options.value,
valueSpec: options.styleSpec.function,
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: { stops: validateFunctionStops }
});
if (options.styleSpec.$version >= 8) {
if (isPropertyFunction && !options.valueSpec['property-function']) {
errors.push(new ValidationError(options.key, options.value, 'property functions not supported'));
} else if (isZoomFunction && !options.valueSpec['zoom-function']) {
errors.push(new ValidationError(options.key, options.value, 'zoom functions not supported'));
}
}
return errors;
function validateFunctionStops(options) {
var errors = [];
var value = options.value;
errors = errors.concat(validateArray({
key: options.key,
value: value,
valueSpec: options.valueSpec,
style: options.style,
styleSpec: options.styleSpec,
arrayElementValidator: validateFunctionStop
}));
if (getType(value) === 'array' && value.length === 0) {
errors.push(new ValidationError(options.key, value, 'array must have at least one stop'));
}
return errors;
}
function validateFunctionStop(options) {
var errors = [];
var value = options.value;
var key = options.key;
if (getType(value) !== 'array') {
return [new ValidationError(key, value, 'array expected, %s found', getType(value))];
}
if (value.length !== 2) {
return [new ValidationError(key, value, 'array length %d expected, length %d found', 2, value.length)];
}
var type = getType(value[0]);
if (!stopKeyType) stopKeyType = type;
if (type !== stopKeyType) {
return [new ValidationError(key, value, '%s stop key type must match previous stop key type %s', type, stopKeyType)];
}
if (type === 'object') {
if (value[0].zoom === undefined) {
return [new ValidationError(key, value, 'object stop key must have zoom')];
}
if (value[0].value === undefined) {
return [new ValidationError(key, value, 'object stop key must have value')];
}
errors = errors.concat(validateObject({
key: key + '[0]',
value: value[0],
valueSpec: { zoom: {} },
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: { zoom: validateNumber, value: validateValue }
}));
} else {
errors = errors.concat((isZoomFunction ? validateNumber : validateValue)({
key: key + '[0]',
value: value[0],
valueSpec: {},
style: options.style,
styleSpec: options.styleSpec
}));
}
errors = errors.concat(validate({
key: key + '[1]',
value: value[1],
valueSpec: functionValueSpec,
style: options.style,
styleSpec: options.styleSpec
}));
if (getType(value[0]) === 'number') {
if (functionValueSpec.function === 'piecewise-constant' && value[0] % 1 !== 0) {
errors.push(new ValidationError(key + '[0]', value[0], 'zoom level for piecewise-constant functions must be an integer'));
}
if (options.arrayIndex !== 0) {
if (value[0] < options.array[options.arrayIndex - 1][0]) {
errors.push(new ValidationError(key + '[0]', value[0], 'array stops must appear in ascending order'));
}
}
}
return errors;
}
function validateValue(options) {
var errors = [];
var type = getType(options.value);
if (type !== 'number' && type !== 'string' && type !== 'array') {
errors.push(new ValidationError(options.key, options.value, 'property value must be a number, string or array'));
}
return errors;
}
};
},{"../error/validation_error":297,"../util/get_type":299,"./validate":301,"./validate_array":302,"./validate_number":312,"./validate_object":313}],309:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var validateString = require('./validate_string');
module.exports = function(options) {
var value = options.value;
var key = options.key;
var errors = validateString(options);
if (errors.length) return errors;
if (value.indexOf('{fontstack}') === -1) {
errors.push(new ValidationError(key, value, '"glyphs" url must include a "{fontstack}" token'));
}
if (value.indexOf('{range}') === -1) {
errors.push(new ValidationError(key, value, '"glyphs" url must include a "{range}" token'));
}
return errors;
};
},{"../error/validation_error":297,"./validate_string":316}],310:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var unbundle = require('../util/unbundle_jsonlint');
var validateObject = require('./validate_object');
var validateFilter = require('./validate_filter');
var validatePaintProperty = require('./validate_paint_property');
var validateLayoutProperty = require('./validate_layout_property');
var extend = require('../util/extend');
module.exports = function validateLayer(options) {
var errors = [];
var layer = options.value;
var key = options.key;
var style = options.style;
var styleSpec = options.styleSpec;
if (!layer.type && !layer.ref) {
errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required'));
}
var type = unbundle(layer.type);
var ref = unbundle(layer.ref);
if (layer.id) {
for (var i = 0; i < options.arrayIndex; i++) {
var otherLayer = style.layers[i];
if (unbundle(otherLayer.id) === unbundle(layer.id)) {
errors.push(new ValidationError(key, layer.id, 'duplicate layer id "%s", previously used at line %d', layer.id, otherLayer.id.__line__));
}
}
}
if ('ref' in layer) {
['type', 'source', 'source-layer', 'filter', 'layout'].forEach(function (p) {
if (p in layer) {
errors.push(new ValidationError(key, layer[p], '"%s" is prohibited for ref layers', p));
}
});
var parent;
style.layers.forEach(function(layer) {
if (layer.id == ref) parent = layer;
});
if (!parent) {
errors.push(new ValidationError(key, layer.ref, 'ref layer "%s" not found', ref));
} else if (parent.ref) {
errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
} else {
type = unbundle(parent.type);
}
} else if (type !== 'background') {
if (!layer.source) {
errors.push(new ValidationError(key, layer, 'missing required property "source"'));
} else {
var source = style.sources && style.sources[layer.source];
if (!source) {
errors.push(new ValidationError(key, layer.source, 'source "%s" not found', layer.source));
} else if (source.type == 'vector' && type == 'raster') {
errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a raster source', layer.id));
} else if (source.type == 'raster' && type != 'raster') {
errors.push(new ValidationError(key, layer.source, 'layer "%s" requires a vector source', layer.id));
} else if (source.type == 'vector' && !layer['source-layer']) {
errors.push(new ValidationError(key, layer, 'layer "%s" must specify a "source-layer"', layer.id));
}
}
}
errors = errors.concat(validateObject({
key: key,
value: layer,
valueSpec: styleSpec.layer,
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: {
filter: validateFilter,
layout: function(options) {
return validateObject({
layer: layer,
key: options.key,
value: options.value,
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: {
'*': function(options) {
return validateLayoutProperty(extend({layerType: type}, options));
}
}
});
},
paint: function(options) {
return validateObject({
layer: layer,
key: options.key,
value: options.value,
style: options.style,
styleSpec: options.styleSpec,
objectElementValidators: {
'*': function(options) {
return validatePaintProperty(extend({layerType: type}, options));
}
}
});
}
}
}));
return errors;
};
},{"../error/validation_error":297,"../util/extend":298,"../util/unbundle_jsonlint":300,"./validate_filter":307,"./validate_layout_property":311,"./validate_object":313,"./validate_paint_property":314}],311:[function(require,module,exports){
'use strict';
var validate = require('./validate');
var ValidationError = require('../error/validation_error');
module.exports = function validateLayoutProperty(options) {
var key = options.key;
var style = options.style;
var styleSpec = options.styleSpec;
var value = options.value;
var propertyKey = options.objectKey;
var layerSpec = styleSpec['layout_' + options.layerType];
if (options.valueSpec || layerSpec[propertyKey]) {
var errors = [];
if (options.layerType === 'symbol') {
if (propertyKey === 'icon-image' && style && !style.sprite) {
errors.push(new ValidationError(key, value, 'use of "icon-image" requires a style "sprite" property'));
} else if (propertyKey === 'text-field' && style && !style.glyphs) {
errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
}
}
return errors.concat(validate({
key: options.key,
value: value,
valueSpec: options.valueSpec || layerSpec[propertyKey],
style: style,
styleSpec: styleSpec
}));
} else {
return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)];
}
};
},{"../error/validation_error":297,"./validate":301}],312:[function(require,module,exports){
'use strict';
var getType = require('../util/get_type');
var ValidationError = require('../error/validation_error');
module.exports = function validateNumber(options) {
var key = options.key;
var value = options.value;
var valueSpec = options.valueSpec;
var type = getType(value);
if (type !== 'number') {
return [new ValidationError(key, value, 'number expected, %s found', type)];
}
if ('minimum' in valueSpec && value < valueSpec.minimum) {
return [new ValidationError(key, value, '%s is less than the minimum value %s', value, valueSpec.minimum)];
}
if ('maximum' in valueSpec && value > valueSpec.maximum) {
return [new ValidationError(key, value, '%s is greater than the maximum value %s', value, valueSpec.maximum)];
}
return [];
};
},{"../error/validation_error":297,"../util/get_type":299}],313:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var getType = require('../util/get_type');
var validate = require('./validate');
module.exports = function validateObject(options) {
var key = options.key;
var object = options.value;
var valueSpec = options.valueSpec;
var objectElementValidators = options.objectElementValidators || {};
var style = options.style;
var styleSpec = options.styleSpec;
var errors = [];
var type = getType(object);
if (type !== 'object') {
return [new ValidationError(key, object, 'object expected, %s found', type)];
}
for (var objectKey in object) {
var valueSpecKey = objectKey.split('.')[0]; // treat 'paint.*' as 'paint'
var objectElementSpec = valueSpec && (valueSpec[valueSpecKey] || valueSpec['*']);
var objectElementValidator = objectElementValidators[valueSpecKey] || objectElementValidators['*'];
if (objectElementSpec || objectElementValidator) {
errors = errors.concat((objectElementValidator || validate)({
key: (key ? key + '.' : key) + objectKey,
value: object[objectKey],
valueSpec: objectElementSpec,
style: style,
styleSpec: styleSpec,
object: object,
objectKey: objectKey
}));
// tolerate root-level extra keys & arbitrary layer properties
// TODO remove this layer-specific logic
} else if (key !== '' && key.split('.').length !== 1) {
errors.push(new ValidationError(key, object[objectKey], 'unknown property "%s"', objectKey));
}
}
for (valueSpecKey in valueSpec) {
if (valueSpec[valueSpecKey].required && valueSpec[valueSpecKey]['default'] === undefined && object[valueSpecKey] === undefined) {
errors.push(new ValidationError(key, object, 'missing required property "%s"', valueSpecKey));
}
}
return errors;
};
},{"../error/validation_error":297,"../util/get_type":299,"./validate":301}],314:[function(require,module,exports){
'use strict';
var validate = require('./validate');
var ValidationError = require('../error/validation_error');
module.exports = function validatePaintProperty(options) {
var key = options.key;
var style = options.style;
var styleSpec = options.styleSpec;
var value = options.value;
var propertyKey = options.objectKey;
var layerSpec = styleSpec['paint_' + options.layerType];
var transitionMatch = propertyKey.match(/^(.*)-transition$/);
if (transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) {
return validate({
key: key,
value: value,
valueSpec: styleSpec.transition,
style: style,
styleSpec: styleSpec
});
} else if (options.valueSpec || layerSpec[propertyKey]) {
return validate({
key: options.key,
value: value,
valueSpec: options.valueSpec || layerSpec[propertyKey],
style: style,
styleSpec: styleSpec
});
} else {
return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)];
}
};
},{"../error/validation_error":297,"./validate":301}],315:[function(require,module,exports){
'use strict';
var ValidationError = require('../error/validation_error');
var unbundle = require('../util/unbundle_jsonlint');
var validateObject = require('./validate_object');
var validateEnum = require('./validate_enum');
module.exports = function validateSource(options) {
var value = options.value;
var key = options.key;
var styleSpec = options.styleSpec;
var style = options.style;
if (!value.type) {
return [new ValidationError(key, value, '"type" is required')];
}
var type = unbundle(value.type);
switch (type) {
case 'vector':
case 'raster':
var errors = [];
errors = errors.concat(validateObject({
key: key,
value: value,
valueSpec: styleSpec.source_tile,
style: options.style,
styleSpec: styleSpec
}));
if ('url' in value) {
for (var prop in value) {
if (['type', 'url', 'tileSize'].indexOf(prop) < 0) {
errors.push(new ValidationError(key + '.' + prop, value[prop], 'a source with a "url" property may not include a "%s" property', prop));
}
}
}
return errors;
case 'geojson':
return validateObject({
key: key,
value: value,
valueSpec: styleSpec.source_geojson,
style: style,
styleSpec: styleSpec
});
case 'video':
return validateObject({
key: key,
value: value,
valueSpec: styleSpec.source_video,
style: style,
styleSpec: styleSpec
});
case 'image':
return validateObject({
key: key,
value: value,
valueSpec: styleSpec.source_image,
style: style,
styleSpec: styleSpec
});
default:
return validateEnum({
key: key + '.type',
value: value.type,
valueSpec: {values: ['vector', 'raster', 'geojson', 'video', 'image']},
style: style,
styleSpec: styleSpec
});
}
};
},{"../error/validation_error":297,"../util/unbundle_jsonlint":300,"./validate_enum":306,"./validate_object":313}],316:[function(require,module,exports){
'use strict';
var getType = require('../util/get_type');
var ValidationError = require('../error/validation_error');
module.exports = function validateString(options) {
var value = options.value;
var key = options.key;
var type = getType(value);
if (type !== 'string') {
return [new ValidationError(key, value, 'string expected, %s found', type)];
}
return [];
};
},{"../error/validation_error":297,"../util/get_type":299}],317:[function(require,module,exports){
'use strict';
var validateConstants = require('./validate/validate_constants');
var validate = require('./validate/validate');
var latestStyleSpec = require('../reference/latest.min');
var validateGlyphsURL = require('./validate/validate_glyphs_url');
/**
* Validate a Mapbox GL style against the style specification. This entrypoint,
* `mapbox-gl-style-spec/lib/validate_style.min`, is designed to produce as
* small a browserify bundle as possible by omitting unnecessary functionality
* and legacy style specifications.
*
* @param {Object} style The style to be validated.
* @param {Object} [styleSpec] The style specification to validate against.
* If omitted, the latest style spec is used.
* @returns {Array}
* @example
* var validate = require('mapbox-gl-style-spec/lib/validate_style.min');
* var errors = validate(style);
*/
function validateStyleMin(style, styleSpec) {
styleSpec = styleSpec || latestStyleSpec;
var errors = [];
errors = errors.concat(validate({
key: '',
value: style,
valueSpec: styleSpec.$root,
styleSpec: styleSpec,
style: style,
objectElementValidators: {
glyphs: validateGlyphsURL
}
}));
if (styleSpec.$version > 7 && style.constants) {
errors = errors.concat(validateConstants({
key: 'constants',
value: style.constants,
style: style,
styleSpec: styleSpec
}));
}
return sortErrors(errors);
}
validateStyleMin.source = wrapCleanErrors(require('./validate/validate_source'));
validateStyleMin.layer = wrapCleanErrors(require('./validate/validate_layer'));
validateStyleMin.filter = wrapCleanErrors(require('./validate/validate_filter'));
validateStyleMin.paintProperty = wrapCleanErrors(require('./validate/validate_paint_property'));
validateStyleMin.layoutProperty = wrapCleanErrors(require('./validate/validate_layout_property'));
function sortErrors(errors) {
return [].concat(errors).sort(function (a, b) {
return a.line - b.line;
});
}
function wrapCleanErrors(inner) {
return function() {
return sortErrors(inner.apply(this, arguments));
};
}
module.exports = validateStyleMin;
},{"../reference/latest.min":318,"./validate/validate":301,"./validate/validate_constants":305,"./validate/validate_filter":307,"./validate/validate_glyphs_url":309,"./validate/validate_layer":310,"./validate/validate_layout_property":311,"./validate/validate_paint_property":314,"./validate/validate_source":315}],318:[function(require,module,exports){
module.exports = require('./v8.min.json');
},{"./v8.min.json":319}],319:[function(require,module,exports){
module.exports={"$version":8,"$root":{"version":{"required":true,"type":"enum","values":[8]},"name":{"type":"string"},"metadata":{"type":"*"},"center":{"type":"array","value":"number"},"zoom":{"type":"number"},"bearing":{"type":"number","default":0,"period":360,"units":"degrees"},"pitch":{"type":"number","default":0,"units":"degrees"},"sources":{"required":true,"type":"sources"},"sprite":{"type":"string"},"glyphs":{"type":"string"},"transition":{"type":"transition"},"layers":{"required":true,"type":"array","value":"layer"}},"sources":{"*":{"type":"source"}},"source":["source_tile","source_geojson","source_video","source_image"],"source_tile":{"type":{"required":true,"type":"enum","values":["vector","raster"]},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"*":{"type":"*"}},"source_geojson":{"type":{"required":true,"type":"enum","values":["geojson"]},"data":{"type":"*"},"maxzoom":{"type":"number","default":14},"buffer":{"type":"number","default":64},"tolerance":{"type":"number","default":3},"cluster":{"type":"boolean","default":false},"clusterRadius":{"type":"number","default":400},"clusterMaxZoom":{"type":"number"}},"source_video":{"type":{"required":true,"type":"enum","values":["video"]},"urls":{"required":true,"type":"array","value":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"source_image":{"type":{"required":true,"type":"enum","values":["image"]},"url":{"required":true,"type":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"layer":{"id":{"type":"string","required":true},"type":{"type":"enum","values":["fill","line","symbol","circle","raster","background"]},"metadata":{"type":"*"},"ref":{"type":"string"},"source":{"type":"string"},"source-layer":{"type":"string"},"minzoom":{"type":"number","minimum":0,"maximum":22},"maxzoom":{"type":"number","minimum":0,"maximum":22},"interactive":{"type":"boolean","default":false},"filter":{"type":"filter"},"layout":{"type":"layout"},"paint":{"type":"paint"},"paint.*":{"type":"paint"}},"layout":["layout_fill","layout_line","layout_circle","layout_symbol","layout_raster","layout_background"],"layout_background":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_fill":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_circle":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_line":{"line-cap":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["butt","round","square"],"default":"butt"},"line-join":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["bevel","round","miter"],"default":"miter"},"line-miter-limit":{"type":"number","default":2,"function":"interpolated","zoom-function":true,"property-function":true,"requires":[{"line-join":"miter"}]},"line-round-limit":{"type":"number","default":1.05,"function":"interpolated","zoom-function":true,"property-function":true,"requires":[{"line-join":"round"}]},"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_symbol":{"symbol-placement":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["point","line"],"default":"point"},"symbol-spacing":{"type":"number","default":250,"minimum":1,"function":"interpolated","zoom-function":true,"property-function":true,"units":"pixels","requires":[{"symbol-placement":"line"}]},"symbol-avoid-edges":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false},"icon-allow-overlap":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image"]},"icon-ignore-placement":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image"]},"icon-optional":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image","text-field"]},"icon-rotation-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"viewport","requires":["icon-image"]},"icon-size":{"type":"number","default":1,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image"]},"icon-text-fit":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":false,"values":["none","both","width","height"],"default":"none","requires":["icon-image","text-field"]},"icon-text-fit-padding":{"type":"array","value":"number","length":4,"default":[0,0,0,0],"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image","icon-text-fit","text-field"]},"icon-image":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"tokens":true},"icon-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","zoom-function":true,"property-function":true,"units":"degrees","requires":["icon-image"]},"icon-padding":{"type":"number","default":2,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"units":"pixels","requires":["icon-image"]},"icon-keep-upright":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":"line"}]},"icon-offset":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"requires":["icon-image"]},"text-pitch-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"requires":["text-field"]},"text-rotation-alignment":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"viewport","requires":["text-field"]},"text-field":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":"","tokens":true},"text-font":{"type":"array","value":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":["Open Sans Regular","Arial Unicode MS Regular"],"requires":["text-field"]},"text-size":{"type":"number","default":16,"minimum":0,"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-max-width":{"type":"number","default":10,"minimum":0,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-line-height":{"type":"number","default":1.2,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-letter-spacing":{"type":"number","default":0,"units":"em","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-justify":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["left","center","right"],"default":"center","requires":["text-field"]},"text-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["center","left","right","top","bottom","top-left","top-right","bottom-left","bottom-right"],"default":"center","requires":["text-field"]},"text-max-angle":{"type":"number","default":45,"units":"degrees","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field",{"symbol-placement":"line"}]},"text-rotate":{"type":"number","default":0,"period":360,"units":"degrees","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","function":"interpolated","zoom-function":true,"property-function":true,"requires":["text-field"]},"text-keep-upright":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":true,"requires":["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":"line"}]},"text-transform":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["none","uppercase","lowercase"],"default":"none","requires":["text-field"]},"text-offset":{"type":"array","value":"number","units":"ems","function":"interpolated","zoom-function":true,"property-function":true,"length":2,"default":[0,0],"requires":["text-field"]},"text-allow-overlap":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field"]},"text-ignore-placement":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field"]},"text-optional":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":false,"requires":["text-field","icon-image"]},"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"layout_raster":{"visibility":{"type":"enum","function":"piecewise-constant","zoom-function":true,"values":["visible","none"],"default":"visible"}},"filter":{"type":"array","value":"*"},"filter_operator":{"type":"enum","values":["==","!=",">",">=","<","<=","in","!in","all","any","none","has","!has"]},"geometry_type":{"type":"enum","values":["Point","LineString","Polygon"]},"color_operation":{"type":"enum","values":["lighten","saturate","spin","fade","mix"]},"function":{"stops":{"type":"array","required":true,"value":"function_stop"},"base":{"type":"number","default":1,"minimum":0},"property":{"type":"string","default":"$zoom"},"type":{"type":"enum","values":["exponential","interval","categorical"],"default":"exponential"}},"function_stop":{"type":"array","minimum":0,"maximum":22,"value":["number","color"],"length":2},"paint":["paint_fill","paint_line","paint_circle","paint_symbol","paint_raster","paint_background"],"paint_fill":{"fill-antialias":{"type":"boolean","function":"piecewise-constant","zoom-function":true,"property-function":true,"default":true},"fill-opacity":{"type":"number","function":"interpolated","zoom-function":true,"property-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"fill-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"fill-pattern"}]},"fill-outline-color":{"type":"color","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"fill-pattern"},{"fill-antialias":true}]},"fill-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"fill-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["fill-translate"]},"fill-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"transition":true}},"paint_line":{"line-opacity":{"type":"number","function":"interpolated","zoom-function":true,"property-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"line-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":[{"!":"line-pattern"}]},"line-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["line-translate"]},"line-width":{"type":"number","default":1,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-gap-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-offset":{"type":"number","default":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"line-dasharray":{"type":"array","value":"number","function":"piecewise-constant","zoom-function":true,"property-function":true,"minimum":0,"transition":true,"units":"line widths","requires":[{"!":"line-pattern"}]},"line-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"property-function":true,"transition":true}},"paint_circle":{"circle-radius":{"type":"number","default":5,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"circle-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-blur":{"type":"number","default":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true},"circle-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels"},"circle-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["circle-translate"]},"circle-pitch-scale":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map"}},"paint_symbol":{"icon-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["icon-image"]},"icon-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["icon-image"]},"icon-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["icon-image","icon-translate"]},"text-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"requires":["text-field"]},"text-halo-width":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-halo-blur":{"type":"number","default":0,"minimum":0,"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-translate":{"type":"array","value":"number","length":2,"default":[0,0],"function":"interpolated","zoom-function":true,"property-function":true,"transition":true,"units":"pixels","requires":["text-field"]},"text-translate-anchor":{"type":"enum","function":"piecewise-constant","zoom-function":true,"property-function":true,"values":["map","viewport"],"default":"map","requires":["text-field","text-translate"]}},"paint_raster":{"raster-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-hue-rotate":{"type":"number","default":0,"period":360,"function":"interpolated","zoom-function":true,"transition":true,"units":"degrees"},"raster-brightness-min":{"type":"number","function":"interpolated","zoom-function":true,"default":0,"minimum":0,"maximum":1,"transition":true},"raster-brightness-max":{"type":"number","function":"interpolated","zoom-function":true,"default":1,"minimum":0,"maximum":1,"transition":true},"raster-saturation":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-contrast":{"type":"number","default":0,"minimum":-1,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true},"raster-fade-duration":{"type":"number","default":300,"minimum":0,"function":"interpolated","zoom-function":true,"transition":true,"units":"milliseconds"}},"paint_background":{"background-color":{"type":"color","default":"#000000","function":"interpolated","zoom-function":true,"transition":true,"requires":[{"!":"background-pattern"}]},"background-pattern":{"type":"string","function":"piecewise-constant","zoom-function":true,"transition":true},"background-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"function":"interpolated","zoom-function":true,"transition":true}},"transition":{"duration":{"type":"number","default":300,"minimum":0,"units":"milliseconds"},"delay":{"type":"number","default":0,"minimum":0,"units":"milliseconds"}}}
},{}],320:[function(require,module,exports){
'use strict';
if (typeof module !== 'undefined' && module.exports) {
module.exports = isSupported;
} else if (window) {
window.mapboxgl = window.mapboxgl || {};
window.mapboxgl.supported = isSupported;
}
/**
* Test whether the current browser supports Mapbox GL JS
* @param {Object} options
* @param {boolean} [options.failIfMajorPerformanceCaveat=false] Return `false`
* if the performance of Mapbox GL JS would be dramatically worse than
* expected (i.e. a software renderer is would be used)
* @return {boolean}
*/
function isSupported(options) {
return !!(
isBrowser() &&
isArraySupported() &&
isFunctionSupported() &&
isObjectSupported() &&
isJSONSupported() &&
isWorkerSupported() &&
isUint8ClampedArraySupported() &&
isWebGLSupportedCached(options && options.failIfMajorPerformanceCaveat)
);
}
function isBrowser() {
return typeof window !== 'undefined' && typeof document !== 'undefined';
}
function isArraySupported() {
return (
Array.prototype &&
Array.prototype.every &&
Array.prototype.filter &&
Array.prototype.forEach &&
Array.prototype.indexOf &&
Array.prototype.lastIndexOf &&
Array.prototype.map &&
Array.prototype.some &&
Array.prototype.reduce &&
Array.prototype.reduceRight &&
Array.isArray
);
}
function isFunctionSupported() {
return Function.prototype && Function.prototype.bind;
}
function isObjectSupported() {
return (
Object.keys &&
Object.create &&
Object.getPrototypeOf &&
Object.getOwnPropertyNames &&
Object.isSealed &&
Object.isFrozen &&
Object.isExtensible &&
Object.getOwnPropertyDescriptor &&
Object.defineProperty &&
Object.defineProperties &&
Object.seal &&
Object.freeze &&
Object.preventExtensions
);
}
function isJSONSupported() {
return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON;
}
function isWorkerSupported() {
return 'Worker' in window;
}
// IE11 only supports `Uint8ClampedArray` as of version
// [KB2929437](https://support.microsoft.com/en-us/kb/2929437)
function isUint8ClampedArraySupported() {
return 'Uint8ClampedArray' in window;
}
var isWebGLSupportedCache = {};
function isWebGLSupportedCached(failIfMajorPerformanceCaveat) {
if (isWebGLSupportedCache[failIfMajorPerformanceCaveat] === undefined) {
isWebGLSupportedCache[failIfMajorPerformanceCaveat] = isWebGLSupported(failIfMajorPerformanceCaveat);
}
return isWebGLSupportedCache[failIfMajorPerformanceCaveat];
}
isSupported.webGLContextAttributes = {
antialias: false,
alpha: true,
stencil: true,
depth: true
};
function isWebGLSupported(failIfMajorPerformanceCaveat) {
var canvas = document.createElement('canvas');
var attributes = Object.create(isSupported.webGLContextAttributes);
attributes.failIfMajorPerformanceCaveat = failIfMajorPerformanceCaveat;
if (canvas.probablySupportsContext) {
return (
canvas.probablySupportsContext('webgl', attributes) ||
canvas.probablySupportsContext('experimental-webgl', attributes)
);
} else if (canvas.supportsContext) {
return (
canvas.supportsContext('webgl', attributes) ||
canvas.supportsContext('experimental-webgl', attributes)
);
} else {
return (
canvas.getContext('webgl', attributes) ||
canvas.getContext('experimental-webgl', attributes)
);
}
}
},{}],321:[function(require,module,exports){
'use strict';
var util = require('../util/util');
module.exports = ArrayGroup;
/**
* A class that manages vertex and element arrays for a range of features. It handles initialization,
* serialization for transfer to the main thread, and certain intervening mutations.
*
* Array elements are broken into array groups based on inherent limits of WebGL. Within a group is:
*
* * A "layout" vertex array, with fixed layout, containing values calculated from layout properties.
* * Zero, one, or two element arrays, with fixed layout, typically for eventual use in
* `gl.drawElements(gl.TRIANGLES, ...)`.
* * Zero or more "paint" vertex arrays keyed by layer ID, each with a dynamic layout which depends
* on which paint properties of that layer use data-driven-functions (property functions or
* property-and-zoom functions). Values are calculated by evaluating those functions.
*
* @private
*/
function ArrayGroup(arrayTypes) {
var LayoutVertexArrayType = arrayTypes.layoutVertexArrayType;
this.layoutVertexArray = new LayoutVertexArrayType();
var ElementArrayType = arrayTypes.elementArrayType;
if (ElementArrayType) this.elementArray = new ElementArrayType();
var ElementArrayType2 = arrayTypes.elementArrayType2;
if (ElementArrayType2) this.elementArray2 = new ElementArrayType2();
this.paintVertexArrays = util.mapObject(arrayTypes.paintVertexArrayTypes, function (PaintVertexArrayType) {
return new PaintVertexArrayType();
});
}
/**
* The maximum size of a vertex array. This limit is imposed by WebGL's 16 bit
* addressing of vertex buffers.
* @private
* @readonly
*/
ArrayGroup.MAX_VERTEX_ARRAY_LENGTH = Math.pow(2, 16) - 1;
ArrayGroup.prototype.hasCapacityFor = function(numVertices) {
return this.layoutVertexArray.length + numVertices <= ArrayGroup.MAX_VERTEX_ARRAY_LENGTH;
};
ArrayGroup.prototype.isEmpty = function() {
return this.layoutVertexArray.length === 0;
};
ArrayGroup.prototype.trim = function() {
this.layoutVertexArray.trim();
if (this.elementArray) {
this.elementArray.trim();
}
if (this.elementArray2) {
this.elementArray2.trim();
}
for (var layerName in this.paintVertexArrays) {
this.paintVertexArrays[layerName].trim();
}
};
ArrayGroup.prototype.serialize = function() {
return {
layoutVertexArray: this.layoutVertexArray.serialize(),
elementArray: this.elementArray && this.elementArray.serialize(),
elementArray2: this.elementArray2 && this.elementArray2.serialize(),
paintVertexArrays: util.mapObject(this.paintVertexArrays, function(array) {
return array.serialize();
})
};
};
ArrayGroup.prototype.getTransferables = function(transferables) {
transferables.push(this.layoutVertexArray.arrayBuffer);
if (this.elementArray) {
transferables.push(this.elementArray.arrayBuffer);
}
if (this.elementArray2) {
transferables.push(this.elementArray2.arrayBuffer);
}
for (var layerName in this.paintVertexArrays) {
transferables.push(this.paintVertexArrays[layerName].arrayBuffer);
}
};
},{"../util/util":435}],322:[function(require,module,exports){
'use strict';
var featureFilter = require('feature-filter');
var ArrayGroup = require('./array_group');
var BufferGroup = require('./buffer_group');
var util = require('../util/util');
var StructArrayType = require('../util/struct_array');
var assert = require('assert');
module.exports = Bucket;
/**
* Instantiate the appropriate subclass of `Bucket` for `options`.
* @private
* @param options See `Bucket` constructor options
* @returns {Bucket}
*/
Bucket.create = function(options) {
var Classes = {
fill: require('./bucket/fill_bucket'),
line: require('./bucket/line_bucket'),
circle: require('./bucket/circle_bucket'),
symbol: require('./bucket/symbol_bucket')
};
return new Classes[options.layer.type](options);
};
/**
* The maximum extent of a feature that can be safely stored in the buffer.
* In practice, all features are converted to this extent before being added.
*
* Positions are stored as signed 16bit integers.
* One bit is lost for signedness to support featuers extending past the left edge of the tile.
* One bit is lost because the line vertex buffer packs 1 bit of other data into the int.
* One bit is lost to support features extending past the extent on the right edge of the tile.
* This leaves us with 2^13 = 8192
*
* @private
* @readonly
*/
Bucket.EXTENT = 8192;
/**
* The `Bucket` class is the single point of knowledge about turning vector
* tiles into WebGL buffers.
*
* `Bucket` is an abstract class. A subclass exists for each Mapbox GL
* style spec layer type. Because `Bucket` is an abstract class,
* instances should be created via the `Bucket.create` method.
*
* @class Bucket
* @private
* @param options
* @param {number} options.zoom Zoom level of the buffers being built. May be
* a fractional zoom level.
* @param options.layer A Mapbox style layer object
* @param {Object.} options.buffers The set of `Buffer`s being
* built for this tile. This object facilitates sharing of `Buffer`s be
between `Bucket`s.
*/
function Bucket(options) {
this.zoom = options.zoom;
this.overscaling = options.overscaling;
this.layer = options.layer;
this.childLayers = options.childLayers;
this.type = this.layer.type;
this.features = [];
this.id = this.layer.id;
this.index = options.index;
this.sourceLayer = this.layer.sourceLayer;
this.sourceLayerIndex = options.sourceLayerIndex;
this.minZoom = this.layer.minzoom;
this.maxZoom = this.layer.maxzoom;
this.paintAttributes = createPaintAttributes(this);
if (options.arrays) {
var programInterfaces = this.programInterfaces;
this.bufferGroups = util.mapObject(options.arrays, function(programArrayGroups, programName) {
var programInterface = programInterfaces[programName];
var paintVertexArrayTypes = options.paintVertexArrayTypes[programName];
return programArrayGroups.map(function(arrayGroup) {
return new BufferGroup(arrayGroup, {
layoutVertexArrayType: programInterface.layoutVertexArrayType.serialize(),
elementArrayType: programInterface.elementArrayType && programInterface.elementArrayType.serialize(),
elementArrayType2: programInterface.elementArrayType2 && programInterface.elementArrayType2.serialize(),
paintVertexArrayTypes: paintVertexArrayTypes
});
});
});
}
}
/**
* Build the arrays! Features are set directly to the `features` property.
* @private
*/
Bucket.prototype.populateArrays = function() {
this.createArrays();
this.recalculateStyleLayers();
for (var i = 0; i < this.features.length; i++) {
this.addFeature(this.features[i]);
}
this.trimArrays();
};
/**
* Check if there is enough space available in the current array group for
* `vertexLength` vertices. If not, append a new array group. Should be called
* by `populateArrays` and its callees.
*
* Array groups are added to this.arrayGroups[programName].
*
* @private
* @param {string} programName the name of the program associated with the buffer that will receive the vertices
* @param {number} vertexLength The number of vertices that will be inserted to the buffer.
* @returns The current array group
*/
Bucket.prototype.prepareArrayGroup = function(programName, numVertices) {
var groups = this.arrayGroups[programName];
var currentGroup = groups.length && groups[groups.length - 1];
if (!currentGroup || !currentGroup.hasCapacityFor(numVertices)) {
currentGroup = new ArrayGroup({
layoutVertexArrayType: this.programInterfaces[programName].layoutVertexArrayType,
elementArrayType: this.programInterfaces[programName].elementArrayType,
elementArrayType2: this.programInterfaces[programName].elementArrayType2,
paintVertexArrayTypes: this.paintVertexArrayTypes[programName]
});
currentGroup.index = groups.length;
groups.push(currentGroup);
}
return currentGroup;
};
/**
* Sets up `this.paintVertexArrayTypes` as { [programName]: { [layerName]: PaintArrayType, ... }, ... }
*
* And `this.arrayGroups` as { [programName]: [], ... }; these get populated
* with array group structure over in `prepareArrayGroup`.
*
* @private
*/
Bucket.prototype.createArrays = function() {
this.arrayGroups = {};
this.paintVertexArrayTypes = {};
for (var programName in this.programInterfaces) {
this.arrayGroups[programName] = [];
var paintVertexArrayTypes = this.paintVertexArrayTypes[programName] = {};
var layerPaintAttributes = this.paintAttributes[programName];
for (var layerName in layerPaintAttributes) {
paintVertexArrayTypes[layerName] = new Bucket.VertexArrayType(layerPaintAttributes[layerName].attributes);
}
}
};
Bucket.prototype.destroy = function(gl) {
for (var programName in this.bufferGroups) {
var programBufferGroups = this.bufferGroups[programName];
for (var i = 0; i < programBufferGroups.length; i++) {
programBufferGroups[i].destroy(gl);
}
}
};
Bucket.prototype.trimArrays = function() {
for (var programName in this.arrayGroups) {
var arrayGroups = this.arrayGroups[programName];
for (var i = 0; i < arrayGroups.length; i++) {
arrayGroups[i].trim();
}
}
};
Bucket.prototype.isEmpty = function() {
for (var programName in this.arrayGroups) {
var arrayGroups = this.arrayGroups[programName];
for (var i = 0; i < arrayGroups.length; i++) {
if (!arrayGroups[i].isEmpty()) {
return false;
}
}
}
return true;
};
Bucket.prototype.getTransferables = function(transferables) {
for (var programName in this.arrayGroups) {
var arrayGroups = this.arrayGroups[programName];
for (var i = 0; i < arrayGroups.length; i++) {
arrayGroups[i].getTransferables(transferables);
}
}
};
Bucket.prototype.setUniforms = function(gl, programName, program, layer, globalProperties) {
var uniforms = this.paintAttributes[programName][layer.id].uniforms;
for (var i = 0; i < uniforms.length; i++) {
var uniform = uniforms[i];
var uniformLocation = program[uniform.name];
gl['uniform' + uniform.components + 'fv'](uniformLocation, uniform.getValue(layer, globalProperties));
}
};
Bucket.prototype.serialize = function() {
return {
layerId: this.layer.id,
zoom: this.zoom,
arrays: util.mapObject(this.arrayGroups, function(programArrayGroups) {
return programArrayGroups.map(function(arrayGroup) {
return arrayGroup.serialize();
});
}),
paintVertexArrayTypes: util.mapObject(this.paintVertexArrayTypes, function(arrayTypes) {
return util.mapObject(arrayTypes, function(arrayType) {
return arrayType.serialize();
});
}),
childLayerIds: this.childLayers.map(function(layer) {
return layer.id;
})
};
};
Bucket.prototype.createFilter = function() {
if (!this.filter) {
this.filter = featureFilter(this.layer.filter);
}
};
var FAKE_ZOOM_HISTORY = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 };
Bucket.prototype.recalculateStyleLayers = function() {
for (var i = 0; i < this.childLayers.length; i++) {
this.childLayers[i].recalculate(this.zoom, FAKE_ZOOM_HISTORY);
}
};
Bucket.prototype.populatePaintArrays = function(interfaceName, globalProperties, featureProperties, startGroup, startIndex) {
for (var l = 0; l < this.childLayers.length; l++) {
var layer = this.childLayers[l];
var groups = this.arrayGroups[interfaceName];
for (var g = startGroup.index; g < groups.length; g++) {
var group = groups[g];
var length = group.layoutVertexArray.length;
var paintArray = group.paintVertexArrays[layer.id];
paintArray.resize(length);
var attributes = this.paintAttributes[interfaceName][layer.id].attributes;
for (var m = 0; m < attributes.length; m++) {
var attribute = attributes[m];
var value = attribute.getValue(layer, globalProperties, featureProperties);
var multiplier = attribute.multiplier || 1;
var components = attribute.components || 1;
var start = g === startGroup.index ? startIndex : 0;
for (var i = start; i < length; i++) {
var vertex = paintArray.get(i);
for (var c = 0; c < components; c++) {
var memberName = components > 1 ? (attribute.name + c) : attribute.name;
vertex[memberName] = value[c] * multiplier;
}
}
}
}
}
};
/**
* A vertex array stores data for each vertex in a geometry. Elements are aligned to 4 byte
* boundaries for best performance in WebGL.
* @private
*/
Bucket.VertexArrayType = function (members) {
return new StructArrayType({
members: members,
alignment: 4
});
};
/**
* An element array stores Uint16 indicies of vertexes in a corresponding vertex array. With no
* arguments, it defaults to three components per element, forming triangles.
* @private
*/
Bucket.ElementArrayType = function (components) {
return new StructArrayType({
members: [{
type: 'Uint16',
name: 'vertices',
components: components || 3
}]
});
};
function createPaintAttributes(bucket) {
var attributes = {};
for (var interfaceName in bucket.programInterfaces) {
var layerPaintAttributes = attributes[interfaceName] = {};
for (var c = 0; c < bucket.childLayers.length; c++) {
var childLayer = bucket.childLayers[c];
layerPaintAttributes[childLayer.id] = {
attributes: [],
uniforms: [],
defines: [],
vertexPragmas: { define: {}, initialize: {} },
fragmentPragmas: { define: {}, initialize: {} }
};
}
var interface_ = bucket.programInterfaces[interfaceName];
if (!interface_.paintAttributes) continue;
// These tokens are replaced by arguments to the pragma
// https://github.com/mapbox/mapbox-gl-shaders#pragmas
var attributePrecision = '{precision}';
var attributeType = '{type}';
for (var i = 0; i < interface_.paintAttributes.length; i++) {
var attribute = interface_.paintAttributes[i];
attribute.multiplier = attribute.multiplier || 1;
for (var j = 0; j < bucket.childLayers.length; j++) {
var layer = bucket.childLayers[j];
var paintAttributes = layerPaintAttributes[layer.id];
var attributeInputName = attribute.name;
assert(attribute.name.slice(0, 2) === 'a_');
var attributeInnerName = attribute.name.slice(2);
var attributeVaryingDefinition;
paintAttributes.fragmentPragmas.initialize[attributeInnerName] = '';
if (layer.isPaintValueFeatureConstant(attribute.paintProperty)) {
paintAttributes.uniforms.push(attribute);
paintAttributes.fragmentPragmas.define[attributeInnerName] = paintAttributes.vertexPragmas.define[attributeInnerName] = [
'uniform',
attributePrecision,
attributeType,
attributeInputName
].join(' ') + ';';
paintAttributes.fragmentPragmas.initialize[attributeInnerName] = paintAttributes.vertexPragmas.initialize[attributeInnerName] = [
attributePrecision,
attributeType,
attributeInnerName,
'=',
attributeInputName
].join(' ') + ';\n';
} else if (layer.isPaintValueZoomConstant(attribute.paintProperty)) {
paintAttributes.attributes.push(util.extend({}, attribute, {
name: attributeInputName
}));
attributeVaryingDefinition = [
'varying',
attributePrecision,
attributeType,
attributeInnerName
].join(' ') + ';\n';
var attributeAttributeDefinition = [
paintAttributes.fragmentPragmas.define[attributeInnerName],
'attribute',
attributePrecision,
attributeType,
attributeInputName
].join(' ') + ';\n';
paintAttributes.fragmentPragmas.define[attributeInnerName] = attributeVaryingDefinition;
paintAttributes.vertexPragmas.define[attributeInnerName] = attributeVaryingDefinition + attributeAttributeDefinition;
paintAttributes.vertexPragmas.initialize[attributeInnerName] = [
attributeInnerName,
'=',
attributeInputName,
'/',
attribute.multiplier.toFixed(1)
].join(' ') + ';\n';
} else {
var tName = 'u_' + attributeInputName.slice(2) + '_t';
var zoomLevels = layer.getPaintValueStopZoomLevels(attribute.paintProperty);
// Pick the index of the first offset to add to the buffers.
// Find the four closest stops, ideally with two on each side of the zoom level.
var numStops = 0;
while (numStops < zoomLevels.length && zoomLevels[numStops] < bucket.zoom) numStops++;
var stopOffset = Math.max(0, Math.min(zoomLevels.length - 4, numStops - 2));
var fourZoomLevels = [];
for (var s = 0; s < 4; s++) {
fourZoomLevels.push(zoomLevels[Math.min(stopOffset + s, zoomLevels.length - 1)]);
}
attributeVaryingDefinition = [
'varying',
attributePrecision,
attributeType,
attributeInnerName
].join(' ') + ';\n';
paintAttributes.vertexPragmas.define[attributeInnerName] = attributeVaryingDefinition + [
'uniform',
'lowp',
'float',
tName
].join(' ') + ';\n';
paintAttributes.fragmentPragmas.define[attributeInnerName] = attributeVaryingDefinition;
paintAttributes.uniforms.push(util.extend({}, attribute, {
name: tName,
getValue: createGetUniform(attribute, stopOffset),
components: 1
}));
var components = attribute.components;
if (components === 1) {
paintAttributes.attributes.push(util.extend({}, attribute, {
getValue: createFunctionGetValue(attribute, fourZoomLevels),
isFunction: true,
components: components * 4
}));
paintAttributes.vertexPragmas.define[attributeInnerName] += [
'attribute',
attributePrecision,
'vec4',
attributeInputName
].join(' ') + ';\n';
paintAttributes.vertexPragmas.initialize[attributeInnerName] = [
attributeInnerName,
'=',
'evaluate_zoom_function_1(' + attributeInputName + ', ' + tName + ')',
'/',
attribute.multiplier.toFixed(1)
].join(' ') + ';\n';
} else {
var attributeInputNames = [];
for (var k = 0; k < 4; k++) {
attributeInputNames.push(attributeInputName + k);
paintAttributes.attributes.push(util.extend({}, attribute, {
getValue: createFunctionGetValue(attribute, [fourZoomLevels[k]]),
isFunction: true,
name: attributeInputName + k
}));
paintAttributes.vertexPragmas.define[attributeInnerName] += [
'attribute',
attributePrecision,
attributeType,
attributeInputName + k
].join(' ') + ';\n';
}
paintAttributes.vertexPragmas.initialize[attributeInnerName] = [
attributeInnerName,
' = ',
'evaluate_zoom_function_4(' + attributeInputNames.join(', ') + ', ' + tName + ')',
'/',
attribute.multiplier.toFixed(1)
].join(' ') + ';\n';
}
}
}
}
}
return attributes;
}
function createFunctionGetValue(attribute, stopZoomLevels) {
return function(layer, globalProperties, featureProperties) {
if (stopZoomLevels.length === 1) {
// return one multi-component value like color0
return attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevels[0] }), featureProperties);
} else {
// pack multiple single-component values into a four component attribute
var values = [];
for (var z = 0; z < stopZoomLevels.length; z++) {
var stopZoomLevel = stopZoomLevels[z];
values.push(attribute.getValue(layer, util.extend({}, globalProperties, { zoom: stopZoomLevel }), featureProperties)[0]);
}
return values;
}
};
}
function createGetUniform(attribute, stopOffset) {
return function(layer, globalProperties) {
// stopInterp indicates which stops need to be interpolated.
// If stopInterp is 3.5 then interpolate half way between stops 3 and 4.
var stopInterp = layer.getPaintInterpolationT(attribute.paintProperty, globalProperties.zoom);
// We can only store four stop values in the buffers. stopOffset is the number of stops that come
// before the stops that were added to the buffers.
return [Math.max(0, Math.min(4, stopInterp - stopOffset))];
};
}
},{"../util/struct_array":433,"../util/util":435,"./array_group":321,"./bucket/circle_bucket":323,"./bucket/fill_bucket":324,"./bucket/line_bucket":325,"./bucket/symbol_bucket":326,"./buffer_group":328,"assert":43,"feature-filter":128}],323:[function(require,module,exports){
'use strict';
var Bucket = require('../bucket');
var util = require('../../util/util');
var loadGeometry = require('../load_geometry');
var EXTENT = Bucket.EXTENT;
module.exports = CircleBucket;
/**
* Circles are represented by two triangles.
*
* Each corner has a pos that is the center of the circle and an extrusion
* vector that is where it points.
* @private
*/
function CircleBucket() {
Bucket.apply(this, arguments);
}
CircleBucket.prototype = util.inherit(Bucket, {});
CircleBucket.prototype.addCircleVertex = function(layoutVertexArray, x, y, extrudeX, extrudeY) {
return layoutVertexArray.emplaceBack(
(x * 2) + ((extrudeX + 1) / 2),
(y * 2) + ((extrudeY + 1) / 2));
};
CircleBucket.prototype.programInterfaces = {
circle: {
layoutVertexArrayType: new Bucket.VertexArrayType([{
name: 'a_pos',
components: 2,
type: 'Int16'
}]),
elementArrayType: new Bucket.ElementArrayType(),
paintAttributes: [{
name: 'a_color',
components: 4,
type: 'Uint8',
getValue: function(layer, globalProperties, featureProperties) {
return layer.getPaintValue("circle-color", globalProperties, featureProperties);
},
multiplier: 255,
paintProperty: 'circle-color'
}, {
name: 'a_radius',
components: 1,
type: 'Uint16',
isLayerConstant: false,
getValue: function(layer, globalProperties, featureProperties) {
return [layer.getPaintValue("circle-radius", globalProperties, featureProperties)];
},
multiplier: 10,
paintProperty: 'circle-radius'
}, {
name: 'a_blur',
components: 1,
type: 'Uint16',
isLayerConstant: false,
getValue: function(layer, globalProperties, featureProperties) {
return [layer.getPaintValue("circle-blur", globalProperties, featureProperties)];
},
multiplier: 10,
paintProperty: 'circle-blur'
}, {
name: 'a_opacity',
components: 1,
type: 'Uint16',
isLayerConstant: false,
getValue: function(layer, globalProperties, featureProperties) {
return [layer.getPaintValue("circle-opacity", globalProperties, featureProperties)];
},
multiplier: 255,
paintProperty: 'circle-opacity'
}]
}
};
CircleBucket.prototype.addFeature = function(feature) {
var globalProperties = {zoom: this.zoom};
var geometries = loadGeometry(feature);
var startGroup = this.prepareArrayGroup('circle', 0);
var startIndex = startGroup.layoutVertexArray.length;
for (var j = 0; j < geometries.length; j++) {
for (var k = 0; k < geometries[j].length; k++) {
var x = geometries[j][k].x;
var y = geometries[j][k].y;
// Do not include points that are outside the tile boundaries.
if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT) continue;
// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
// ┌─────────┐
// │ 3 2 │
// │ │
// │ 0 1 │
// └─────────┘
var group = this.prepareArrayGroup('circle', 4);
var layoutVertexArray = group.layoutVertexArray;
var index = this.addCircleVertex(layoutVertexArray, x, y, -1, -1);
this.addCircleVertex(layoutVertexArray, x, y, 1, -1);
this.addCircleVertex(layoutVertexArray, x, y, 1, 1);
this.addCircleVertex(layoutVertexArray, x, y, -1, 1);
group.elementArray.emplaceBack(index, index + 1, index + 2);
group.elementArray.emplaceBack(index, index + 3, index + 2);
}
}
this.populatePaintArrays('circle', globalProperties, feature.properties, startGroup, startIndex);
};
},{"../../util/util":435,"../bucket":322,"../load_geometry":330}],324:[function(require,module,exports){
'use strict';
var Bucket = require('../bucket');
var util = require('../../util/util');
var loadGeometry = require('../load_geometry');
var earcut = require('earcut');
var classifyRings = require('../../util/classify_rings');
var EARCUT_MAX_RINGS = 500;
module.exports = FillBucket;
function FillBucket() {
Bucket.apply(this, arguments);
}
FillBucket.prototype = util.inherit(Bucket, {});
FillBucket.prototype.programInterfaces = {
fill: {
layoutVertexArrayType: new Bucket.VertexArrayType([{
name: 'a_pos',
components: 2,
type: 'Int16'
}]),
elementArrayType: new Bucket.ElementArrayType(1),
elementArrayType2: new Bucket.ElementArrayType(2),
paintAttributes: [{
name: 'a_color',
components: 4,
type: 'Uint8',
getValue: function(layer, globalProperties, featureProperties) {
return layer.getPaintValue("fill-color", globalProperties, featureProperties);
},
multiplier: 255,
paintProperty: 'fill-color'
}, {
name: 'a_outline_color',
components: 4,
type: 'Uint8',
getValue: function(layer, globalProperties, featureProperties) {
return layer.getPaintValue("fill-outline-color", globalProperties, featureProperties);
},
multiplier: 255,
paintProperty: 'fill-outline-color'
}, {
name: 'a_opacity',
components: 1,
type: 'Uint8',
getValue: function(layer, globalProperties, featureProperties) {
return [layer.getPaintValue("fill-opacity", globalProperties, featureProperties)];
},
multiplier: 255,
paintProperty: 'fill-opacity'
}]
}
};
FillBucket.prototype.addFeature = function(feature) {
var lines = loadGeometry(feature);
var polygons = classifyRings(lines, EARCUT_MAX_RINGS);
var startGroup = this.prepareArrayGroup('fill', 0);
var startIndex = startGroup.layoutVertexArray.length;
for (var i = 0; i < polygons.length; i++) {
this.addPolygon(polygons[i]);
}
this.populatePaintArrays('fill', {zoom: this.zoom}, feature.properties, startGroup, startIndex);
};
FillBucket.prototype.addPolygon = function(polygon) {
var numVertices = 0;
for (var k = 0; k < polygon.length; k++) {
numVertices += polygon[k].length;
}
var group = this.prepareArrayGroup('fill', numVertices);
var flattened = [];
var holeIndices = [];
var startIndex = group.layoutVertexArray.length;
for (var r = 0; r < polygon.length; r++) {
var ring = polygon[r];
if (r > 0) holeIndices.push(flattened.length / 2);
for (var v = 0; v < ring.length; v++) {
var vertex = ring[v];
var index = group.layoutVertexArray.emplaceBack(vertex.x, vertex.y);
if (v >= 1) {
group.elementArray2.emplaceBack(index - 1, index);
}
// convert to format used by earcut
flattened.push(vertex.x);
flattened.push(vertex.y);
}
}
var triangleIndices = earcut(flattened, holeIndices);
for (var i = 0; i < triangleIndices.length; i++) {
group.elementArray.emplaceBack(triangleIndices[i] + startIndex);
}
};
},{"../../util/classify_rings":423,"../../util/util":435,"../bucket":322,"../load_geometry":330,"earcut":122}],325:[function(require,module,exports){
'use strict';
var Bucket = require('../bucket');
var util = require('../../util/util');
var loadGeometry = require('../load_geometry');
var EXTENT = Bucket.EXTENT;
// NOTE ON EXTRUDE SCALE:
// scale the extrusion vector so that the normal length is this value.
// contains the "texture" normals (-1..1). this is distinct from the extrude
// normals for line joins, because the x-value remains 0 for the texture
// normal array, while the extrude normal actually moves the vertex to create
// the acute/bevelled line join.
var EXTRUDE_SCALE = 63;
/*
* Sharp corners cause dashed lines to tilt because the distance along the line
* is the same at both the inner and outer corners. To improve the appearance of
* dashed lines we add extra points near sharp corners so that a smaller part
* of the line is tilted.
*
* COS_HALF_SHARP_CORNER controls how sharp a corner has to be for us to add an
* extra vertex. The default is 75 degrees.
*
* The newly created vertices are placed SHARP_CORNER_OFFSET pixels from the corner.
*/
var COS_HALF_SHARP_CORNER = Math.cos(75 / 2 * (Math.PI / 180));
var SHARP_CORNER_OFFSET = 15;
// The number of bits that is used to store the line distance in the buffer.
var LINE_DISTANCE_BUFFER_BITS = 15;
// We don't have enough bits for the line distance as we'd like to have, so
// use this value to scale the line distance (in tile units) down to a smaller
// value. This lets us store longer distances while sacrificing precision.
var LINE_DISTANCE_SCALE = 1 / 2;
// The maximum line distance, in tile units, that fits in the buffer.
var MAX_LINE_DISTANCE = Math.pow(2, LINE_DISTANCE_BUFFER_BITS - 1) / LINE_DISTANCE_SCALE;
module.exports = LineBucket;
/**
* @private
*/
function LineBucket() {
Bucket.apply(this, arguments);
}
LineBucket.prototype = util.inherit(Bucket, {});
LineBucket.prototype.addLineVertex = function(layoutVertexBuffer, point, extrude, tx, ty, dir, linesofar) {
return layoutVertexBuffer.emplaceBack(
// a_pos
(point.x << 1) | tx,
(point.y << 1) | ty,
// a_data
// add 128 to store an byte in an unsigned byte
Math.round(EXTRUDE_SCALE * extrude.x) + 128,
Math.round(EXTRUDE_SCALE * extrude.y) + 128,
// Encode the -1/0/1 direction value into the first two bits of .z of a_data.
// Combine it with the lower 6 bits of `linesofar` (shifted by 2 bites to make
// room for the direction value). The upper 8 bits of `linesofar` are placed in
// the `w` component. `linesofar` is scaled down by `LINE_DISTANCE_SCALE` so that
// we can store longer distances while sacrificing precision.
((dir === 0 ? 0 : (dir < 0 ? -1 : 1)) + 1) | (((linesofar * LINE_DISTANCE_SCALE) & 0x3F) << 2),
(linesofar * LINE_DISTANCE_SCALE) >> 6);
};
LineBucket.prototype.programInterfaces = {
line: {
layoutVertexArrayType: new Bucket.VertexArrayType([{
name: 'a_pos',
components: 2,
type: 'Int16'
}, {
name: 'a_data',
components: 4,
type: 'Uint8'
}]),
elementArrayType: new Bucket.ElementArrayType()
}
};
LineBucket.prototype.addFeature = function(feature) {
var lines = loadGeometry(feature, LINE_DISTANCE_BUFFER_BITS);
for (var i = 0; i < lines.length; i++) {
this.addLine(
lines[i],
this.layer.layout['line-join'],
this.layer.layout['line-cap'],
this.layer.layout['line-miter-limit'],
this.layer.layout['line-round-limit']
);
}
};
LineBucket.prototype.addLine = function(vertices, join, cap, miterLimit, roundLimit) {
var len = vertices.length;
// If the line has duplicate vertices at the end, adjust length to remove them.
while (len > 2 && vertices[len - 1].equals(vertices[len - 2])) {
len--;
}
// a line must have at least two vertices
if (vertices.length < 2) return;
if (join === 'bevel') miterLimit = 1.05;
var sharpCornerOffset = SHARP_CORNER_OFFSET * (EXTENT / (512 * this.overscaling));
var firstVertex = vertices[0],
lastVertex = vertices[len - 1],
closed = firstVertex.equals(lastVertex);
// we could be more precise, but it would only save a negligible amount of space
this.prepareArrayGroup('line', len * 10);
// a line may not have coincident points
if (len === 2 && closed) return;
this.distance = 0;
var beginCap = cap,
endCap = closed ? 'butt' : cap,
startOfLine = true,
currentVertex, prevVertex, nextVertex, prevNormal, nextNormal, offsetA, offsetB;
// the last three vertices added
this.e1 = this.e2 = this.e3 = -1;
if (closed) {
currentVertex = vertices[len - 2];
nextNormal = firstVertex.sub(currentVertex)._unit()._perp();
}
for (var i = 0; i < len; i++) {
nextVertex = closed && i === len - 1 ?
vertices[1] : // if the line is closed, we treat the last vertex like the first
vertices[i + 1]; // just the next vertex
// if two consecutive vertices exist, skip the current one
if (nextVertex && vertices[i].equals(nextVertex)) continue;
if (nextNormal) prevNormal = nextNormal;
if (currentVertex) prevVertex = currentVertex;
currentVertex = vertices[i];
// Calculate the normal towards the next vertex in this line. In case
// there is no next vertex, pretend that the line is continuing straight,
// meaning that we are just using the previous normal.
nextNormal = nextVertex ? nextVertex.sub(currentVertex)._unit()._perp() : prevNormal;
// If we still don't have a previous normal, this is the beginning of a
// non-closed line, so we're doing a straight "join".
prevNormal = prevNormal || nextNormal;
// Determine the normal of the join extrusion. It is the angle bisector
// of the segments between the previous line and the next line.
var joinNormal = prevNormal.add(nextNormal)._unit();
/* joinNormal prevNormal
* ↖ ↑
* .________. prevVertex
* |
* nextNormal ← | currentVertex
* |
* nextVertex !
*
*/
// Calculate the length of the miter (the ratio of the miter to the width).
// Find the cosine of the angle between the next and join normals
// using dot product. The inverse of that is the miter length.
var cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y;
var miterLength = 1 / cosHalfAngle;
var isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevVertex && nextVertex;
if (isSharpCorner && i > 0) {
var prevSegmentLength = currentVertex.dist(prevVertex);
if (prevSegmentLength > 2 * sharpCornerOffset) {
var newPrevVertex = currentVertex.sub(currentVertex.sub(prevVertex)._mult(sharpCornerOffset / prevSegmentLength)._round());
this.distance += newPrevVertex.dist(prevVertex);
this.addCurrentVertex(newPrevVertex, this.distance, prevNormal.mult(1), 0, 0, false);
prevVertex = newPrevVertex;
}
}
// The join if a middle vertex, otherwise the cap.
var middleVertex = prevVertex && nextVertex;
var currentJoin = middleVertex ? join : nextVertex ? beginCap : endCap;
if (middleVertex && currentJoin === 'round') {
if (miterLength < roundLimit) {
currentJoin = 'miter';
} else if (miterLength <= 2) {
currentJoin = 'fakeround';
}
}
if (currentJoin === 'miter' && miterLength > miterLimit) {
currentJoin = 'bevel';
}
if (currentJoin === 'bevel') {
// The maximum extrude length is 128 / 63 = 2 times the width of the line
// so if miterLength >= 2 we need to draw a different type of bevel where.
if (miterLength > 2) currentJoin = 'flipbevel';
// If the miterLength is really small and the line bevel wouldn't be visible,
// just draw a miter join to save a triangle.
if (miterLength < miterLimit) currentJoin = 'miter';
}
// Calculate how far along the line the currentVertex is
if (prevVertex) this.distance += currentVertex.dist(prevVertex);
if (currentJoin === 'miter') {
joinNormal._mult(miterLength);
this.addCurrentVertex(currentVertex, this.distance, joinNormal, 0, 0, false);
} else if (currentJoin === 'flipbevel') {
// miter is too big, flip the direction to make a beveled join
if (miterLength > 100) {
// Almost parallel lines
joinNormal = nextNormal.clone();
} else {
var direction = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0 ? -1 : 1;
var bevelLength = miterLength * prevNormal.add(nextNormal).mag() / prevNormal.sub(nextNormal).mag();
joinNormal._perp()._mult(bevelLength * direction);
}
this.addCurrentVertex(currentVertex, this.distance, joinNormal, 0, 0, false);
this.addCurrentVertex(currentVertex, this.distance, joinNormal.mult(-1), 0, 0, false);
} else if (currentJoin === 'bevel' || currentJoin === 'fakeround') {
var lineTurnsLeft = (prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x) > 0;
var offset = -Math.sqrt(miterLength * miterLength - 1);
if (lineTurnsLeft) {
offsetB = 0;
offsetA = offset;
} else {
offsetA = 0;
offsetB = offset;
}
// Close previous segment with a bevel
if (!startOfLine) {
this.addCurrentVertex(currentVertex, this.distance, prevNormal, offsetA, offsetB, false);
}
if (currentJoin === 'fakeround') {
// The join angle is sharp enough that a round join would be visible.
// Bevel joins fill the gap between segments with a single pie slice triangle.
// Create a round join by adding multiple pie slices. The join isn't actually round, but
// it looks like it is at the sizes we render lines at.
// Add more triangles for sharper angles.
// This math is just a good enough approximation. It isn't "correct".
var n = Math.floor((0.5 - (cosHalfAngle - 0.5)) * 8);
var approxFractionalJoinNormal;
for (var m = 0; m < n; m++) {
approxFractionalJoinNormal = nextNormal.mult((m + 1) / (n + 1))._add(prevNormal)._unit();
this.addPieSliceVertex(currentVertex, this.distance, approxFractionalJoinNormal, lineTurnsLeft);
}
this.addPieSliceVertex(currentVertex, this.distance, joinNormal, lineTurnsLeft);
for (var k = n - 1; k >= 0; k--) {
approxFractionalJoinNormal = prevNormal.mult((k + 1) / (n + 1))._add(nextNormal)._unit();
this.addPieSliceVertex(currentVertex, this.distance, approxFractionalJoinNormal, lineTurnsLeft);
}
}
// Start next segment
if (nextVertex) {
this.addCurrentVertex(currentVertex, this.distance, nextNormal, -offsetA, -offsetB, false);
}
} else if (currentJoin === 'butt') {
if (!startOfLine) {
// Close previous segment with a butt
this.addCurrentVertex(currentVertex, this.distance, prevNormal, 0, 0, false);
}
// Start next segment with a butt
if (nextVertex) {
this.addCurrentVertex(currentVertex, this.distance, nextNormal, 0, 0, false);
}
} else if (currentJoin === 'square') {
if (!startOfLine) {
// Close previous segment with a square cap
this.addCurrentVertex(currentVertex, this.distance, prevNormal, 1, 1, false);
// The segment is done. Unset vertices to disconnect segments.
this.e1 = this.e2 = -1;
}
// Start next segment
if (nextVertex) {
this.addCurrentVertex(currentVertex, this.distance, nextNormal, -1, -1, false);
}
} else if (currentJoin === 'round') {
if (!startOfLine) {
// Close previous segment with butt
this.addCurrentVertex(currentVertex, this.distance, prevNormal, 0, 0, false);
// Add round cap or linejoin at end of segment
this.addCurrentVertex(currentVertex, this.distance, prevNormal, 1, 1, true);
// The segment is done. Unset vertices to disconnect segments.
this.e1 = this.e2 = -1;
}
// Start next segment with a butt
if (nextVertex) {
// Add round cap before first segment
this.addCurrentVertex(currentVertex, this.distance, nextNormal, -1, -1, true);
this.addCurrentVertex(currentVertex, this.distance, nextNormal, 0, 0, false);
}
}
if (isSharpCorner && i < len - 1) {
var nextSegmentLength = currentVertex.dist(nextVertex);
if (nextSegmentLength > 2 * sharpCornerOffset) {
var newCurrentVertex = currentVertex.add(nextVertex.sub(currentVertex)._mult(sharpCornerOffset / nextSegmentLength)._round());
this.distance += newCurrentVertex.dist(currentVertex);
this.addCurrentVertex(newCurrentVertex, this.distance, nextNormal.mult(1), 0, 0, false);
currentVertex = newCurrentVertex;
}
}
startOfLine = false;
}
};
/**
* Add two vertices to the buffers.
*
* @param {Object} currentVertex the line vertex to add buffer vertices for
* @param {number} distance the distance from the beginning of the line to the vertex
* @param {number} endLeft extrude to shift the left vertex along the line
* @param {number} endRight extrude to shift the left vertex along the line
* @param {boolean} round whether this is a round cap
* @private
*/
LineBucket.prototype.addCurrentVertex = function(currentVertex, distance, normal, endLeft, endRight, round) {
var tx = round ? 1 : 0;
var extrude;
var arrayGroup = this.arrayGroups.line[this.arrayGroups.line.length - 1];
var layoutVertexArray = arrayGroup.layoutVertexArray;
var elementArray = arrayGroup.elementArray;
extrude = normal.clone();
if (endLeft) extrude._sub(normal.perp()._mult(endLeft));
this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, tx, 0, endLeft, distance);
if (this.e1 >= 0 && this.e2 >= 0) {
elementArray.emplaceBack(this.e1, this.e2, this.e3);
}
this.e1 = this.e2;
this.e2 = this.e3;
extrude = normal.mult(-1);
if (endRight) extrude._sub(normal.perp()._mult(endRight));
this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, tx, 1, -endRight, distance);
if (this.e1 >= 0 && this.e2 >= 0) {
elementArray.emplaceBack(this.e1, this.e2, this.e3);
}
this.e1 = this.e2;
this.e2 = this.e3;
// There is a maximum "distance along the line" that we can store in the buffers.
// When we get close to the distance, reset it to zero and add the vertex again with
// a distance of zero. The max distance is determined by the number of bits we allocate
// to `linesofar`.
if (distance > MAX_LINE_DISTANCE / 2) {
this.distance = 0;
this.addCurrentVertex(currentVertex, this.distance, normal, endLeft, endRight, round);
}
};
/**
* Add a single new vertex and a triangle using two previous vertices.
* This adds a pie slice triangle near a join to simulate round joins
*
* @param {Object} currentVertex the line vertex to add buffer vertices for
* @param {number} distance the distance from the beggining of the line to the vertex
* @param {Object} extrude the offset of the new vertex from the currentVertex
* @param {boolean} whether the line is turning left or right at this angle
* @private
*/
LineBucket.prototype.addPieSliceVertex = function(currentVertex, distance, extrude, lineTurnsLeft) {
var ty = lineTurnsLeft ? 1 : 0;
extrude = extrude.mult(lineTurnsLeft ? -1 : 1);
var arrayGroup = this.arrayGroups.line[this.arrayGroups.line.length - 1];
var layoutVertexArray = arrayGroup.layoutVertexArray;
var elementArray = arrayGroup.elementArray;
this.e3 = this.addLineVertex(layoutVertexArray, currentVertex, extrude, 0, ty, 0, distance);
if (this.e1 >= 0 && this.e2 >= 0) {
elementArray.emplaceBack(this.e1, this.e2, this.e3);
}
if (lineTurnsLeft) {
this.e2 = this.e3;
} else {
this.e1 = this.e3;
}
};
},{"../../util/util":435,"../bucket":322,"../load_geometry":330}],326:[function(require,module,exports){
'use strict';
var Point = require('point-geometry');
var Bucket = require('../bucket');
var Anchor = require('../../symbol/anchor');
var getAnchors = require('../../symbol/get_anchors');
var resolveTokens = require('../../util/token');
var Quads = require('../../symbol/quads');
var Shaping = require('../../symbol/shaping');
var resolveText = require('../../symbol/resolve_text');
var mergeLines = require('../../symbol/mergelines');
var clipLine = require('../../symbol/clip_line');
var util = require('../../util/util');
var loadGeometry = require('../load_geometry');
var CollisionFeature = require('../../symbol/collision_feature');
var shapeText = Shaping.shapeText;
var shapeIcon = Shaping.shapeIcon;
var getGlyphQuads = Quads.getGlyphQuads;
var getIconQuads = Quads.getIconQuads;
var EXTENT = Bucket.EXTENT;
module.exports = SymbolBucket;
function SymbolBucket(options) {
Bucket.apply(this, arguments);
this.showCollisionBoxes = options.showCollisionBoxes;
this.overscaling = options.overscaling;
this.collisionBoxArray = options.collisionBoxArray;
this.symbolQuadsArray = options.symbolQuadsArray;
this.symbolInstancesArray = options.symbolInstancesArray;
this.sdfIcons = options.sdfIcons;
this.iconsNeedLinear = options.iconsNeedLinear;
this.adjustedTextSize = options.adjustedTextSize;
this.adjustedIconSize = options.adjustedIconSize;
this.fontstack = options.fontstack;
}
// this constant is based on the size of the glyphQuadEndIndex and iconQuadEndIndex
// in the symbol_instances StructArrayType
// eg the max valid UInt16 is 65,535
SymbolBucket.MAX_QUADS = 65535;
SymbolBucket.prototype = util.inherit(Bucket, {});
SymbolBucket.prototype.serialize = function() {
var serialized = Bucket.prototype.serialize.apply(this);
serialized.sdfIcons = this.sdfIcons;
serialized.iconsNeedLinear = this.iconsNeedLinear;
serialized.adjustedTextSize = this.adjustedTextSize;
serialized.adjustedIconSize = this.adjustedIconSize;
serialized.fontstack = this.fontstack;
return serialized;
};
var layoutVertexArrayType = new Bucket.VertexArrayType([{
name: 'a_pos',
components: 2,
type: 'Int16'
}, {
name: 'a_offset',
components: 2,
type: 'Int16'
}, {
name: 'a_texture_pos',
components: 2,
type: 'Uint16'
}, {
name: 'a_data',
components: 4,
type: 'Uint8'
}]);
var elementArrayType = new Bucket.ElementArrayType();
function addVertex(array, x, y, ox, oy, tx, ty, minzoom, maxzoom, labelminzoom, labelangle) {
return array.emplaceBack(
// a_pos
x,
y,
// a_offset
Math.round(ox * 64),
Math.round(oy * 64),
// a_texture_pos
tx / 4, // x coordinate of symbol on glyph atlas texture
ty / 4, // y coordinate of symbol on glyph atlas texture
// a_data
(labelminzoom || 0) * 10, // labelminzoom
labelangle, // labelangle
(minzoom || 0) * 10, // minzoom
Math.min(maxzoom || 25, 25) * 10); // maxzoom
}
SymbolBucket.prototype.addCollisionBoxVertex = function(layoutVertexArray, point, extrude, maxZoom, placementZoom) {
return layoutVertexArray.emplaceBack(
// pos
point.x,
point.y,
// extrude
Math.round(extrude.x),
Math.round(extrude.y),
// data
maxZoom * 10,
placementZoom * 10);
};
SymbolBucket.prototype.programInterfaces = {
glyph: {
layoutVertexArrayType: layoutVertexArrayType,
elementArrayType: elementArrayType
},
icon: {
layoutVertexArrayType: layoutVertexArrayType,
elementArrayType: elementArrayType
},
collisionBox: {
layoutVertexArrayType: new Bucket.VertexArrayType([{
name: 'a_pos',
components: 2,
type: 'Int16'
}, {
name: 'a_extrude',
components: 2,
type: 'Int16'
}, {
name: 'a_data',
components: 2,
type: 'Uint8'
}])
}
};
SymbolBucket.prototype.populateArrays = function(collisionTile, stacks, icons) {
// To reduce the number of labels that jump around when zooming we need
// to use a text-size value that is the same for all zoom levels.
// This calculates text-size at a high zoom level so that all tiles can
// use the same value when calculating anchor positions.
var zoomHistory = { lastIntegerZoom: Infinity, lastIntegerZoomTime: 0, lastZoom: 0 };
this.adjustedTextMaxSize = this.layer.getLayoutValue('text-size', {zoom: 18, zoomHistory: zoomHistory});
this.adjustedTextSize = this.layer.getLayoutValue('text-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory});
this.adjustedIconMaxSize = this.layer.getLayoutValue('icon-size', {zoom: 18, zoomHistory: zoomHistory});
this.adjustedIconSize = this.layer.getLayoutValue('icon-size', {zoom: this.zoom + 1, zoomHistory: zoomHistory});
var tileSize = 512 * this.overscaling;
this.tilePixelRatio = EXTENT / tileSize;
this.compareText = {};
this.iconsNeedLinear = false;
this.symbolInstancesStartIndex = this.symbolInstancesArray.length;
var layout = this.layer.layout;
var features = this.features;
var textFeatures = this.textFeatures;
var horizontalAlign = 0.5,
verticalAlign = 0.5;
switch (layout['text-anchor']) {
case 'right':
case 'top-right':
case 'bottom-right':
horizontalAlign = 1;
break;
case 'left':
case 'top-left':
case 'bottom-left':
horizontalAlign = 0;
break;
}
switch (layout['text-anchor']) {
case 'bottom':
case 'bottom-right':
case 'bottom-left':
verticalAlign = 1;
break;
case 'top':
case 'top-right':
case 'top-left':
verticalAlign = 0;
break;
}
var justify = layout['text-justify'] === 'right' ? 1 :
layout['text-justify'] === 'left' ? 0 :
0.5;
var oneEm = 24;
var lineHeight = layout['text-line-height'] * oneEm;
var maxWidth = layout['symbol-placement'] !== 'line' ? layout['text-max-width'] * oneEm : 0;
var spacing = layout['text-letter-spacing'] * oneEm;
var textOffset = [layout['text-offset'][0] * oneEm, layout['text-offset'][1] * oneEm];
var fontstack = this.fontstack = layout['text-font'].join(',');
var geometries = [];
for (var g = 0; g < features.length; g++) {
geometries.push(loadGeometry(features[g]));
}
if (layout['symbol-placement'] === 'line') {
// Merge adjacent lines with the same text to improve labelling.
// It's better to place labels on one long line than on many short segments.
var merged = mergeLines(features, textFeatures, geometries);
geometries = merged.geometries;
features = merged.features;
textFeatures = merged.textFeatures;
}
var shapedText, shapedIcon;
for (var k = 0; k < features.length; k++) {
if (!geometries[k]) continue;
if (textFeatures[k]) {
shapedText = shapeText(textFeatures[k], stacks[fontstack], maxWidth,
lineHeight, horizontalAlign, verticalAlign, justify, spacing, textOffset);
} else {
shapedText = null;
}
if (layout['icon-image']) {
var iconName = resolveTokens(features[k].properties, layout['icon-image']);
var image = icons[iconName];
shapedIcon = shapeIcon(image, layout);
if (image) {
if (this.sdfIcons === undefined) {
this.sdfIcons = image.sdf;
} else if (this.sdfIcons !== image.sdf) {
util.warnOnce('Style sheet warning: Cannot mix SDF and non-SDF icons in one buffer');
}
if (image.pixelRatio !== 1) {
this.iconsNeedLinear = true;
} else if (layout['icon-rotate'] !== 0 || !this.layer.isLayoutValueFeatureConstant('icon-rotate')) {
this.iconsNeedLinear = true;
}
}
} else {
shapedIcon = null;
}
if (shapedText || shapedIcon) {
this.addFeature(geometries[k], shapedText, shapedIcon, features[k]);
}
}
this.symbolInstancesEndIndex = this.symbolInstancesArray.length;
this.placeFeatures(collisionTile, this.showCollisionBoxes);
this.trimArrays();
};
SymbolBucket.prototype.addFeature = function(lines, shapedText, shapedIcon, feature) {
var layout = this.layer.layout;
var glyphSize = 24;
var fontScale = this.adjustedTextSize / glyphSize,
textMaxSize = this.adjustedTextMaxSize !== undefined ? this.adjustedTextMaxSize : this.adjustedTextSize,
textBoxScale = this.tilePixelRatio * fontScale,
textMaxBoxScale = this.tilePixelRatio * textMaxSize / glyphSize,
iconBoxScale = this.tilePixelRatio * this.adjustedIconSize,
symbolMinDistance = this.tilePixelRatio * layout['symbol-spacing'],
avoidEdges = layout['symbol-avoid-edges'],
textPadding = layout['text-padding'] * this.tilePixelRatio,
iconPadding = layout['icon-padding'] * this.tilePixelRatio,
textMaxAngle = layout['text-max-angle'] / 180 * Math.PI,
textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line',
iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line',
mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] ||
layout['text-ignore-placement'] || layout['icon-ignore-placement'],
isLine = layout['symbol-placement'] === 'line',
textRepeatDistance = symbolMinDistance / 2;
if (isLine) {
lines = clipLine(lines, 0, 0, EXTENT, EXTENT);
}
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
// Calculate the anchor points around which you want to place labels
var anchors;
if (isLine) {
anchors = getAnchors(
line,
symbolMinDistance,
textMaxAngle,
shapedText,
shapedIcon,
glyphSize,
textMaxBoxScale,
this.overscaling,
EXTENT
);
} else {
anchors = [ new Anchor(line[0].x, line[0].y, 0) ];
}
// For each potential label, create the placement features used to check for collisions, and the quads use for rendering.
for (var j = 0, len = anchors.length; j < len; j++) {
var anchor = anchors[j];
if (shapedText && isLine) {
if (this.anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
continue;
}
}
var inside = !(anchor.x < 0 || anchor.x > EXTENT || anchor.y < 0 || anchor.y > EXTENT);
if (avoidEdges && !inside) continue;
// Normally symbol layers are drawn across tile boundaries. Only symbols
// with their anchors within the tile boundaries are added to the buffers
// to prevent symbols from being drawn twice.
//
// Symbols in layers with overlap are sorted in the y direction so that
// symbols lower on the canvas are drawn on top of symbols near the top.
// To preserve this order across tile boundaries these symbols can't
// be drawn across tile boundaries. Instead they need to be included in
// the buffers for both tiles and clipped to tile boundaries at draw time.
var addToBuffers = inside || mayOverlap;
this.addSymbolInstance(anchor, line, shapedText, shapedIcon, this.layer,
addToBuffers, this.symbolInstancesArray.length, this.collisionBoxArray, feature.index, this.sourceLayerIndex, this.index,
textBoxScale, textPadding, textAlongLine,
iconBoxScale, iconPadding, iconAlongLine, {zoom: this.zoom}, feature.properties);
}
}
};
SymbolBucket.prototype.anchorIsTooClose = function(text, repeatDistance, anchor) {
var compareText = this.compareText;
if (!(text in compareText)) {
compareText[text] = [];
} else {
var otherAnchors = compareText[text];
for (var k = otherAnchors.length - 1; k >= 0; k--) {
if (anchor.dist(otherAnchors[k]) < repeatDistance) {
// If it's within repeatDistance of one anchor, stop looking
return true;
}
}
}
// If anchor is not within repeatDistance of any other anchor, add to array
compareText[text].push(anchor);
return false;
};
SymbolBucket.prototype.placeFeatures = function(collisionTile, showCollisionBoxes) {
this.recalculateStyleLayers();
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
this.createArrays();
var layout = this.layer.layout;
var maxScale = collisionTile.maxScale;
var textAlongLine = layout['text-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line';
var iconAlongLine = layout['icon-rotation-alignment'] === 'map' && layout['symbol-placement'] === 'line';
var mayOverlap = layout['text-allow-overlap'] || layout['icon-allow-overlap'] ||
layout['text-ignore-placement'] || layout['icon-ignore-placement'];
// Sort symbols by their y position on the canvas so that the lower symbols
// are drawn on top of higher symbols.
// Don't sort symbols that won't overlap because it isn't necessary and
// because it causes more labels to pop in and out when rotating.
if (mayOverlap) {
// Only need the symbol instances from the current tile to sort, so convert those instances into an array
// of `StructType`s to enable sorting
var symbolInstancesStructTypeArray = this.symbolInstancesArray.toArray(this.symbolInstancesStartIndex, this.symbolInstancesEndIndex);
var angle = collisionTile.angle;
var sin = Math.sin(angle),
cos = Math.cos(angle);
this.sortedSymbolInstances = symbolInstancesStructTypeArray.sort(function(a, b) {
var aRotated = (sin * a.anchorPointX + cos * a.anchorPointY) | 0;
var bRotated = (sin * b.anchorPointX + cos * b.anchorPointY) | 0;
return (aRotated - bRotated) || (b.index - a.index);
});
}
for (var p = this.symbolInstancesStartIndex; p < this.symbolInstancesEndIndex; p++) {
var symbolInstance = this.sortedSymbolInstances ? this.sortedSymbolInstances[p - this.symbolInstancesStartIndex] : this.symbolInstancesArray.get(p);
var textCollisionFeature = {
boxStartIndex: symbolInstance.textBoxStartIndex,
boxEndIndex: symbolInstance.textBoxEndIndex
};
var iconCollisionFeature = {
boxStartIndex: symbolInstance.iconBoxStartIndex,
boxEndIndex: symbolInstance.iconBoxEndIndex
};
var hasText = !(symbolInstance.textBoxStartIndex === symbolInstance.textBoxEndIndex);
var hasIcon = !(symbolInstance.iconBoxStartIndex === symbolInstance.iconBoxEndIndex);
var iconWithoutText = layout['text-optional'] || !hasText,
textWithoutIcon = layout['icon-optional'] || !hasIcon;
// Calculate the scales at which the text and icon can be placed without collision.
var glyphScale = hasText ?
collisionTile.placeCollisionFeature(textCollisionFeature,
layout['text-allow-overlap'], layout['symbol-avoid-edges']) :
collisionTile.minScale;
var iconScale = hasIcon ?
collisionTile.placeCollisionFeature(iconCollisionFeature,
layout['icon-allow-overlap'], layout['symbol-avoid-edges']) :
collisionTile.minScale;
// Combine the scales for icons and text.
if (!iconWithoutText && !textWithoutIcon) {
iconScale = glyphScale = Math.max(iconScale, glyphScale);
} else if (!textWithoutIcon && glyphScale) {
glyphScale = Math.max(iconScale, glyphScale);
} else if (!iconWithoutText && iconScale) {
iconScale = Math.max(iconScale, glyphScale);
}
// Insert final placement into collision tree and add glyphs/icons to buffers
if (hasText) {
collisionTile.insertCollisionFeature(textCollisionFeature, glyphScale, layout['text-ignore-placement']);
if (glyphScale <= maxScale) {
this.addSymbols('glyph', symbolInstance.glyphQuadStartIndex, symbolInstance.glyphQuadEndIndex, glyphScale, layout['text-keep-upright'], textAlongLine, collisionTile.angle);
}
}
if (hasIcon) {
collisionTile.insertCollisionFeature(iconCollisionFeature, iconScale, layout['icon-ignore-placement']);
if (iconScale <= maxScale) {
this.addSymbols('icon', symbolInstance.iconQuadStartIndex, symbolInstance.iconQuadEndIndex, iconScale, layout['icon-keep-upright'], iconAlongLine, collisionTile.angle);
}
}
}
if (showCollisionBoxes) this.addToDebugBuffers(collisionTile);
};
SymbolBucket.prototype.addSymbols = function(programName, quadsStart, quadsEnd, scale, keepUpright, alongLine, placementAngle) {
var group = this.prepareArrayGroup(programName, 4 * (quadsEnd - quadsStart));
var elementArray = group.elementArray;
var layoutVertexArray = group.layoutVertexArray;
var zoom = this.zoom;
var placementZoom = Math.max(Math.log(scale) / Math.LN2 + zoom, 0);
for (var k = quadsStart; k < quadsEnd; k++) {
var symbol = this.symbolQuadsArray.get(k).SymbolQuad;
// drop upside down versions of glyphs
var a = (symbol.anchorAngle + placementAngle + Math.PI) % (Math.PI * 2);
if (keepUpright && alongLine && (a <= Math.PI / 2 || a > Math.PI * 3 / 2)) continue;
var tl = symbol.tl,
tr = symbol.tr,
bl = symbol.bl,
br = symbol.br,
tex = symbol.tex,
anchorPoint = symbol.anchorPoint,
minZoom = Math.max(zoom + Math.log(symbol.minScale) / Math.LN2, placementZoom),
maxZoom = Math.min(zoom + Math.log(symbol.maxScale) / Math.LN2, 25);
if (maxZoom <= minZoom) continue;
// Lower min zoom so that while fading out the label it can be shown outside of collision-free zoom levels
if (minZoom === placementZoom) minZoom = 0;
// Encode angle of glyph
var glyphAngle = Math.round((symbol.glyphAngle / (Math.PI * 2)) * 256);
var index = addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, tl.x, tl.y, tex.x, tex.y, minZoom, maxZoom, placementZoom, glyphAngle);
addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, tr.x, tr.y, tex.x + tex.w, tex.y, minZoom, maxZoom, placementZoom, glyphAngle);
addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, bl.x, bl.y, tex.x, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle);
addVertex(layoutVertexArray, anchorPoint.x, anchorPoint.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h, minZoom, maxZoom, placementZoom, glyphAngle);
elementArray.emplaceBack(index, index + 1, index + 2);
elementArray.emplaceBack(index + 1, index + 2, index + 3);
}
};
SymbolBucket.prototype.updateIcons = function(icons) {
this.recalculateStyleLayers();
var iconValue = this.layer.layout['icon-image'];
if (!iconValue) return;
for (var i = 0; i < this.features.length; i++) {
var iconName = resolveTokens(this.features[i].properties, iconValue);
if (iconName)
icons[iconName] = true;
}
};
SymbolBucket.prototype.updateFont = function(stacks) {
this.recalculateStyleLayers();
var fontName = this.layer.layout['text-font'],
stack = stacks[fontName] = stacks[fontName] || {};
this.textFeatures = resolveText(this.features, this.layer.layout, stack);
};
SymbolBucket.prototype.addToDebugBuffers = function(collisionTile) {
var group = this.prepareArrayGroup('collisionBox', 0);
var layoutVertexArray = group.layoutVertexArray;
var angle = -collisionTile.angle;
var yStretch = collisionTile.yStretch;
for (var j = this.symbolInstancesStartIndex; j < this.symbolInstancesEndIndex; j++) {
var symbolInstance = this.symbolInstancesArray.get(j);
symbolInstance.textCollisionFeature = {boxStartIndex: symbolInstance.textBoxStartIndex, boxEndIndex: symbolInstance.textBoxEndIndex};
symbolInstance.iconCollisionFeature = {boxStartIndex: symbolInstance.iconBoxStartIndex, boxEndIndex: symbolInstance.iconBoxEndIndex};
for (var i = 0; i < 2; i++) {
var feature = symbolInstance[i === 0 ? 'textCollisionFeature' : 'iconCollisionFeature'];
if (!feature) continue;
for (var b = feature.boxStartIndex; b < feature.boxEndIndex; b++) {
var box = this.collisionBoxArray.get(b);
var anchorPoint = box.anchorPoint;
var tl = new Point(box.x1, box.y1 * yStretch)._rotate(angle);
var tr = new Point(box.x2, box.y1 * yStretch)._rotate(angle);
var bl = new Point(box.x1, box.y2 * yStretch)._rotate(angle);
var br = new Point(box.x2, box.y2 * yStretch)._rotate(angle);
var maxZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.maxScale) / Math.LN2));
var placementZoom = Math.max(0, Math.min(25, this.zoom + Math.log(box.placementScale) / Math.LN2));
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tl, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tr, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tr, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, br, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, br, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, bl, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, bl, maxZoom, placementZoom);
this.addCollisionBoxVertex(layoutVertexArray, anchorPoint, tl, maxZoom, placementZoom);
}
}
}
};
SymbolBucket.prototype.addSymbolInstance = function(anchor, line, shapedText, shapedIcon, layer, addToBuffers, index, collisionBoxArray, featureIndex, sourceLayerIndex, bucketIndex,
textBoxScale, textPadding, textAlongLine,
iconBoxScale, iconPadding, iconAlongLine, globalProperties, featureProperties) {
var glyphQuadStartIndex, glyphQuadEndIndex, iconQuadStartIndex, iconQuadEndIndex, textCollisionFeature, iconCollisionFeature, glyphQuads, iconQuads;
if (shapedText) {
glyphQuads = addToBuffers ? getGlyphQuads(anchor, shapedText, textBoxScale, line, layer, textAlongLine) : [];
textCollisionFeature = new CollisionFeature(collisionBoxArray, line, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedText, textBoxScale, textPadding, textAlongLine, false);
}
glyphQuadStartIndex = this.symbolQuadsArray.length;
if (glyphQuads && glyphQuads.length) {
for (var i = 0; i < glyphQuads.length; i++) {
this.addSymbolQuad(glyphQuads[i]);
}
}
glyphQuadEndIndex = this.symbolQuadsArray.length;
var textBoxStartIndex = textCollisionFeature ? textCollisionFeature.boxStartIndex : this.collisionBoxArray.length;
var textBoxEndIndex = textCollisionFeature ? textCollisionFeature.boxEndIndex : this.collisionBoxArray.length;
if (shapedIcon) {
iconQuads = addToBuffers ? getIconQuads(anchor, shapedIcon, iconBoxScale, line, layer, iconAlongLine, shapedText, globalProperties, featureProperties) : [];
iconCollisionFeature = new CollisionFeature(collisionBoxArray, line, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedIcon, iconBoxScale, iconPadding, iconAlongLine, true);
}
iconQuadStartIndex = this.symbolQuadsArray.length;
if (iconQuads && iconQuads.length === 1) {
this.addSymbolQuad(iconQuads[0]);
}
iconQuadEndIndex = this.symbolQuadsArray.length;
var iconBoxStartIndex = iconCollisionFeature ? iconCollisionFeature.boxStartIndex : this.collisionBoxArray.length;
var iconBoxEndIndex = iconCollisionFeature ? iconCollisionFeature.boxEndIndex : this.collisionBoxArray.length;
if (iconQuadEndIndex > SymbolBucket.MAX_QUADS) util.warnOnce("Too many symbols being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907");
if (glyphQuadEndIndex > SymbolBucket.MAX_QUADS) util.warnOnce("Too many glyphs being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907");
return this.symbolInstancesArray.emplaceBack(
textBoxStartIndex,
textBoxEndIndex,
iconBoxStartIndex,
iconBoxEndIndex,
glyphQuadStartIndex,
glyphQuadEndIndex,
iconQuadStartIndex,
iconQuadEndIndex,
anchor.x,
anchor.y,
index);
};
SymbolBucket.prototype.addSymbolQuad = function(symbolQuad) {
return this.symbolQuadsArray.emplaceBack(
// anchorPoints
symbolQuad.anchorPoint.x,
symbolQuad.anchorPoint.y,
// corners
symbolQuad.tl.x,
symbolQuad.tl.y,
symbolQuad.tr.x,
symbolQuad.tr.y,
symbolQuad.bl.x,
symbolQuad.bl.y,
symbolQuad.br.x,
symbolQuad.br.y,
// texture
symbolQuad.tex.h,
symbolQuad.tex.w,
symbolQuad.tex.x,
symbolQuad.tex.y,
//angle
symbolQuad.anchorAngle,
symbolQuad.glyphAngle,
// scales
symbolQuad.maxScale,
symbolQuad.minScale);
};
},{"../../symbol/anchor":384,"../../symbol/clip_line":386,"../../symbol/collision_feature":388,"../../symbol/get_anchors":390,"../../symbol/mergelines":393,"../../symbol/quads":394,"../../symbol/resolve_text":395,"../../symbol/shaping":396,"../../util/token":434,"../../util/util":435,"../bucket":322,"../load_geometry":330,"point-geometry":476}],327:[function(require,module,exports){
'use strict';
module.exports = Buffer;
/**
* The `Buffer` class turns a `StructArray` into a WebGL buffer. Each member of the StructArray's
* Struct type is converted to a WebGL atribute.
*
* @class Buffer
* @private
* @param {object} array A serialized StructArray.
* @param {object} arrayType A serialized StructArrayType.
* @param {BufferType} type
*/
function Buffer(array, arrayType, type) {
this.arrayBuffer = array.arrayBuffer;
this.length = array.length;
this.attributes = arrayType.members;
this.itemSize = arrayType.bytesPerElement;
this.type = type;
this.arrayType = arrayType;
}
/**
* Bind this buffer to a WebGL context.
* @private
* @param gl The WebGL context
*/
Buffer.prototype.bind = function(gl) {
var type = gl[this.type];
if (!this.buffer) {
this.buffer = gl.createBuffer();
gl.bindBuffer(type, this.buffer);
gl.bufferData(type, this.arrayBuffer, gl.STATIC_DRAW);
// dump array buffer once it's bound to gl
this.arrayBuffer = null;
} else {
gl.bindBuffer(type, this.buffer);
}
};
/**
* @enum {string} AttributeType
* @private
* @readonly
*/
var AttributeType = {
Int8: 'BYTE',
Uint8: 'UNSIGNED_BYTE',
Int16: 'SHORT',
Uint16: 'UNSIGNED_SHORT'
};
/**
* Set the attribute pointers in a WebGL context
* @private
* @param gl The WebGL context
* @param program The active WebGL program
*/
Buffer.prototype.setVertexAttribPointers = function(gl, program) {
for (var j = 0; j < this.attributes.length; j++) {
var member = this.attributes[j];
var attribIndex = program[member.name];
if (attribIndex !== undefined) {
gl.vertexAttribPointer(
attribIndex,
member.components,
gl[AttributeType[member.type]],
false,
this.arrayType.bytesPerElement,
member.offset
);
}
}
};
/**
* Destroy the GL buffer bound to the given WebGL context
* @private
* @param gl The WebGL context
*/
Buffer.prototype.destroy = function(gl) {
if (this.buffer) {
gl.deleteBuffer(this.buffer);
}
};
/**
* @enum {string} BufferType
* @private
* @readonly
*/
Buffer.BufferType = {
VERTEX: 'ARRAY_BUFFER',
ELEMENT: 'ELEMENT_ARRAY_BUFFER'
};
},{}],328:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var Buffer = require('./buffer');
var VertexArrayObject = require('../render/vertex_array_object');
module.exports = BufferGroup;
function BufferGroup(arrayGroup, arrayTypes) {
this.layoutVertexBuffer = new Buffer(arrayGroup.layoutVertexArray,
arrayTypes.layoutVertexArrayType, Buffer.BufferType.VERTEX);
if (arrayGroup.elementArray) {
this.elementBuffer = new Buffer(arrayGroup.elementArray,
arrayTypes.elementArrayType, Buffer.BufferType.ELEMENT);
}
var vaos = this.vaos = {};
var secondVaos;
if (arrayGroup.elementArray2) {
this.elementBuffer2 = new Buffer(arrayGroup.elementArray2,
arrayTypes.elementArrayType2, Buffer.BufferType.ELEMENT);
secondVaos = this.secondVaos = {};
}
this.paintVertexBuffers = util.mapObject(arrayGroup.paintVertexArrays, function(array, name) {
vaos[name] = new VertexArrayObject();
if (arrayGroup.elementArray2) {
secondVaos[name] = new VertexArrayObject();
}
return new Buffer(array, arrayTypes.paintVertexArrayTypes[name], Buffer.BufferType.VERTEX);
});
}
BufferGroup.prototype.destroy = function(gl) {
this.layoutVertexBuffer.destroy(gl);
if (this.elementBuffer) {
this.elementBuffer.destroy(gl);
}
if (this.elementBuffer2) {
this.elementBuffer2.destroy(gl);
}
for (var n in this.paintVertexBuffers) {
this.paintVertexBuffers[n].destroy(gl);
}
for (var j in this.vaos) {
this.vaos[j].destroy(gl);
}
for (var k in this.secondVaos) {
this.secondVaos[k].destroy(gl);
}
};
},{"../render/vertex_array_object":350,"../util/util":435,"./buffer":327}],329:[function(require,module,exports){
'use strict';
var Point = require('point-geometry');
var loadGeometry = require('./load_geometry');
var EXTENT = require('./bucket').EXTENT;
var featureFilter = require('feature-filter');
var StructArrayType = require('../util/struct_array');
var Grid = require('grid-index');
var DictionaryCoder = require('../util/dictionary_coder');
var vt = require('vector-tile');
var Protobuf = require('pbf');
var GeoJSONFeature = require('../util/vectortile_to_geojson');
var arraysIntersect = require('../util/util').arraysIntersect;
var intersection = require('../util/intersection_tests');
var multiPolygonIntersectsBufferedMultiPoint = intersection.multiPolygonIntersectsBufferedMultiPoint;
var multiPolygonIntersectsMultiPolygon = intersection.multiPolygonIntersectsMultiPolygon;
var multiPolygonIntersectsBufferedMultiLine = intersection.multiPolygonIntersectsBufferedMultiLine;
var FeatureIndexArray = new StructArrayType({
members: [
// the index of the feature in the original vectortile
{ type: 'Uint32', name: 'featureIndex' },
// the source layer the feature appears in
{ type: 'Uint16', name: 'sourceLayerIndex' },
// the bucket the feature appears in
{ type: 'Uint16', name: 'bucketIndex' }
]});
module.exports = FeatureIndex;
function FeatureIndex(coord, overscaling, collisionTile) {
if (coord.grid) {
var serialized = coord;
var rawTileData = overscaling;
coord = serialized.coord;
overscaling = serialized.overscaling;
this.grid = new Grid(serialized.grid);
this.featureIndexArray = new FeatureIndexArray(serialized.featureIndexArray);
this.rawTileData = rawTileData;
this.bucketLayerIDs = serialized.bucketLayerIDs;
} else {
this.grid = new Grid(EXTENT, 16, 0);
this.featureIndexArray = new FeatureIndexArray();
}
this.coord = coord;
this.overscaling = overscaling;
this.x = coord.x;
this.y = coord.y;
this.z = coord.z - Math.log(overscaling) / Math.LN2;
this.setCollisionTile(collisionTile);
}
FeatureIndex.prototype.insert = function(feature, featureIndex, sourceLayerIndex, bucketIndex) {
var key = this.featureIndexArray.length;
this.featureIndexArray.emplaceBack(featureIndex, sourceLayerIndex, bucketIndex);
var geometry = loadGeometry(feature);
for (var r = 0; r < geometry.length; r++) {
var ring = geometry[r];
var bbox = [Infinity, Infinity, -Infinity, -Infinity];
for (var i = 0; i < ring.length; i++) {
var p = ring[i];
bbox[0] = Math.min(bbox[0], p.x);
bbox[1] = Math.min(bbox[1], p.y);
bbox[2] = Math.max(bbox[2], p.x);
bbox[3] = Math.max(bbox[3], p.y);
}
this.grid.insert(key, bbox[0], bbox[1], bbox[2], bbox[3]);
}
};
FeatureIndex.prototype.setCollisionTile = function(collisionTile) {
this.collisionTile = collisionTile;
};
FeatureIndex.prototype.serialize = function() {
var data = {
coord: this.coord,
overscaling: this.overscaling,
grid: this.grid.toArrayBuffer(),
featureIndexArray: this.featureIndexArray.serialize(),
bucketLayerIDs: this.bucketLayerIDs
};
return {
data: data,
transferables: [data.grid, data.featureIndexArray.arrayBuffer]
};
};
function translateDistance(translate) {
return Math.sqrt(translate[0] * translate[0] + translate[1] * translate[1]);
}
// Finds features in this tile at a particular position.
FeatureIndex.prototype.query = function(args, styleLayers) {
if (!this.vtLayers) {
this.vtLayers = new vt.VectorTile(new Protobuf(new Uint8Array(this.rawTileData))).layers;
this.sourceLayerCoder = new DictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']);
}
var result = {};
var params = args.params || {},
pixelsToTileUnits = EXTENT / args.tileSize / args.scale,
filter = featureFilter(params.filter);
// Features are indexed their original geometries. The rendered geometries may
// be buffered, translated or offset. Figure out how much the search radius needs to be
// expanded by to include these features.
var additionalRadius = 0;
for (var id in styleLayers) {
var styleLayer = styleLayers[id];
var paint = styleLayer.paint;
var styleLayerDistance = 0;
if (styleLayer.type === 'line') {
styleLayerDistance = getLineWidth(paint) / 2 + Math.abs(paint['line-offset']) + translateDistance(paint['line-translate']);
} else if (styleLayer.type === 'fill') {
styleLayerDistance = translateDistance(paint['fill-translate']);
} else if (styleLayer.type === 'circle') {
styleLayerDistance = paint['circle-radius'] + translateDistance(paint['circle-translate']);
}
additionalRadius = Math.max(additionalRadius, styleLayerDistance * pixelsToTileUnits);
}
var queryGeometry = args.queryGeometry.map(function(q) {
return q.map(function(p) {
return new Point(p.x, p.y);
});
});
var minX = Infinity;
var minY = Infinity;
var maxX = -Infinity;
var maxY = -Infinity;
for (var i = 0; i < queryGeometry.length; i++) {
var ring = queryGeometry[i];
for (var k = 0; k < ring.length; k++) {
var p = ring[k];
minX = Math.min(minX, p.x);
minY = Math.min(minY, p.y);
maxX = Math.max(maxX, p.x);
maxY = Math.max(maxY, p.y);
}
}
var matching = this.grid.query(minX - additionalRadius, minY - additionalRadius, maxX + additionalRadius, maxY + additionalRadius);
matching.sort(topDownFeatureComparator);
this.filterMatching(result, matching, this.featureIndexArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits);
var matchingSymbols = this.collisionTile.queryRenderedSymbols(minX, minY, maxX, maxY, args.scale);
matchingSymbols.sort();
this.filterMatching(result, matchingSymbols, this.collisionTile.collisionBoxArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits);
return result;
};
function topDownFeatureComparator(a, b) {
return b - a;
}
function getLineWidth(paint) {
if (paint['line-gap-width'] > 0) {
return paint['line-gap-width'] + 2 * paint['line-width'];
} else {
return paint['line-width'];
}
}
FeatureIndex.prototype.filterMatching = function(result, matching, array, queryGeometry, filter, filterLayerIDs, styleLayers, bearing, pixelsToTileUnits) {
var previousIndex;
for (var k = 0; k < matching.length; k++) {
var index = matching[k];
// don't check the same feature more than once
if (index === previousIndex) continue;
previousIndex = index;
var match = array.get(index);
var layerIDs = this.bucketLayerIDs[match.bucketIndex];
if (filterLayerIDs && !arraysIntersect(filterLayerIDs, layerIDs)) continue;
var sourceLayerName = this.sourceLayerCoder.decode(match.sourceLayerIndex);
var sourceLayer = this.vtLayers[sourceLayerName];
var feature = sourceLayer.feature(match.featureIndex);
if (!filter(feature)) continue;
var geometry = null;
for (var l = 0; l < layerIDs.length; l++) {
var layerID = layerIDs[l];
if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) {
continue;
}
var styleLayer = styleLayers[layerID];
if (!styleLayer) continue;
var translatedPolygon;
if (styleLayer.type !== 'symbol') {
// all symbols already match the style
if (!geometry) geometry = loadGeometry(feature);
var paint = styleLayer.paint;
if (styleLayer.type === 'line') {
translatedPolygon = translate(queryGeometry,
paint['line-translate'], paint['line-translate-anchor'],
bearing, pixelsToTileUnits);
var halfWidth = getLineWidth(paint) / 2 * pixelsToTileUnits;
if (paint['line-offset']) {
geometry = offsetLine(geometry, paint['line-offset'] * pixelsToTileUnits);
}
if (!multiPolygonIntersectsBufferedMultiLine(translatedPolygon, geometry, halfWidth)) continue;
} else if (styleLayer.type === 'fill') {
translatedPolygon = translate(queryGeometry,
paint['fill-translate'], paint['fill-translate-anchor'],
bearing, pixelsToTileUnits);
if (!multiPolygonIntersectsMultiPolygon(translatedPolygon, geometry)) continue;
} else if (styleLayer.type === 'circle') {
translatedPolygon = translate(queryGeometry,
paint['circle-translate'], paint['circle-translate-anchor'],
bearing, pixelsToTileUnits);
var circleRadius = paint['circle-radius'] * pixelsToTileUnits;
if (!multiPolygonIntersectsBufferedMultiPoint(translatedPolygon, geometry, circleRadius)) continue;
}
}
var geojsonFeature = new GeoJSONFeature(feature, this.z, this.x, this.y);
geojsonFeature.layer = styleLayer.serialize({
includeRefProperties: true
});
var layerResult = result[layerID];
if (layerResult === undefined) {
layerResult = result[layerID] = [];
}
layerResult.push(geojsonFeature);
}
}
};
function translate(queryGeometry, translate, translateAnchor, bearing, pixelsToTileUnits) {
if (!translate[0] && !translate[1]) {
return queryGeometry;
}
translate = Point.convert(translate);
if (translateAnchor === "viewport") {
translate._rotate(-bearing);
}
var translated = [];
for (var i = 0; i < queryGeometry.length; i++) {
var ring = queryGeometry[i];
var translatedRing = [];
for (var k = 0; k < ring.length; k++) {
translatedRing.push(ring[k].sub(translate._mult(pixelsToTileUnits)));
}
translated.push(translatedRing);
}
return translated;
}
function offsetLine(rings, offset) {
var newRings = [];
var zero = new Point(0, 0);
for (var k = 0; k < rings.length; k++) {
var ring = rings[k];
var newRing = [];
for (var i = 0; i < ring.length; i++) {
var a = ring[i - 1];
var b = ring[i];
var c = ring[i + 1];
var aToB = i === 0 ? zero : b.sub(a)._unit()._perp();
var bToC = i === ring.length - 1 ? zero : c.sub(b)._unit()._perp();
var extrude = aToB._add(bToC)._unit();
var cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
extrude._mult(1 / cosHalfAngle);
newRing.push(extrude._mult(offset)._add(b));
}
newRings.push(newRing);
}
return newRings;
}
},{"../util/dictionary_coder":425,"../util/intersection_tests":430,"../util/struct_array":433,"../util/util":435,"../util/vectortile_to_geojson":436,"./bucket":322,"./load_geometry":330,"feature-filter":128,"grid-index":282,"pbf":470,"point-geometry":476,"vector-tile":542}],330:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var EXTENT = require('./bucket').EXTENT;
var assert = require('assert');
// These bounds define the minimum and maximum supported coordinate values.
// While visible coordinates are within [0, EXTENT], tiles may theoretically
// contain cordinates within [-Infinity, Infinity]. Our range is limited by the
// number of bits used to represent the coordinate.
function createBounds(bits) {
return {
min: -1 * Math.pow(2, bits - 1),
max: Math.pow(2, bits - 1) - 1
};
}
var boundsLookup = {
15: createBounds(15),
16: createBounds(16)
};
/**
* Loads a geometry from a VectorTileFeature and scales it to the common extent
* used internally.
* @param {VectorTileFeature} feature
* @param {number} [bits=16] The number of signed integer bits available to store
* each coordinate. A warning will be issued if any coordinate will not fits
* in the specified number of bits.
* @private
*/
module.exports = function loadGeometry(feature, bits) {
var bounds = boundsLookup[bits || 16];
assert(bounds);
var scale = EXTENT / feature.extent;
var geometry = feature.loadGeometry();
for (var r = 0; r < geometry.length; r++) {
var ring = geometry[r];
for (var p = 0; p < ring.length; p++) {
var point = ring[p];
// round here because mapbox-gl-native uses integers to represent
// points and we need to do the same to avoid renering differences.
point.x = Math.round(point.x * scale);
point.y = Math.round(point.y * scale);
if (point.x < bounds.min || point.x > bounds.max || point.y < bounds.min || point.y > bounds.max) {
util.warnOnce('Geometry exceeds allowed extent, reduce your vector tile buffer size');
}
}
}
return geometry;
};
},{"../util/util":435,"./bucket":322,"assert":43}],331:[function(require,module,exports){
'use strict';
module.exports = Coordinate;
/**
* A coordinate is a column, row, zoom combination, often used
* as the data component of a tile.
*
* @param {number} column
* @param {number} row
* @param {number} zoom
* @private
*/
function Coordinate(column, row, zoom) {
this.column = column;
this.row = row;
this.zoom = zoom;
}
Coordinate.prototype = {
/**
* Create a clone of this coordinate that can be mutated without
* changing the original coordinate
*
* @returns {Coordinate} clone
* @private
* var coord = new Coordinate(0, 0, 0);
* var c2 = coord.clone();
* // since coord is cloned, modifying a property of c2 does
* // not modify it.
* c2.zoom = 2;
*/
clone: function() {
return new Coordinate(this.column, this.row, this.zoom);
},
/**
* Zoom this coordinate to a given zoom level. This returns a new
* coordinate object, not mutating the old one.
*
* @param {number} zoom
* @returns {Coordinate} zoomed coordinate
* @private
* @example
* var coord = new Coordinate(0, 0, 0);
* var c2 = coord.zoomTo(1);
* c2 // equals new Coordinate(0, 0, 1);
*/
zoomTo: function(zoom) { return this.clone()._zoomTo(zoom); },
/**
* Subtract the column and row values of this coordinate from those
* of another coordinate. The other coordinat will be zoomed to the
* same level as `this` before the subtraction occurs
*
* @param {Coordinate} c other coordinate
* @returns {Coordinate} result
* @private
*/
sub: function(c) { return this.clone()._sub(c); },
_zoomTo: function(zoom) {
var scale = Math.pow(2, zoom - this.zoom);
this.column *= scale;
this.row *= scale;
this.zoom = zoom;
return this;
},
_sub: function(c) {
c = c.zoomTo(this.zoom);
this.column -= c.column;
this.row -= c.row;
return this;
}
};
},{}],332:[function(require,module,exports){
'use strict';
module.exports = LngLat;
var wrap = require('../util/util').wrap;
/**
* A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.
*
* Mapbox GL uses longitude, latitude coordinate order (as opposed to latitude, longitude) to match GeoJSON.
*
* Note that any Mapbox GL method that accepts a `LngLat` object as an argument or option
* can also accept an `Array` of two numbers and will perform an implicit conversion.
* This flexible type is documented as [`LngLatLike`](#LngLatLike).
*
* @class LngLat
* @param {number} lng Longitude, measured in degrees.
* @param {number} lat Latitude, measured in degrees.
* @example
* var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
*/
function LngLat(lng, lat) {
if (isNaN(lng) || isNaN(lat)) {
throw new Error('Invalid LngLat object: (' + lng + ', ' + lat + ')');
}
this.lng = +lng;
this.lat = +lat;
if (this.lat > 90 || this.lat < -90) {
throw new Error('Invalid LngLat latitude value: must be between -90 and 90');
}
}
/**
* Returns a new `LngLat` object whose longitude is wrapped to the range (-180, 180).
*
* @returns {LngLat} The wrapped `LngLat` object.
* @example
* var ll = new mapboxgl.LngLat(286.0251, 40.7736);
* var wrapped = ll.wrap();
* wrapped.lng; // = -73.9749
*/
LngLat.prototype.wrap = function () {
return new LngLat(wrap(this.lng, -180, 180), this.lat);
};
/**
* Returns the coordinates represented as an array of two numbers.
*
* @returns {Array} The coordinates represeted as an array of longitude and latitude.
* @example
* var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
* ll.toArray(); // = [-73.9749, 40.7736]
*/
LngLat.prototype.toArray = function () {
return [this.lng, this.lat];
};
/**
* Returns the coordinates represent as a string.
*
* @returns {string} The coordinates represented as a string of the format `'LngLat(lng, lat)'`.
* @example
* var ll = new mapboxgl.LngLat(-73.9749, 40.7736);
* ll.toString(); // = "LngLat(-73.9749, 40.7736)"
*/
LngLat.prototype.toString = function () {
return 'LngLat(' + this.lng + ', ' + this.lat + ')';
};
/**
* Converts an array of two numbers to a `LngLat` object.
*
* If a `LngLat` object is passed in, the function returns it unchanged.
*
* @param {LngLatLike} input An array of two numbers to convert, or a `LngLat` object to return.
* @returns {LngLat} A new `LngLat` object, if a conversion occurred, or the original `LngLat` object.
* @example
* var arr = [-73.9749, 40.7736];
* var ll = mapboxgl.LngLat.convert(arr);
* ll; // = LngLat {lng: -73.9749, lat: 40.7736}
*/
LngLat.convert = function (input) {
if (input instanceof LngLat) {
return input;
}
if (Array.isArray(input)) {
return new LngLat(input[0], input[1]);
}
return input;
};
},{"../util/util":435}],333:[function(require,module,exports){
'use strict';
module.exports = LngLatBounds;
var LngLat = require('./lng_lat');
/**
* A `LngLatBounds` object represents a geographical bounding box,
* defined by its southwest and northeast points in longitude and latitude.
*
* If no arguments are provided to the constructor, a `null` bounding box is created.
*
* Note that any Mapbox GL method that accepts a `LngLatBounds` object as an argument or option
* can also accept an `Array` of two [`LngLatLike`](#LngLatLike) constructs and will perform an implicit conversion.
* This flexible type is documented as [`LngLatBoundsLike`](#LngLatBoundsLike).
*
* @class LngLatBounds
* @param {LngLatLike} sw The southwest corner of the bounding box.
* @param {LngLatLike} ne The northeast corner of the bounding box.
* @example
* var sw = new mapboxgl.LngLat(-73.9876, 40.7661);
* var ne = new mapboxgl.LngLat(-73.9397, 40.8002);
* var llb = new mapboxgl.LngLatBounds(sw, ne);
*/
function LngLatBounds(sw, ne) {
if (!sw) {
return;
} else if (ne) {
this.extend(sw).extend(ne);
} else if (sw.length === 4) {
this.extend([sw[0], sw[1]]).extend([sw[2], sw[3]]);
} else {
this.extend(sw[0]).extend(sw[1]);
}
}
LngLatBounds.prototype = {
/**
* Extends the bounding box to include an area represented by a `LngLat` or `LngLatBounds`.
*
* @param {LngLatLike|LngLatBoundsLike} obj The area that the bounding box will extend to include.
* @returns {LngLatBounds} `this`
*/
extend: function(obj) {
var sw = this._sw,
ne = this._ne,
sw2, ne2;
if (obj instanceof LngLat) {
sw2 = obj;
ne2 = obj;
} else if (obj instanceof LngLatBounds) {
sw2 = obj._sw;
ne2 = obj._ne;
if (!sw2 || !ne2) return this;
} else {
return obj ? this.extend(LngLat.convert(obj) || LngLatBounds.convert(obj)) : this;
}
if (!sw && !ne) {
this._sw = new LngLat(sw2.lng, sw2.lat);
this._ne = new LngLat(ne2.lng, ne2.lat);
} else {
sw.lng = Math.min(sw2.lng, sw.lng);
sw.lat = Math.min(sw2.lat, sw.lat);
ne.lng = Math.max(ne2.lng, ne.lng);
ne.lat = Math.max(ne2.lat, ne.lat);
}
return this;
},
/**
* Returns the geographical coordinate equidistant from the bounding box's corners.
*
* @returns {LngLat} The bounding box's center.
* @example
* var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]);
* llb.getCenter(); // = LngLat {lng: -73.96365, lat: 40.78315}
*/
getCenter: function() {
return new LngLat((this._sw.lng + this._ne.lng) / 2, (this._sw.lat + this._ne.lat) / 2);
},
/**
* Returns the southwest corner of the bounding box.
*
* @returns {LngLat} The southwest corner of the bounding box.
*/
getSouthWest: function() { return this._sw; },
/**
* Returns the northeast corner of the bounding box.
*
* @returns {LngLat} The northeast corner of the bounding box.
*/
getNorthEast: function() { return this._ne; },
/**
* Returns the northwest corner of the bounding box.
*
* @returns {LngLat} The northwest corner of the bounding box.
*/
getNorthWest: function() { return new LngLat(this.getWest(), this.getNorth()); },
/**
* Returns the southeast corner of the bounding box.
*
* @returns {LngLat} The southeast corner of the bounding box.
*/
getSouthEast: function() { return new LngLat(this.getEast(), this.getSouth()); },
/**
* Returns the west edge of the bounding box.
*
* @returns {LngLat} The west edge of the bounding box.
*/
getWest: function() { return this._sw.lng; },
/**
* Returns the south edge of the bounding box.
*
* @returns {LngLat} The south edge of the bounding box.
*/
getSouth: function() { return this._sw.lat; },
/**
* Returns the east edge of the bounding box.
*
* @returns {LngLat} The east edge of the bounding box.
*/
getEast: function() { return this._ne.lng; },
/**
* Returns the north edge of the bounding box.
*
* @returns {LngLat} The north edge of the bounding box.
*/
getNorth: function() { return this._ne.lat; },
/**
* Returns the bounding box represented as an array.
*
* @returns {Array>} The bounding box represented as an array, consisting of the
* southwest and northeast coordinates of the bounding represented as arrays of numbers.
* @example
* var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]);
* llb.toArray(); // = [[-73.9876, 40.7661], [-73.9397, 40.8002]]
*/
toArray: function () {
return [this._sw.toArray(), this._ne.toArray()];
},
/**
* Return the bounding box represented as a string.
*
* @returns {string} The bounding box represents as a string of the format
* `'LngLatBounds(LngLat(lng, lat), LngLat(lng, lat))'`.
* @example
* var llb = new mapboxgl.LngLatBounds([-73.9876, 40.7661], [-73.9397, 40.8002]);
* llb.toString(); // = "LngLatBounds(LngLat(-73.9876, 40.7661), LngLat(-73.9397, 40.8002))"
*/
toString: function () {
return 'LngLatBounds(' + this._sw.toString() + ', ' + this._ne.toString() + ')';
}
};
/**
* Converts an array to a `LngLatBounds` object.
*
* If a `LngLatBounds` object is passed in, the function returns it unchanged.
*
* Internally, the function calls `LngLat#convert` to convert arrays to `LngLat` values.
*
* @param {LngLatBoundsLike} input An array of two coordinates to convert, or a `LngLatBounds` object to return.
* @returns {LngLatBounds} A new `LngLatBounds` object, if a conversion occurred, or the original `LngLatBounds` object.
* @example
* var arr = [[-73.9876, 40.7661], [-73.9397, 40.8002]];
* var llb = mapboxgl.LngLatBounds.convert(arr);
* llb; // = LngLatBounds {_sw: LngLat {lng: -73.9876, lat: 40.7661}, _ne: LngLat {lng: -73.9397, lat: 40.8002}}
*/
LngLatBounds.convert = function (input) {
if (!input || input instanceof LngLatBounds) return input;
return new LngLatBounds(input);
};
},{"./lng_lat":332}],334:[function(require,module,exports){
'use strict';
var LngLat = require('./lng_lat'),
Point = require('point-geometry'),
Coordinate = require('./coordinate'),
wrap = require('../util/util').wrap,
interp = require('../util/interpolate'),
TileCoord = require('../source/tile_coord'),
EXTENT = require('../data/bucket').EXTENT,
glmatrix = require('gl-matrix');
var vec4 = glmatrix.vec4,
mat4 = glmatrix.mat4,
mat2 = glmatrix.mat2;
module.exports = Transform;
/**
* A single transform, generally used for a single tile to be
* scaled, rotated, and zoomed.
*
* @param {number} minZoom
* @param {number} maxZoom
* @private
*/
function Transform(minZoom, maxZoom) {
this.tileSize = 512; // constant
this._minZoom = minZoom || 0;
this._maxZoom = maxZoom || 22;
this.latRange = [-85.05113, 85.05113];
this.width = 0;
this.height = 0;
this._center = new LngLat(0, 0);
this.zoom = 0;
this.angle = 0;
this._altitude = 1.5;
this._pitch = 0;
this._unmodified = true;
}
Transform.prototype = {
get minZoom() { return this._minZoom; },
set minZoom(zoom) {
if (this._minZoom === zoom) return;
this._minZoom = zoom;
this.zoom = Math.max(this.zoom, zoom);
},
get maxZoom() { return this._maxZoom; },
set maxZoom(zoom) {
if (this._maxZoom === zoom) return;
this._maxZoom = zoom;
this.zoom = Math.min(this.zoom, zoom);
},
get worldSize() {
return this.tileSize * this.scale;
},
get centerPoint() {
return this.size._div(2);
},
get size() {
return new Point(this.width, this.height);
},
get bearing() {
return -this.angle / Math.PI * 180;
},
set bearing(bearing) {
var b = -wrap(bearing, -180, 180) * Math.PI / 180;
if (this.angle === b) return;
this._unmodified = false;
this.angle = b;
this._calcMatrices();
// 2x2 matrix for rotating points
this.rotationMatrix = mat2.create();
mat2.rotate(this.rotationMatrix, this.rotationMatrix, this.angle);
},
get pitch() {
return this._pitch / Math.PI * 180;
},
set pitch(pitch) {
var p = Math.min(60, pitch) / 180 * Math.PI;
if (this._pitch === p) return;
this._unmodified = false;
this._pitch = p;
this._calcMatrices();
},
get altitude() {
return this._altitude;
},
set altitude(altitude) {
var a = Math.max(0.75, altitude);
if (this._altitude === a) return;
this._unmodified = false;
this._altitude = a;
this._calcMatrices();
},
get zoom() { return this._zoom; },
set zoom(zoom) {
var z = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);
if (this._zoom === z) return;
this._unmodified = false;
this._zoom = z;
this.scale = this.zoomScale(z);
this.tileZoom = Math.floor(z);
this.zoomFraction = z - this.tileZoom;
this._calcMatrices();
this._constrain();
},
get center() { return this._center; },
set center(center) {
if (center.lat === this._center.lat && center.lng === this._center.lng) return;
this._unmodified = false;
this._center = center;
this._calcMatrices();
this._constrain();
},
/**
* Return a zoom level that will cover all tiles the transform
* @param {Object} options
* @param {number} options.tileSize
* @param {boolean} options.roundZoom
* @returns {number} zoom level
* @private
*/
coveringZoomLevel: function(options) {
return (options.roundZoom ? Math.round : Math.floor)(
this.zoom + this.scaleZoom(this.tileSize / options.tileSize)
);
},
/**
* Return all coordinates that could cover this transform for a covering
* zoom level.
* @param {Object} options
* @param {number} options.tileSize
* @param {number} options.minzoom
* @param {number} options.maxzoom
* @param {boolean} options.roundZoom
* @param {boolean} options.reparseOverscaled
* @returns {Array} tiles
* @private
*/
coveringTiles: function(options) {
var z = this.coveringZoomLevel(options);
var actualZ = z;
if (z < options.minzoom) return [];
if (z > options.maxzoom) z = options.maxzoom;
var tr = this,
tileCenter = tr.locationCoordinate(tr.center)._zoomTo(z),
centerPoint = new Point(tileCenter.column - 0.5, tileCenter.row - 0.5);
return TileCoord.cover(z, [
tr.pointCoordinate(new Point(0, 0))._zoomTo(z),
tr.pointCoordinate(new Point(tr.width, 0))._zoomTo(z),
tr.pointCoordinate(new Point(tr.width, tr.height))._zoomTo(z),
tr.pointCoordinate(new Point(0, tr.height))._zoomTo(z)
], options.reparseOverscaled ? actualZ : z).sort(function(a, b) {
return centerPoint.dist(a) - centerPoint.dist(b);
});
},
resize: function(width, height) {
this.width = width;
this.height = height;
this.pixelsToGLUnits = [2 / width, -2 / height];
this._calcMatrices();
this._constrain();
},
get unmodified() { return this._unmodified; },
zoomScale: function(zoom) { return Math.pow(2, zoom); },
scaleZoom: function(scale) { return Math.log(scale) / Math.LN2; },
project: function(lnglat, worldSize) {
return new Point(
this.lngX(lnglat.lng, worldSize),
this.latY(lnglat.lat, worldSize));
},
unproject: function(point, worldSize) {
return new LngLat(
this.xLng(point.x, worldSize),
this.yLat(point.y, worldSize));
},
get x() { return this.lngX(this.center.lng); },
get y() { return this.latY(this.center.lat); },
get point() { return new Point(this.x, this.y); },
/**
* latitude to absolute x coord
* @param {number} lon
* @param {number} [worldSize=this.worldSize]
* @returns {number} pixel coordinate
* @private
*/
lngX: function(lng, worldSize) {
return (180 + lng) * (worldSize || this.worldSize) / 360;
},
/**
* latitude to absolute y coord
* @param {number} lat
* @param {number} [worldSize=this.worldSize]
* @returns {number} pixel coordinate
* @private
*/
latY: function(lat, worldSize) {
var y = 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));
return (180 - y) * (worldSize || this.worldSize) / 360;
},
xLng: function(x, worldSize) {
return x * 360 / (worldSize || this.worldSize) - 180;
},
yLat: function(y, worldSize) {
var y2 = 180 - y * 360 / (worldSize || this.worldSize);
return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;
},
panBy: function(offset) {
var point = this.centerPoint._add(offset);
this.center = this.pointLocation(point);
},
setLocationAtPoint: function(lnglat, point) {
var c = this.locationCoordinate(lnglat);
var coordAtPoint = this.pointCoordinate(point);
var coordCenter = this.pointCoordinate(this.centerPoint);
var translate = coordAtPoint._sub(c);
this._unmodified = false;
this.center = this.coordinateLocation(coordCenter._sub(translate));
},
/**
* Given a location, return the screen point that corresponds to it
* @param {LngLat} lnglat location
* @returns {Point} screen point
* @private
*/
locationPoint: function(lnglat) {
return this.coordinatePoint(this.locationCoordinate(lnglat));
},
/**
* Given a point on screen, return its lnglat
* @param {Point} p screen point
* @returns {LngLat} lnglat location
* @private
*/
pointLocation: function(p) {
return this.coordinateLocation(this.pointCoordinate(p));
},
/**
* Given a geographical lnglat, return an unrounded
* coordinate that represents it at this transform's zoom level and
* worldsize.
* @param {LngLat} lnglat
* @returns {Coordinate}
* @private
*/
locationCoordinate: function(lnglat) {
var k = this.zoomScale(this.tileZoom) / this.worldSize,
ll = LngLat.convert(lnglat);
return new Coordinate(
this.lngX(ll.lng) * k,
this.latY(ll.lat) * k,
this.tileZoom);
},
/**
* Given a Coordinate, return its geographical position.
* @param {Coordinate} coord
* @returns {LngLat} lnglat
* @private
*/
coordinateLocation: function(coord) {
var worldSize = this.zoomScale(coord.zoom);
return new LngLat(
this.xLng(coord.column, worldSize),
this.yLat(coord.row, worldSize));
},
pointCoordinate: function(p) {
var targetZ = 0;
// since we don't know the correct projected z value for the point,
// unproject two points to get a line and then find the point on that
// line with z=0
var coord0 = [p.x, p.y, 0, 1];
var coord1 = [p.x, p.y, 1, 1];
vec4.transformMat4(coord0, coord0, this.pixelMatrixInverse);
vec4.transformMat4(coord1, coord1, this.pixelMatrixInverse);
var w0 = coord0[3];
var w1 = coord1[3];
var x0 = coord0[0] / w0;
var x1 = coord1[0] / w1;
var y0 = coord0[1] / w0;
var y1 = coord1[1] / w1;
var z0 = coord0[2] / w0;
var z1 = coord1[2] / w1;
var t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);
var scale = this.worldSize / this.zoomScale(this.tileZoom);
return new Coordinate(
interp(x0, x1, t) / scale,
interp(y0, y1, t) / scale,
this.tileZoom);
},
/**
* Given a coordinate, return the screen point that corresponds to it
* @param {Coordinate} coord
* @returns {Point} screen point
* @private
*/
coordinatePoint: function(coord) {
var scale = this.worldSize / this.zoomScale(coord.zoom);
var p = [coord.column * scale, coord.row * scale, 0, 1];
vec4.transformMat4(p, p, this.pixelMatrix);
return new Point(p[0] / p[3], p[1] / p[3]);
},
/**
* Calculate the posMatrix that, given a tile coordinate, would be used to display the tile on a map.
* @param {TileCoord|Coordinate} coord
* @param {Number} maxZoom maximum source zoom to account for overscaling
* @private
*/
calculatePosMatrix: function(coord, maxZoom) {
if (maxZoom === undefined) maxZoom = Infinity;
if (coord instanceof TileCoord) coord = coord.toCoordinate(maxZoom);
// Initialize model-view matrix that converts from the tile coordinates to screen coordinates.
// if z > maxzoom then the tile is actually a overscaled maxzoom tile,
// so calculate the matrix the maxzoom tile would use.
var z = Math.min(coord.zoom, maxZoom);
var scale = this.worldSize / Math.pow(2, z);
var posMatrix = new Float64Array(16);
mat4.identity(posMatrix);
mat4.translate(posMatrix, posMatrix, [coord.column * scale, coord.row * scale, 0]);
mat4.scale(posMatrix, posMatrix, [ scale / EXTENT, scale / EXTENT, 1 ]);
mat4.multiply(posMatrix, this.projMatrix, posMatrix);
return new Float32Array(posMatrix);
},
_constrain: function() {
if (!this.center || !this.width || !this.height || this._constraining) return;
this._constraining = true;
var minY, maxY, minX, maxX, sy, sx, x2, y2,
size = this.size,
unmodified = this._unmodified;
if (this.latRange) {
minY = this.latY(this.latRange[1]);
maxY = this.latY(this.latRange[0]);
sy = maxY - minY < size.y ? size.y / (maxY - minY) : 0;
}
if (this.lngRange) {
minX = this.lngX(this.lngRange[0]);
maxX = this.lngX(this.lngRange[1]);
sx = maxX - minX < size.x ? size.x / (maxX - minX) : 0;
}
// how much the map should scale to fit the screen into given latitude/longitude ranges
var s = Math.max(sx || 0, sy || 0);
if (s) {
this.center = this.unproject(new Point(
sx ? (maxX + minX) / 2 : this.x,
sy ? (maxY + minY) / 2 : this.y));
this.zoom += this.scaleZoom(s);
this._unmodified = unmodified;
this._constraining = false;
return;
}
if (this.latRange) {
var y = this.y,
h2 = size.y / 2;
if (y - h2 < minY) y2 = minY + h2;
if (y + h2 > maxY) y2 = maxY - h2;
}
if (this.lngRange) {
var x = this.x,
w2 = size.x / 2;
if (x - w2 < minX) x2 = minX + w2;
if (x + w2 > maxX) x2 = maxX - w2;
}
// pan the map if the screen goes off the range
if (x2 !== undefined || y2 !== undefined) {
this.center = this.unproject(new Point(
x2 !== undefined ? x2 : this.x,
y2 !== undefined ? y2 : this.y));
}
this._unmodified = unmodified;
this._constraining = false;
},
_calcMatrices: function() {
if (!this.height) return;
// Find the distance from the center point to the center top in altitude units using law of sines.
var halfFov = Math.atan(0.5 / this.altitude);
var topHalfSurfaceDistance = Math.sin(halfFov) * this.altitude / Math.sin(Math.PI / 2 - this._pitch - halfFov);
// Calculate z value of the farthest fragment that should be rendered.
var farZ = Math.cos(Math.PI / 2 - this._pitch) * topHalfSurfaceDistance + this.altitude;
// matrix for conversion from location to GL coordinates (-1 .. 1)
var m = new Float64Array(16);
mat4.perspective(m, 2 * Math.atan((this.height / 2) / this.altitude), this.width / this.height, 0.1, farZ);
mat4.translate(m, m, [0, 0, -this.altitude]);
// After the rotateX, z values are in pixel units. Convert them to
// altitude units. 1 altitude unit = the screen height.
mat4.scale(m, m, [1, -1, 1 / this.height]);
mat4.rotateX(m, m, this._pitch);
mat4.rotateZ(m, m, this.angle);
mat4.translate(m, m, [-this.x, -this.y, 0]);
this.projMatrix = m;
// matrix for conversion from location to screen coordinates
m = mat4.create();
mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);
mat4.translate(m, m, [1, -1, 0]);
this.pixelMatrix = mat4.multiply(new Float64Array(16), m, this.projMatrix);
// inverse matrix for conversion from screen coordinaes to location
m = mat4.invert(new Float64Array(16), this.pixelMatrix);
if (!m) throw new Error("failed to invert matrix");
this.pixelMatrixInverse = m;
}
};
},{"../data/bucket":322,"../source/tile_coord":362,"../util/interpolate":429,"../util/util":435,"./coordinate":331,"./lng_lat":332,"gl-matrix":188,"point-geometry":476}],335:[function(require,module,exports){
'use strict';
// Font data From Hershey Simplex Font
// http://paulbourke.net/dataformats/hershey/
var simplexFont = {
" ": [16, []],
"!": [10, [5, 21, 5, 7, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2]],
"\"": [16, [4, 21, 4, 14, -1, -1, 12, 21, 12, 14]],
"#": [21, [11, 25, 4, -7, -1, -1, 17, 25, 10, -7, -1, -1, 4, 12, 18, 12, -1, -1, 3, 6, 17, 6]],
"$": [20, [8, 25, 8, -4, -1, -1, 12, 25, 12, -4, -1, -1, 17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3]],
"%": [24, [21, 21, 3, 0, -1, -1, 8, 21, 10, 19, 10, 17, 9, 15, 7, 14, 5, 14, 3, 16, 3, 18, 4, 20, 6, 21, 8, 21, 10, 20, 13, 19, 16, 19, 19, 20, 21, 21, -1, -1, 17, 7, 15, 6, 14, 4, 14, 2, 16, 0, 18, 0, 20, 1, 21, 3, 21, 5, 19, 7, 17, 7]],
"&": [26, [23, 12, 23, 13, 22, 14, 21, 14, 20, 13, 19, 11, 17, 6, 15, 3, 13, 1, 11, 0, 7, 0, 5, 1, 4, 2, 3, 4, 3, 6, 4, 8, 5, 9, 12, 13, 13, 14, 14, 16, 14, 18, 13, 20, 11, 21, 9, 20, 8, 18, 8, 16, 9, 13, 11, 10, 16, 3, 18, 1, 20, 0, 22, 0, 23, 1, 23, 2]],
"'": [10, [5, 19, 4, 20, 5, 21, 6, 20, 6, 18, 5, 16, 4, 15]],
"(": [14, [11, 25, 9, 23, 7, 20, 5, 16, 4, 11, 4, 7, 5, 2, 7, -2, 9, -5, 11, -7]],
")": [14, [3, 25, 5, 23, 7, 20, 9, 16, 10, 11, 10, 7, 9, 2, 7, -2, 5, -5, 3, -7]],
"*": [16, [8, 21, 8, 9, -1, -1, 3, 18, 13, 12, -1, -1, 13, 18, 3, 12]],
"+": [26, [13, 18, 13, 0, -1, -1, 4, 9, 22, 9]],
",": [10, [6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4]],
"-": [26, [4, 9, 22, 9]],
".": [10, [5, 2, 4, 1, 5, 0, 6, 1, 5, 2]],
"/": [22, [20, 25, 2, -7]],
"0": [20, [9, 21, 6, 20, 4, 17, 3, 12, 3, 9, 4, 4, 6, 1, 9, 0, 11, 0, 14, 1, 16, 4, 17, 9, 17, 12, 16, 17, 14, 20, 11, 21, 9, 21]],
"1": [20, [6, 17, 8, 18, 11, 21, 11, 0]],
"2": [20, [4, 16, 4, 17, 5, 19, 6, 20, 8, 21, 12, 21, 14, 20, 15, 19, 16, 17, 16, 15, 15, 13, 13, 10, 3, 0, 17, 0]],
"3": [20, [5, 21, 16, 21, 10, 13, 13, 13, 15, 12, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4]],
"4": [20, [13, 21, 3, 7, 18, 7, -1, -1, 13, 21, 13, 0]],
"5": [20, [15, 21, 5, 21, 4, 12, 5, 13, 8, 14, 11, 14, 14, 13, 16, 11, 17, 8, 17, 6, 16, 3, 14, 1, 11, 0, 8, 0, 5, 1, 4, 2, 3, 4]],
"6": [20, [16, 18, 15, 20, 12, 21, 10, 21, 7, 20, 5, 17, 4, 12, 4, 7, 5, 3, 7, 1, 10, 0, 11, 0, 14, 1, 16, 3, 17, 6, 17, 7, 16, 10, 14, 12, 11, 13, 10, 13, 7, 12, 5, 10, 4, 7]],
"7": [20, [17, 21, 7, 0, -1, -1, 3, 21, 17, 21]],
"8": [20, [8, 21, 5, 20, 4, 18, 4, 16, 5, 14, 7, 13, 11, 12, 14, 11, 16, 9, 17, 7, 17, 4, 16, 2, 15, 1, 12, 0, 8, 0, 5, 1, 4, 2, 3, 4, 3, 7, 4, 9, 6, 11, 9, 12, 13, 13, 15, 14, 16, 16, 16, 18, 15, 20, 12, 21, 8, 21]],
"9": [20, [16, 14, 15, 11, 13, 9, 10, 8, 9, 8, 6, 9, 4, 11, 3, 14, 3, 15, 4, 18, 6, 20, 9, 21, 10, 21, 13, 20, 15, 18, 16, 14, 16, 9, 15, 4, 13, 1, 10, 0, 8, 0, 5, 1, 4, 3]],
":": [10, [5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 5, 2, 4, 1, 5, 0, 6, 1, 5, 2]],
";": [10, [5, 14, 4, 13, 5, 12, 6, 13, 5, 14, -1, -1, 6, 1, 5, 0, 4, 1, 5, 2, 6, 1, 6, -1, 5, -3, 4, -4]],
"<": [24, [20, 18, 4, 9, 20, 0]],
"=": [26, [4, 12, 22, 12, -1, -1, 4, 6, 22, 6]],
">": [24, [4, 18, 20, 9, 4, 0]],
"?": [18, [3, 16, 3, 17, 4, 19, 5, 20, 7, 21, 11, 21, 13, 20, 14, 19, 15, 17, 15, 15, 14, 13, 13, 12, 9, 10, 9, 7, -1, -1, 9, 2, 8, 1, 9, 0, 10, 1, 9, 2]],
"@": [27, [18, 13, 17, 15, 15, 16, 12, 16, 10, 15, 9, 14, 8, 11, 8, 8, 9, 6, 11, 5, 14, 5, 16, 6, 17, 8, -1, -1, 12, 16, 10, 14, 9, 11, 9, 8, 10, 6, 11, 5, -1, -1, 18, 16, 17, 8, 17, 6, 19, 5, 21, 5, 23, 7, 24, 10, 24, 12, 23, 15, 22, 17, 20, 19, 18, 20, 15, 21, 12, 21, 9, 20, 7, 19, 5, 17, 4, 15, 3, 12, 3, 9, 4, 6, 5, 4, 7, 2, 9, 1, 12, 0, 15, 0, 18, 1, 20, 2, 21, 3, -1, -1, 19, 16, 18, 8, 18, 6, 19, 5]],
"A": [18, [9, 21, 1, 0, -1, -1, 9, 21, 17, 0, -1, -1, 4, 7, 14, 7]],
"B": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, -1, -1, 4, 11, 13, 11, 16, 10, 17, 9, 18, 7, 18, 4, 17, 2, 16, 1, 13, 0, 4, 0]],
"C": [21, [18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5]],
"D": [21, [4, 21, 4, 0, -1, -1, 4, 21, 11, 21, 14, 20, 16, 18, 17, 16, 18, 13, 18, 8, 17, 5, 16, 3, 14, 1, 11, 0, 4, 0]],
"E": [19, [4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11, -1, -1, 4, 0, 17, 0]],
"F": [18, [4, 21, 4, 0, -1, -1, 4, 21, 17, 21, -1, -1, 4, 11, 12, 11]],
"G": [21, [18, 16, 17, 18, 15, 20, 13, 21, 9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 18, 8, -1, -1, 13, 8, 18, 8]],
"H": [22, [4, 21, 4, 0, -1, -1, 18, 21, 18, 0, -1, -1, 4, 11, 18, 11]],
"I": [8, [4, 21, 4, 0]],
"J": [16, [12, 21, 12, 5, 11, 2, 10, 1, 8, 0, 6, 0, 4, 1, 3, 2, 2, 5, 2, 7]],
"K": [21, [4, 21, 4, 0, -1, -1, 18, 21, 4, 7, -1, -1, 9, 12, 18, 0]],
"L": [17, [4, 21, 4, 0, -1, -1, 4, 0, 16, 0]],
"M": [24, [4, 21, 4, 0, -1, -1, 4, 21, 12, 0, -1, -1, 20, 21, 12, 0, -1, -1, 20, 21, 20, 0]],
"N": [22, [4, 21, 4, 0, -1, -1, 4, 21, 18, 0, -1, -1, 18, 21, 18, 0]],
"O": [22, [9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21]],
"P": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 14, 17, 12, 16, 11, 13, 10, 4, 10]],
"Q": [22, [9, 21, 7, 20, 5, 18, 4, 16, 3, 13, 3, 8, 4, 5, 5, 3, 7, 1, 9, 0, 13, 0, 15, 1, 17, 3, 18, 5, 19, 8, 19, 13, 18, 16, 17, 18, 15, 20, 13, 21, 9, 21, -1, -1, 12, 4, 18, -2]],
"R": [21, [4, 21, 4, 0, -1, -1, 4, 21, 13, 21, 16, 20, 17, 19, 18, 17, 18, 15, 17, 13, 16, 12, 13, 11, 4, 11, -1, -1, 11, 11, 18, 0]],
"S": [20, [17, 18, 15, 20, 12, 21, 8, 21, 5, 20, 3, 18, 3, 16, 4, 14, 5, 13, 7, 12, 13, 10, 15, 9, 16, 8, 17, 6, 17, 3, 15, 1, 12, 0, 8, 0, 5, 1, 3, 3]],
"T": [16, [8, 21, 8, 0, -1, -1, 1, 21, 15, 21]],
"U": [22, [4, 21, 4, 6, 5, 3, 7, 1, 10, 0, 12, 0, 15, 1, 17, 3, 18, 6, 18, 21]],
"V": [18, [1, 21, 9, 0, -1, -1, 17, 21, 9, 0]],
"W": [24, [2, 21, 7, 0, -1, -1, 12, 21, 7, 0, -1, -1, 12, 21, 17, 0, -1, -1, 22, 21, 17, 0]],
"X": [20, [3, 21, 17, 0, -1, -1, 17, 21, 3, 0]],
"Y": [18, [1, 21, 9, 11, 9, 0, -1, -1, 17, 21, 9, 11]],
"Z": [20, [17, 21, 3, 0, -1, -1, 3, 21, 17, 21, -1, -1, 3, 0, 17, 0]],
"[": [14, [4, 25, 4, -7, -1, -1, 5, 25, 5, -7, -1, -1, 4, 25, 11, 25, -1, -1, 4, -7, 11, -7]],
"\\": [14, [0, 21, 14, -3]],
"]": [14, [9, 25, 9, -7, -1, -1, 10, 25, 10, -7, -1, -1, 3, 25, 10, 25, -1, -1, 3, -7, 10, -7]],
"^": [16, [6, 15, 8, 18, 10, 15, -1, -1, 3, 12, 8, 17, 13, 12, -1, -1, 8, 17, 8, 0]],
"_": [16, [0, -2, 16, -2]],
"`": [10, [6, 21, 5, 20, 4, 18, 4, 16, 5, 15, 6, 16, 5, 17]],
"a": [19, [15, 14, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"b": [19, [4, 21, 4, 0, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3]],
"c": [18, [15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"d": [19, [15, 21, 15, 0, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"e": [18, [3, 8, 15, 8, 15, 10, 14, 12, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"f": [12, [10, 21, 8, 21, 6, 20, 5, 17, 5, 0, -1, -1, 2, 14, 9, 14]],
"g": [19, [15, 14, 15, -2, 14, -5, 13, -6, 11, -7, 8, -7, 6, -6, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"h": [19, [4, 21, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0]],
"i": [8, [3, 21, 4, 20, 5, 21, 4, 22, 3, 21, -1, -1, 4, 14, 4, 0]],
"j": [10, [5, 21, 6, 20, 7, 21, 6, 22, 5, 21, -1, -1, 6, 14, 6, -3, 5, -6, 3, -7, 1, -7]],
"k": [17, [4, 21, 4, 0, -1, -1, 14, 14, 4, 4, -1, -1, 8, 8, 15, 0]],
"l": [8, [4, 21, 4, 0]],
"m": [30, [4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0, -1, -1, 15, 10, 18, 13, 20, 14, 23, 14, 25, 13, 26, 10, 26, 0]],
"n": [19, [4, 14, 4, 0, -1, -1, 4, 10, 7, 13, 9, 14, 12, 14, 14, 13, 15, 10, 15, 0]],
"o": [19, [8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3, 16, 6, 16, 8, 15, 11, 13, 13, 11, 14, 8, 14]],
"p": [19, [4, 14, 4, -7, -1, -1, 4, 11, 6, 13, 8, 14, 11, 14, 13, 13, 15, 11, 16, 8, 16, 6, 15, 3, 13, 1, 11, 0, 8, 0, 6, 1, 4, 3]],
"q": [19, [15, 14, 15, -7, -1, -1, 15, 11, 13, 13, 11, 14, 8, 14, 6, 13, 4, 11, 3, 8, 3, 6, 4, 3, 6, 1, 8, 0, 11, 0, 13, 1, 15, 3]],
"r": [13, [4, 14, 4, 0, -1, -1, 4, 8, 5, 11, 7, 13, 9, 14, 12, 14]],
"s": [17, [14, 11, 13, 13, 10, 14, 7, 14, 4, 13, 3, 11, 4, 9, 6, 8, 11, 7, 13, 6, 14, 4, 14, 3, 13, 1, 10, 0, 7, 0, 4, 1, 3, 3]],
"t": [12, [5, 21, 5, 4, 6, 1, 8, 0, 10, 0, -1, -1, 2, 14, 9, 14]],
"u": [19, [4, 14, 4, 4, 5, 1, 7, 0, 10, 0, 12, 1, 15, 4, -1, -1, 15, 14, 15, 0]],
"v": [16, [2, 14, 8, 0, -1, -1, 14, 14, 8, 0]],
"w": [22, [3, 14, 7, 0, -1, -1, 11, 14, 7, 0, -1, -1, 11, 14, 15, 0, -1, -1, 19, 14, 15, 0]],
"x": [17, [3, 14, 14, 0, -1, -1, 14, 14, 3, 0]],
"y": [16, [2, 14, 8, 0, -1, -1, 14, 14, 8, 0, 6, -4, 4, -6, 2, -7, 1, -7]],
"z": [17, [14, 14, 3, 0, -1, -1, 3, 14, 14, 14, -1, -1, 3, 0, 14, 0]],
"{": [14, [9, 25, 7, 24, 6, 23, 5, 21, 5, 19, 6, 17, 7, 16, 8, 14, 8, 12, 6, 10, -1, -1, 7, 24, 6, 22, 6, 20, 7, 18, 8, 17, 9, 15, 9, 13, 8, 11, 4, 9, 8, 7, 9, 5, 9, 3, 8, 1, 7, 0, 6, -2, 6, -4, 7, -6, -1, -1, 6, 8, 8, 6, 8, 4, 7, 2, 6, 1, 5, -1, 5, -3, 6, -5, 7, -6, 9, -7]],
"|": [8, [4, 25, 4, -7]],
"}": [14, [5, 25, 7, 24, 8, 23, 9, 21, 9, 19, 8, 17, 7, 16, 6, 14, 6, 12, 8, 10, -1, -1, 7, 24, 8, 22, 8, 20, 7, 18, 6, 17, 5, 15, 5, 13, 6, 11, 10, 9, 6, 7, 5, 5, 5, 3, 6, 1, 7, 0, 8, -2, 8, -4, 7, -6, -1, -1, 8, 8, 6, 6, 6, 4, 7, 2, 8, 1, 9, -1, 9, -3, 8, -5, 7, -6, 5, -7]],
"~": [24, [3, 6, 3, 8, 4, 11, 6, 12, 8, 12, 10, 11, 14, 8, 16, 7, 18, 7, 20, 8, 21, 10, -1, -1, 3, 8, 4, 10, 6, 11, 8, 11, 10, 10, 14, 7, 16, 6, 18, 6, 20, 7, 21, 10, 21, 12]]
};
module.exports = function textVertices(text, left, baseline, scale) {
scale = scale || 1;
var strokes = [],
i, len, j, len2, glyph, x, y, prev;
for (i = 0, len = text.length; i < len; i++) {
glyph = simplexFont[text[i]];
if (!glyph) continue;
prev = null;
for (j = 0, len2 = glyph[1].length; j < len2; j += 2) {
if (glyph[1][j] === -1 && glyph[1][j + 1] === -1) {
prev = null;
} else {
x = left + glyph[1][j] * scale;
y = baseline - glyph[1][j + 1] * scale;
if (prev) {
strokes.push(prev.x, prev.y, x, y);
}
prev = {x: x, y: y};
}
}
left += glyph[0] * scale;
}
return strokes;
};
},{}],336:[function(require,module,exports){
'use strict';
// jshint -W079
var mapboxgl = module.exports = {};
mapboxgl.version = require('../package.json').version;
mapboxgl.Map = require('./ui/map');
mapboxgl.Control = require('./ui/control/control');
mapboxgl.Navigation = require('./ui/control/navigation');
mapboxgl.Geolocate = require('./ui/control/geolocate');
mapboxgl.Attribution = require('./ui/control/attribution');
mapboxgl.Popup = require('./ui/popup');
mapboxgl.Marker = require('./ui/marker');
mapboxgl.Style = require('./style/style');
mapboxgl.LngLat = require('./geo/lng_lat');
mapboxgl.LngLatBounds = require('./geo/lng_lat_bounds');
mapboxgl.Point = require('point-geometry');
mapboxgl.Evented = require('./util/evented');
mapboxgl.util = require('./util/util');
mapboxgl.supported = require('./util/browser').supported;
var ajax = require('./util/ajax');
mapboxgl.util.getJSON = ajax.getJSON;
mapboxgl.util.getArrayBuffer = ajax.getArrayBuffer;
var config = require('./util/config');
mapboxgl.config = config;
Object.defineProperty(mapboxgl, 'accessToken', {
get: function() { return config.ACCESS_TOKEN; },
set: function(token) { config.ACCESS_TOKEN = token; }
});
/**
* Gets and sets the map's [access token](https://www.mapbox.com/help/define-access-token/).
*
* @var {string} accessToken
* @example
* mapboxgl.accessToken = myAccessToken;
*/
/**
* The version of Mapbox GL JS in use as specified in `package.json`,
* `CHANGELOG.md`, and the GitHub release.
*
* @var {string} version
*/
/**
* Returns a Boolean indicating whether the browser [supports Mapbox GL JS](https://www.mapbox.com/help/mapbox-browser-support/#mapbox-gl-js).
*
* @function supported
* @param {Object} options
* @param {boolean} [options.failIfMajorPerformanceCaveat=false] If `true`,
* the function will return `false` if the performance of Mapbox GL JS would
* be dramatically worse than expected (i.e. a software renderer would be used).
* @return {boolean}
* @example
* mapboxgl.supported() // = true
*/
},{"../package.json":437,"./geo/lng_lat":332,"./geo/lng_lat_bounds":333,"./style/style":371,"./ui/control/attribution":402,"./ui/control/control":403,"./ui/control/geolocate":404,"./ui/control/navigation":405,"./ui/map":414,"./ui/marker":415,"./ui/popup":416,"./util/ajax":418,"./util/browser":419,"./util/config":424,"./util/evented":427,"./util/util":435,"point-geometry":476}],337:[function(require,module,exports){
'use strict';
var assert = require('assert');
module.exports = function(uniforms) {
var pragmas = { define: {}, initialize: {} };
for (var i = 0; i < uniforms.length; i++) {
var uniform = uniforms[i];
assert(uniform.name.slice(0, 2) === 'u_');
var type = '{precision} ' + (uniform.components === 1 ? 'float' : 'vec' + uniform.components);
pragmas.define[uniform.name.slice(2)] = 'uniform ' + type + ' ' + uniform.name + ';\n';
pragmas.initialize[uniform.name.slice(2)] = type + ' ' + uniform.name.slice(2) + ' = ' + uniform.name + ';\n';
}
return pragmas;
};
},{"assert":43}],338:[function(require,module,exports){
'use strict';
var pixelsToTileUnits = require('../source/pixels_to_tile_units');
var createUniformPragmas = require('./create_uniform_pragmas');
var tileSize = 512;
module.exports = drawBackground;
function drawBackground(painter, source, layer) {
var gl = painter.gl;
var transform = painter.transform;
var color = layer.paint['background-color'];
var image = layer.paint['background-pattern'];
var opacity = layer.paint['background-opacity'];
var program;
var imagePosA = image ? painter.spriteAtlas.getPosition(image.from, true) : null;
var imagePosB = image ? painter.spriteAtlas.getPosition(image.to, true) : null;
painter.setDepthSublayer(0);
if (imagePosA && imagePosB) {
if (painter.isOpaquePass) return;
// Draw texture fill
program = painter.useProgram('pattern');
gl.uniform1i(program.u_image, 0);
gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(program.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_mix, image.t);
gl.uniform2fv(program.u_pattern_size_a, imagePosA.size);
gl.uniform2fv(program.u_pattern_size_b, imagePosB.size);
gl.uniform1f(program.u_scale_a, image.fromScale);
gl.uniform1f(program.u_scale_b, image.toScale);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);
painter.tileExtentPatternVAO.bind(gl, program, painter.tileExtentBuffer);
} else {
// Draw filling rectangle.
if (painter.isOpaquePass !== (color[3] === 1)) return;
var pragmas = createUniformPragmas([
{name: 'u_color', components: 4},
{name: 'u_opacity', components: 1}
]);
program = painter.useProgram('fill', [], pragmas, pragmas);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, opacity);
painter.tileExtentVAO.bind(gl, program, painter.tileExtentBuffer);
}
gl.disable(gl.STENCIL_TEST);
// We need to draw the background in tiles in order to use calculatePosMatrix
// which applies the projection matrix (transform.projMatrix). Otherwise
// the depth and stencil buffers get into a bad state.
// This can be refactored into a single draw call once earcut lands and
// we don't have so much going on in the stencil buffer.
var coords = transform.coveringTiles({ tileSize: tileSize });
for (var c = 0; c < coords.length; c++) {
var coord = coords[c];
// var pixelsToTileUnitsBound = pixelsToTileUnits.bind({coord:coord, tileSize: tileSize});
if (imagePosA && imagePosB) {
var tile = {coord:coord, tileSize: tileSize};
gl.uniform1f(program.u_tile_units_to_pixels, 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom));
var tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom - tile.coord.z);
var pixelX = tileSizeAtNearestZoom * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z));
var pixelY = tileSizeAtNearestZoom * tile.coord.y;
// split the pixel coord into two pairs of 16 bit numbers. The glsl spec only guarantees 16 bits of precision.
gl.uniform2f(program.u_pixel_coord_upper, pixelX >> 16, pixelY >> 16);
gl.uniform2f(program.u_pixel_coord_lower, pixelX & 0xFFFF, pixelY & 0xFFFF);
}
gl.uniformMatrix4fv(program.u_matrix, false, painter.transform.calculatePosMatrix(coord));
gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.tileExtentBuffer.length);
}
gl.stencilMask(0x00);
gl.stencilFunc(gl.EQUAL, 0x80, 0x80);
}
},{"../source/pixels_to_tile_units":356,"./create_uniform_pragmas":337}],339:[function(require,module,exports){
'use strict';
var browser = require('../util/browser');
module.exports = drawCircles;
function drawCircles(painter, source, layer, coords) {
if (painter.isOpaquePass) return;
var gl = painter.gl;
painter.setDepthSublayer(0);
painter.depthMask(false);
// Allow circles to be drawn across boundaries, so that
// large circles are not clipped to tiles
gl.disable(gl.STENCIL_TEST);
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
var tile = source.getTile(coord);
var bucket = tile.getBucket(layer);
if (!bucket) continue;
var bufferGroups = bucket.bufferGroups.circle;
if (!bufferGroups) continue;
var programOptions = bucket.paintAttributes.circle[layer.id];
var program = painter.useProgram(
'circle',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);
if (layer.paint['circle-pitch-scale'] === 'map') {
gl.uniform1i(program.u_scale_with_map, true);
gl.uniform2f(program.u_extrude_scale,
painter.transform.pixelsToGLUnits[0] * painter.transform.altitude,
painter.transform.pixelsToGLUnits[1] * painter.transform.altitude);
} else {
gl.uniform1i(program.u_scale_with_map, false);
gl.uniform2fv(program.u_extrude_scale, painter.transform.pixelsToGLUnits);
}
gl.uniform1f(program.u_devicepixelratio, browser.devicePixelRatio);
gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(
coord.posMatrix,
tile,
layer.paint['circle-translate'],
layer.paint['circle-translate-anchor']
));
bucket.setUniforms(gl, 'circle', program, layer, {zoom: painter.transform.zoom});
for (var k = 0; k < bufferGroups.length; k++) {
var group = bufferGroups[k];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0);
}
}
}
},{"../util/browser":419}],340:[function(require,module,exports){
'use strict';
module.exports = drawCollisionDebug;
function drawCollisionDebug(painter, source, layer, coords) {
var gl = painter.gl;
gl.enable(gl.STENCIL_TEST);
var program = painter.useProgram('collisionbox');
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
var tile = source.getTile(coord);
var bucket = tile.getBucket(layer);
if (!bucket) continue;
var bufferGroups = bucket.bufferGroups.collisionBox;
if (!bufferGroups || !bufferGroups.length) continue;
var group = bufferGroups[0];
if (group.layoutVertexBuffer.length === 0) continue;
gl.uniformMatrix4fv(program.u_matrix, false, coord.posMatrix);
painter.enableTileClippingMask(coord);
painter.lineWidth(1);
gl.uniform1f(program.u_scale, Math.pow(2, painter.transform.zoom - tile.coord.z));
gl.uniform1f(program.u_zoom, painter.transform.zoom * 10);
gl.uniform1f(program.u_maxzoom, (tile.coord.z + 1) * 10);
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer);
gl.drawArrays(gl.LINES, 0, group.layoutVertexBuffer.length);
}
}
},{}],341:[function(require,module,exports){
'use strict';
var textVertices = require('../lib/debugtext');
var browser = require('../util/browser');
var mat4 = require('gl-matrix').mat4;
var EXTENT = require('../data/bucket').EXTENT;
var Buffer = require('../data/buffer');
var VertexArrayObject = require('./vertex_array_object');
module.exports = drawDebug;
function drawDebug(painter, source, coords) {
if (painter.isOpaquePass) return;
if (!painter.options.debug) return;
for (var i = 0; i < coords.length; i++) {
drawDebugTile(painter, source, coords[i]);
}
}
function drawDebugTile(painter, source, coord) {
var gl = painter.gl;
gl.disable(gl.STENCIL_TEST);
painter.lineWidth(1 * browser.devicePixelRatio);
var posMatrix = coord.posMatrix;
var program = painter.useProgram('debug');
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
gl.uniform4f(program.u_color, 1, 0, 0, 1);
painter.debugVAO.bind(gl, program, painter.debugBuffer);
gl.drawArrays(gl.LINE_STRIP, 0, painter.debugBuffer.length);
var vertices = textVertices(coord.toString(), 50, 200, 5);
var debugTextArray = new painter.PosArray();
for (var v = 0; v < vertices.length; v += 2) {
debugTextArray.emplaceBack(vertices[v], vertices[v + 1]);
}
var debugTextBuffer = new Buffer(debugTextArray.serialize(), painter.PosArray.serialize(), Buffer.BufferType.VERTEX);
var debugTextVAO = new VertexArrayObject();
debugTextVAO.bind(gl, program, debugTextBuffer);
gl.uniform4f(program.u_color, 1, 1, 1, 1);
// Draw the halo with multiple 1px lines instead of one wider line because
// the gl spec doesn't guarantee support for lines with width > 1.
var tileSize = source.getTile(coord).tileSize;
var onePixel = EXTENT / (Math.pow(2, painter.transform.zoom - coord.z) * tileSize);
var translations = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
for (var i = 0; i < translations.length; i++) {
var translation = translations[i];
gl.uniformMatrix4fv(program.u_matrix, false, mat4.translate([], posMatrix, [onePixel * translation[0], onePixel * translation[1], 0]));
gl.drawArrays(gl.LINES, 0, debugTextBuffer.length);
}
gl.uniform4f(program.u_color, 0, 0, 0, 1);
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
gl.drawArrays(gl.LINES, 0, debugTextBuffer.length);
}
},{"../data/bucket":322,"../data/buffer":327,"../lib/debugtext":335,"../util/browser":419,"./vertex_array_object":350,"gl-matrix":188}],342:[function(require,module,exports){
'use strict';
var pixelsToTileUnits = require('../source/pixels_to_tile_units');
module.exports = draw;
function draw(painter, source, layer, coords) {
var gl = painter.gl;
gl.enable(gl.STENCIL_TEST);
var isOpaque;
if (layer.paint['fill-pattern']) {
isOpaque = false;
} else {
isOpaque = (
layer.isPaintValueFeatureConstant('fill-color') &&
layer.isPaintValueFeatureConstant('fill-opacity') &&
layer.paint['fill-color'][3] === 1 &&
layer.paint['fill-opacity'] === 1
);
}
// Draw fill
if (painter.isOpaquePass === isOpaque) {
// Once we switch to earcut drawing we can pull most of the WebGL setup
// outside of this coords loop.
painter.setDepthSublayer(1);
for (var i = 0; i < coords.length; i++) {
drawFill(painter, source, layer, coords[i]);
}
}
if (!painter.isOpaquePass && layer.paint['fill-antialias']) {
painter.lineWidth(2);
painter.depthMask(false);
var isOutlineColorDefined = layer.getPaintProperty('fill-outline-color');
if (isOutlineColorDefined || !layer.paint['fill-pattern']) {
if (isOutlineColorDefined) {
// If we defined a different color for the fill outline, we are
// going to ignore the bits in 0x07 and just care about the global
// clipping mask.
painter.setDepthSublayer(2);
} else {
// Otherwise, we only want to drawFill the antialiased parts that are
// *outside* the current shape. This is important in case the fill
// or stroke color is translucent. If we wouldn't clip to outside
// the current shape, some pixels from the outline stroke overlapped
// the (non-antialiased) fill.
painter.setDepthSublayer(0);
}
} else {
// Otherwise, we only want to drawFill the antialiased parts that are
// *outside* the current shape. This is important in case the fill
// or stroke color is translucent. If we wouldn't clip to outside
// the current shape, some pixels from the outline stroke overlapped
// the (non-antialiased) fill.
painter.setDepthSublayer(0);
}
for (var j = 0; j < coords.length; j++) {
drawStroke(painter, source, layer, coords[j]);
}
}
}
function drawFill(painter, source, layer, coord) {
var tile = source.getTile(coord);
var bucket = tile.getBucket(layer);
if (!bucket) return;
var bufferGroups = bucket.bufferGroups.fill;
if (!bufferGroups) return;
var gl = painter.gl;
var image = layer.paint['fill-pattern'];
var program;
if (!image) {
var programOptions = bucket.paintAttributes.fill[layer.id];
program = painter.useProgram(
'fill',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);
bucket.setUniforms(gl, 'fill', program, layer, {zoom: painter.transform.zoom});
} else {
// Draw texture fill
program = painter.useProgram('pattern');
setPattern(image, layer.paint['fill-opacity'], tile, coord, painter, program);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);
}
gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(
coord.posMatrix,
tile,
layer.paint['fill-translate'],
layer.paint['fill-translate-anchor']
));
painter.enableTileClippingMask(coord);
for (var i = 0; i < bufferGroups.length; i++) {
var group = bufferGroups[i];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length, gl.UNSIGNED_SHORT, 0);
}
}
function drawStroke(painter, source, layer, coord) {
var tile = source.getTile(coord);
var bucket = tile.getBucket(layer);
if (!bucket) return;
var gl = painter.gl;
var bufferGroups = bucket.bufferGroups.fill;
var image = layer.paint['fill-pattern'];
var opacity = layer.paint['fill-opacity'];
var isOutlineColorDefined = layer.getPaintProperty('fill-outline-color');
var program;
if (image && !isOutlineColorDefined) {
program = painter.useProgram('outlinepattern');
gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight);
} else {
var programOptions = bucket.paintAttributes.fill[layer.id];
program = painter.useProgram(
'outline',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);
gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.uniform1f(program.u_opacity, opacity);
bucket.setUniforms(gl, 'fill', program, layer, {zoom: painter.transform.zoom});
}
gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(
coord.posMatrix,
tile,
layer.paint['fill-translate'],
layer.paint['fill-translate-anchor']
));
if (image) { setPattern(image, opacity, tile, coord, painter, program); }
painter.enableTileClippingMask(coord);
for (var k = 0; k < bufferGroups.length; k++) {
var group = bufferGroups[k];
group.secondVaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer2, group.paintVertexBuffers[layer.id]);
gl.drawElements(gl.LINES, group.elementBuffer2.length * 2, gl.UNSIGNED_SHORT, 0);
}
}
function setPattern(image, opacity, tile, coord, painter, program) {
var gl = painter.gl;
var imagePosA = painter.spriteAtlas.getPosition(image.from, true);
var imagePosB = painter.spriteAtlas.getPosition(image.to, true);
if (!imagePosA || !imagePosB) return;
gl.uniform1i(program.u_image, 0);
gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(program.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_mix, image.t);
gl.uniform1f(program.u_tile_units_to_pixels, 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom));
gl.uniform2fv(program.u_pattern_size_a, imagePosA.size);
gl.uniform2fv(program.u_pattern_size_b, imagePosB.size);
gl.uniform1f(program.u_scale_a, image.fromScale);
gl.uniform1f(program.u_scale_b, image.toScale);
var tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom - tile.coord.z);
var pixelX = tileSizeAtNearestZoom * (tile.coord.x + coord.w * Math.pow(2, tile.coord.z));
var pixelY = tileSizeAtNearestZoom * tile.coord.y;
// split the pixel coord into two pairs of 16 bit numbers. The glsl spec only guarantees 16 bits of precision.
gl.uniform2f(program.u_pixel_coord_upper, pixelX >> 16, pixelY >> 16);
gl.uniform2f(program.u_pixel_coord_lower, pixelX & 0xFFFF, pixelY & 0xFFFF);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);
}
},{"../source/pixels_to_tile_units":356}],343:[function(require,module,exports){
'use strict';
var browser = require('../util/browser');
var mat2 = require('gl-matrix').mat2;
var pixelsToTileUnits = require('../source/pixels_to_tile_units');
/**
* Draw a line. Under the hood this will read elements from
* a tile, dash textures from a lineAtlas, and style properties from a layer.
* @param {Object} painter
* @param {Object} layer
* @param {Object} posMatrix
* @param {Tile} tile
* @returns {undefined} draws with the painter
* @private
*/
module.exports = function drawLine(painter, source, layer, coords) {
if (painter.isOpaquePass) return;
painter.setDepthSublayer(0);
painter.depthMask(false);
var gl = painter.gl;
gl.enable(gl.STENCIL_TEST);
// don't draw zero-width lines
if (layer.paint['line-width'] <= 0) return;
// the distance over which the line edge fades out.
// Retina devices need a smaller distance to avoid aliasing.
var antialiasing = 1 / browser.devicePixelRatio;
var blur = layer.paint['line-blur'] + antialiasing;
var color = layer.paint['line-color'];
var tr = painter.transform;
var antialiasingMatrix = mat2.create();
mat2.scale(antialiasingMatrix, antialiasingMatrix, [1, Math.cos(tr._pitch)]);
mat2.rotate(antialiasingMatrix, antialiasingMatrix, painter.transform.angle);
// calculate how much longer the real world distance is at the top of the screen
// than at the middle of the screen.
var topedgelength = Math.sqrt(tr.height * tr.height / 4 * (1 + tr.altitude * tr.altitude));
var x = tr.height / 2 * Math.tan(tr._pitch);
var extra = (topedgelength + x) / topedgelength - 1;
var dasharray = layer.paint['line-dasharray'];
var image = layer.paint['line-pattern'];
var program, posA, posB, imagePosA, imagePosB;
if (dasharray) {
program = painter.useProgram('linesdfpattern');
gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2);
gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);
posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round');
posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round');
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.lineAtlas.bind(gl);
gl.uniform1f(program.u_tex_y_a, posA.y);
gl.uniform1f(program.u_tex_y_b, posB.y);
gl.uniform1f(program.u_mix, dasharray.t);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
} else if (image) {
imagePosA = painter.spriteAtlas.getPosition(image.from, true);
imagePosB = painter.spriteAtlas.getPosition(image.to, true);
if (!imagePosA || !imagePosB) return;
program = painter.useProgram('linepattern');
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);
gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2);
gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(program.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_fade, image.t);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
} else {
program = painter.useProgram('line');
gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2);
gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);
}
for (var k = 0; k < coords.length; k++) {
var coord = coords[k];
var tile = source.getTile(coord);
var bucket = tile.getBucket(layer);
if (!bucket) continue;
var bufferGroups = bucket.bufferGroups.line;
if (!bufferGroups) continue;
painter.enableTileClippingMask(coord);
// set uniforms that are different for each tile
var posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']);
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
var ratio = 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom);
if (dasharray) {
var widthA = posA.width * dasharray.fromScale;
var widthB = posB.width * dasharray.toScale;
var scaleA = [1 / pixelsToTileUnits(tile, widthA, painter.transform.tileZoom), -posA.height / 2];
var scaleB = [1 / pixelsToTileUnits(tile, widthB, painter.transform.tileZoom), -posB.height / 2];
var gamma = painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2;
gl.uniform1f(program.u_ratio, ratio);
gl.uniform2fv(program.u_patternscale_a, scaleA);
gl.uniform2fv(program.u_patternscale_b, scaleB);
gl.uniform1f(program.u_sdfgamma, gamma);
} else if (image) {
gl.uniform1f(program.u_ratio, ratio);
gl.uniform2fv(program.u_pattern_size_a, [
pixelsToTileUnits(tile, imagePosA.size[0] * image.fromScale, painter.transform.tileZoom),
imagePosB.size[1]
]);
gl.uniform2fv(program.u_pattern_size_b, [
pixelsToTileUnits(tile, imagePosB.size[0] * image.toScale, painter.transform.tileZoom),
imagePosB.size[1]
]);
} else {
gl.uniform1f(program.u_ratio, ratio);
}
for (var i = 0; i < bufferGroups.length; i++) {
var group = bufferGroups[i];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0);
}
}
};
},{"../source/pixels_to_tile_units":356,"../util/browser":419,"gl-matrix":188}],344:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var StructArrayType = require('../util/struct_array');
module.exports = drawRaster;
function drawRaster(painter, source, layer, coords) {
if (painter.isOpaquePass) return;
var gl = painter.gl;
gl.enable(gl.DEPTH_TEST);
painter.depthMask(true);
// Change depth function to prevent double drawing in areas where tiles overlap.
gl.depthFunc(gl.LESS);
var minTileZ = coords.length && coords[0].z;
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
// set the lower zoom level to sublayer 0, and higher zoom levels to higher sublayers
painter.setDepthSublayer(coord.z - minTileZ);
drawRasterTile(painter, source, layer, coord);
}
gl.depthFunc(gl.LEQUAL);
}
drawRaster.RasterBoundsArray = new StructArrayType({
members: [
{ name: 'a_pos', type: 'Int16', components: 2 },
{ name: 'a_texture_pos', type: 'Int16', components: 2 }
]
});
function drawRasterTile(painter, source, layer, coord) {
var gl = painter.gl;
gl.disable(gl.STENCIL_TEST);
var tile = source.getTile(coord);
var posMatrix = painter.transform.calculatePosMatrix(coord, source.maxzoom);
var program = painter.useProgram('raster');
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
// color parameters
gl.uniform1f(program.u_brightness_low, layer.paint['raster-brightness-min']);
gl.uniform1f(program.u_brightness_high, layer.paint['raster-brightness-max']);
gl.uniform1f(program.u_saturation_factor, saturationFactor(layer.paint['raster-saturation']));
gl.uniform1f(program.u_contrast_factor, contrastFactor(layer.paint['raster-contrast']));
gl.uniform3fv(program.u_spin_weights, spinWeights(layer.paint['raster-hue-rotate']));
var parentTile = tile.source && tile.source.findLoadedParent(coord, 0, {}),
opacities = getOpacities(tile, parentTile, layer, painter.transform);
var parentScaleBy, parentTL;
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tile.texture);
gl.activeTexture(gl.TEXTURE1);
if (parentTile) {
gl.bindTexture(gl.TEXTURE_2D, parentTile.texture);
parentScaleBy = Math.pow(2, parentTile.coord.z - tile.coord.z);
parentTL = [tile.coord.x * parentScaleBy % 1, tile.coord.y * parentScaleBy % 1];
} else {
gl.bindTexture(gl.TEXTURE_2D, tile.texture);
opacities[1] = 0;
}
// cross-fade parameters
gl.uniform2fv(program.u_tl_parent, parentTL || [0, 0]);
gl.uniform1f(program.u_scale_parent, parentScaleBy || 1);
gl.uniform1f(program.u_buffer_scale, 1);
gl.uniform1f(program.u_opacity0, opacities[0]);
gl.uniform1f(program.u_opacity1, opacities[1]);
gl.uniform1i(program.u_image0, 0);
gl.uniform1i(program.u_image1, 1);
var buffer = tile.boundsBuffer || painter.rasterBoundsBuffer;
var vao = tile.boundsVAO || painter.rasterBoundsVAO;
vao.bind(gl, program, buffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, buffer.length);
}
function spinWeights(angle) {
angle *= Math.PI / 180;
var s = Math.sin(angle);
var c = Math.cos(angle);
return [
(2 * c + 1) / 3,
(-Math.sqrt(3) * s - c + 1) / 3,
(Math.sqrt(3) * s - c + 1) / 3
];
}
function contrastFactor(contrast) {
return contrast > 0 ?
1 / (1 - contrast) :
1 + contrast;
}
function saturationFactor(saturation) {
return saturation > 0 ?
1 - 1 / (1.001 - saturation) :
-saturation;
}
function getOpacities(tile, parentTile, layer, transform) {
var opacity = [1, 0];
var fadeDuration = layer.paint['raster-fade-duration'];
if (tile.source && fadeDuration > 0) {
var now = new Date().getTime();
var sinceTile = (now - tile.timeAdded) / fadeDuration;
var sinceParent = parentTile ? (now - parentTile.timeAdded) / fadeDuration : -1;
var idealZ = transform.coveringZoomLevel(tile.source);
var parentFurther = parentTile ? Math.abs(parentTile.coord.z - idealZ) > Math.abs(tile.coord.z - idealZ) : false;
if (!parentTile || parentFurther) {
// if no parent or parent is older
opacity[0] = util.clamp(sinceTile, 0, 1);
opacity[1] = 1 - opacity[0];
} else {
// parent is younger, zooming out
opacity[0] = util.clamp(1 - sinceParent, 0, 1);
opacity[1] = 1 - opacity[0];
}
}
var op = layer.paint['raster-opacity'];
opacity[0] *= op;
opacity[1] *= op;
return opacity;
}
},{"../util/struct_array":433,"../util/util":435}],345:[function(require,module,exports){
'use strict';
var browser = require('../util/browser');
var drawCollisionDebug = require('./draw_collision_debug');
var pixelsToTileUnits = require('../source/pixels_to_tile_units');
module.exports = drawSymbols;
function drawSymbols(painter, source, layer, coords) {
if (painter.isOpaquePass) return;
var drawAcrossEdges = !(layer.layout['text-allow-overlap'] || layer.layout['icon-allow-overlap'] ||
layer.layout['text-ignore-placement'] || layer.layout['icon-ignore-placement']);
var gl = painter.gl;
// Disable the stencil test so that labels aren't clipped to tile boundaries.
//
// Layers with features that may be drawn overlapping aren't clipped. These
// layers are sorted in the y direction, and to draw the correct ordering near
// tile edges the icons are included in both tiles and clipped when drawing.
if (drawAcrossEdges) {
gl.disable(gl.STENCIL_TEST);
} else {
gl.enable(gl.STENCIL_TEST);
}
painter.setDepthSublayer(0);
painter.depthMask(false);
gl.disable(gl.DEPTH_TEST);
drawLayerSymbols(painter, source, layer, coords, false,
layer.paint['icon-translate'],
layer.paint['icon-translate-anchor'],
layer.layout['icon-rotation-alignment'],
// icon-pitch-alignment is not yet implemented
// and we simply inherit the rotation alignment
layer.layout['icon-rotation-alignment'],
layer.layout['icon-size'],
layer.paint['icon-halo-width'],
layer.paint['icon-halo-color'],
layer.paint['icon-halo-blur'],
layer.paint['icon-opacity'],
layer.paint['icon-color']);
drawLayerSymbols(painter, source, layer, coords, true,
layer.paint['text-translate'],
layer.paint['text-translate-anchor'],
layer.layout['text-rotation-alignment'],
layer.layout['text-pitch-alignment'],
layer.layout['text-size'],
layer.paint['text-halo-width'],
layer.paint['text-halo-color'],
layer.paint['text-halo-blur'],
layer.paint['text-opacity'],
layer.paint['text-color']);
gl.enable(gl.DEPTH_TEST);
if (source.map.showCollisionBoxes) {
drawCollisionDebug(painter, source, layer, coords);
}
}
function drawLayerSymbols(painter, source, layer, coords, isText,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color) {
for (var j = 0; j < coords.length; j++) {
var tile = source.getTile(coords[j]);
var bucket = tile.getBucket(layer);
if (!bucket) continue;
var bothBufferGroups = bucket.bufferGroups;
var bufferGroups = isText ? bothBufferGroups.glyph : bothBufferGroups.icon;
if (!bufferGroups.length) continue;
painter.enableTileClippingMask(coords[j]);
drawSymbol(painter, layer, coords[j].posMatrix, tile, bucket, bufferGroups, isText,
isText || bucket.sdfIcons, !isText && bucket.iconsNeedLinear,
isText ? bucket.adjustedTextSize : bucket.adjustedIconSize, bucket.fontstack,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color);
}
}
function drawSymbol(painter, layer, posMatrix, tile, bucket, bufferGroups, isText, sdf, iconsNeedLinear, adjustedSize, fontstack,
translate,
translateAnchor,
rotationAlignment,
pitchAlignment,
size,
haloWidth,
haloColor,
haloBlur,
opacity,
color) {
var gl = painter.gl;
var tr = painter.transform;
var rotateWithMap = rotationAlignment === 'map';
var pitchWithMap = pitchAlignment === 'map';
var defaultSize = isText ? 24 : 1;
var fontScale = size / defaultSize;
var extrudeScale, s, gammaScale;
if (pitchWithMap) {
s = pixelsToTileUnits(tile, 1, painter.transform.zoom) * fontScale;
gammaScale = 1 / Math.cos(tr._pitch);
extrudeScale = [s, s];
} else {
s = painter.transform.altitude * fontScale;
gammaScale = 1;
extrudeScale = [ tr.pixelsToGLUnits[0] * s, tr.pixelsToGLUnits[1] * s];
}
if (!isText && !painter.style.sprite.loaded())
return;
var program = painter.useProgram(sdf ? 'sdf' : 'icon');
gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(posMatrix, tile, translate, translateAnchor));
gl.uniform1i(program.u_rotate_with_map, rotateWithMap);
gl.uniform1i(program.u_pitch_with_map, pitchWithMap);
gl.uniform2fv(program.u_extrude_scale, extrudeScale);
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(program.u_texture, 0);
if (isText) {
// use the fonstack used when parsing the tile, not the fontstack
// at the current zoom level (layout['text-font']).
var glyphAtlas = fontstack && painter.glyphSource.getGlyphAtlas(fontstack);
if (!glyphAtlas) return;
glyphAtlas.updateTexture(gl);
gl.uniform2f(program.u_texsize, glyphAtlas.width / 4, glyphAtlas.height / 4);
} else {
var mapMoving = painter.options.rotating || painter.options.zooming;
var iconScaled = fontScale !== 1 || browser.devicePixelRatio !== painter.spriteAtlas.pixelRatio || iconsNeedLinear;
var iconTransformed = pitchWithMap || painter.transform.pitch;
painter.spriteAtlas.bind(gl, sdf || mapMoving || iconScaled || iconTransformed);
gl.uniform2f(program.u_texsize, painter.spriteAtlas.width / 4, painter.spriteAtlas.height / 4);
}
// adjust min/max zooms for variable font sizes
var zoomAdjust = Math.log(size / adjustedSize) / Math.LN2 || 0;
gl.uniform1f(program.u_zoom, (painter.transform.zoom - zoomAdjust) * 10); // current zoom level
gl.activeTexture(gl.TEXTURE1);
painter.frameHistory.bind(gl);
gl.uniform1i(program.u_fadetexture, 1);
var group;
if (sdf) {
var sdfPx = 8;
var blurOffset = 1.19;
var haloOffset = 6;
var gamma = 0.105 * defaultSize / size / browser.devicePixelRatio;
if (haloWidth) {
// Draw halo underneath the text.
gl.uniform1f(program.u_gamma, (haloBlur * blurOffset / fontScale / sdfPx + gamma) * gammaScale);
gl.uniform4fv(program.u_color, haloColor);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_buffer, (haloOffset - haloWidth / fontScale) / sdfPx);
for (var j = 0; j < bufferGroups.length; j++) {
group = bufferGroups[j];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0);
}
}
gl.uniform1f(program.u_gamma, gamma * gammaScale);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, opacity);
gl.uniform1f(program.u_buffer, (256 - 64) / 256);
gl.uniform1f(program.u_pitch, tr.pitch / 360 * 2 * Math.PI);
gl.uniform1f(program.u_bearing, tr.bearing / 360 * 2 * Math.PI);
gl.uniform1f(program.u_aspect_ratio, tr.width / tr.height);
for (var i = 0; i < bufferGroups.length; i++) {
group = bufferGroups[i];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0);
}
} else {
gl.uniform1f(program.u_opacity, opacity);
for (var k = 0; k < bufferGroups.length; k++) {
group = bufferGroups[k];
group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer);
gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0);
}
}
}
},{"../source/pixels_to_tile_units":356,"../util/browser":419,"./draw_collision_debug":340}],346:[function(require,module,exports){
'use strict';
module.exports = FrameHistory;
function FrameHistory() {
this.changeTimes = new Float64Array(256);
this.changeOpacities = new Uint8Array(256);
this.opacities = new Uint8ClampedArray(256);
this.array = new Uint8Array(this.opacities.buffer);
this.fadeDuration = 300;
this.previousZoom = 0;
this.firstFrame = true;
}
FrameHistory.prototype.record = function(zoom) {
var now = Date.now();
if (this.firstFrame) {
now = 0;
this.firstFrame = false;
}
zoom = Math.floor(zoom * 10);
var z;
if (zoom < this.previousZoom) {
for (z = zoom + 1; z <= this.previousZoom; z++) {
this.changeTimes[z] = now;
this.changeOpacities[z] = this.opacities[z];
}
} else {
for (z = zoom; z > this.previousZoom; z--) {
this.changeTimes[z] = now;
this.changeOpacities[z] = this.opacities[z];
}
}
for (z = 0; z < 256; z++) {
var timeSince = now - this.changeTimes[z];
var opacityChange = timeSince / this.fadeDuration * 255;
if (z <= zoom) {
this.opacities[z] = this.changeOpacities[z] + opacityChange;
} else {
this.opacities[z] = this.changeOpacities[z] - opacityChange;
}
}
this.changed = true;
this.previousZoom = zoom;
};
FrameHistory.prototype.bind = function(gl) {
if (!this.texture) {
this.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, 256, 1, 0, gl.ALPHA, gl.UNSIGNED_BYTE, this.array);
} else {
gl.bindTexture(gl.TEXTURE_2D, this.texture);
if (this.changed) {
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 256, 1, gl.ALPHA, gl.UNSIGNED_BYTE, this.array);
this.changed = false;
}
}
};
},{}],347:[function(require,module,exports){
'use strict';
var util = require('../util/util');
module.exports = LineAtlas;
/**
* A LineAtlas lets us reuse rendered dashed lines
* by writing many of them to a texture and then fetching their positions
* using .getDash.
*
* @param {number} width
* @param {number} height
* @private
*/
function LineAtlas(width, height) {
this.width = width;
this.height = height;
this.nextRow = 0;
this.bytes = 4;
this.data = new Uint8Array(this.width * this.height * this.bytes);
this.positions = {};
}
LineAtlas.prototype.setSprite = function(sprite) {
this.sprite = sprite;
};
/**
* Get or create a dash line pattern.
*
* @param {Array} dasharray
* @param {boolean} round whether to add circle caps in between dash segments
* @returns {Object} position of dash texture in { y, height, width }
* @private
*/
LineAtlas.prototype.getDash = function(dasharray, round) {
var key = dasharray.join(",") + round;
if (!this.positions[key]) {
this.positions[key] = this.addDash(dasharray, round);
}
return this.positions[key];
};
LineAtlas.prototype.addDash = function(dasharray, round) {
var n = round ? 7 : 0;
var height = 2 * n + 1;
var offset = 128;
if (this.nextRow + height > this.height) {
util.warnOnce('LineAtlas out of space');
return null;
}
var length = 0;
for (var i = 0; i < dasharray.length; i++) {
length += dasharray[i];
}
var stretch = this.width / length;
var halfWidth = stretch / 2;
// If dasharray has an odd length, both the first and last parts
// are dashes and should be joined seamlessly.
var oddLength = dasharray.length % 2 === 1;
for (var y = -n; y <= n; y++) {
var row = this.nextRow + n + y;
var index = this.width * row;
var left = oddLength ? -dasharray[dasharray.length - 1] : 0;
var right = dasharray[0];
var partIndex = 1;
for (var x = 0; x < this.width; x++) {
while (right < x / stretch) {
left = right;
right = right + dasharray[partIndex];
if (oddLength && partIndex === dasharray.length - 1) {
right += dasharray[0];
}
partIndex++;
}
var distLeft = Math.abs(x - left * stretch);
var distRight = Math.abs(x - right * stretch);
var dist = Math.min(distLeft, distRight);
var inside = (partIndex % 2) === 1;
var signedDistance;
if (round) {
// Add circle caps
var distMiddle = n ? y / n * (halfWidth + 1) : 0;
if (inside) {
var distEdge = halfWidth - Math.abs(distMiddle);
signedDistance = Math.sqrt(dist * dist + distEdge * distEdge);
} else {
signedDistance = halfWidth - Math.sqrt(dist * dist + distMiddle * distMiddle);
}
} else {
signedDistance = (inside ? 1 : -1) * dist;
}
this.data[3 + (index + x) * 4] = Math.max(0, Math.min(255, signedDistance + offset));
}
}
var pos = {
y: (this.nextRow + n + 0.5) / this.height,
height: 2 * n / this.height,
width: length
};
this.nextRow += height;
this.dirty = true;
return pos;
};
LineAtlas.prototype.bind = function(gl) {
if (!this.texture) {
this.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.width, this.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.data);
} else {
gl.bindTexture(gl.TEXTURE_2D, this.texture);
if (this.dirty) {
this.dirty = false;
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.width, this.height, gl.RGBA, gl.UNSIGNED_BYTE, this.data);
}
}
};
},{"../util/util":435}],348:[function(require,module,exports){
'use strict';
var browser = require('../util/browser');
var mat4 = require('gl-matrix').mat4;
var FrameHistory = require('./frame_history');
var SourceCache = require('../source/source_cache');
var EXTENT = require('../data/bucket').EXTENT;
var pixelsToTileUnits = require('../source/pixels_to_tile_units');
var util = require('../util/util');
var StructArrayType = require('../util/struct_array');
var Buffer = require('../data/buffer');
var VertexArrayObject = require('./vertex_array_object');
var RasterBoundsArray = require('./draw_raster').RasterBoundsArray;
var createUniformPragmas = require('./create_uniform_pragmas');
module.exports = Painter;
/**
* Initialize a new painter object.
*
* @param {Canvas} gl an experimental-webgl drawing context
* @private
*/
function Painter(gl, transform) {
this.gl = gl;
this.transform = transform;
this.reusableTextures = {};
this.preFbos = {};
this.frameHistory = new FrameHistory();
this.setup();
// Within each layer there are multiple distinct z-planes that can be drawn to.
// This is implemented using the WebGL depth buffer.
this.numSublayers = SourceCache.maxUnderzooming + SourceCache.maxOverzooming + 1;
this.depthEpsilon = 1 / Math.pow(2, 16);
this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE);
}
util.extend(Painter.prototype, require('./painter/use_program'));
/*
* Update the GL viewport, projection matrix, and transforms to compensate
* for a new width and height value.
*/
Painter.prototype.resize = function(width, height) {
var gl = this.gl;
this.width = width * browser.devicePixelRatio;
this.height = height * browser.devicePixelRatio;
gl.viewport(0, 0, this.width, this.height);
};
Painter.prototype.setup = function() {
var gl = this.gl;
gl.verbose = true;
// We are blending the new pixels *behind* the existing pixels. That way we can
// draw front-to-back and use then stencil buffer to cull opaque pixels early.
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.STENCIL_TEST);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
this._depthMask = false;
gl.depthMask(false);
var PosArray = this.PosArray = new StructArrayType({
members: [{ name: 'a_pos', type: 'Int16', components: 2 }]
});
var tileExtentArray = new PosArray();
tileExtentArray.emplaceBack(0, 0);
tileExtentArray.emplaceBack(EXTENT, 0);
tileExtentArray.emplaceBack(0, EXTENT);
tileExtentArray.emplaceBack(EXTENT, EXTENT);
this.tileExtentBuffer = new Buffer(tileExtentArray.serialize(), PosArray.serialize(), Buffer.BufferType.VERTEX);
this.tileExtentVAO = new VertexArrayObject();
this.tileExtentPatternVAO = new VertexArrayObject();
var debugArray = new PosArray();
debugArray.emplaceBack(0, 0);
debugArray.emplaceBack(EXTENT, 0);
debugArray.emplaceBack(EXTENT, EXTENT);
debugArray.emplaceBack(0, EXTENT);
debugArray.emplaceBack(0, 0);
this.debugBuffer = new Buffer(debugArray.serialize(), PosArray.serialize(), Buffer.BufferType.VERTEX);
this.debugVAO = new VertexArrayObject();
var rasterBoundsArray = new RasterBoundsArray();
rasterBoundsArray.emplaceBack(0, 0, 0, 0);
rasterBoundsArray.emplaceBack(EXTENT, 0, 32767, 0);
rasterBoundsArray.emplaceBack(0, EXTENT, 0, 32767);
rasterBoundsArray.emplaceBack(EXTENT, EXTENT, 32767, 32767);
this.rasterBoundsBuffer = new Buffer(rasterBoundsArray.serialize(), RasterBoundsArray.serialize(), Buffer.BufferType.VERTEX);
this.rasterBoundsVAO = new VertexArrayObject();
};
/*
* Reset the color buffers of the drawing canvas.
*/
Painter.prototype.clearColor = function() {
var gl = this.gl;
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
};
/*
* Reset the drawing canvas by clearing the stencil buffer so that we can draw
* new tiles at the same location, while retaining previously drawn pixels.
*/
Painter.prototype.clearStencil = function() {
var gl = this.gl;
gl.clearStencil(0x0);
gl.stencilMask(0xFF);
gl.clear(gl.STENCIL_BUFFER_BIT);
};
Painter.prototype.clearDepth = function() {
var gl = this.gl;
gl.clearDepth(1);
this.depthMask(true);
gl.clear(gl.DEPTH_BUFFER_BIT);
};
Painter.prototype._renderTileClippingMasks = function(coords) {
var gl = this.gl;
gl.colorMask(false, false, false, false);
this.depthMask(false);
gl.disable(gl.DEPTH_TEST);
gl.enable(gl.STENCIL_TEST);
// Only write clipping IDs to the last 5 bits. The first three are used for drawing fills.
gl.stencilMask(0xF8);
// Tests will always pass, and ref value will be written to stencil buffer.
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
var idNext = 1;
this._tileClippingMaskIDs = {};
for (var i = 0; i < coords.length; i++) {
var coord = coords[i];
var id = this._tileClippingMaskIDs[coord.id] = (idNext++) << 3;
gl.stencilFunc(gl.ALWAYS, id, 0xF8);
var pragmas = createUniformPragmas([
{name: 'u_color', components: 4},
{name: 'u_opacity', components: 1}
]);
var program = this.useProgram('fill', [], pragmas, pragmas);
gl.uniformMatrix4fv(program.u_matrix, false, coord.posMatrix);
// Draw the clipping mask
this.tileExtentVAO.bind(gl, program, this.tileExtentBuffer);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, this.tileExtentBuffer.length);
}
gl.stencilMask(0x00);
gl.colorMask(true, true, true, true);
this.depthMask(true);
gl.enable(gl.DEPTH_TEST);
};
Painter.prototype.enableTileClippingMask = function(coord) {
var gl = this.gl;
gl.stencilFunc(gl.EQUAL, this._tileClippingMaskIDs[coord.id], 0xF8);
};
// Overridden by headless tests.
Painter.prototype.prepareBuffers = function() {};
Painter.prototype.bindDefaultFramebuffer = function() {
var gl = this.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
var draw = {
symbol: require('./draw_symbol'),
circle: require('./draw_circle'),
line: require('./draw_line'),
fill: require('./draw_fill'),
raster: require('./draw_raster'),
background: require('./draw_background'),
debug: require('./draw_debug')
};
Painter.prototype.render = function(style, options) {
this.style = style;
this.options = options;
this.lineAtlas = style.lineAtlas;
this.spriteAtlas = style.spriteAtlas;
this.spriteAtlas.setSprite(style.sprite);
this.glyphSource = style.glyphSource;
this.frameHistory.record(this.transform.zoom);
this.prepareBuffers();
this.clearColor();
this.clearDepth();
this.showOverdrawInspector(options.showOverdrawInspector);
this.depthRange = (style._order.length + 2) * this.numSublayers * this.depthEpsilon;
this.renderPass({isOpaquePass: true});
this.renderPass({isOpaquePass: false});
};
Painter.prototype.renderPass = function(options) {
var groups = this.style._groups;
var isOpaquePass = options.isOpaquePass;
this.currentLayer = isOpaquePass ? this.style._order.length : -1;
for (var i = 0; i < groups.length; i++) {
var group = groups[isOpaquePass ? groups.length - 1 - i : i];
var source = this.style.sources[group.source];
var j;
var coords = [];
if (source) {
coords = source.getVisibleCoordinates();
for (j = 0; j < coords.length; j++) {
coords[j].posMatrix = this.transform.calculatePosMatrix(coords[j], source.maxzoom);
}
this.clearStencil();
if (source.prepare) source.prepare();
if (source.isTileClipped) {
this._renderTileClippingMasks(coords);
}
}
if (isOpaquePass) {
if (!this._showOverdrawInspector) {
this.gl.disable(this.gl.BLEND);
}
this.isOpaquePass = true;
} else {
this.gl.enable(this.gl.BLEND);
this.isOpaquePass = false;
coords.reverse();
}
for (j = 0; j < group.length; j++) {
var layer = group[isOpaquePass ? group.length - 1 - j : j];
this.currentLayer += isOpaquePass ? -1 : 1;
this.renderLayer(this, source, layer, coords);
}
if (source) {
draw.debug(this, source, coords);
}
}
};
Painter.prototype.depthMask = function(mask) {
if (mask !== this._depthMask) {
this._depthMask = mask;
this.gl.depthMask(mask);
}
};
Painter.prototype.renderLayer = function(painter, source, layer, coords) {
if (layer.isHidden(this.transform.zoom)) return;
if (layer.type !== 'background' && !coords.length) return;
this.id = layer.id;
draw[layer.type](painter, source, layer, coords);
};
Painter.prototype.setDepthSublayer = function(n) {
var farDepth = 1 - ((1 + this.currentLayer) * this.numSublayers + n) * this.depthEpsilon;
var nearDepth = farDepth - 1 + this.depthRange;
this.gl.depthRange(nearDepth, farDepth);
};
Painter.prototype.translatePosMatrix = function(matrix, tile, translate, anchor) {
if (!translate[0] && !translate[1]) return matrix;
if (anchor === 'viewport') {
var sinA = Math.sin(-this.transform.angle);
var cosA = Math.cos(-this.transform.angle);
translate = [
translate[0] * cosA - translate[1] * sinA,
translate[0] * sinA + translate[1] * cosA
];
}
var translation = [
pixelsToTileUnits(tile, translate[0], this.transform.zoom),
pixelsToTileUnits(tile, translate[1], this.transform.zoom),
0
];
var translatedMatrix = new Float32Array(16);
mat4.translate(translatedMatrix, matrix, translation);
return translatedMatrix;
};
Painter.prototype.saveTexture = function(texture) {
var textures = this.reusableTextures[texture.size];
if (!textures) {
this.reusableTextures[texture.size] = [texture];
} else {
textures.push(texture);
}
};
Painter.prototype.getTexture = function(size) {
var textures = this.reusableTextures[size];
return textures && textures.length > 0 ? textures.pop() : null;
};
Painter.prototype.lineWidth = function(width) {
this.gl.lineWidth(util.clamp(width, this.lineWidthRange[0], this.lineWidthRange[1]));
};
Painter.prototype.showOverdrawInspector = function(enabled) {
if (!enabled && !this._showOverdrawInspector) return;
this._showOverdrawInspector = enabled;
var gl = this.gl;
if (enabled) {
gl.blendFunc(gl.CONSTANT_COLOR, gl.ONE);
var numOverdrawSteps = 8;
var a = 1 / numOverdrawSteps;
gl.blendColor(a, a, a, 0);
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
} else {
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
}
};
},{"../data/bucket":322,"../data/buffer":327,"../source/pixels_to_tile_units":356,"../source/source_cache":360,"../util/browser":419,"../util/struct_array":433,"../util/util":435,"./create_uniform_pragmas":337,"./draw_background":338,"./draw_circle":339,"./draw_debug":341,"./draw_fill":342,"./draw_line":343,"./draw_raster":344,"./draw_symbol":345,"./frame_history":346,"./painter/use_program":349,"./vertex_array_object":350,"gl-matrix":188}],349:[function(require,module,exports){
'use strict';
var assert = require('assert');
var util = require('../../util/util');
var shaders = require('mapbox-gl-shaders');
var utilSource = shaders.util;
module.exports._createProgram = function(name, defines, vertexPragmas, fragmentPragmas) {
var gl = this.gl;
var program = gl.createProgram();
var definition = shaders[name];
var definesSource = '#define MAPBOX_GL_JS;\n';
for (var j = 0; j < defines.length; j++) {
definesSource += '#define ' + defines[j] + ';\n';
}
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, applyPragmas(definesSource + definition.fragmentSource, fragmentPragmas));
gl.compileShader(fragmentShader);
assert(gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(fragmentShader));
gl.attachShader(program, fragmentShader);
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, applyPragmas(definesSource + utilSource + definition.vertexSource, vertexPragmas));
gl.compileShader(vertexShader);
assert(gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS), gl.getShaderInfoLog(vertexShader));
gl.attachShader(program, vertexShader);
gl.linkProgram(program);
assert(gl.getProgramParameter(program, gl.LINK_STATUS), gl.getProgramInfoLog(program));
var attributes = {};
var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (var i = 0; i < numAttributes; i++) {
var attribute = gl.getActiveAttrib(program, i);
attributes[attribute.name] = gl.getAttribLocation(program, attribute.name);
}
var uniforms = {};
var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (var ui = 0; ui < numUniforms; ui++) {
var uniform = gl.getActiveUniform(program, ui);
uniforms[uniform.name] = gl.getUniformLocation(program, uniform.name);
}
return util.extend({
program: program,
definition: definition,
attributes: attributes,
numAttributes: numAttributes
}, attributes, uniforms);
};
module.exports._createProgramCached = function(name, defines, vertexPragmas, fragmentPragmas) {
this.cache = this.cache || {};
var key = JSON.stringify({
name: name,
defines: defines,
vertexPragmas: vertexPragmas,
fragmentPragmas: fragmentPragmas
});
if (!this.cache[key]) {
this.cache[key] = this._createProgram(name, defines, vertexPragmas, fragmentPragmas);
}
return this.cache[key];
};
module.exports.useProgram = function (nextProgramName, defines, vertexPragmas, fragmentPragmas) {
var gl = this.gl;
defines = defines || [];
if (this._showOverdrawInspector) {
defines = defines.concat('OVERDRAW_INSPECTOR');
}
var nextProgram = this._createProgramCached(nextProgramName, defines, vertexPragmas, fragmentPragmas);
var previousProgram = this.currentProgram;
if (previousProgram !== nextProgram) {
gl.useProgram(nextProgram.program);
this.currentProgram = nextProgram;
}
return nextProgram;
};
function applyPragmas(source, pragmas) {
return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, function(match, operation, precision, type, name) {
return pragmas[operation][name].replace(/{type}/g, type).replace(/{precision}/g, precision);
});
}
},{"../../util/util":435,"assert":43,"mapbox-gl-shaders":296}],350:[function(require,module,exports){
'use strict';
var assert = require('assert');
module.exports = VertexArrayObject;
function VertexArrayObject() {
this.boundProgram = null;
this.boundVertexBuffer = null;
this.boundVertexBuffer2 = null;
this.boundElementBuffer = null;
this.vao = null;
}
VertexArrayObject.prototype.bind = function(gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2) {
if (gl.extVertexArrayObject === undefined) {
gl.extVertexArrayObject = gl.getExtension("OES_vertex_array_object");
}
var isFreshBindRequired = (
!this.vao ||
this.boundProgram !== program ||
this.boundVertexBuffer !== layoutVertexBuffer ||
this.boundVertexBuffer2 !== vertexBuffer2 ||
this.boundElementBuffer !== elementBuffer
);
if (!gl.extVertexArrayObject || isFreshBindRequired) {
this.freshBind(gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2);
} else {
gl.extVertexArrayObject.bindVertexArrayOES(this.vao);
}
};
VertexArrayObject.prototype.freshBind = function(gl, program, layoutVertexBuffer, elementBuffer, vertexBuffer2) {
var numPrevAttributes;
var numNextAttributes = program.numAttributes;
if (gl.extVertexArrayObject) {
if (this.vao) this.destroy(gl);
this.vao = gl.extVertexArrayObject.createVertexArrayOES();
gl.extVertexArrayObject.bindVertexArrayOES(this.vao);
numPrevAttributes = 0;
// store the arguments so that we can verify them when the vao is bound again
this.boundProgram = program;
this.boundVertexBuffer = layoutVertexBuffer;
this.boundVertexBuffer2 = vertexBuffer2;
this.boundElementBuffer = elementBuffer;
} else {
numPrevAttributes = gl.currentNumAttributes || 0;
// Disable all attributes from the previous program that aren't used in
// the new program. Note: attribute indices are *not* program specific!
for (var i = numNextAttributes; i < numPrevAttributes; i++) {
// WebGL breaks if you disable attribute 0.
// http://stackoverflow.com/questions/20305231
assert(i !== 0);
gl.disableVertexAttribArray(i);
}
}
// Enable all attributes for the new program.
for (var j = numPrevAttributes; j < numNextAttributes; j++) {
gl.enableVertexAttribArray(j);
}
layoutVertexBuffer.bind(gl);
layoutVertexBuffer.setVertexAttribPointers(gl, program);
if (vertexBuffer2) {
vertexBuffer2.bind(gl);
vertexBuffer2.setVertexAttribPointers(gl, program);
}
if (elementBuffer) {
elementBuffer.bind(gl);
}
gl.currentNumAttributes = numNextAttributes;
};
VertexArrayObject.prototype.unbind = function(gl) {
var ext = gl.extVertexArrayObject;
if (ext) {
ext.bindVertexArrayOES(null);
}
};
VertexArrayObject.prototype.destroy = function(gl) {
var ext = gl.extVertexArrayObject;
if (ext && this.vao) {
ext.deleteVertexArrayOES(this.vao);
this.vao = null;
}
};
},{"assert":43}],351:[function(require,module,exports){
'use strict';
var Evented = require('../util/evented');
var util = require('../util/util');
var urlResolve = require('resolve-url');
var EXTENT = require('../data/bucket').EXTENT;
module.exports = GeoJSONSource;
/**
* A source containing GeoJSON.
*
* @class GeoJSONSource
* @param {Object} [options]
* @param {Object|string} [options.data] A GeoJSON data object or a URL to one. The latter is preferable in the case of large GeoJSON objects.
* @param {number} [options.maxzoom=18] The maximum zoom level at which to preserve detail (1-20).
* @param {number} [options.buffer=128] The tile buffer, measured in pixels. The buffer extends each
* tile's data just past its visible edges, helping to ensure seamless rendering across tile boundaries.
* The default value, 128, is a safe value for label layers, preventing text clipping at boundaries.
* You can read more about buffers and clipping in the
* [Mapbox Vector Tile Specification](https://www.mapbox.com/vector-tiles/specification/#clipping).
* @param {number} [options.tolerance=0.375] The simplification tolerance, measured in pixels.
* This value is passed into a modified [Ramer–Douglas–Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm)
* to simplify (i.e. reduce the number of points) in curves. Higher values result in greater simplification.
* @param {boolean} [options.cluster] If `true`, a collection of point features will be clustered into groups,
* according to `options.clusterRadius`.
* @param {number} [options.clusterRadius=50] The radius of each cluster when clustering points, measured in pixels.
* @param {number} [options.clusterMaxZoom] The maximum zoom level to cluster points in. By default, this value is
* one zoom level less than the map's `maxzoom`, so that at the highest zoom level features are not clustered.
*
* @example
* map.addSource('some id', {
* data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_ports.geojson'
* });
*
* @example
* map.addSource('some id', {
* type: 'geojson',
* data: {
* "type": "FeatureCollection",
* "features": [{
* "type": "Feature",
* "geometry": {
* "type": "Point",
* "coordinates": [
* -76.53063297271729,
* 39.18174077994108
* ]
* }
* }]
* }
* });
*
* @example
* map.getSource('some id').setData({
* data: {
* "type": "FeatureCollection",
* "features": [{
* "type": "Feature",
* "properties": { "name": "Null Island" },
* "geometry": {
* "type": "Point",
* "coordinates": [ 0, 0 ]
* }
* }]
* }
* });
*/
function GeoJSONSource(id, options, dispatcher) {
options = options || {};
this.id = id;
this.dispatcher = dispatcher;
this._data = options.data;
if (options.maxzoom !== undefined) this.maxzoom = options.maxzoom;
if (options.type) this.type = options.type;
var scale = EXTENT / this.tileSize;
// sent to the worker, along with `url: ...` or `data: literal geojson`,
// so that it can load/parse/index the geojson data
// extending with `options.workerOptions` helps to make it easy for
// third-party sources to hack/reuse GeoJSONSource.
this.workerOptions = util.extend({
source: this.id,
cluster: options.cluster || false,
geojsonVtOptions: {
buffer: (options.buffer !== undefined ? options.buffer : 128) * scale,
tolerance: (options.tolerance !== undefined ? options.tolerance : 0.375) * scale,
extent: EXTENT,
maxZoom: this.maxzoom
},
superclusterOptions: {
maxZoom: Math.min(options.clusterMaxZoom, this.maxzoom - 1) || (this.maxzoom - 1),
extent: EXTENT,
radius: (options.clusterRadius || 50) * scale,
log: false
}
}, options.workerOptions);
this._updateWorkerData(function done(err) {
if (err) {
this.fire('error', {error: err});
return;
}
this.fire('load');
}.bind(this));
}
GeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototype */ {
// `type` is a property rather than a constant to make it easy for 3rd
// parties to use GeoJSONSource to build their own source types.
type: 'geojson',
minzoom: 0,
maxzoom: 18,
tileSize: 512,
isTileClipped: true,
reparseOverscaled: true,
onAdd: function (map) {
this.map = map;
},
/**
* Sets the GeoJSON data and re-renders the map.
*
* @param {Object|string} data A GeoJSON data object or a URL to one. The latter is preferable in the case of large GeoJSON files.
* @returns {GeoJSONSource} this
*/
setData: function(data) {
this._data = data;
this._updateWorkerData(function (err) {
if (err) {
return this.fire('error', { error: err });
}
this.fire('change');
}.bind(this));
return this;
},
/*
* Responsible for invoking WorkerSource's geojson.loadData target, which
* handles loading the geojson data and preparing to serve it up as tiles,
* using geojson-vt or supercluster as appropriate.
*/
_updateWorkerData: function(callback) {
var options = util.extend({}, this.workerOptions);
var data = this._data;
if (typeof data === 'string') {
options.url = typeof window != 'undefined' ? urlResolve(window.location.href, data) : data;
} else {
options.data = JSON.stringify(data);
}
// target {this.type}.loadData rather than literally geojson.loadData,
// so that other geojson-like source types can easily reuse this
// implementation
this.workerID = this.dispatcher.send(this.type + '.loadData', options, function(err) {
this._loaded = true;
callback(err);
}.bind(this));
},
loadTile: function (tile, callback) {
var overscaling = tile.coord.z > this.maxzoom ? Math.pow(2, tile.coord.z - this.maxzoom) : 1;
var params = {
type: this.type,
uid: tile.uid,
coord: tile.coord,
zoom: tile.coord.z,
maxZoom: this.maxzoom,
tileSize: this.tileSize,
source: this.id,
overscaling: overscaling,
angle: this.map.transform.angle,
pitch: this.map.transform.pitch,
showCollisionBoxes: this.map.showCollisionBoxes
};
tile.workerID = this.dispatcher.send('load tile', params, function(err, data) {
tile.unloadVectorData(this.map.painter);
if (tile.aborted)
return;
if (err) {
return callback(err);
}
tile.loadVectorData(data, this.map.style);
if (tile.redoWhenDone) {
tile.redoWhenDone = false;
tile.redoPlacement(this);
}
return callback(null);
}.bind(this), this.workerID);
},
abortTile: function(tile) {
tile.aborted = true;
},
unloadTile: function(tile) {
tile.unloadVectorData(this.map.painter);
this.dispatcher.send('remove tile', { uid: tile.uid, source: this.id }, function() {}, tile.workerID);
},
serialize: function() {
return {
type: this.type,
data: this._data
};
}
});
},{"../data/bucket":322,"../util/evented":427,"../util/util":435,"resolve-url":493}],352:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var ajax = require('../util/ajax');
var rewind = require('geojson-rewind');
var GeoJSONWrapper = require('./geojson_wrapper');
var vtpbf = require('vt-pbf');
var supercluster = require('supercluster');
var geojsonvt = require('geojson-vt');
var VectorTileWorkerSource = require('./vector_tile_worker_source');
module.exports = GeoJSONWorkerSource;
/**
* The {@link WorkerSource} implementation that supports {@link GeoJSONSource}.
* This class is designed to be easily reused to support custom source types
* for data formats that can be parsed/converted into an in-memory GeoJSON
* representation. To do so, create it with
* `new GeoJSONWorkerSource(actor, styleLayers, customLoadGeoJSONFunction)`. For a full example, see [mapbox-gl-topojson](https://github.com/developmentseed/mapbox-gl-topojson).
*
* @class GeoJSONWorkerSource
* @private
* @param {Function} [loadGeoJSON] Optional method for custom loading/parsing of GeoJSON based on parameters passed from the main-thread Source. See {@link GeoJSONWorkerSource#loadGeoJSON}.
*/
function GeoJSONWorkerSource (actor, styleLayers, loadGeoJSON) {
if (loadGeoJSON) { this.loadGeoJSON = loadGeoJSON; }
VectorTileWorkerSource.call(this, actor, styleLayers);
}
GeoJSONWorkerSource.prototype = util.inherit(VectorTileWorkerSource, /** @lends GeoJSONWorkerSource.prototype */ {
// object mapping source ids to geojson-vt-like tile indexes
_geoJSONIndexes: {},
/**
* See {@link VectorTileWorkerSource#loadTile}.
*/
loadVectorData: function (params, callback) {
var source = params.source,
coord = params.coord;
if (!this._geoJSONIndexes[source]) return callback(null, null); // we couldn't load the file
var geoJSONTile = this._geoJSONIndexes[source].getTile(Math.min(coord.z, params.maxZoom), coord.x, coord.y);
if (geoJSONTile) {
var geojsonWrapper = new GeoJSONWrapper(geoJSONTile.features);
geojsonWrapper.name = '_geojsonTileLayer';
var pbf = vtpbf({ layers: { '_geojsonTileLayer': geojsonWrapper }});
if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
// Compatibility with node Buffer (https://github.com/mapbox/pbf/issues/35)
pbf = new Uint8Array(pbf);
}
callback(null, { tile: geojsonWrapper, rawTileData: pbf.buffer });
// tile.parse(geojsonWrapper, this.layerFamilies, this.actor, rawTileData, callback);
} else {
return callback(null, null); // nothing in the given tile
}
},
/**
* Fetches (if appropriate), parses, and index geojson data into tiles. This
* preparatory method must be called before {@link GeoJSONWorkerSource#loadTile}
* can correctly serve up tiles.
*
* Defers to {@link GeoJSONWorkerSource#loadGeoJSON} for the fetching/parsing,
* expecting `callback(error, data)` to be called with either an error or a
* parsed GeoJSON object.
* @param {object} params
* @param {string} params.source The id of the source.
* @param {Function} callback
*/
loadData: function (params, callback) {
var handleData = function(err, data) {
if (err) return callback(err);
if (typeof data != 'object') {
return callback(new Error("Input data is not a valid GeoJSON object."));
}
rewind(data, true);
this._indexData(data, params, function (err, indexed) {
if (err) { return callback(err); }
this._geoJSONIndexes[params.source] = indexed;
callback(null);
}.bind(this));
}.bind(this);
this.loadGeoJSON(params, handleData);
},
/**
* Fetch and parse GeoJSON according to the given params. Calls `callback`
* with `(err, data)`, where `data` is a parsed GeoJSON object.
*
* GeoJSON is loaded and parsed from `params.url` if it exists, or else
* expected as a literal (string or object) `params.data`.
*
* @param {object} params
* @param {string} [params.url] A URL to the remote GeoJSON data.
* @param {object} [params.data] Literal GeoJSON data. Must be provided if `params.url` is not.
*/
loadGeoJSON: function (params, callback) {
// Because of same origin issues, urls must either include an explicit
// origin or absolute path.
// ie: /foo/bar.json or http://example.com/bar.json
// but not ../foo/bar.json
if (params.url) {
ajax.getJSON(params.url, callback);
} else if (typeof params.data === 'string') {
try {
return callback(null, JSON.parse(params.data));
} catch (e) {
return callback(new Error("Input data is not a valid GeoJSON object."));
}
} else {
return callback(new Error("Input data is not a valid GeoJSON object."));
}
},
/**
* Index the data using either geojson-vt or supercluster
* @param {GeoJSON} data
* @param {object} params forwarded from loadTile.
* @param {callback} (err, indexedData)
* @private
*/
_indexData: function (data, params, callback) {
try {
if (params.cluster) {
callback(null, supercluster(params.superclusterOptions).load(data.features));
} else {
callback(null, geojsonvt(data, params.geojsonVtOptions));
}
} catch (err) {
return callback(err);
}
}
});
},{"../util/ajax":418,"../util/util":435,"./geojson_wrapper":353,"./vector_tile_worker_source":364,"geojson-rewind":134,"geojson-vt":138,"supercluster":521,"vt-pbf":548}],353:[function(require,module,exports){
'use strict';
var Point = require('point-geometry');
var VectorTileFeature = require('vector-tile').VectorTileFeature;
var EXTENT = require('../data/bucket').EXTENT;
module.exports = GeoJSONWrapper;
// conform to vectortile api
function GeoJSONWrapper(features) {
this.features = features;
this.length = features.length;
this.extent = EXTENT;
}
GeoJSONWrapper.prototype.feature = function(i) {
return new FeatureWrapper(this.features[i]);
};
function FeatureWrapper(feature) {
this.type = feature.type;
if (feature.type === 1) {
this.rawGeometry = [];
for (var i = 0; i < feature.geometry.length; i++) {
this.rawGeometry.push([feature.geometry[i]]);
}
} else {
this.rawGeometry = feature.geometry;
}
this.properties = feature.tags;
this.extent = EXTENT;
}
FeatureWrapper.prototype.loadGeometry = function() {
var rings = this.rawGeometry;
this.geometry = [];
for (var i = 0; i < rings.length; i++) {
var ring = rings[i],
newRing = [];
for (var j = 0; j < ring.length; j++) {
newRing.push(new Point(ring[j][0], ring[j][1]));
}
this.geometry.push(newRing);
}
return this.geometry;
};
FeatureWrapper.prototype.bbox = function() {
if (!this.geometry) this.loadGeometry();
var rings = this.geometry,
x1 = Infinity,
x2 = -Infinity,
y1 = Infinity,
y2 = -Infinity;
for (var i = 0; i < rings.length; i++) {
var ring = rings[i];
for (var j = 0; j < ring.length; j++) {
var coord = ring[j];
x1 = Math.min(x1, coord.x);
x2 = Math.max(x2, coord.x);
y1 = Math.min(y1, coord.y);
y2 = Math.max(y2, coord.y);
}
}
return [x1, y1, x2, y2];
};
FeatureWrapper.prototype.toGeoJSON = VectorTileFeature.prototype.toGeoJSON;
},{"../data/bucket":322,"point-geometry":476,"vector-tile":542}],354:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var TileCoord = require('./tile_coord');
var LngLat = require('../geo/lng_lat');
var Point = require('point-geometry');
var Evented = require('../util/evented');
var ajax = require('../util/ajax');
var EXTENT = require('../data/bucket').EXTENT;
var RasterBoundsArray = require('../render/draw_raster').RasterBoundsArray;
var Buffer = require('../data/buffer');
var VertexArrayObject = require('../render/vertex_array_object');
module.exports = ImageSource;
/**
* A data source containing an image.
* (See the [Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/#sources-image) for detailed documentation of options.)
*
* @interface ImageSource
* @example
* // add to map
* map.addSource('some id', {
* type: 'image',
* url: 'https://www.mapbox.com/images/foo.png',
* coordinates: [
* [-76.54, 39.18],
* [-76.52, 39.18],
* [-76.52, 39.17],
* [-76.54, 39.17]
* ]
* });
*
* // update
* var mySource = map.getSource('some id');
* mySource.setCoordinates([
* [-76.54335737228394, 39.18579907229748],
* [-76.52803659439087, 39.1838364847587],
* [-76.5295386314392, 39.17683392507606],
* [-76.54520273208618, 39.17876344106642]
* ]);
*
* map.removeSource('some id'); // remove
*/
function ImageSource(id, options, dispatcher) {
this.id = id;
this.dispatcher = dispatcher;
this.url = options.url;
this.coordinates = options.coordinates;
ajax.getImage(options.url, function(err, image) {
if (err) return this.fire('error', {error: err});
this.image = image;
this.image.addEventListener('load', function() {
this.map._rerender();
}.bind(this));
this._loaded = true;
this.fire('load');
if (this.map) {
this.setCoordinates(options.coordinates);
}
}.bind(this));
}
ImageSource.prototype = util.inherit(Evented, /** @lends ImageSource.prototype */ {
minzoom: 0,
maxzoom: 22,
tileSize: 512,
onAdd: function(map) {
this.map = map;
if (this.image) {
this.setCoordinates(this.coordinates);
}
},
/**
* Sets the image's coordinates and re-renders the map.
*
* @param {Array>} coordinates Four geographical coordinates,
* represented as arrays of longitude and latitude numbers, which define the corners of the image.
* The coordinates start at the top left corner of the image and proceed in clockwise order.
* They do not have to represent a rectangle.
* @returns {ImageSource} this
*/
setCoordinates: function(coordinates) {
this.coordinates = coordinates;
// Calculate which mercator tile is suitable for rendering the video in
// and create a buffer with the corner coordinates. These coordinates
// may be outside the tile, because raster tiles aren't clipped when rendering.
var map = this.map;
var cornerZ0Coords = coordinates.map(function(coord) {
return map.transform.locationCoordinate(LngLat.convert(coord)).zoomTo(0);
});
var centerCoord = this.centerCoord = util.getCoordinatesCenter(cornerZ0Coords);
centerCoord.column = Math.round(centerCoord.column);
centerCoord.row = Math.round(centerCoord.row);
this.minzoom = this.maxzoom = centerCoord.zoom;
this._coord = new TileCoord(centerCoord.zoom, centerCoord.column, centerCoord.row);
this._tileCoords = cornerZ0Coords.map(function(coord) {
var zoomedCoord = coord.zoomTo(centerCoord.zoom);
return new Point(
Math.round((zoomedCoord.column - centerCoord.column) * EXTENT),
Math.round((zoomedCoord.row - centerCoord.row) * EXTENT));
});
this.fire('change');
return this;
},
_setTile: function (tile) {
this._prepared = false;
this.tile = tile;
var maxInt16 = 32767;
var array = new RasterBoundsArray();
array.emplaceBack(this._tileCoords[0].x, this._tileCoords[0].y, 0, 0);
array.emplaceBack(this._tileCoords[1].x, this._tileCoords[1].y, maxInt16, 0);
array.emplaceBack(this._tileCoords[3].x, this._tileCoords[3].y, 0, maxInt16);
array.emplaceBack(this._tileCoords[2].x, this._tileCoords[2].y, maxInt16, maxInt16);
this.tile.buckets = {};
this.tile.boundsBuffer = new Buffer(array.serialize(), RasterBoundsArray.serialize(), Buffer.BufferType.VERTEX);
this.tile.boundsVAO = new VertexArrayObject();
this.tile.state = 'loaded';
},
prepare: function() {
if (!this._loaded || !this.image || !this.image.complete) return;
if (!this.tile) return;
var painter = this.map.painter;
var gl = painter.gl;
if (!this._prepared) {
this.tile.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.image);
} else {
gl.bindTexture(gl.TEXTURE_2D, this.tile.texture);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.image);
}
},
loadTile: function(tile, callback) {
// We have a single tile -- whoose coordinates are this._coord -- that
// covers the image we want to render. If that's the one being
// requested, set it up with the image; otherwise, mark the tile as
// `errored` to indicate that we have no data for it.
if (this._coord && this._coord.toString() === tile.coord.toString()) {
this._setTile(tile);
callback(null);
} else {
tile.state = 'errored';
callback(null);
}
},
serialize: function() {
return {
type: 'image',
urls: this.url,
coordinates: this.coordinates
};
}
});
},{"../data/bucket":322,"../data/buffer":327,"../geo/lng_lat":332,"../render/draw_raster":344,"../render/vertex_array_object":350,"../util/ajax":418,"../util/evented":427,"../util/util":435,"./tile_coord":362,"point-geometry":476}],355:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var ajax = require('../util/ajax');
var browser = require('../util/browser');
var normalizeURL = require('../util/mapbox').normalizeSourceURL;
module.exports = function(options, callback) {
var loaded = function(err, tileJSON) {
if (err) {
return callback(err);
}
var result = util.pick(tileJSON, ['tiles', 'minzoom', 'maxzoom', 'attribution']);
if (tileJSON.vector_layers) {
result.vectorLayers = tileJSON.vector_layers;
result.vectorLayerIds = result.vectorLayers.map(function(layer) { return layer.id; });
}
callback(null, result);
};
if (options.url) {
ajax.getJSON(normalizeURL(options.url), loaded);
} else {
browser.frame(loaded.bind(null, null, options));
}
};
},{"../util/ajax":418,"../util/browser":419,"../util/mapbox":432,"../util/util":435}],356:[function(require,module,exports){
'use strict';
var Bucket = require('../data/bucket');
/**
* Converts a pixel value at a the given zoom level to tile units.
*
* The shaders mostly calculate everything in tile units so style
* properties need to be converted from pixels to tile units using this.
*
* For example, a translation by 30 pixels at zoom 6.5 will be a
* translation by pixelsToTileUnits(30, 6.5) tile units.
*
* @param {object} tile a {Tile object} will work well, but any object that follows the format {coord: {TileCord object}, tileSize: {number}} will work
* @param {number} pixelValue
* @param {number} z
* @returns {number} value in tile units
* @private
*/
module.exports = function(tile, pixelValue, z) {
return pixelValue * (Bucket.EXTENT / (tile.tileSize * Math.pow(2, z - tile.coord.z)));
};
},{"../data/bucket":322}],357:[function(require,module,exports){
'use strict';
var TileCoord = require('./tile_coord');
exports.rendered = function(sourceCache, styleLayers, queryGeometry, params, zoom, bearing) {
var tilesIn = sourceCache.tilesIn(queryGeometry);
tilesIn.sort(sortTilesIn);
var renderedFeatureLayers = [];
for (var r = 0; r < tilesIn.length; r++) {
var tileIn = tilesIn[r];
if (!tileIn.tile.featureIndex) continue;
renderedFeatureLayers.push(tileIn.tile.featureIndex.query({
queryGeometry: tileIn.queryGeometry,
scale: tileIn.scale,
tileSize: tileIn.tile.tileSize,
bearing: bearing,
params: params
}, styleLayers));
}
return mergeRenderedFeatureLayers(renderedFeatureLayers);
};
exports.source = function(sourceCache, params) {
var tiles = sourceCache.getRenderableIds().map(function(id) {
return sourceCache.getTileByID(id);
});
var result = [];
var dataTiles = {};
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
var dataID = new TileCoord(Math.min(tile.sourceMaxZoom, tile.coord.z), tile.coord.x, tile.coord.y, 0).id;
if (!dataTiles[dataID]) {
dataTiles[dataID] = true;
tile.querySourceFeatures(result, params);
}
}
return result;
};
function sortTilesIn(a, b) {
var coordA = a.coord;
var coordB = b.coord;
return (coordA.z - coordB.z) || (coordA.y - coordB.y) || (coordA.w - coordB.w) || (coordA.x - coordB.x);
}
function mergeRenderedFeatureLayers(tiles) {
var result = tiles[0] || {};
for (var i = 1; i < tiles.length; i++) {
var tile = tiles[i];
for (var layerID in tile) {
var tileFeatures = tile[layerID];
var resultFeatures = result[layerID];
if (resultFeatures === undefined) {
resultFeatures = result[layerID] = tileFeatures;
} else {
for (var f = 0; f < tileFeatures.length; f++) {
resultFeatures.push(tileFeatures[f]);
}
}
}
}
return result;
}
},{"./tile_coord":362}],358:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var ajax = require('../util/ajax');
var Evented = require('../util/evented');
var loadTileJSON = require('./load_tilejson');
var normalizeURL = require('../util/mapbox').normalizeTileURL;
module.exports = RasterTileSource;
function RasterTileSource(id, options, dispatcher) {
this.id = id;
this.dispatcher = dispatcher;
util.extend(this, util.pick(options, ['url', 'scheme', 'tileSize']));
loadTileJSON(options, function (err, tileJSON) {
if (err) {
return this.fire('error', err);
}
util.extend(this, tileJSON);
this.fire('load');
}.bind(this));
}
RasterTileSource.prototype = util.inherit(Evented, {
minzoom: 0,
maxzoom: 22,
roundZoom: true,
scheme: 'xyz',
tileSize: 512,
_loaded: false,
onAdd: function (map) {
this.map = map;
},
serialize: function() {
return {
type: 'raster',
url: this.url,
tileSize: this.tileSize
};
},
loadTile: function(tile, callback) {
var url = normalizeURL(tile.coord.url(this.tiles, null, this.scheme), this.url, this.tileSize);
tile.request = ajax.getImage(url, done.bind(this));
function done(err, img) {
delete tile.request;
if (tile.aborted)
return;
if (err) {
return callback(err);
}
var gl = this.map.painter.gl;
tile.texture = this.map.painter.getTexture(img.width);
if (tile.texture) {
gl.bindTexture(gl.TEXTURE_2D, tile.texture);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img);
} else {
tile.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tile.texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
tile.texture.size = img.width;
}
gl.generateMipmap(gl.TEXTURE_2D);
this.map.animationLoop.set(this.map.style.rasterFadeDuration);
tile.state = 'loaded';
callback(null);
}
},
abortTile: function(tile) {
if (tile.request) {
tile.request.abort();
delete tile.request;
}
},
unloadTile: function(tile) {
if (tile.texture) this.map.painter.saveTexture(tile.texture);
}
});
},{"../util/ajax":418,"../util/evented":427,"../util/mapbox":432,"../util/util":435,"./load_tilejson":355}],359:[function(require,module,exports){
'use strict';
var util = require('../util/util');
var sourceTypes = {
'vector': require('../source/vector_tile_source'),
'raster': require('../source/raster_tile_source'),
'geojson': require('../source/geojson_source'),
'video': require('../source/video_source'),
'image': require('../source/image_source')
};
/*
* Creates a tiled data source instance given an options object.
*
* @param {string} id
* @param {Object} source A source definition object compliant with [`mapbox-gl-style-spec`](https://www.mapbox.com/mapbox-gl-style-spec/#sources) or, for a third-party source type, with that type's requirements.
* @param {string} options.type A source type like `raster`, `vector`, `video`, etc.
* @param {Dispatcher} dispatcher
* @returns {Source}
*/
exports.create = function(id, source, dispatcher) {
source = new sourceTypes[source.type](id, source, dispatcher);
if (source.id !== id) {
throw new Error('Expected Source id to be ' + id + ' instead of ' + source.id);
}
util.bindAll(['load', 'abort', 'unload', 'serialize', 'prepare'], source);
return source;
};
exports.getType = function (name) {
return sourceTypes[name];
};
exports.setType = function (name, type) {
sourceTypes[name] = type;
};
/**
* The `Source` interface must be implemented by each source type, including "core" types (`vector`, `raster`, `video`, etc.) and all custom, third-party types.
*
* @class Source
* @private
*
* @param {string} id The id for the source. Must not be used by any existing source.
* @param {Object} options Source options, specific to the source type (except for `options.type`, which is always required).
* @param {string} options.type The source type, matching the value of `name` used in {@link Style#addSourceType}.
* @param {Dispatcher} dispatcher A {@link Dispatcher} instance, which can be used to send messages to the workers.
*
* @fires load to indicate source data has been loaded, so that it's okay to call `loadTile`
* @fires change to indicate source data has changed, so that any current caches should be flushed
* @property {string} id The id for the source. Must match the id passed to the constructor.
* @property {number} minzoom
* @property {number} maxzoom
* @property {boolean} isTileClipped `false` if tiles can be drawn outside their boundaries, `true` if they cannot.
* @property {boolean} reparseOverscaled `true` if tiles should be sent back to the worker for each overzoomed zoom level, `false` if not.
* @property {boolean} roundZoom `true` if zoom levels are rounded to the nearest integer in the source data, `false` if they are floor-ed to the nearest integer.
*/
/**
* An optional URL to a script which, when run by a Worker, registers a {@link WorkerSource} implementation for this Source type by calling `self.registerWorkerSource(workerSource: WorkerSource)`.
*
* @member {URL|undefined} workerSourceURL
* @memberof Source
* @static
*/
/**
* @method
* @name loadTile
* @param {Tile} tile
* @param {Funtion} callback Called when tile has been loaded
* @memberof Source
* @instance
*/
/**
* @method
* @name abortTile
* @param {Tile} tile
* @memberof Source
* @instance
*/
/**
* @method
* @name unloadTile
* @param {Tile} tile
* @memberof Source
* @instance
*/
/**
* @method
* @name serialize
* @returns {Object} A plain (stringifiable) JS object representing the current state of the source. Creating a source using the returned object as the `options` should result in a Source that is equivalent to this one.
* @memberof Source
* @instance
*/
/**
* @method
* @name prepare
* @memberof Source
* @instance
*/
/**
* May be implemented by custom source types to provide code that can be run on
* the WebWorkers. In addition to providing a custom
* {@link WorkerSource#loadTile}, any other methods attached to a `WorkerSource`
* implementation may also be targeted by the {@link Source} via
* `dispatcher.send('source-type.methodname', params, callback)`.
*
* @see {@link Map#addSourceType}
* @private
*
* @class WorkerSource
* @param {Actor} actor
* @param {object} styleLayers An accessor provided by the Worker to get the current style layers and layer families.
* @param {Function} styleLayers.getLayers
* @param {Function} styleLayers.getLayerFamilies
*/
/**
* Loads a tile from the given params and parse it into buckets ready to send
* back to the main thread for rendering. Should call the callback with:
* `{ buckets, featureIndex, collisionTile, symbolInstancesArray, symbolQuadsArray, rawTileData}`.
*
* @method
* @name loadTile
* @param {object} params Parameters sent by the main-thread Source identifying the tile to load.
* @param {Function} callback
* @memberof WorkerSource
* @instance
*/
/**
* Re-parses a tile that has already been loaded. Yields the same data as
* {@link WorkerSource#loadTile}.
*
* @method
* @name reloadTile
* @param {object} params
* @param {Function} callback
* @memberof WorkerSource
* @instance
*/
/**
* Aborts loading a tile that is in progress.
* @method
* @name abortTile
* @param {object} params
* @memberof WorkerSource
* @instance
*/
/**
* Removes this tile from any local caches.
* @method
* @name removeTile
* @memberof WorkerSource
* @instance
*/
},{"../source/geojson_source":351,"../source/image_source":354,"../source/raster_tile_source":358,"../source/vector_tile_source":363,"../source/video_source":365,"../util/util":435}],360:[function(require,module,exports){
'use strict';
var Source = require('./source');
var Tile = require('./tile');
var Evented = require('../util/evented');
var TileCoord = require('./tile_coord');
var Cache = require('../util/lru_cache');
var Coordinate = require('../geo/coordinate');
var util = require('../util/util');
var EXTENT = require('../data/bucket').EXTENT;
module.exports = SourceCache;
/**
* A tile pyramid is a specialized cache and datastructure
* that contains tiles. It's used by sources to manage their
* data.
*
* @param {Object} options
* @private
*/
function SourceCache(id, options, dispatcher) {
this.id = id;
this.dispatcher = dispatcher;
var source = this._source = Source.create(id, options, dispatcher)
.on('load', function () {
if (this.map && this._source.onAdd) { this._source.onAdd(this.map); }
this._sourceLoaded = true;
this.tileSize = source.tileSize;
this.minzoom = source.minzoom;
this.maxzoom = source.maxzoom;
this.roundZoom = source.roundZoom;
this.reparseOverscaled = source.reparseOverscaled;
this.isTileClipped = source.isTileClipped;
this.attribution = source.attribution;
this.vectorLayerIds = source.vectorLayerIds;
this.fire('load');
}.bind(this))
.on('error', function (e) {
this._sourceErrored = true;
this.fire('error', e);
}.bind(this))
.on('change', function () {
this.reload();
if (this.transform) {
this.update(this.transform, this.map && this.map.style.rasterFadeDuration);
}
this.fire('change');
}.bind(this));
this._tiles = {};
this._cache = new Cache(0, this.unloadTile.bind(this));
this._isIdRenderable = this._isIdRenderable.bind(this);
}
SourceCache.maxOverzooming = 10;
SourceCache.maxUnderzooming = 3;
SourceCache.prototype = util.inherit(Evented, {
onAdd: function (map) {
this.map = map;
if (this._source && this._source.onAdd) {
this._source.onAdd(map);
}
},
/**
* Return true if no tile data is pending, tiles will not change unless
* an additional API call is received.
* @returns {boolean}
* @private
*/
loaded: function() {
if (this._sourceErrored) { return true; }
if (!this._sourceLoaded) { return false; }
for (var t in this._tiles) {
var tile = this._tiles[t];
if (tile.state !== 'loaded' && tile.state !== 'errored')
return false;
}
return true;
},
/**
* @returns {Source} The underlying source object
* @private
*/
getSource: function () {
return this._source;
},
loadTile: function (tile, callback) {
return this._source.loadTile(tile, callback);
},
unloadTile: function (tile) {
if (this._source.unloadTile)
return this._source.unloadTile(tile);
},
abortTile: function (tile) {
if (this._source.abortTile)
return this._source.abortTile(tile);
},
serialize: function () {
return this._source.serialize();
},
prepare: function () {
if (this._sourceLoaded && this._source.prepare)
return this._source.prepare();
},
/**
* Return all tile ids ordered with z-order, and cast to numbers
* @returns {Array} ids
* @private
*/
getIds: function() {
return Object.keys(this._tiles).map(Number).sort(compareKeyZoom);
},
getRenderableIds: function() {
return this.getIds().filter(this._isIdRenderable);
},
_isIdRenderable: function(id) {
return this._tiles[id].isRenderable() && !this._coveredTiles[id];
},
reload: function() {
this._cache.reset();
for (var i in this._tiles) {
var tile = this._tiles[i];
// The difference between "loading" tiles and "reloading" tiles is
// that "reloading" tiles are "renderable". Therefore, a "loading"
// tile cannot become a "reloading" tile without first becoming
// a "loaded" tile.
if (tile.state !== 'loading') {
tile.state = 'reloading';
}
this.loadTile(this._tiles[i], this._tileLoaded.bind(this, this._tiles[i]));
}
},
_tileLoaded: function (tile, err) {
if (err) {
tile.state = 'errored';
this.fire('tile.error', {tile: tile, error: err});
this._source.fire('tile.error', {tile: tile, error: err});
return;
}
tile.source = this;
tile.timeAdded = new Date().getTime();
this.fire('tile.load', {tile: tile});
this._source.fire('tile.load', {tile: tile});
},
/**
* Get a specific tile by TileCoordinate
* @param {TileCoordinate} coord
* @returns {Object} tile
* @private
*/
getTile: function(coord) {
return this.getTileByID(coord.id);
},
/**
* Get a specific tile by id
* @param {number|string} id
* @returns {Object} tile
* @private
*/
getTileByID: function(id) {
return this._tiles[id];
},
/**
* get the zoom level adjusted for the difference in map and source tilesizes
* @param {Object} transform
* @returns {number} zoom level
* @private
*/
getZoom: function(transform) {
return transform.zoom + transform.scaleZoom(transform.tileSize / this.tileSize);
},
/**
* Recursively find children of the given tile (up to maxCoveringZoom) that are already loaded;
* adds found tiles to retain object; returns true if any child is found.
*
* @param {Coordinate} coord
* @param {number} maxCoveringZoom
* @param {boolean} retain
* @returns {boolean} whether the operation was complete
* @private
*/
findLoadedChildren: function(coord, maxCoveringZoom, retain) {
var found = false;
for (var id in this._tiles) {
var tile = this._tiles[id];
// only consider renderable tiles on higher zoom levels (up to maxCoveringZoom)
if (retain[id] || !tile.isRenderable() || tile.coord.z <= coord.z || tile.coord.z > maxCoveringZoom) continue;
// disregard tiles that are not descendants of the given tile coordinate
var z2 = Math.pow(2, Math.min(tile.coord.z, this.maxzoom) - Math.min(coord.z, this.maxzoom));
if (Math.floor(tile.coord.x / z2) !== coord.x ||
Math.floor(tile.coord.y / z2) !== coord.y)
continue;
// found loaded child
retain[id] = true;
found = true;
// loop through parents; retain the topmost loaded one if found
while (tile && tile.coord.z - 1 > coord.z) {
var parentId = tile.coord.parent(this.maxzoom).id;
tile = this._tiles[parentId];
if (tile && tile.isRenderable()) {
delete retain[id];
retain[parentId] = true;
}
}
}
return found;
},
/**
* Find a loaded parent of the given tile (up to minCoveringZoom);
* adds the found tile to retain object and returns the tile if found
*
* @param {Coordinate} coord
* @param {number} minCoveringZoom
* @param {boolean} retain
* @returns {Tile} tile object
* @private
*/
findLoadedParent: function(coord, minCoveringZoom, retain) {
for (var z = coord.z - 1; z >= minCoveringZoom; z--) {
coord = coord.parent(this.maxzoom);
var tile = this._tiles[coord.id];
if (tile && tile.isRenderable()) {
retain[coord.id] = true;
return tile;
}
if (this._cache.has(coord.id)) {
this.addTile(coord);
retain[coord.id] = true;
return this._tiles[coord.id];
}
}
},
/**
* Resizes the tile cache based on the current viewport's size.
*
* Larger viewports use more tiles and need larger caches. Larger viewports
* are more likely to be found on devices with more memory and on pages where
* the map is more important.
*
* @private
*/
updateCacheSize: function(transform) {
var widthInTiles = Math.ceil(transform.width / transform.tileSize) + 1;
var heightInTiles = Math.ceil(transform.height / transform.tileSize) + 1;
var approxTilesInView = widthInTiles * heightInTiles;
var commonZoomRange = 5;
this._cache.setMaxSize(Math.floor(approxTilesInView * commonZoomRange));
},
/**
* Removes tiles that are outside the viewport and adds new tiles that
* are inside the viewport.
* @private
*/
update: function(transform, fadeDuration) {
if (!this._sourceLoaded) { return; }
var i;
var coord;
var tile;
this.updateCacheSize(transform);
// Determine the overzooming/underzooming amounts.
var zoom = (this.roundZoom ? Math.round : Math.floor)(this.getZoom(transform));
var minCoveringZoom = Math.max(zoom - SourceCache.maxOverzooming, this.minzoom);
var maxCoveringZoom = Math.max(zoom + SourceCache.maxUnderzooming, this.minzoom);
// Retain is a list of tiles that we shouldn't delete, even if they are not
// the most ideal tile for the current viewport. This may include tiles like
// parent or child tiles that are *already* loaded.
var retain = {};
var now = new Date().getTime();
// Covered is a list of retained tiles who's areas are full covered by other,
// better, retained tiles. They are not drawn separately.
this._coveredTiles = {};
var required = this.used ? transform.coveringTiles(this._source) : [];
for (i = 0; i < required.length; i++) {
coord = required[i];
tile = this.addTile(coord);
retain[coord.id] = true;
if (tile.isRenderable())
continue;
// The tile we require is not yet loaded.
// Retain child or parent tiles that cover the same area.
if (!this.findLoadedChildren(coord, maxCoveringZoom, retain)) {
this.findLoadedParent(coord, minCoveringZoom, retain);
}
}
var parentsForFading = {};
var ids = Object.keys(retain);
for (var k = 0; k < ids.length; k++) {
var id = ids[k];
coord = TileCoord.fromID(id);
tile = this._tiles[id];
if (tile && tile.timeAdded > now - (fadeDuration || 0)) {
// This tile is still fading in. Find tiles to cross-fade with it.
if (this.findLoadedChildren(coord, maxCoveringZoom, retain)) {
retain[id] = true;
}
this.findLoadedParent(coord, minCoveringZoom, parentsForFading);
}
}
var fadedParent;
for (fadedParent in parentsForFading) {
if (!retain[fadedParent]) {
// If a tile is only needed for fading, mark it as covered so that it isn't rendered on it's own.
this._coveredTiles[fadedParent] = true;
}
}
for (fadedParent in parentsForFading) {
retain[fadedParent] = true;
}
// Remove the tiles we don't need anymore.
var remove = util.keysDifference(this._tiles, retain);
for (i = 0; i < remove.length; i++) {
this.removeTile(+remove[i]);
}
this.transform = transform;
},
/**
* Add a tile, given its coordinate, to the pyramid.
* @param {Coordinate} coord
* @returns {Coordinate} the coordinate.
* @private
*/
addTile: function(coord) {
var tile = this._tiles[coord.id];
if (tile)
return tile;
var wrapped = coord.wrapped();
tile = this._tiles[wrapped.id];
if (!tile) {
tile = this._cache.get(wrapped.id);
if (tile && this._redoPlacement) {
this._redoPlacement(tile);
}
}
if (!tile) {
var zoom = coord.z;
var overscaling = zoom > this.maxzoom ? Math.pow(2, zoom - this.maxzoom) : 1;
tile = new Tile(wrapped, this.tileSize * overscaling, this.maxzoom);
this.loadTile(tile, this._tileLoaded.bind(this, tile));
}
tile.uses++;
this._tiles[coord.id] = tile;
this.fire('tile.add', {tile: tile});
this._source.fire('tile.add', {tile: tile});
return tile;
},
/**
* Remove a tile, given its id, from the pyramid
* @param {string|number} id tile id
* @returns {undefined} nothing
* @private
*/
removeTile: function(id) {
var tile = this._tiles[id];
if (!tile)
return;
tile.uses--;
delete this._tiles[id];
this.fire('tile.remove', {tile: tile});
this._source.fire('tile.remove', {tile: tile});
if (tile.uses > 0)
return;
if (tile.isRenderable()) {
this._cache.add(tile.coord.wrapped().id, tile);
} else {
tile.aborted = true;
this.abortTile(tile);
this.unloadTile(tile);
}
},
/**
* Remove all tiles from this pyramid
* @private
*/
clearTiles: function() {
for (var id in this._tiles)
this.removeTile(id);
this._cache.reset();
},
/**
* Search through our current tiles and attempt to find the tiles that
* cover the given bounds.
* @param {Array} queryGeometry coordinates of the corners of bounding rectangle
* @returns {Array