├── .bowerrc ├── .gitignore ├── LICENSE ├── README.md ├── docs └── ndtv-d3.md ├── examples ├── data │ ├── .htaccess │ ├── .msmSim.json.swp │ ├── EpiSim.html │ ├── EpiSim.json │ ├── EpiSim.mp4 │ ├── mcfarlandClass.html │ ├── mcfarlandClass.json │ ├── mcfarlandClass.mp4 │ ├── msmSim.html │ ├── msmSim.json │ ├── msmSim.mp4 │ ├── msmSim.orig.json │ ├── msmSim2.json │ ├── shortStergm.html │ ├── shortStergm.json │ ├── shortStergm.mp4 │ ├── testDataGenerationScript.R │ ├── tooltipTest.html │ ├── tooltipTest.json │ ├── windsurfers.html │ ├── windsurfers.json │ └── windsurfers.mp4 └── index.html ├── networkPlotFunctionImplPriorities.txt └── src ├── css └── styles.css ├── index.html ├── index.html.tpl ├── js └── ndtv-d3.js └── lib ├── d3.slider.css ├── d3.slider.js ├── d3 ├── .bower.json ├── .spmignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── composer.json ├── d3.js └── d3.min.js └── jquery ├── .bower.json ├── MIT-LICENSE.txt ├── bower.json ├── dist ├── jquery.js ├── jquery.min.js └── jquery.min.map └── src ├── ajax.js ├── ajax ├── jsonp.js ├── load.js ├── parseJSON.js ├── parseXML.js ├── script.js ├── var │ ├── nonce.js │ └── rquery.js └── xhr.js ├── attributes.js ├── attributes ├── attr.js ├── classes.js ├── prop.js ├── support.js └── val.js ├── callbacks.js ├── core.js ├── core ├── access.js ├── init.js ├── parseHTML.js ├── ready.js └── var │ └── rsingleTag.js ├── css.js ├── css ├── addGetHookIf.js ├── curCSS.js ├── defaultDisplay.js ├── hiddenVisibleSelectors.js ├── support.js ├── swap.js └── var │ ├── cssExpand.js │ ├── getStyles.js │ ├── isHidden.js │ ├── rmargin.js │ └── rnumnonpx.js ├── data.js ├── data ├── Data.js ├── accepts.js └── var │ ├── data_priv.js │ └── data_user.js ├── deferred.js ├── deprecated.js ├── dimensions.js ├── effects.js ├── effects ├── Tween.js └── animatedSelector.js ├── event.js ├── event ├── alias.js └── support.js ├── exports ├── amd.js └── global.js ├── intro.js ├── jquery.js ├── manipulation.js ├── manipulation ├── _evalUrl.js ├── support.js └── var │ └── rcheckableType.js ├── offset.js ├── outro.js ├── queue.js ├── queue └── delay.js ├── selector-native.js ├── selector-sizzle.js ├── selector.js ├── serialize.js ├── sizzle └── dist │ ├── sizzle.js │ ├── sizzle.min.js │ └── sizzle.min.map ├── traversing.js ├── traversing ├── findFilter.js └── var │ └── rneedsContext.js ├── var ├── arr.js ├── class2type.js ├── concat.js ├── hasOwn.js ├── indexOf.js ├── pnum.js ├── push.js ├── rnotwhite.js ├── slice.js ├── strundefined.js ├── support.js └── toString.js └── wrap.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *sublime* 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ndtv-d3 is a d3-based HTML5 network animation player for the ndtv package (http://cran.r-project.org/web/packages/ndtv/index.html) 2 | 3 | The ndtv-d3 library was created by Greg Michalec and Skye Bender-deMoll for the statnet project http://statnet.org funded by NICHD grant R01HD068395. 4 | 5 | This software is distributed under the GPL-3 license (http://choosealicense.com/licenses/gpl-3.0/). It is free, open source, and has the attribution requirements (GPL Section 7) at http://statnet.org/attribution: 6 | 7 | a. you agree to retain in ndtv-d3 and any modifications to ndtv-d3 the copyright, author attribution and URL information as provided at a http://statnetproject.org/attribution. 8 | 9 | b. you agree that ndtv-d3 and any modifications to ndtv-d3 will, when used, display the attribution: 10 | 11 | Based on 'statnet' project software (http://statnetproject.org). For license and citation information see http://statnetproject.org/attribution 12 | 13 | Copyright 2014 Statnet Commons http://statnet.org 14 | 15 | To cite this project, please use: 16 | 17 | Greg Michalec, Skye Bender-deMoll, Martina Morris (2014) 'ndtv-d3: an HTML5 network animation player for the ndtv package' The statnet project. http://statnet.org 18 | 19 | 20 | This repository/distribution may also include copies of several other javascript libraries in the lib directory each of which includes its own license file. Those libraries are: 21 | 22 | * d3 http://d3js.org Michael Bostock BSD license: http://opensource.org/licenses/BSD-3-Clause 23 | * d3.slider http://blog.thematicmapping.org Bjorn Sandvik BSD license: http://opensource.org/licenses/BSD-3-Clause 24 | * jQuery http://jquery.com/ jQuery Foundation MIT License 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | output: html_document 3 | --- 4 | ndtv-d3 : Interactive HTML5 Network Graph Animation for NDTV-generated graphs using D3 5 | ======= 6 | 7 | ndtv-d3 is an web-based interactive player app for animations of dynamic networks created with the [ndtv R package](http://cran.r-project.org/web/packages/ndtv/index.html). It takes JSON-formatted input files (normally produced by ndtv) describing the node positions, changing network relationships and graphic properties and displays them as a 'movie' illustrating the changes in a network object over time. The 'movie' is a zoomable, interactive SVG object with animation play controls and a scrub-able timeline for navigation. 8 | 9 | The ndtv-d3 library was created by Greg Michalec and Skye Bender-deMoll for the [statnet project](http://statnet.org) funded by NICHD grant R01HD068395. Based on 'statnet' project software (http://statnetproject.org). For license and attribution information, please see the [LICENSE file](https://github.com/michalgm/ndtv-d3/blob/master/LICENSE) or http://statnetproject.org/attribution 10 | 11 | For a demo, please see http://michalgm.github.io/ndtv-d3 12 | 13 | If the ndtv package is install in R, networks can be exported with 14 | ``` 15 | library(ndtv) 16 | data(short.stergm.sim) 17 | render.d3movie(short.stergm.sim) 18 | ``` 19 | 20 | For a quick vignette, see http://statnet.csde.washington.edu/workshops/SUNBELT/current/ndtv/ndtv-d3_vignette.html 21 | 22 | 23 | Copyright 2015 Statnet Commons http://statnet.org 24 | 25 | To cite this project, please use: 26 | ``` 27 | Greg Michalec, Skye Bender-deMoll, Martina Morris (2014) 'ndtv-d3: an HTML5 network animation player for the ndtv package' The statnet project. http://statnet.org 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/ndtv-d3.md: -------------------------------------------------------------------------------- 1 | #Index 2 | 3 | **Modules** 4 | 5 | * [ndtv-d3](#module_ndtv-d3) 6 | 7 | **Classes** 8 | 9 | * [class: ndtv_d3](#ndtv_d3) 10 | * [new ndtv_d3()](#new_ndtv_d3) 11 | * [ndtv_d3.SVGSetup(domTarget)](#ndtv_d3#SVGSetup) 12 | * [ndtv_d3.updateDimensions()](#ndtv_d3#updateDimensions) 13 | * [ndtv_d3.createDataChooser()](#ndtv_d3#createDataChooser) 14 | * [ndtv_d3.createMenu()](#ndtv_d3#createMenu) 15 | * [ndtv_d3.createPlayControls()](#ndtv_d3#createPlayControls) 16 | * [ndtv_d3.createSliderControl()](#ndtv_d3#createSliderControl) 17 | * [ndtv_d3.loadData(graphData)](#ndtv_d3#loadData) 18 | * [ndtv_d3.updateSelectedNetwork()](#ndtv_d3#updateSelectedNetwork) 19 | * [ndtv_d3.unSelectNetwork()](#ndtv_d3#unSelectNetwork) 20 | * [ndtv_d3.updateGraph(duration)](#ndtv_d3#updateGraph) 21 | * [ndtv_d3.resizeGraph()](#ndtv_d3#resizeGraph) 22 | * [ndtv_d3.animateGraph(time, endTime, immediate)](#ndtv_d3#animateGraph) 23 | * [ndtv_d3.moveTooltip()](#ndtv_d3#moveTooltip) 24 | * [ndtv_d3.convertCoords()](#ndtv_d3#convertCoords) 25 | * [ndtv_d3.hideTooltip()](#ndtv_d3#hideTooltip) 26 | * [ndtv_d3.endAnimation(noHalt)](#ndtv_d3#endAnimation) 27 | * [ndtv_d3.stepAnimation(reverse)](#ndtv_d3#stepAnimation) 28 | * [ndtv_d3.playAnimation(reverse)](#ndtv_d3#playAnimation) 29 | 30 | **Constants** 31 | 32 | * [const: default_options](#default_options) 33 | * [const: ndtvProperties](#ndtvProperties) 34 | 35 | 36 | #ndtv-d3 37 | ndtv-d3 is a d3-based HTML5 network animation player for the ndtv package (http://cran.r-project.org/web/packages/ndtv/index.html) 38 | 39 | The ndtv-d3 library was created by Greg Michalec and Skye Bender-deMoll for the statnet project http://statnet.org funded by NICHD grant R01HD068395. 40 | 41 | This software is distributed under the GPL-3 license (http://choosealicense.com/licenses/gpl-3.0/). It is free, open source, and has the attribution requirements (GPL Section 7) at http://statnet.org/attribution: 42 | 43 | a. you agree to retain in ndtv-d3 and any modifications to ndtv-d3 the copyright, author attribution and URL information as provided at a http://statnetproject.org/attribution. 44 | 45 | b. you agree that ndtv-d3 and any modifications to ndtv-d3 will, when used, display the attribution: 46 | 47 | Based on 'statnet' project software (http://statnetproject.org). For license and citation information see http://statnetproject.org/attribution 48 | 49 | Copyright 2014 Statnet Commons http://statnet.org 50 | 51 | To cite this project, please use: 52 | 53 | Greg Michalec, Skye Bender-deMoll, Martina Morris (2014) 'ndtv-d3: an HTML5 network animation player for the ndtv package' The statnet project. http://statnet.org 54 | 55 | 56 | #class: ndtv_d3 57 | **Members** 58 | 59 | * [class: ndtv_d3](#ndtv_d3) 60 | * [new ndtv_d3()](#new_ndtv_d3) 61 | * [ndtv_d3.SVGSetup(domTarget)](#ndtv_d3#SVGSetup) 62 | * [ndtv_d3.updateDimensions()](#ndtv_d3#updateDimensions) 63 | * [ndtv_d3.createDataChooser()](#ndtv_d3#createDataChooser) 64 | * [ndtv_d3.createMenu()](#ndtv_d3#createMenu) 65 | * [ndtv_d3.createPlayControls()](#ndtv_d3#createPlayControls) 66 | * [ndtv_d3.createSliderControl()](#ndtv_d3#createSliderControl) 67 | * [ndtv_d3.loadData(graphData)](#ndtv_d3#loadData) 68 | * [ndtv_d3.updateSelectedNetwork()](#ndtv_d3#updateSelectedNetwork) 69 | * [ndtv_d3.unSelectNetwork()](#ndtv_d3#unSelectNetwork) 70 | * [ndtv_d3.updateGraph(duration)](#ndtv_d3#updateGraph) 71 | * [ndtv_d3.resizeGraph()](#ndtv_d3#resizeGraph) 72 | * [ndtv_d3.animateGraph(time, endTime, immediate)](#ndtv_d3#animateGraph) 73 | * [ndtv_d3.moveTooltip()](#ndtv_d3#moveTooltip) 74 | * [ndtv_d3.convertCoords()](#ndtv_d3#convertCoords) 75 | * [ndtv_d3.hideTooltip()](#ndtv_d3#hideTooltip) 76 | * [ndtv_d3.endAnimation(noHalt)](#ndtv_d3#endAnimation) 77 | * [ndtv_d3.stepAnimation(reverse)](#ndtv_d3#stepAnimation) 78 | * [ndtv_d3.playAnimation(reverse)](#ndtv_d3#playAnimation) 79 | 80 | 81 | ##new ndtv_d3() 82 | Initialize a new ndtv-d3 instance 83 | 84 | **Params** 85 | 86 | - `object` - An object of default options overrides 87 | - `string` | `HTMLElement` - A CSS selector string or DOM element reference specifying the target dom element the network should be initialized to 88 | 89 | 90 | ##ndtv_d3.SVGSetup(domTarget) 91 | Initialize the SVG element and related DOM elements and listeners 92 | 93 | **Params** 94 | 95 | - domTarget `D3Selection` - DOM element to insert svg into 96 | 97 | 98 | ##ndtv_d3.updateDimensions() 99 | sets positioning on svg elements based on current DOM container size and sets data scaling factors accordingly 100 | 101 | 102 | ##ndtv_d3.createDataChooser() 103 | creates the optional dataChooser element to be used for slecting among multiple JSON files for debugging 104 | 105 | 106 | ##ndtv_d3.createMenu() 107 | creates the optional menu element to be used for controlling settings and displaying 'about' link 108 | 109 | 110 | ##ndtv_d3.createPlayControls() 111 | creates the optional play controls div using svg icons and defines the attached events 112 | 113 | 114 | ##ndtv_d3.createSliderControl() 115 | creates the time slider controls and defines attached events 116 | 117 | 118 | ##ndtv_d3.loadData(graphData) 119 | load and process the JSON formatted data 120 | 121 | **Params** 122 | 123 | - graphData `url` | `JSON` - either a NDTV-generated JSON object, or a URL path to file containing JSON data 124 | 125 | 126 | ##ndtv_d3.updateSelectedNetwork() 127 | highlights the currently selected network 128 | 129 | 130 | ##ndtv_d3.unSelectNetwork() 131 | unhighlights the currently selected network 132 | 133 | 134 | ##ndtv_d3.updateGraph(duration) 135 | render the graph to reflect the state at currTime, transitioning elements over a given duration 136 | 137 | **Params** 138 | 139 | - duration `milliseconds` - the amount of time the transition animation should take 140 | 141 | 142 | ##ndtv_d3.resizeGraph() 143 | resizes graph and other display elements to fill the target viewport 144 | 145 | 146 | ##ndtv_d3.animateGraph(time, endTime, immediate) 147 | graph animation controller 148 | 149 | **Params** 150 | 151 | - time `integer` - render the graph to the state at this timeslice index 152 | - endTime `integer` - function will recursively call itself until time equals this value 153 | - immediate `boolean` - should the graph update immediately, or animate? 154 | 155 | 156 | ##ndtv_d3.moveTooltip() 157 | redraw the info popover //FIXME - needs renamed 158 | 159 | 160 | ##ndtv_d3.convertCoords() 161 | get center point of edge or node, in DOM pixels 162 | 163 | 164 | ##ndtv_d3.hideTooltip() 165 | hide the tooltip and unset the selected global 166 | 167 | 168 | ##ndtv_d3.endAnimation(noHalt) 169 | stop the current animation cycle 170 | 171 | **Params** 172 | 173 | - noHalt `boolean` - if true, immediate halt all active transitions (otherwise, let animation continue to next time slice) 174 | 175 | 176 | ##ndtv_d3.stepAnimation(reverse) 177 | step the animation by one time slice 178 | 179 | **Params** 180 | 181 | - reverse `boolean` - if true, go to previous time slice, else go forward 182 | 183 | 184 | ##ndtv_d3.playAnimation(reverse) 185 | animate the graph over all time slices, starting at current slice 186 | 187 | **Params** 188 | 189 | - reverse `boolean` - if true, animate slices backwards until beginning of time index, other play until end 190 | 191 | 192 | #const: default_options 193 | Public options to control visualization functionality 194 | 195 | **Type**: `object` 196 | **Default**: `{"animationDuration":800,"enterExitAnimationFactor":0,"labelOffset":"","baseFontSize":"14","nodeSizeFactor":0.01,"dataChooser":false,"dataChooserDir":"data/","playControls":true,"slider":true,"menu":true,"animateOnLoad":false,"margin":"","graphData":null,"debugFrameInfo":false,"durationControl":true}` 197 | 198 | #const: ndtvProperties 199 | Supported NDTV network properties and their default values 200 | 201 | **Type**: `object` 202 | **Default**: `{"graph":"","node":"","edge":""}` 203 | -------------------------------------------------------------------------------- /examples/data/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | AddOutputFilterByType DEFLATE application/json text/javascript 3 | 4 | -------------------------------------------------------------------------------- /examples/data/.msmSim.json.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/.msmSim.json.swp -------------------------------------------------------------------------------- /examples/data/EpiSim.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/EpiSim.mp4 -------------------------------------------------------------------------------- /examples/data/mcfarlandClass.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/mcfarlandClass.mp4 -------------------------------------------------------------------------------- /examples/data/msmSim.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/msmSim.mp4 -------------------------------------------------------------------------------- /examples/data/shortStergm.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/shortStergm.mp4 -------------------------------------------------------------------------------- /examples/data/testDataGenerationScript.R: -------------------------------------------------------------------------------- 1 | # these files are R scripts to generate the example data files 2 | # i'm including them all in one place so we can re-do when we make 3 | # changes to the export script 4 | library(ndtv) 5 | 6 | saveVideo=TRUE # should video versions of the json files be rendered for debugging? (slower) 7 | saveHTML=TRUE 8 | 9 | # delete the various movie files so that they can be overwritten 10 | unlink('inst/javascript/ndtv-d3/examples/data/shortStergm.mp4') 11 | unlink('inst/javascript/ndtv-d3/examples/data/msmSim.mp4') 12 | unlink('inst/javascript/ndtv-d3/examples/data/windsurfers.mp4') 13 | unlink('inst/javascript/ndtv-d3/examples/data/mcfarlandClass.mp4') 14 | unlink('inst/javascript/ndtv-d3/examples/data/EpiSim.mp4') 15 | 16 | # this renders out a version of the 'flo-marriage' short.stergm.sim object 17 | # added some arbitrary vertex attribute transformations to make it useful 18 | # includes a formula rendered using 'show.stats' which should appear as the plot xlable 19 | data(short.stergm.sim) 20 | library(tergm) 21 | compute.animation(short.stergm.sim) 22 | render.d3movie(short.stergm.sim,filename='inst/javascript/ndtv-d3/examples/data/shortStergm.json', 23 | vertex.col=function(slice,onset){rgb(((slice%v%'wealth')/146),0.5,0.5)}, 24 | vertex.cex=function(slice,onset){slice%v%'wealth'/100+onset}, 25 | render.par=list(show.stats="~edges+gwesp(0,fixed=TRUE)"), 26 | output.mode='JSON') 27 | if(saveHTML){ 28 | render.d3movie(short.stergm.sim,filename='inst/javascript/ndtv-d3/examples/data/shortStergm.html', 29 | vertex.col=function(slice,onset){rgb(((slice%v%'wealth')/146),0.5,0.5)}, 30 | vertex.cex=function(slice,onset){slice%v%'wealth'/100+onset}, 31 | render.par=list(show.stats="~edges+gwesp(0,fixed=TRUE)"), 32 | output.mode='HTML') 33 | } 34 | 35 | if(saveVideo){ 36 | saveVideo(render.animation(short.stergm.sim, 37 | vertex.col=function(slice,onset){rgb(((slice%v%'wealth')/146),0.5,0.5)}, 38 | vertex.cex=function(slice,onset){slice%v%'wealth'/100+onset}, 39 | render.par=list(show.stats="~edges+gwesp(0,fixed=TRUE)"),render.cache='none'),video.name='inst/javascript/ndtv-d3/examples/data/shortStergm.mp4') 40 | } 41 | 42 | # msm.sim is a much larger network 43 | # but still has static attributes 44 | # it also has a bunch of deleted edges which will appear as blank entries on mel 45 | data(msm.sim) 46 | msm.sim <- compute.animation(msm.sim,slice.par=list(start=0,end=10,interval=1,aggregate.dur=3, rule='earliest')) 47 | render.d3movie(msm.sim,filename='inst/javascript/ndtv-d3/examples/data/msmSim.json', 48 | vertex.sides=ifelse(msm.sim%v%'race'==1,3,4), # change shape based on race 49 | edge.lwd=function(slice){runif(network.edgecount(slice),0.5,5)},# change edge width randomly 50 | vertex.cex=function(slice){sapply(1:network.size(slice),function(v){0.1+length(get.edgeIDs(slice,v))/4})}, # change sizes in proportion to number of edges 51 | displaylabels=FALSE, # don't show labels 52 | output.mode='JSON' 53 | ) 54 | if (saveHTML){ 55 | render.d3movie(msm.sim,filename='inst/javascript/ndtv-d3/examples/data/msmSim.html', 56 | vertex.sides=ifelse(msm.sim%v%'race'==1,3,4), # change shape based on race 57 | edge.lwd=function(slice){runif(network.edgecount(slice),0.5,5)},# change edge width randomly 58 | vertex.cex=function(slice){sapply(1:network.size(slice),function(v){0.1+length(get.edgeIDs(slice,v))/4})}, # change sizes in proportion to number of edges 59 | displaylabels=FALSE, # don't show labels 60 | output.mode='HTML') 61 | } 62 | if (saveVideo){ 63 | saveVideo(render.animation(msm.sim, 64 | vertex.sides=ifelse(msm.sim%v%'race'==1,3,4), # change shape based on race 65 | edge.lwd=function(slice){runif(network.edgecount(slice),0.5,5)},# change edge width randomly 66 | vertex.cex=function(slice){sapply(1:network.size(slice),function(v){0.1+length(get.edgeIDs(slice,v))/4})}, # change sizes in proportion to number of edges 67 | vertex.col='gray', 68 | displaylabels=FALSE, # don't show labels 69 | render.cache = 'none'), 70 | video.name ='inst/javascript/ndtv-d3/examples/data/msmSim.mp4') 71 | } 72 | 73 | # example including vertex activity 74 | # layout calculated with mdsj 75 | # includes a main plot label 76 | data(windsurfers) 77 | slice.par<-list(start=0,end=24,interval=1,aggregate.dur=7,rule="latest") 78 | windsurfers<-compute.animation(windsurfers,slice.par=slice.par, default.dist=3, animation.mode='MDSJ') 79 | render.d3movie(windsurfers, 80 | vertex.col="group1", 81 | edge.col="darkgray", 82 | displaylabels=TRUE, 83 | label.cex=.6, 84 | label.col="blue", 85 | main="Freeman's windsurfer contact network\nwith 7 day aggregation", 86 | bg='yellow', 87 | filename='inst/javascript/ndtv-d3/examples/data/windsurfers.json', 88 | output.mode='JSON') 89 | if(saveHTML){ 90 | render.d3movie(windsurfers, 91 | vertex.col="group1", 92 | edge.col="darkgray", 93 | displaylabels=TRUE, 94 | label.cex=.6, 95 | label.col="blue", 96 | main="Freeman's windsurfer contact network\nwith 7 day aggregation", 97 | bg='yellow', 98 | filename='inst/javascript/ndtv-d3/examples/data/windsurfers.html', 99 | output.mode='HTML') 100 | } 101 | if(saveVideo){ 102 | saveVideo(render.animation(windsurfers, 103 | vertex.col="group1", 104 | edge.col="darkgray", 105 | displaylabels=TRUE, 106 | label.cex=.6, 107 | label.col="blue", 108 | main="Freeman's windsurfer contact network\nwith 7 day aggregation", 109 | render.cache='none'),video.name='inst/javascript/ndtv-d3/examples/data/windsurfers.mp4') 110 | } 111 | 112 | 113 | # mcfarland example this is in continous time with 0-duration events 114 | data(McFarland_cls33_10_16_96) 115 | slice.par<-list(start=0,end=40,interval=0.5,aggregate.dur=2.5,rule="latest") 116 | compute.animation(cls33_10_16_96,slice.par=slice.par,animation.mode='MDSJ') 117 | render.d3movie(cls33_10_16_96,filename='inst/javascript/ndtv-d3/examples/data/mcfarlandClass.json',output.mode='JSON',vertex.col='type',vertex.sides=ifelse(cls33_10_16_96%v%'gender'==1,4,50)) 118 | 119 | if(saveHTML){ 120 | slice.par<-list(start=0,end=40,interval=0.5,aggregate.dur=2.5,rule="latest") 121 | compute.animation(cls33_10_16_96,slice.par=slice.par,animation.mode='MDSJ') 122 | render.d3movie(cls33_10_16_96,filename='inst/javascript/ndtv-d3/examples/data/mcfarlandClass.html',output.mode='HTML',vertex.col='type',vertex.sides=ifelse(cls33_10_16_96%v%'gender'==1,4,50)) 123 | } 124 | 125 | if(saveVideo){ 126 | saveVideo(render.animation(cls33_10_16_96,,vertex.col='type',vertex.sides=ifelse(cls33_10_16_96%v%'gender'==1,4,50),render.cache='none'), video.name='inst/javascript/ndtv-d3/examples/data/mcfarlandClass.mp4') 127 | } 128 | 129 | # example including edge and vertex labels 130 | render.d3movie(short.stergm.sim, 131 | vertex.tooltip=function(slice){paste('name:',network.vertex.names(slice),"
", 132 | 'randomVal:',runif(network.size(slice)),"
", 133 | 'wealth:',slice%v%'wealth',"
", 134 | 'priorates:',slice%v%'priorates')}, 135 | edge.tooltip="I have a blue label!", 136 | displaylabels=FALSE, 137 | filename='inst/javascript/ndtv-d3/examples/data/tooltipTest.json',output.mode='JSON') 138 | if(saveHTML){ 139 | render.d3movie(short.stergm.sim, 140 | vertex.tooltip=function(slice){paste('name:',network.vertex.names(slice),"
", 141 | 'randomVal:',runif(network.size(slice)),"
", 142 | 'wealth:',slice%v%'wealth',"
", 143 | 'priorates:',slice%v%'priorates')}, 144 | edge.tooltip="I have a blue label!", 145 | displaylabels=FALSE, 146 | filename='inst/javascript/ndtv-d3/examples/data/tooltipTest.html') 147 | } 148 | 149 | # example including html classes 150 | test<-network.initialize(5) 151 | test[,]<-1 152 | activate.vertex.attribute(test,'vertex.css.class','myVertex1',onset=0,terminus=1) 153 | activate.vertex.attribute(test,'vertex.css.class','myVertex2',onset=1,terminus=2) 154 | activate.vertex.attribute(test,'vertex.label.css.class','myLabel1',onset=0,terminus=1) 155 | activate.vertex.attribute(test,'vertex.label.css.class','myLabel2',onset=1,terminus=2) 156 | activate.vertex.attribute(test,'edge.css.class','myEdge1',onset=0,terminus=1) 157 | activate.vertex.attribute(test,'edge.css.class','myEdge2',onset=1,terminus=2) 158 | render.d3movie(test, 159 | vertex.css.class=function(slice){slice%v%'vertex.css.class'}, 160 | edge.css.class=function(slice){slice%e%'edge.css.class'}, 161 | vertex.label.css.class=function(slice){slice%v%'vertex.label.css.class'}, 162 | filename='cssClassTest.html') 163 | if(saveHTML){ 164 | render.d3movie(test, 165 | vertex.css.class=function(slice){slice%v%'vertex.css.class'}, 166 | edge.css.class=function(slice){slice%e%'edge.css.class'}, 167 | vertex.label.css.class=function(slice){slice%v%'vertex.label.css.class'}, 168 | filename='cssClassTest.json',output.mode='JSON') 169 | } 170 | 171 | 172 | 173 | # epimodel example 174 | library(EpiModel) 175 | 176 | ## Estimation 177 | nw <- network.initialize(n = 100, directed = FALSE) 178 | formation <- ~ edges 179 | target.stats <- 50 180 | dissolution <- ~ offset(edges) 181 | coef.diss <- dissolution_coefs(dissolution, duration = 10) 182 | est <- netest(nw, 183 | formation, 184 | dissolution, 185 | target.stats, 186 | coef.diss, 187 | verbose = FALSE) 188 | 189 | ## Epidemic simulation 190 | param <- param.net(inf.prob = 0.8) 191 | init <- init.net(i.num = 5) 192 | control <- control.net(type = "SI", nsteps = 25, nsims = 1, verbose = 193 | FALSE) 194 | sim <- netsim(est, param, init, control) 195 | ## Movies 196 | nw.sim <- get_network(sim) 197 | nw.sim <- color_tea(nw.sim) 198 | 199 | slice.par <- list(start = 1, end = 25, interval = 1, 200 | aggregate.dur = 1, rule = "any") 201 | render.par <- list(tween.frames = 10, show.time = FALSE) 202 | plot.par <- list(mar = c(0, 0, 0, 0)) 203 | 204 | compute.animation(nw.sim, slice.par = slice.par) 205 | 206 | render.d3movie( 207 | nw.sim, 208 | render.par = render.par, 209 | plot.par = plot.par, 210 | vertex.cex = 0.9, 211 | vertex.col = "ndtvcol", 212 | edge.col = "darkgrey", 213 | vertex.border = "lightgrey", 214 | displaylabels = FALSE, 215 | vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','
','status:', slice%v%'testatus')}, 216 | filename='inst/javascript/ndtv-d3/examples/data/EpiSim.json',output.mode='JSON') 217 | 218 | 219 | if (saveHTML){ 220 | render.d3movie( 221 | nw.sim, 222 | render.par = render.par, 223 | plot.par = plot.par, 224 | vertex.cex = 0.9, 225 | vertex.col = "ndtvcol", 226 | edge.col = "darkgrey", 227 | vertex.border = "lightgrey", 228 | displaylabels = FALSE, 229 | vertex.tooltip = function(slice){paste('name:',slice%v%'vertex.names','
','status:', slice%v%'testatus')}, 230 | filename='inst/javascript/ndtv-d3/examples/data/EpiSim.html') 231 | } 232 | 233 | if(saveVideo){ 234 | 235 | saveVideo(render.animation( 236 | nw.sim, 237 | render.par = render.par, 238 | plot.par = plot.par, 239 | vertex.cex = 0.9, 240 | vertex.col = "ndtvcol", 241 | edge.col = "darkgrey", 242 | vertex.border = "lightgrey", 243 | displaylabels = FALSE,render.cache='none'), ani.width = 500, ani.height = 500, video.name='inst/javascript/ndtv-d3/examples/data/EpiSim.mp4') 244 | 245 | } 246 | 247 | -------------------------------------------------------------------------------- /examples/data/windsurfers.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michalgm/ndtv-d3/7f25a1dde07aa2098f36453b602ee3688f997339/examples/data/windsurfers.mp4 -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /networkPlotFunctionImplPriorities.txt: -------------------------------------------------------------------------------- 1 | 2 | TODO list for feature implementation 3 | 4 | below are a list of the various params for the plot.network.default R plotting function. In R, you can display the manpage to give their formal definitions with 5 | 6 | ?plot.network.default 7 | 8 | and print the function code with 9 | plot.network.default 10 | 11 | To plot a network: 12 | 13 | library(ndtv) 14 | data(short.stergm.sim) 15 | plot(short.stergm.sim,vertex.col='blue',vertex.cex=2) 16 | 17 | 18 | prioraties for implementation: 19 | ------- 20 | high priority 21 | ----- 22 | 23 | label = IMPLEMENTED 24 | coord = IGNORE 25 | jitter = IGNORE 26 | usearrows = TRUE, If the graph is directed, draw an arrowhead on the "head" side 27 | displaylabels = !missing(label), 28 | xlab = NULL, IMPLEMENTED 29 | edge.col = 1, 30 | label.col = 1, 31 | vertex.col = 2, 32 | vertex.sides = 50, 33 | vertex.rot = 0, 34 | vertex.lwd=1, 35 | label.pos = 0, the js code will ignore this, but I need to add a properity that gives the actual coordinates 36 | label.border = 1, 37 | vertex.border = 1, 38 | edge.lwd = 0, 39 | edge.label = NULL, 40 | 41 | 42 | bg= background color (this is actually value from somewhere else, but we will need it) 43 | main = A 'main' headline, to be drawn in a bold font as a caption over the image (like xlab is below) 44 | 45 | ------------------- 46 | Lower priority: 47 | --------- 48 | ylab = NULL, Will need 49 | 50 | xlim = NULL, for zooming 51 | ylim = NULL, 52 | 53 | displayisolates = TRUE, if FALSE, hide all the vertices with no edges 54 | interactive = FALSE, # for this we will implement something entirely different 55 | 56 | pad = 0.2, i'm not sure what this does 57 | label.pad = 0.5, 58 | 59 | boxed.labels = FALSE, 60 | label.bg = "white", 61 | arrowhead.cex = 1, 62 | label.cex = 1, 63 | loop.cex = 1, 64 | vertex.cex = 1, 65 | edge.lty = 1, 66 | label.lty = NULL, 67 | vertex.lty = 1, 68 | edge.lwd = 0, 69 | edge.label = NULL, 70 | edge.label.cex = 1, 71 | edge.label.col = 1, 72 | label.lwd = par("lwd"), 73 | edge.len = 0.5, 74 | edge.curve = 0.1, 75 | edge.steps = 50, 76 | loop.steps = 20, 77 | object.scale = 0.01, 78 | uselen = FALSE, 79 | usecurve = FALSE, 80 | suppress.axes = TRUE, 81 | vertices.last = TRUE, new = TRUE, 82 | 83 | ------ 84 | low priority 85 | ------- 86 | family = font family name (for the entire plot) 87 | -------------------------------------------------------------------------------- /src/css/styles.css: -------------------------------------------------------------------------------- 1 | .ndtv-fullscreen { 2 | padding: 0; 3 | margin: 0; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | .ndtv-d3-container { 9 | position: relative; 10 | } 11 | 12 | .main, .xlab { 13 | text-anchor: middle; 14 | } 15 | 16 | .label, .main, .xlab, .tooltip { 17 | font-family: sans-serif; 18 | } 19 | 20 | .dragging { 21 | cursor: move; 22 | } 23 | 24 | .node { 25 | stroke-width: 1px; 26 | fill: red; 27 | stroke: black; 28 | } 29 | 30 | .node, .edge { 31 | cursor: pointer; 32 | /*transition: stroke-width 0.2s ease;*/ 33 | } 34 | 35 | /*.node:hover, .edge:hover { 36 | stroke-width: 5px !important; 37 | }*/ 38 | 39 | .edge { 40 | stroke: black; 41 | } 42 | 43 | .label { 44 | pointer-events: none; 45 | } 46 | 47 | .graph { 48 | position: relative; 49 | overflow: hidden; 50 | } 51 | 52 | .key { 53 | padding: 10px; 54 | text-align: center; 55 | } 56 | 57 | .controls { 58 | margin: 10px 20px; 59 | height: 40px; 60 | box-sizing: border-box; 61 | position: absolute; 62 | bottom: 0px; 63 | left: 0px; 64 | right: 0px; 65 | } 66 | 67 | .play-control-container>div { 68 | width: 25px; 69 | height: 25px; 70 | overflow: hidden; 71 | display: inline-block; 72 | } 73 | 74 | .controls .icon, .ndtv-menu-container .icon { 75 | width: 100%; 76 | height: 100%; 77 | cursor: pointer; 78 | } 79 | 80 | .controls .icon:hover { 81 | fill: blue; 82 | } 83 | 84 | .data_chooser_container { 85 | position: absolute; top: 10px; left: 10px; 86 | } 87 | 88 | .play-control-container { 89 | float: right; 90 | background: #ccc; 91 | border-radius: 5px; 92 | padding: 7px; 93 | padding-bottom: 3px; 94 | box-sizing: border-box; 95 | } 96 | 97 | .ndtv-d3-container { 98 | position: relative; 99 | box-sizing: border-box; 100 | border: 1px solid; 101 | } 102 | 103 | .slider-control-container { 104 | margin-right: 160px; 105 | box-sizing: border-box; 106 | } 107 | 108 | .d3-slider-handle { 109 | min-width: 10px; 110 | } 111 | 112 | .d3-slider-axis { 113 | height: 20px; 114 | } 115 | 116 | .tooltip { 117 | display: none; 118 | position: absolute; 119 | z-index: 1000; 120 | padding: 10px 10px; 121 | background: rgba(255,255,255, 1); 122 | border: 1px solid #666; 123 | } 124 | 125 | .frameInfo { 126 | display: none; 127 | position: absolute; 128 | bottom: 0px; 129 | left: 0px; 130 | padding: 5px; 131 | } 132 | 133 | .durationControl { 134 | width: 150px; 135 | margin-bottom: 20px; 136 | } 137 | 138 | .container .screen { 139 | opacity: 0; 140 | pointer-events: none; 141 | fill: none; 142 | } 143 | 144 | .container .screen.network-selected { 145 | opacity: .6; 146 | } 147 | 148 | .ndtv-menu-container { 149 | position: absolute; 150 | top: 5px; 151 | right: 5px; 152 | } 153 | 154 | .ndtv-menu-icon { 155 | width: 25px; 156 | height: 25px; 157 | float: right; 158 | z-index: 100; 159 | } 160 | 161 | .ndtv-menu-icon.menu-active { 162 | background: #fff; 163 | border: 1px solid #666; 164 | border-bottom: 1px solid #fff; 165 | } 166 | 167 | .ndtv-menu { 168 | background: white; 169 | border: 1px solid #666; 170 | box-shadow: 0px 2px 4px rgba(0,0,0,0.2); 171 | padding: 10px; 172 | margin-top: 25px; 173 | display: none; 174 | } 175 | 176 | .menu-item { 177 | padding: 10px 0px; 178 | border-bottom: 1px solid #CCC; 179 | } 180 | 181 | .menu-item:first-child { 182 | padding-top: 0px; 183 | } 184 | 185 | .menu-item:last-child { 186 | padding-bottom: 0px; 187 | border: none; 188 | } 189 | -------------------------------------------------------------------------------- /src/index.html.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/lib/d3.slider.css: -------------------------------------------------------------------------------- 1 | .d3-slider { 2 | position: relative; 3 | font-family: Verdana,Arial,sans-serif; 4 | font-size: 1.1em; 5 | border: 1px solid #aaaaaa; 6 | z-index: 2; 7 | } 8 | 9 | .d3-slider-horizontal { 10 | height: .8em; 11 | } 12 | 13 | .d3-slider-range { 14 | background:#2980b9; 15 | left:0px; 16 | right:0px; 17 | height: 0.8em; 18 | position: absolute; 19 | } 20 | 21 | .d3-slider-range-vertical { 22 | background:#2980b9; 23 | left:0px; 24 | right:0px; 25 | position: absolute; 26 | top:0; 27 | } 28 | 29 | .d3-slider-vertical { 30 | width: .8em; 31 | height: 100px; 32 | } 33 | 34 | .d3-slider-handle { 35 | position: absolute; 36 | width: 1.2em; 37 | height: 1.2em; 38 | border: 1px solid #d3d3d3; 39 | border-radius: 4px; 40 | background: #eee; 41 | background: linear-gradient(to bottom, #eee 0%, #ddd 100%); 42 | z-index: 3; 43 | cursor: move; 44 | } 45 | 46 | .d3-slider-handle:hover { 47 | border: 1px solid #999999; 48 | } 49 | 50 | .d3-slider-horizontal .d3-slider-handle { 51 | top: -.3em; 52 | } 53 | 54 | .d3-slider-axis { 55 | position: relative; 56 | z-index: 1; 57 | } 58 | 59 | .d3-slider-axis-bottom { 60 | top: .8em; 61 | } 62 | 63 | .d3-slider-axis-right { 64 | left: .8em; 65 | } 66 | 67 | .d3-slider-axis path { 68 | stroke-width: 0; 69 | fill: none; 70 | } 71 | 72 | .d3-slider-axis line { 73 | fill: none; 74 | stroke: #aaa; 75 | shape-rendering: crispEdges; 76 | } 77 | 78 | .d3-slider-axis text { 79 | font-size: 11px; 80 | } 81 | 82 | .d3-slider-vertical .d3-slider-handle { 83 | left: -.25em; 84 | margin-left: 0; 85 | margin-bottom: -.6em; 86 | } -------------------------------------------------------------------------------- /src/lib/d3.slider.js: -------------------------------------------------------------------------------- 1 | /* 2 | D3.js Slider 3 | Inspired by jQuery UI Slider 4 | Copyright (c) 2013, Bjorn Sandvik - http://blog.thematicmapping.org 5 | BSD license: http://opensource.org/licenses/BSD-3-Clause 6 | */ 7 | (function (root, factory) { 8 | if (typeof define === 'function' && define.amd) { 9 | // AMD. Register as an anonymous module. 10 | define(['d3'], factory); 11 | } else if (typeof exports === 'object') { 12 | if (process.browser) { 13 | // Browserify. Import css too using cssify. 14 | require('./d3.slider.css'); 15 | } 16 | // Node. Does not work with strict CommonJS, but 17 | // only CommonJS-like environments that support module.exports, 18 | // like Node. 19 | module.exports = factory(require('d3')); 20 | } else { 21 | // Browser globals (root is window) 22 | root.d3.slider = factory(root.d3); 23 | } 24 | }(this, function (d3) { 25 | return function module() { 26 | "use strict"; 27 | 28 | // Public variables width default settings 29 | var min = 0, 30 | max = 100, 31 | step = 0.01, 32 | animate = true, 33 | orientation = "horizontal", 34 | axis = false, 35 | margin = 50, 36 | value, 37 | active = 1, 38 | scale, 39 | interval=1; 40 | 41 | // Private variables 42 | var axisScale, 43 | dispatch = d3.dispatch("slide", "slideend"), 44 | formatPercent = d3.format(".2%"), 45 | tickFormat = d3.format(".0"), 46 | handle1, 47 | handle2 = null, 48 | sliderLength; 49 | 50 | function slider(selection) { 51 | selection.each(function() { 52 | 53 | // Create scale if not defined by user 54 | if (!scale) { 55 | scale = d3.scale.linear().domain([min, max]); 56 | } 57 | 58 | // Start value 59 | value = value || scale.domain()[0]; 60 | 61 | // DIV container 62 | var div = d3.select(this).classed("d3-slider d3-slider-" + orientation, true); 63 | 64 | var drag = d3.behavior.drag(); 65 | drag.on('dragend', function () { 66 | dispatch.slideend(d3.event, value); 67 | }) 68 | 69 | // Slider handle 70 | //if range slider, create two 71 | var divRange; 72 | 73 | if ( value.length == 2 ) { 74 | handle1 = div.append("a") 75 | .classed("d3-slider-handle", true) 76 | .attr("xlink:href", "#") 77 | .attr('id', "handle-one") 78 | .on("click", stopPropagation) 79 | .call(drag); 80 | handle2 = div.append("a") 81 | .classed("d3-slider-handle", true) 82 | .attr('id', "handle-two") 83 | .attr("xlink:href", "#") 84 | .on("click", stopPropagation) 85 | .call(drag); 86 | } else { 87 | handle1 = div.append("a") 88 | .classed("d3-slider-handle", true) 89 | .attr("xlink:href", "#") 90 | .attr('id', "handle-one") 91 | .on("click", stopPropagation) 92 | .call(drag); 93 | } 94 | // Horizontal slider 95 | if (orientation === "horizontal") { 96 | 97 | div.on("click", onClickHorizontal); 98 | 99 | if ( value.length == 2 ) { 100 | divRange = d3.select(this).append('div').classed("d3-slider-range", true); 101 | 102 | handle1.style("left", formatPercent(scale(value[ 0 ]))); 103 | divRange.style("left", formatPercent(scale(value[ 0 ]))); 104 | drag.on("drag", onDragHorizontal); 105 | 106 | var width = 100 - parseFloat(formatPercent(scale(value[ 1 ]))); 107 | handle2.style("left", formatPercent(scale(value[ 1 ]))); 108 | divRange.style("right", width+"%"); 109 | drag.on("drag", onDragHorizontal); 110 | 111 | } else { 112 | handle1.style("left", formatPercent(scale(value))); 113 | drag.on("drag", onDragHorizontal); 114 | } 115 | 116 | 117 | sliderLength = parseInt(div.style("width"), 10); 118 | handle1.style('width', ((scale(interval+min)*sliderLength))+'px') 119 | 120 | } else { // Vertical 121 | 122 | div.on("click", onClickVertical); 123 | drag.on("drag", onDragVertical); 124 | if ( value.length == 2 ) { 125 | divRange = d3.select(this).append('div').classed("d3-slider-range-vertical", true); 126 | 127 | handle1.style("bottom", formatPercent(scale(value[ 0 ]))); 128 | divRange.style("bottom", formatPercent(scale(value[ 0 ]))); 129 | drag.on("drag", onDragVertical); 130 | 131 | var top = 100 - parseFloat(formatPercent(scale(value[ 1 ]))); 132 | handle2.style("bottom", formatPercent(scale(value[ 1 ]))); 133 | divRange.style("top", top+"%"); 134 | drag.on("drag", onDragVertical); 135 | 136 | } else { 137 | handle1.style("bottom", formatPercent(scale(value))); 138 | drag.on("drag", onDragVertical); 139 | } 140 | 141 | sliderLength = parseInt(div.style("height"), 10); 142 | 143 | } 144 | 145 | if (axis) { 146 | createAxis(div); 147 | } 148 | 149 | 150 | function createAxis(dom) { 151 | 152 | // Create axis if not defined by user 153 | if (typeof axis === "boolean") { 154 | 155 | axis = d3.svg.axis() 156 | .ticks(Math.round(sliderLength / 100)) 157 | .tickFormat(tickFormat) 158 | .orient((orientation === "horizontal") ? "bottom" : "right"); 159 | 160 | } 161 | 162 | // Copy slider scale to move from percentages to pixels 163 | axisScale = scale.copy().range([0, sliderLength]); 164 | axis.scale(axisScale); 165 | 166 | // Create SVG axis container 167 | var svg = dom.append("svg") 168 | .classed("d3-slider-axis d3-slider-axis-" + axis.orient(), true) 169 | .on("click", stopPropagation); 170 | 171 | var g = svg.append("g"); 172 | 173 | // Horizontal axis 174 | if (orientation === "horizontal") { 175 | 176 | svg.style("margin-left", -margin + "px"); 177 | 178 | svg.attr({ 179 | width: sliderLength + margin * 2, 180 | height: margin 181 | }); 182 | 183 | if (axis.orient() === "top") { 184 | svg.style("top", -margin + "px"); 185 | g.attr("transform", "translate(" + margin + "," + margin + ")"); 186 | } else { // bottom 187 | g.attr("transform", "translate(" + margin + ",0)"); 188 | } 189 | 190 | } else { // Vertical 191 | 192 | svg.style("top", -margin + "px"); 193 | 194 | svg.attr({ 195 | width: margin, 196 | height: sliderLength + margin * 2 197 | }); 198 | 199 | if (axis.orient() === "left") { 200 | svg.style("left", -margin + "px"); 201 | g.attr("transform", "translate(" + margin + "," + margin + ")"); 202 | } else { // right 203 | g.attr("transform", "translate(" + 0 + "," + margin + ")"); 204 | } 205 | 206 | } 207 | 208 | g.call(axis); 209 | 210 | } 211 | 212 | function onClickHorizontal() { 213 | if (!value.length) { 214 | var pos = Math.max(0, Math.min(sliderLength, d3.event.offsetX || d3.event.layerX)); 215 | moveHandle(stepValue(scale.invert(pos / sliderLength))); 216 | } 217 | } 218 | 219 | function onClickVertical() { 220 | if (!value.length) { 221 | var pos = sliderLength - Math.max(0, Math.min(sliderLength, d3.event.offsetY || d3.event.layerY)); 222 | moveHandle(stepValue(scale.invert(pos / sliderLength))); 223 | } 224 | } 225 | 226 | function onDragHorizontal() { 227 | if ( d3.event.sourceEvent.target.id === "handle-one") { 228 | active = 1; 229 | } else if ( d3.event.sourceEvent.target.id == "handle-two" ) { 230 | active = 2; 231 | } 232 | var pos = Math.max(0, Math.min(sliderLength, d3.event.x)); 233 | moveHandle(stepValue(scale.invert(pos / sliderLength))); 234 | } 235 | 236 | function onDragVertical() { 237 | if ( d3.event.sourceEvent.target.id === "handle-one") { 238 | active = 1; 239 | } else if ( d3.event.sourceEvent.target.id == "handle-two" ) { 240 | active = 2; 241 | } 242 | var pos = sliderLength - Math.max(0, Math.min(sliderLength, d3.event.y)) 243 | moveHandle(stepValue(scale.invert(pos / sliderLength))); 244 | } 245 | 246 | function stopPropagation() { 247 | d3.event.stopPropagation(); 248 | } 249 | 250 | }); 251 | 252 | } 253 | 254 | // Move slider handle on click/drag 255 | function moveHandle(newValue) { 256 | if (slider.max()-slider.interval() < newValue) { 257 | newValue = slider.max() - slider.interval(); 258 | } 259 | 260 | var currentValue = value.length ? value[active - 1]: value; 261 | 262 | if (currentValue !== newValue) { 263 | var oldPos = formatPercent(scale(stepValue(currentValue))), 264 | newPos = formatPercent(scale(stepValue(newValue))), 265 | position = (orientation === "horizontal") ? "left" : "bottom"; 266 | 267 | if ( value.length === 2) { 268 | value[ active - 1 ] = newValue; 269 | if (d3.event) { 270 | dispatch.slide(d3.event, value ); 271 | }; 272 | } else { 273 | if (d3.event) { 274 | dispatch.slide(d3.event.sourceEvent || d3.event, value = newValue); 275 | }; 276 | } 277 | 278 | if ( value[ 0 ] >= value[ 1 ] ) return; 279 | if ( active === 1 ) { 280 | 281 | if (value.length === 2) { 282 | (position === "left") ? divRange.style("left", newPos) : divRange.style("bottom", newPos); 283 | } 284 | 285 | if (animate) { 286 | handle1.transition() 287 | .styleTween(position, function() { return d3.interpolate(oldPos, newPos); }) 288 | .duration((typeof animate === "number") ? animate : 250); 289 | } else { 290 | handle1.style(position, newPos); 291 | } 292 | } else { 293 | 294 | var width = 100 - parseFloat(newPos); 295 | var top = 100 - parseFloat(newPos); 296 | 297 | (position === "left") ? divRange.style("right", width + "%") : divRange.style("top", top + "%"); 298 | 299 | if (animate) { 300 | handle2.transition() 301 | .styleTween(position, function() { return d3.interpolate(oldPos, newPos); }) 302 | .duration((typeof animate === "number") ? animate : 250); 303 | } else { 304 | handle2.style(position, newPos); 305 | } 306 | } 307 | } 308 | } 309 | 310 | // Calculate nearest step value 311 | function stepValue(val) { 312 | 313 | if (val === scale.domain()[0] || val === scale.domain()[1]) { 314 | return val; 315 | } 316 | 317 | var valModStep = (val - scale.domain()[0]) % step, 318 | alignValue = val - valModStep; 319 | 320 | if (Math.abs(valModStep) * 2 >= step) { 321 | alignValue += (valModStep > 0) ? step : -step; 322 | } 323 | 324 | return alignValue; 325 | 326 | } 327 | 328 | // Getter/setter functions 329 | slider.min = function(_) { 330 | if (!arguments.length) return min; 331 | min = _; 332 | return slider; 333 | }; 334 | 335 | slider.max = function(_) { 336 | if (!arguments.length) return max; 337 | max = _; 338 | return slider; 339 | }; 340 | 341 | slider.step = function(_) { 342 | if (!arguments.length) return step; 343 | step = _; 344 | return slider; 345 | }; 346 | 347 | slider.animate = function(_) { 348 | if (!arguments.length) return animate; 349 | animate = _; 350 | return slider; 351 | }; 352 | 353 | slider.orientation = function(_) { 354 | if (!arguments.length) return orientation; 355 | orientation = _; 356 | return slider; 357 | }; 358 | 359 | slider.axis = function(_) { 360 | if (!arguments.length) return axis; 361 | axis = _; 362 | return slider; 363 | }; 364 | 365 | slider.margin = function(_) { 366 | if (!arguments.length) return margin; 367 | margin = _; 368 | return slider; 369 | }; 370 | 371 | slider.value = function(_) { 372 | if (!arguments.length) return value; 373 | if (value !== undefined) { 374 | moveHandle(stepValue(_)); 375 | }; 376 | value = _; 377 | return slider; 378 | }; 379 | 380 | slider.scale = function(_) { 381 | if (!arguments.length) return scale; 382 | scale = _; 383 | return slider; 384 | }; 385 | 386 | slider.interval = function(_) { 387 | if (!arguments.length) return interval; 388 | interval = _; 389 | return slider; 390 | }; 391 | 392 | 393 | d3.rebind(slider, dispatch, "on"); 394 | 395 | return slider; 396 | 397 | } 398 | })); 399 | -------------------------------------------------------------------------------- /src/lib/d3/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "version": "3.4.12", 4 | "main": "d3.js", 5 | "scripts": [ 6 | "d3.js" 7 | ], 8 | "ignore": [ 9 | ".DS_Store", 10 | ".git", 11 | ".gitignore", 12 | ".npmignore", 13 | ".travis.yml", 14 | "Makefile", 15 | "bin", 16 | "component.json", 17 | "index.js", 18 | "lib", 19 | "node_modules", 20 | "package.json", 21 | "src", 22 | "test" 23 | ], 24 | "homepage": "https://github.com/mbostock/d3", 25 | "_release": "3.4.12", 26 | "_resolution": { 27 | "type": "version", 28 | "tag": "v3.4.12", 29 | "commit": "269c727f88710ea86075b3ff6d396331cf8ede14" 30 | }, 31 | "_source": "git://github.com/mbostock/d3.git", 32 | "_target": "~3.4.12", 33 | "_originalSource": "d3", 34 | "_direct": true 35 | } -------------------------------------------------------------------------------- /src/lib/d3/.spmignore: -------------------------------------------------------------------------------- 1 | bin 2 | lib 3 | src 4 | test 5 | -------------------------------------------------------------------------------- /src/lib/d3/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you’re looking for ways to contribute, please [peruse open issues](https://github.com/mbostock/d3/issues?milestone=&page=1&state=open). The icebox is a good place to find ideas that are not currently in development. If you already have an idea, please check past issues to see whether your idea or a similar one was previously discussed. 4 | 5 | Before submitting a pull request, consider implementing a live example first, say using [bl.ocks.org](http://bl.ocks.org). Real-world use cases go a long way to demonstrating the usefulness of a proposed feature. The more complex a feature’s implementation, the more usefulness it should provide. Share your demo using the #d3js tag on Twitter or by sending it to the d3-js Google group. 6 | 7 | If your proposed feature does not involve changing core functionality, consider submitting it instead as a [D3 plugin](https://github.com/d3/d3-plugins). New core features should be for general use, whereas plugins are suitable for more specialized use cases. When in doubt, it’s easier to start with a plugin before “graduating” to core. 8 | 9 | To contribute new documentation or add examples to the gallery, just [edit the Wiki](https://github.com/mbostock/d3/wiki)! 10 | 11 | ## How to Submit a Pull Request 12 | 13 | 1. Click the “Fork” button to create your personal fork of the D3 repository. 14 | 15 | 2. After cloning your fork of the D3 repository in the terminal, run `npm install` to install D3’s dependencies. 16 | 17 | 3. Create a new branch for your new feature. For example: `git checkout -b my-awesome-feature`. A dedicated branch for your pull request means you can develop multiple features at the same time, and ensures that your pull request is stable even if you later decide to develop an unrelated feature. 18 | 19 | 4. The `d3.js` and `d3.min.js` files are built from source files in the `src` directory. _Do not edit `d3.js` directly._ Instead, edit the source files, and then run `make` to build the generated files. 20 | 21 | 5. Use `make test` to run tests and verify your changes. If you are adding a new feature, you should add new tests! If you are changing existing functionality, make sure the existing tests run, or update them as appropriate. 22 | 23 | 6. Sign D3’s [Individual Contributor License Agreement](https://docs.google.com/forms/d/1CzjdBKtDuA8WeuFJinadx956xLQ4Xriv7-oDvXnZMaI/viewform). Unless you are submitting a trivial patch (such as fixing a typo), this form is needed to verify that you are able to contribute. 24 | 25 | 7. Submit your pull request, and good luck! 26 | -------------------------------------------------------------------------------- /src/lib/d3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2014, Michael Bostock 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Michael Bostock may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /src/lib/d3/README.md: -------------------------------------------------------------------------------- 1 | # Data-Driven Documents 2 | 3 | 4 | 5 | **D3.js** is a JavaScript library for manipulating documents based on data. **D3** helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation. 6 | 7 | Want to learn more? [See the wiki.](https://github.com/mbostock/d3/wiki) 8 | 9 | For examples, [see the gallery](https://github.com/mbostock/d3/wiki/Gallery) and [mbostock’s bl.ocks](http://bl.ocks.org/mbostock). 10 | -------------------------------------------------------------------------------- /src/lib/d3/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "version": "3.4.12", 4 | "main": "d3.js", 5 | "scripts": [ 6 | "d3.js" 7 | ], 8 | "ignore": [ 9 | ".DS_Store", 10 | ".git", 11 | ".gitignore", 12 | ".npmignore", 13 | ".travis.yml", 14 | "Makefile", 15 | "bin", 16 | "component.json", 17 | "index.js", 18 | "lib", 19 | "node_modules", 20 | "package.json", 21 | "src", 22 | "test" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/d3/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mbostock/d3", 3 | "description": "A small, free JavaScript library for manipulating documents based on data.", 4 | "keywords": ["dom", "svg", "visualization", "js", "canvas"], 5 | "homepage": "http://d3js.org/", 6 | "license": "BSD-3-Clause", 7 | "authors": [ 8 | { 9 | "name": "Mike Bostock", 10 | "homepage": "http://bost.ocks.org/mike" 11 | } 12 | ], 13 | "support": { 14 | "issues": "https://github.com/mbostock/d3/issues", 15 | "wiki": "https://github.com/mbostock/d3/wiki", 16 | "API": "https://github.com/mbostock/d3/wiki/API-Reference", 17 | "source": "https://github.com/mbostock/d3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.1.1", 4 | "main": "dist/jquery.js", 5 | "license": "MIT", 6 | "ignore": [ 7 | "**/.*", 8 | "build", 9 | "speed", 10 | "test", 11 | "*.md", 12 | "AUTHORS.txt", 13 | "Gruntfile.js", 14 | "package.json" 15 | ], 16 | "devDependencies": { 17 | "sizzle": "1.10.19", 18 | "requirejs": "2.1.10", 19 | "qunit": "1.14.0", 20 | "sinon": "1.8.1" 21 | }, 22 | "keywords": [ 23 | "jquery", 24 | "javascript", 25 | "library" 26 | ], 27 | "homepage": "https://github.com/jquery/jquery", 28 | "_release": "2.1.1", 29 | "_resolution": { 30 | "type": "version", 31 | "tag": "2.1.1", 32 | "commit": "4dec426aa2a6cbabb1b064319ba7c272d594a688" 33 | }, 34 | "_source": "git://github.com/jquery/jquery.git", 35 | "_target": "~2.1.1", 36 | "_originalSource": "jquery", 37 | "_direct": true 38 | } -------------------------------------------------------------------------------- /src/lib/jquery/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 jQuery Foundation and other contributors 2 | http://jquery.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib/jquery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.1.1", 4 | "main": "dist/jquery.js", 5 | "license": "MIT", 6 | "ignore": [ 7 | "**/.*", 8 | "build", 9 | "speed", 10 | "test", 11 | "*.md", 12 | "AUTHORS.txt", 13 | "Gruntfile.js", 14 | "package.json" 15 | ], 16 | "devDependencies": { 17 | "sizzle": "1.10.19", 18 | "requirejs": "2.1.10", 19 | "qunit": "1.14.0", 20 | "sinon": "1.8.1" 21 | }, 22 | "keywords": [ 23 | "jquery", 24 | "javascript", 25 | "library" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/jquery/src/ajax/jsonp.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "./var/nonce", 4 | "./var/rquery", 5 | "../ajax" 6 | ], function( jQuery, nonce, rquery ) { 7 | 8 | var oldCallbacks = [], 9 | rjsonp = /(=)\?(?=&|$)|\?\?/; 10 | 11 | // Default jsonp settings 12 | jQuery.ajaxSetup({ 13 | jsonp: "callback", 14 | jsonpCallback: function() { 15 | var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); 16 | this[ callback ] = true; 17 | return callback; 18 | } 19 | }); 20 | 21 | // Detect, normalize options and install callbacks for jsonp requests 22 | jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 23 | 24 | var callbackName, overwritten, responseContainer, 25 | jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 26 | "url" : 27 | typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data" 28 | ); 29 | 30 | // Handle iff the expected data type is "jsonp" or we have a parameter to set 31 | if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 32 | 33 | // Get callback name, remembering preexisting value associated with it 34 | callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 35 | s.jsonpCallback() : 36 | s.jsonpCallback; 37 | 38 | // Insert callback into url or form data 39 | if ( jsonProp ) { 40 | s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 41 | } else if ( s.jsonp !== false ) { 42 | s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 43 | } 44 | 45 | // Use data converter to retrieve json after script execution 46 | s.converters["script json"] = function() { 47 | if ( !responseContainer ) { 48 | jQuery.error( callbackName + " was not called" ); 49 | } 50 | return responseContainer[ 0 ]; 51 | }; 52 | 53 | // force json dataType 54 | s.dataTypes[ 0 ] = "json"; 55 | 56 | // Install callback 57 | overwritten = window[ callbackName ]; 58 | window[ callbackName ] = function() { 59 | responseContainer = arguments; 60 | }; 61 | 62 | // Clean-up function (fires after converters) 63 | jqXHR.always(function() { 64 | // Restore preexisting value 65 | window[ callbackName ] = overwritten; 66 | 67 | // Save back as free 68 | if ( s[ callbackName ] ) { 69 | // make sure that re-using the options doesn't screw things around 70 | s.jsonpCallback = originalSettings.jsonpCallback; 71 | 72 | // save the callback name for future use 73 | oldCallbacks.push( callbackName ); 74 | } 75 | 76 | // Call if it was a function and we have a response 77 | if ( responseContainer && jQuery.isFunction( overwritten ) ) { 78 | overwritten( responseContainer[ 0 ] ); 79 | } 80 | 81 | responseContainer = overwritten = undefined; 82 | }); 83 | 84 | // Delegate to script 85 | return "script"; 86 | } 87 | }); 88 | 89 | }); 90 | -------------------------------------------------------------------------------- /src/lib/jquery/src/ajax/load.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../core/parseHTML", 4 | "../ajax", 5 | "../traversing", 6 | "../manipulation", 7 | "../selector", 8 | // Optional event/alias dependency 9 | "../event/alias" 10 | ], function( jQuery ) { 11 | 12 | // Keep a copy of the old load method 13 | var _load = jQuery.fn.load; 14 | 15 | /** 16 | * Load a url into a page 17 | */ 18 | jQuery.fn.load = function( url, params, callback ) { 19 | if ( typeof url !== "string" && _load ) { 20 | return _load.apply( this, arguments ); 21 | } 22 | 23 | var selector, type, response, 24 | self = this, 25 | off = url.indexOf(" "); 26 | 27 | if ( off >= 0 ) { 28 | selector = jQuery.trim( url.slice( off ) ); 29 | url = url.slice( 0, off ); 30 | } 31 | 32 | // If it's a function 33 | if ( jQuery.isFunction( params ) ) { 34 | 35 | // We assume that it's the callback 36 | callback = params; 37 | params = undefined; 38 | 39 | // Otherwise, build a param string 40 | } else if ( params && typeof params === "object" ) { 41 | type = "POST"; 42 | } 43 | 44 | // If we have elements to modify, make the request 45 | if ( self.length > 0 ) { 46 | jQuery.ajax({ 47 | url: url, 48 | 49 | // if "type" variable is undefined, then "GET" method will be used 50 | type: type, 51 | dataType: "html", 52 | data: params 53 | }).done(function( responseText ) { 54 | 55 | // Save response for use in complete callback 56 | response = arguments; 57 | 58 | self.html( selector ? 59 | 60 | // If a selector was specified, locate the right elements in a dummy div 61 | // Exclude scripts to avoid IE 'Permission Denied' errors 62 | jQuery("
").append( jQuery.parseHTML( responseText ) ).find( selector ) : 63 | 64 | // Otherwise use the full result 65 | responseText ); 66 | 67 | }).complete( callback && function( jqXHR, status ) { 68 | self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); 69 | }); 70 | } 71 | 72 | return this; 73 | }; 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /src/lib/jquery/src/ajax/parseJSON.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // Support: Android 2.3 6 | // Workaround failure to string-cast null input 7 | jQuery.parseJSON = function( data ) { 8 | return JSON.parse( data + "" ); 9 | }; 10 | 11 | return jQuery.parseJSON; 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /src/lib/jquery/src/ajax/parseXML.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // Cross-browser xml parsing 6 | jQuery.parseXML = function( data ) { 7 | var xml, tmp; 8 | if ( !data || typeof data !== "string" ) { 9 | return null; 10 | } 11 | 12 | // Support: IE9 13 | try { 14 | tmp = new DOMParser(); 15 | xml = tmp.parseFromString( data, "text/xml" ); 16 | } catch ( e ) { 17 | xml = undefined; 18 | } 19 | 20 | if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { 21 | jQuery.error( "Invalid XML: " + data ); 22 | } 23 | return xml; 24 | }; 25 | 26 | return jQuery.parseXML; 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /src/lib/jquery/src/ajax/script.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../ajax" 4 | ], function( jQuery ) { 5 | 6 | // Install script dataType 7 | jQuery.ajaxSetup({ 8 | accepts: { 9 | script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" 10 | }, 11 | contents: { 12 | script: /(?:java|ecma)script/ 13 | }, 14 | converters: { 15 | "text script": function( text ) { 16 | jQuery.globalEval( text ); 17 | return text; 18 | } 19 | } 20 | }); 21 | 22 | // Handle cache's special case and crossDomain 23 | jQuery.ajaxPrefilter( "script", function( s ) { 24 | if ( s.cache === undefined ) { 25 | s.cache = false; 26 | } 27 | if ( s.crossDomain ) { 28 | s.type = "GET"; 29 | } 30 | }); 31 | 32 | // Bind script tag hack transport 33 | jQuery.ajaxTransport( "script", function( s ) { 34 | // This transport only deals with cross domain requests 35 | if ( s.crossDomain ) { 36 | var script, callback; 37 | return { 38 | send: function( _, complete ) { 39 | script = jQuery("