├── .gitignore ├── icon.png ├── src ├── viz │ ├── methods │ │ ├── style.coffee │ │ ├── dev.coffee │ │ ├── depth.coffee │ │ ├── background.coffee │ │ ├── error.coffee │ │ ├── descs.coffee │ │ ├── timing.coffee │ │ ├── width.coffee │ │ ├── aggs.coffee │ │ ├── height.coffee │ │ ├── history.coffee │ │ ├── order.coffee │ │ ├── type.coffee │ │ ├── total.coffee │ │ ├── temp.coffee │ │ ├── id.coffee │ │ ├── cols.js │ │ ├── focus.coffee │ │ ├── text.coffee │ │ ├── axes.coffee │ │ ├── active.coffee │ │ ├── attrs.coffee │ │ ├── nodes.coffee │ │ ├── container.coffee │ │ ├── zoom.js │ │ ├── icon.coffee │ │ ├── messages.coffee │ │ ├── time.coffee │ │ ├── legend.coffee │ │ ├── timeline.coffee │ │ ├── shape.coffee │ │ ├── links.coffee │ │ ├── labels.coffee │ │ ├── footer.coffee │ │ ├── coords.coffee │ │ ├── size.coffee │ │ ├── font.coffee │ │ ├── data.js │ │ ├── tooltip.coffee │ │ ├── color.coffee │ │ ├── ui.coffee │ │ ├── margin.coffee │ │ ├── format.coffee │ │ ├── draw.js │ │ ├── title.coffee │ │ ├── csv.coffee │ │ └── edges.js │ ├── types │ │ ├── helpers │ │ │ └── graph │ │ │ │ ├── draw.coffee │ │ │ │ ├── stack.coffee │ │ │ │ ├── nest.coffee │ │ │ │ ├── dataTicks.coffee │ │ │ │ └── includes │ │ │ │ └── buffer.coffee │ │ ├── deprecated │ │ │ └── chart.coffee │ │ ├── geo_map.coffee │ │ ├── line.coffee │ │ ├── pie.coffee │ │ ├── scatter.coffee │ │ ├── tree_map.coffee │ │ ├── stacked.coffee │ │ └── bar.coffee │ └── helpers │ │ ├── zoom │ │ ├── propagation.coffee │ │ ├── transform.coffee │ │ ├── direction.coffee │ │ ├── labels.js │ │ ├── mouse.coffee │ │ ├── bounds.js │ │ └── controls.js │ │ ├── shapes │ │ ├── style.coffee │ │ ├── color.coffee │ │ ├── cross.js │ │ ├── diamond.js │ │ ├── triangle_up.js │ │ ├── triangle_down.js │ │ ├── check.js │ │ └── arc.coffee │ │ ├── types │ │ └── run.coffee │ │ ├── focus │ │ └── tooltip.coffee │ │ ├── container.coffee │ │ └── svg │ │ └── update.js ├── form │ ├── methods │ │ ├── depth.coffee │ │ ├── dev.coffee │ │ ├── timing.coffee │ │ ├── color.coffee │ │ ├── hover.coffee │ │ ├── type.coffee │ │ ├── width.coffee │ │ ├── height.coffee │ │ ├── history.coffee │ │ ├── open.coffee │ │ ├── active.coffee │ │ ├── search.coffee │ │ ├── remove.coffee │ │ ├── order.coffee │ │ ├── alt.coffee │ │ ├── keywords.coffee │ │ ├── select.coffee │ │ ├── selectAll.coffee │ │ ├── id.coffee │ │ ├── text.coffee │ │ ├── container.coffee │ │ ├── focus.coffee │ │ ├── font.coffee │ │ ├── title.coffee │ │ ├── ui.coffee │ │ ├── icon.coffee │ │ ├── margin.coffee │ │ ├── format.coffee │ │ ├── data.js │ │ └── draw.js │ └── types │ │ ├── auto.js │ │ ├── button │ │ ├── functions │ │ │ ├── style.js │ │ │ ├── mouseevents.js │ │ │ └── color.js │ │ └── button.js │ │ ├── drop │ │ └── functions │ │ │ ├── selector.js │ │ │ ├── list.js │ │ │ ├── arrow.js │ │ │ ├── active.js │ │ │ ├── height.js │ │ │ ├── element.js │ │ │ ├── window.js │ │ │ ├── button.js │ │ │ ├── items.coffee │ │ │ └── width.js │ │ └── toggle.js ├── libs.coffee ├── textwrap │ ├── methods │ │ ├── dev.coffee │ │ ├── resize.coffee │ │ ├── size.coffee │ │ ├── width.coffee │ │ ├── height.coffee │ │ ├── shape.coffee │ │ ├── text.coffee │ │ ├── container.coffee │ │ ├── format.coffee │ │ └── draw.coffee │ ├── helpers │ │ ├── flow.coffee │ │ ├── getSize.coffee │ │ ├── getText.coffee │ │ ├── getDimensions.coffee │ │ ├── foreign.coffee │ │ └── wrap.coffee │ └── textwrap.coffee ├── client │ ├── ie.js │ ├── rtl.coffee │ ├── touch.coffee │ ├── css.coffee │ ├── prefix.coffee │ ├── pointer.coffee │ └── scrollbar.coffee ├── color │ ├── lighter.coffee │ ├── legible.coffee │ ├── random.coffee │ ├── sort.coffee │ ├── text.coffee │ ├── mix.coffee │ ├── scale.coffee │ └── validate.coffee ├── core │ ├── methods │ │ ├── filter.coffee │ │ ├── font │ │ │ ├── transform.coffee │ │ │ ├── decoration.coffee │ │ │ ├── position.coffee │ │ │ ├── family.coffee │ │ │ └── align.coffee │ │ ├── rendering.coffee │ │ ├── process │ │ │ ├── icon.coffee │ │ │ ├── detect.coffee │ │ │ └── data.coffee │ │ ├── reset.coffee │ │ └── rejected.coffee │ ├── locale │ │ └── locale.coffee │ ├── font │ │ └── tester.coffee │ ├── data │ │ ├── group.coffee │ │ ├── keys.js │ │ ├── color.js │ │ └── load.coffee │ ├── fetch │ │ ├── sort.coffee │ │ ├── color.coffee │ │ └── text.js │ ├── parse │ │ ├── nodes.js │ │ └── edges.js │ └── console │ │ ├── wiki.coffee │ │ └── print.coffee ├── util │ ├── buckets.coffee │ ├── closest.coffee │ ├── d3selection.coffee │ ├── child.coffee │ ├── dataURL.coffee │ ├── copy.coffee │ └── uniques.coffee ├── array │ ├── contains.coffee │ ├── sort.coffee │ ├── update.coffee │ └── comparator.coffee ├── object │ ├── validate.coffee │ └── merge.coffee ├── network │ └── distances.coffee ├── tooltip │ └── remove.coffee ├── string │ ├── title.coffee │ ├── list.coffee │ ├── format.js │ └── strip.js ├── font │ ├── sizes.coffee │ └── validate.coffee ├── data │ ├── mad.coffee │ ├── lof.coffee │ └── bestRegress.coffee ├── geom │ ├── path2poly.coffee │ └── offset.coffee └── number │ └── format.js ├── docs ├── assets │ ├── css │ │ ├── logo.png │ │ └── external-small.png │ ├── favicon.png │ ├── img │ │ └── spinner.gif │ ├── index.html │ ├── js │ │ ├── yui-prettify.js │ │ └── api-filter.js │ └── vendor │ │ └── prettify │ │ └── prettify-min.css └── api.js ├── lib └── font-awesome-4.2.0 │ └── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── gulp ├── error.coffee ├── docs.coffee ├── server.coffee ├── rebuild.coffee └── compile.coffee ├── gulpfile.js ├── bower.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | /tests/ 2 | /node_modules/ 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/icon.png -------------------------------------------------------------------------------- /src/viz/methods/style.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | value: false 3 | -------------------------------------------------------------------------------- /src/form/methods/depth.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Number] 3 | value: 0 4 | -------------------------------------------------------------------------------- /src/libs.coffee: -------------------------------------------------------------------------------- 1 | window.d3 = require "d3" 2 | window.topojson = require "topojson" 3 | -------------------------------------------------------------------------------- /docs/assets/css/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/docs/assets/css/logo.png -------------------------------------------------------------------------------- /docs/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/docs/assets/favicon.png -------------------------------------------------------------------------------- /src/form/methods/dev.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/form/methods/timing.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | mouseevents: 60 3 | ui: 200 4 | -------------------------------------------------------------------------------- /src/viz/methods/dev.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | value: false 4 | -------------------------------------------------------------------------------- /docs/assets/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/docs/assets/img/spinner.gif -------------------------------------------------------------------------------- /src/form/methods/color.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [String] 3 | value: "color" 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/dev.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/resize.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/viz/methods/depth.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Function, Number] 3 | value: 0 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/size.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Array, false] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/width.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/viz/methods/background.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [String] 3 | value: "#ffffff" 4 | -------------------------------------------------------------------------------- /src/viz/methods/error.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean, String] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/form/methods/hover.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number, String] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/height.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/textwrap/methods/shape.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: ["circle", "square"] 3 | value: false 4 | -------------------------------------------------------------------------------- /src/viz/methods/descs.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Function, Object] 3 | value: false 4 | -------------------------------------------------------------------------------- /docs/assets/css/external-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/docs/assets/css/external-small.png -------------------------------------------------------------------------------- /src/client/ie.js: -------------------------------------------------------------------------------- 1 | // Determines if the current browser is Internet Explorer. 2 | module.exports = /*@cc_on!@*/false 3 | -------------------------------------------------------------------------------- /src/form/methods/type.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: (vars) -> d3.keys vars.types 3 | value: "auto" 4 | -------------------------------------------------------------------------------- /src/viz/methods/timing.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | mouseevents: 60 3 | transitions: 600 4 | ui: 200 5 | -------------------------------------------------------------------------------- /src/form/methods/width.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | secondary: false 4 | value: false 5 | -------------------------------------------------------------------------------- /lib/font-awesome-4.2.0/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/lib/font-awesome-4.2.0/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/client/rtl.coffee: -------------------------------------------------------------------------------- 1 | # Detects right-to-left text direction on the page. 2 | module.exports = d3.select("html").attr("dir") is "rtl" 3 | -------------------------------------------------------------------------------- /lib/font-awesome-4.2.0/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/lib/font-awesome-4.2.0/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /lib/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/lib/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/form/methods/height.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | max: 600 4 | secondary: false 5 | value: false 6 | -------------------------------------------------------------------------------- /src/viz/methods/width.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | secondary: false 4 | small: 200 5 | value: false 6 | -------------------------------------------------------------------------------- /lib/font-awesome-4.2.0/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tkh44/d3plus/HEAD/lib/font-awesome-4.2.0/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/viz/methods/aggs.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Object] 3 | deprecated: "nesting_aggs" 4 | objectAccess: false 5 | value: {} 6 | -------------------------------------------------------------------------------- /src/form/methods/history.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | back: -> 3 | @states.pop()() if @states.length 4 | return 5 | chain: [] 6 | states: [] 7 | -------------------------------------------------------------------------------- /src/form/methods/open.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | flipped: 4 | accepted: [Boolean] 5 | value: false 6 | value: false 7 | -------------------------------------------------------------------------------- /src/viz/methods/height.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number] 3 | max: 600 4 | secondary: false 5 | small: 200 6 | value: false 7 | -------------------------------------------------------------------------------- /gulp/error.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | title: "D3plus" 3 | subtitle: "Build Error" 4 | message: "Error: <%= error.message %>" 5 | icon: __dirname + "/../icon.png" 6 | -------------------------------------------------------------------------------- /src/form/methods/active.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Function, Number, String] 5 | value: false 6 | -------------------------------------------------------------------------------- /src/form/methods/search.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: ["auto", Boolean] 3 | process: (value) -> 4 | @enabled = value if typeof value is "Boolean" 5 | value 6 | value: "auto" 7 | -------------------------------------------------------------------------------- /src/form/methods/remove.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: undefined 3 | process: (value, vars) -> 4 | vars.container.value.remove() if @initialized 5 | return 6 | value: undefined 7 | -------------------------------------------------------------------------------- /src/viz/methods/history.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | back: -> 4 | @states.pop()() if @states.length 5 | return 6 | chain: [] 7 | states: [] 8 | value: true 9 | -------------------------------------------------------------------------------- /src/client/touch.coffee: -------------------------------------------------------------------------------- 1 | # Detects is the current browser supports touch events 2 | module.exports = if ("ontouchstart" of window) or window.DocumentTouch and document instanceof DocumentTouch then true else false 3 | -------------------------------------------------------------------------------- /src/color/lighter.coffee: -------------------------------------------------------------------------------- 1 | # Lightens a color 2 | module.exports = (color, increment) -> 3 | increment = 0.5 if increment is undefined 4 | c = d3.hsl(color) 5 | c.l += (1 - c.l) * increment 6 | c.toString() 7 | -------------------------------------------------------------------------------- /src/core/methods/filter.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (g) -> 2 | 3 | g = false unless g 4 | 5 | accepted: [false, Array, Function, Number, Object, String] 6 | global: g 7 | process: Array 8 | value: [] 9 | -------------------------------------------------------------------------------- /src/core/methods/font/transform.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (transform) -> 2 | 3 | transform = "none" unless transform 4 | 5 | accepted: ["capitalize", "lowercase", "none", "uppercase"] 6 | value: transform 7 | -------------------------------------------------------------------------------- /src/form/methods/order.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Function, String] 3 | sort: 4 | accepted: ["asc", "desc"] 5 | deprecates: ["sort"] 6 | value: "asc" 7 | value: false 8 | -------------------------------------------------------------------------------- /src/viz/methods/order.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Function, String] 3 | deprecates: ["sort"] 4 | sort: 5 | accepted: ["asc", "desc"] 6 | value: "asc" 7 | value: false 8 | -------------------------------------------------------------------------------- /src/core/methods/font/decoration.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (decoration) -> 2 | 3 | decoration = "none" unless decoration 4 | 5 | accepted: ["line-through", "none", "overline", "underline"] 6 | value: decoration 7 | -------------------------------------------------------------------------------- /src/core/locale/locale.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | en_US: require "./languages/en_US.coffee" 3 | mk_MK: require "./languages/mk_MK.js" 4 | pt_BR: require "./languages/pt_BR.js" 5 | zh_CN: require "./languages/zh_CN.js" 6 | -------------------------------------------------------------------------------- /src/util/buckets.coffee: -------------------------------------------------------------------------------- 1 | # Expands a min/max into a specified number of buckets 2 | module.exports = (arr, n) -> 3 | 4 | buckets = [] 5 | step = 1 / (n - 1) * (arr[1] - arr[0]) 6 | 7 | d3.range arr[0], arr[1]+step, step 8 | -------------------------------------------------------------------------------- /src/viz/methods/type.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: (vars) -> d3.keys vars.types 3 | mode: 4 | accepted: (vars) -> vars.types[vars.type.value].modes or [false] 5 | value: false 6 | value: "tree_map" 7 | -------------------------------------------------------------------------------- /src/color/legible.coffee: -------------------------------------------------------------------------------- 1 | # Darkens a color if it's too light to appear on white 2 | module.exports = (color) -> 3 | hsl = d3.hsl color 4 | if hsl.l > .45 5 | hsl.s = 0.8 if hsl.s > .8 6 | hsl.l = 0.45 7 | hsl.toString() 8 | -------------------------------------------------------------------------------- /src/form/methods/alt.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | module.exports = 3 | accepted: [false, Array, Function, Object, String] 4 | mute: filter true 5 | solo: filter true 6 | value: "alt" 7 | -------------------------------------------------------------------------------- /src/color/random.coffee: -------------------------------------------------------------------------------- 1 | defaultScale = require("./scale.coffee") 2 | 3 | # Returns a random color 4 | module.exports = (x, scale) -> 5 | rand_int = x or Math.floor(Math.random() * 20) 6 | scale = scale or defaultScale 7 | scale rand_int 8 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | require('coffee-script/register'); 3 | require("require-dir")("./gulp"); 4 | 5 | gulp.task("default", ["server", "rebuild"]); 6 | 7 | gulp.task("release", ["compile", "docs"], function() { process.exit(); }); 8 | -------------------------------------------------------------------------------- /src/form/methods/keywords.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Function, Object, String] 5 | mute: filter(true) 6 | solo: filter(true) 7 | value: "keywords" 8 | -------------------------------------------------------------------------------- /src/textwrap/helpers/flow.coffee: -------------------------------------------------------------------------------- 1 | foreign = require "./foreign.coffee" 2 | tspan = require "./tspan.js" 3 | 4 | # Flows the text into the container 5 | module.exports = (vars) -> 6 | if vars.text.html.value then foreign vars else tspan vars 7 | return 8 | -------------------------------------------------------------------------------- /src/util/closest.coffee: -------------------------------------------------------------------------------- 1 | # Finds closest numeric value in array 2 | module.exports = (arr, value) -> 3 | 4 | closest = arr[0] 5 | 6 | arr.forEach (p) -> 7 | closest = p if Math.abs(value - p) < Math.abs(value - closest) 8 | 9 | closest 10 | -------------------------------------------------------------------------------- /src/form/methods/select.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [String] 3 | chainable: false 4 | process: (value, vars) -> 5 | container = vars.container.value 6 | if container and value then container.select(value) else value 7 | value: undefined 8 | -------------------------------------------------------------------------------- /src/color/sort.coffee: -------------------------------------------------------------------------------- 1 | # Sorts 2 colors based on hue. 2 | module.exports = (a, b) -> 3 | aHSL = d3.hsl a 4 | bHSL = d3.hsl b 5 | a = if aHSL.s is 0 then 361 else aHSL.h 6 | b = if bHSL.s is 0 then 361 else bHSL.h 7 | if a is b then aHSL.l - bHSL.l else a - b 8 | -------------------------------------------------------------------------------- /src/form/methods/selectAll.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [String] 3 | chainable: false 4 | process: (value, vars) -> 5 | container = vars.container.value 6 | if container and value then container.selectAll(value) else value 7 | value: undefined 8 | -------------------------------------------------------------------------------- /src/array/contains.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (arr, value) -> 2 | if arr instanceof Array 3 | constructor = if value is undefined then value else value.constructor 4 | arr.indexOf(value) >= 0 or (value isnt undefined and arr.indexOf(constructor) >= 0) 5 | else false 6 | -------------------------------------------------------------------------------- /src/core/methods/rendering.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (rendering) -> 2 | 3 | accepted = ["auto", "optimizeSpeed", "crispEdges", "geometricPrecision"] 4 | rendering = "crispEdges" unless accepted.indexOf(rendering) >= 0 5 | 6 | accepted: accepted 7 | value: rendering 8 | -------------------------------------------------------------------------------- /src/util/d3selection.coffee: -------------------------------------------------------------------------------- 1 | ie = require "../client/ie.js" 2 | 3 | # Cross-browser detect for D3 element 4 | module.exports = (elem) -> 5 | if ie then typeof elem is "object" and elem instanceof Array and "size" of elem and "select" of elem else elem instanceof d3.selection 6 | -------------------------------------------------------------------------------- /src/viz/methods/total.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Function, Object, String] 5 | deprecates: ["total_var"] 6 | mute: filter(true) 7 | solo: filter(true) 8 | value: false 9 | -------------------------------------------------------------------------------- /src/viz/methods/temp.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Function, Object, String] 5 | deprecates: ["else_var", "else"] 6 | mute: filter(true) 7 | solo: filter(true) 8 | value: false 9 | -------------------------------------------------------------------------------- /docs/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redirector 5 | 6 | 7 | 8 | Click here to redirect 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/form/methods/id.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [Array, String] 5 | dataFilter: true 6 | mute: filter(true) 7 | nesting: ["value"] 8 | solo: filter(true) 9 | value: "value" 10 | -------------------------------------------------------------------------------- /src/core/methods/process/icon.coffee: -------------------------------------------------------------------------------- 1 | stylesheet = require "../../../client/css.coffee" 2 | 3 | module.exports = (value, vars, method) -> 4 | if value is false or value.indexOf("fa-") < 0 or (value.indexOf("fa-") is 0 and stylesheet("font-awesome")) 5 | value 6 | else 7 | method.fallback 8 | -------------------------------------------------------------------------------- /src/color/text.coffee: -------------------------------------------------------------------------------- 1 | # Returns appropriate text color based off of a given color 2 | module.exports = (color) -> 3 | rgbColor = d3.rgb(color) 4 | r = rgbColor.r 5 | g = rgbColor.g 6 | b = rgbColor.b 7 | yiq = (r * 299 + g * 587 + b * 114) / 1000 8 | if yiq >= 128 then "#444444" else "#f7f7f7" 9 | -------------------------------------------------------------------------------- /src/viz/methods/id.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [Array, String] 5 | dataFilter: true 6 | deprecates: ["id_var", "nesting"] 7 | mute: filter(true) 8 | nesting: ["id"] 9 | solo: filter(true) 10 | value: "id" 11 | -------------------------------------------------------------------------------- /src/viz/methods/cols.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "accepted": [Array, Function, String], 3 | "index": { 4 | "accepted": [Boolean], 5 | "value": true 6 | }, 7 | "process": function(value, vars) { 8 | if (typeof value === "string") value = [value] 9 | return value 10 | }, 11 | "value": false 12 | } 13 | -------------------------------------------------------------------------------- /src/viz/methods/focus.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Array, Function, Number, String] 3 | deprecates: "highlight" 4 | process: (value) -> if value is false then [] else if value instanceof Array then value else [value] 5 | tooltip: 6 | accepted: [Boolean] 7 | value: true 8 | value: [] 9 | -------------------------------------------------------------------------------- /src/viz/methods/text.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [Array, Boolean, Function, Object, String] 5 | deprecates: ["name_array", "text_var"] 6 | nesting: true 7 | mute: filter(true) 8 | solo: filter(true) 9 | value: false 10 | -------------------------------------------------------------------------------- /src/core/methods/font/position.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (position) -> 2 | 3 | position = "bottom" unless position 4 | 5 | accepted: ["top", "middle", "bottom"] 6 | mapping: 7 | top: "0ex" 8 | middle: "0.5ex" 9 | bottom: "1ex" 10 | process: (value) -> 11 | @text = value 12 | @mapping[value] 13 | value: position 14 | -------------------------------------------------------------------------------- /src/form/methods/text.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, String] 5 | nesting: true 6 | mute: filter(true) 7 | solo: filter(true) 8 | secondary: 9 | accepted: [false, String] 10 | nesting: true 11 | value: false 12 | value: false 13 | -------------------------------------------------------------------------------- /src/viz/methods/axes.coffee: -------------------------------------------------------------------------------- 1 | rendering = require "../../core/methods/rendering.coffee" 2 | 3 | module.exports = 4 | background: 5 | color: "#fafafa" 6 | rendering: rendering() 7 | stroke: 8 | color: "#ccc" 9 | width: 1 10 | mirror: 11 | accepted: [Boolean] 12 | deprecates: ["mirror_axis", "mirror_axes"] 13 | value: false 14 | -------------------------------------------------------------------------------- /src/core/methods/font/family.coffee: -------------------------------------------------------------------------------- 1 | validate = require "../../../font/validate.coffee" 2 | helvetica = ["Helvetica Neue", "HelveticaNeue", "Helvetica", "Arial", "sans-serif"] 3 | 4 | # Constructs font family property using the validate function 5 | module.exports = (family) -> 6 | 7 | family = helvetica unless family 8 | 9 | process: validate 10 | value: family 11 | -------------------------------------------------------------------------------- /src/viz/methods/active.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Function, Object, String] 5 | deprecates: "active_var" 6 | mute: filter true 7 | solo: filter true 8 | spotlight: 9 | accepted: [Boolean] 10 | deprecates: "spotlight" 11 | value: false 12 | value: false 13 | -------------------------------------------------------------------------------- /src/viz/methods/attrs.coffee: -------------------------------------------------------------------------------- 1 | process = require "../../core/methods/process/data.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Object, String] 5 | delimiter: 6 | accepted: String 7 | value: "|" 8 | filetype: 9 | accepted: [false, "json", "xml", "html", "csv", "dsv", "tsv", "txt"] 10 | value: false 11 | process: process 12 | value: false 13 | -------------------------------------------------------------------------------- /src/textwrap/methods/text.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Array, Number, String] 3 | html: 4 | accepted: [Boolean] 5 | value: false 6 | init: (vars) -> 7 | s = @split.value 8 | @break = new RegExp "[^\\s\\" + s.join("\\") + "]+\\" + s.join("?\\") + "?", "g" 9 | false 10 | split: 11 | accepted: [Array] 12 | value: ["-", "/", ";", ":", "&"] 13 | -------------------------------------------------------------------------------- /src/viz/methods/nodes.coffee: -------------------------------------------------------------------------------- 1 | process = require "../../core/methods/process/data.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Function, String] 5 | delimiter: 6 | accepted: [String] 7 | value: "|" 8 | filetype: 9 | accepted: [false, "json", "xml", "html", "csv", "dsv", "tsv", "txt"] 10 | value: false 11 | overlap: 0.6 12 | process: process 13 | value: false 14 | -------------------------------------------------------------------------------- /src/core/methods/font/align.coffee: -------------------------------------------------------------------------------- 1 | rtl = require "../../../client/rtl.coffee" 2 | 3 | module.exports = (align) -> 4 | 5 | align = "left" unless align 6 | 7 | accepted: ["left", "center", "right"] 8 | process: (value) -> 9 | if rtl 10 | if value is "left" 11 | "right" 12 | else 13 | if value is "right" 14 | "left" 15 | else value 16 | else value 17 | value: align 18 | -------------------------------------------------------------------------------- /src/core/methods/reset.coffee: -------------------------------------------------------------------------------- 1 | validObject = require("../../object/validate.coffee") 2 | 3 | # Resets certain keys in global variables. 4 | reset = (obj, method) -> 5 | obj.changed = false if obj.changed 6 | if method is "draw" 7 | obj.frozen = false 8 | obj.update = true 9 | obj.first = false 10 | for o of obj 11 | reset obj[o], o if validObject(obj[o]) 12 | return 13 | 14 | module.exports = reset 15 | -------------------------------------------------------------------------------- /src/viz/types/helpers/graph/draw.coffee: -------------------------------------------------------------------------------- 1 | axes = require "./includes/axes.coffee" 2 | draw = require "./includes/svg.coffee" 3 | mouse = require "./includes/mouse.coffee" 4 | plot = require "./includes/plot.coffee" 5 | 6 | module.exports = (vars, opts) -> 7 | opts = {} if opts is undefined 8 | axes vars, opts 9 | plot vars, opts 10 | draw vars, opts 11 | vars.mouse = if opts.mouse is true then mouse else false 12 | return 13 | -------------------------------------------------------------------------------- /src/viz/methods/container.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require("../../util/d3selection.coffee") 2 | 3 | module.exports = 4 | accepted: [false, Array, Object, String] 5 | id: "default" 6 | process: (value) -> 7 | if value is false 8 | false 9 | else if d3selection(value) 10 | value 11 | else if value instanceof Array 12 | d3.select value[0][0] 13 | else 14 | d3.select value 15 | value: false 16 | -------------------------------------------------------------------------------- /src/color/mix.coffee: -------------------------------------------------------------------------------- 1 | # Mixes 2 colors with optional opacities 2 | module.exports = (c1, c2, o1, o2) -> 3 | o1 = 1 unless o1 4 | o2 = 1 unless o2 5 | c1 = d3.rgb(c1) 6 | c2 = d3.rgb(c2) 7 | r = (o1 * c1.r + o2 * c2.r - o1 * o2 * c2.r) / (o1 + o2 - o1 * o2) 8 | g = (o1 * c1.g + o2 * c2.g - o1 * o2 * c2.g) / (o1 + o2 - o1 * o2) 9 | b = (o1 * c1.b + o2 * c2.b - o1 * o2 * c2.b) / (o1 + o2 - o1 * o2) 10 | d3.rgb(r, g, b).toString() 11 | -------------------------------------------------------------------------------- /src/color/scale.coffee: -------------------------------------------------------------------------------- 1 | # Default D3plus color scale 2 | module.exports = d3.scale.ordinal().range([ 3 | "#b22200", 4 | "#EACE3F", 5 | "#282F6B", 6 | 7 | "#B35C1E", 8 | "#224F20", 9 | "#5F487C", 10 | 11 | "#759143", 12 | "#419391", 13 | "#993F88", 14 | 15 | "#e89c89", 16 | "#ffee8d", 17 | "#afd5e8", 18 | 19 | "#f7ba77", 20 | "#a5c697", 21 | "#c5b5e5", 22 | 23 | "#d1d392", 24 | "#bbefd0", 25 | "#e099cf" 26 | ]) 27 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/propagation.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (vars, event) -> 2 | 3 | zoom = vars.zoom 4 | event = d3.event unless event 5 | 6 | zoomed = zoom.scale > zoom.behavior.scaleExtent()[0] 7 | enabled = vars.types[vars.type.value].zoom and zoom.value and zoom.scroll.value 8 | zoomable = event.touches and event.touches.length > 1 and enabled 9 | 10 | event.stopPropagation() if not zoomable and not zoomed 11 | return 12 | -------------------------------------------------------------------------------- /src/textwrap/methods/container.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require("../../util/d3selection.coffee") 2 | 3 | module.exports = 4 | accepted: [false, Array, Object, String] 5 | element: false 6 | id: "default" 7 | process: (value) -> 8 | if value is false 9 | false 10 | else if d3selection(value) 11 | value 12 | else if value instanceof Array 13 | d3.select value[0][0] 14 | else 15 | d3.select value 16 | value: false 17 | -------------------------------------------------------------------------------- /gulp/docs.coffee: -------------------------------------------------------------------------------- 1 | gulp = require "gulp" 2 | project = require "../package.json" 3 | rimraf = require "gulp-rimraf" 4 | yuidoc = require "gulp-yuidoc" 5 | 6 | gulp.task "docs", -> 7 | 8 | gulp.src("./docs/files/*.*", {read: false}).pipe rimraf() 9 | 10 | scan "js" 11 | scan "coffee" 12 | 13 | scan = (type) -> 14 | gulp.src("./src/**/*."+type).pipe(yuidoc( 15 | project: project 16 | syntaxtype: type 17 | )) 18 | .pipe gulp.dest("./docs") 19 | -------------------------------------------------------------------------------- /src/textwrap/helpers/getSize.coffee: -------------------------------------------------------------------------------- 1 | # Fetches text if not specified, and formats text to array. 2 | module.exports = (vars) -> 3 | 4 | size = vars.container.value.attr "font-size" or vars.container.value.style "font-size" 5 | vars.container.fontSize = size 6 | 7 | unless vars.size.value 8 | size = parseFloat(size, 10) 9 | if vars.resize.value 10 | vars.self.size [size, size * 2] 11 | else 12 | vars.self.size [size / 2, size] 13 | 14 | return 15 | -------------------------------------------------------------------------------- /src/util/child.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require "./d3selection.coffee" 2 | 3 | # Checks to see if element is inside of another element 4 | module.exports = (parent, child) -> 5 | 6 | return false if not parent or not child 7 | 8 | parent = parent.node() if d3selection(parent) 9 | child = child.node() if d3selection(parent) 10 | node = child.parentNode 11 | 12 | while node isnt null 13 | return true if node is parent 14 | node = node.parentNode 15 | 16 | false 17 | -------------------------------------------------------------------------------- /src/client/css.coffee: -------------------------------------------------------------------------------- 1 | # Checks to see if a stylesheet is loaded 2 | sheet = (name) -> 3 | 4 | tested = sheet.tested 5 | return tested[name] if name of tested 6 | i = 0 7 | returnBoolean = false 8 | 9 | while i < document.styleSheets.length 10 | css = document.styleSheets[i] 11 | if css.href and css.href.indexOf(name) >= 0 12 | returnBoolean = true 13 | break 14 | i++ 15 | returnBoolean 16 | 17 | sheet.tested = {} 18 | 19 | module.exports = sheet 20 | -------------------------------------------------------------------------------- /src/form/methods/container.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require("../../util/d3selection.coffee") 2 | 3 | module.exports = 4 | accepted: [false, Array, Object, String] 5 | element: false 6 | id: "default" 7 | process: (value) -> 8 | if value is false 9 | d3.select("body") 10 | else if d3selection(value) 11 | value 12 | else if value instanceof Array 13 | d3.select value[0][0] 14 | else 15 | d3.select value 16 | value: d3.select("body") 17 | -------------------------------------------------------------------------------- /src/object/validate.coffee: -------------------------------------------------------------------------------- 1 | ###* 2 | # This function returns true if the variable passed is a literal javascript keyed Object. It's a small, simple function, but it catches some edge-cases that can throw off your code (such as Arrays and `null`). 3 | # @method d3plus.object.validate 4 | # @for d3plus.object 5 | # @param obj {Object} The object to validate. 6 | # @return {Boolean} 7 | ### 8 | module.exports = (obj) -> 9 | obj isnt null and typeof obj is "object" and (obj not instanceof Array) 10 | -------------------------------------------------------------------------------- /src/viz/methods/zoom.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "accepted" : [ Boolean ], 3 | "behavior" : d3.behavior.zoom().scaleExtent([ 1 , 1 ]), 4 | "click" : { 5 | "accepted" : [ Boolean ], 6 | "value" : true 7 | }, 8 | "pan" : { 9 | "accepted" : [ Boolean ], 10 | "value" : true 11 | }, 12 | "scroll" : { 13 | "accepted" : [ Boolean ], 14 | "deprecates" : "scroll_zoom", 15 | "value" : true 16 | }, 17 | "value" : true 18 | } 19 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/transform.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (vars, timing) -> 2 | 3 | timing = vars.timing.transitions if typeof timing isnt "number" 4 | translate = vars.zoom.translate 5 | scale = vars.zoom.scale 6 | 7 | if timing 8 | vars.g.viz.transition().duration(timing) 9 | .attr "transform", "translate(" + translate + ")scale(" + scale + ")" 10 | else 11 | vars.g.viz 12 | .attr "transform", "translate(" + translate + ")scale(" + scale + ")" 13 | 14 | return 15 | -------------------------------------------------------------------------------- /src/array/sort.coffee: -------------------------------------------------------------------------------- 1 | comparator = require "./comparator.coffee" 2 | fetchSort = require "../core/fetch/sort.coffee" 3 | 4 | # Sorts an array of objects 5 | module.exports = (arr, keys, sort, colors, vars, depth) -> 6 | 7 | if not arr or arr.length <= 1 or not keys 8 | arr or [] 9 | else 10 | 11 | if vars 12 | for d in arr 13 | d.d3plus.sortKeys = fetchSort(vars, d, keys, colors, depth) if d.d3plus 14 | 15 | arr.sort (a, b) -> comparator a, b, keys, sort, colors, vars, depth 16 | -------------------------------------------------------------------------------- /src/viz/methods/icon.coffee: -------------------------------------------------------------------------------- 1 | process = require "../../core/methods/process/icon.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Function, Object, String] 5 | back: 6 | accepted: [false, String] 7 | fallback: "❮" 8 | opacity: 1 9 | process: process 10 | rotate: 0 11 | value: "fa-angle-left" 12 | deprecates: "icon_var" 13 | style: 14 | accepted: [Object, String] 15 | deprecates: "icon_style" 16 | value: "default" 17 | value: "icon" 18 | -------------------------------------------------------------------------------- /src/viz/methods/messages.coffee: -------------------------------------------------------------------------------- 1 | decoration = require "../../core/methods/font/decoration.coffee" 2 | family = require "../../core/methods/font/family.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | module.exports = 6 | accepted: [Boolean, String] 7 | font: 8 | color: "#444" 9 | decoration: decoration() 10 | family: family() 11 | size: 16 12 | transform: transform() 13 | weight: 200 14 | padding: 5 15 | value: true 16 | -------------------------------------------------------------------------------- /src/viz/methods/time.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [Array, Boolean, Function, Object, String] 5 | dataFilter: true 6 | deprecates: ["year", "year_var"] 7 | fixed: 8 | accepted: [Boolean] 9 | deprecates: ["static_axis", "static_axes"] 10 | value: true 11 | format: 12 | accepted: [false, String] 13 | value: false 14 | mute: filter(false) 15 | solo: filter(false) 16 | value: false 17 | -------------------------------------------------------------------------------- /src/core/methods/process/detect.coffee: -------------------------------------------------------------------------------- 1 | copy = require("../../../util/copy.coffee") 2 | update = require("../../../array/update.coffee") 3 | 4 | # Process object's value 5 | module.exports = (vars, object, value) -> 6 | 7 | if object.process is Array 8 | update copy(object.value), value 9 | else if typeof object.process is "object" and typeof value is "string" 10 | object.process[value] 11 | else if typeof object.process is "function" 12 | object.process value, vars, object 13 | else 14 | value 15 | -------------------------------------------------------------------------------- /src/client/prefix.coffee: -------------------------------------------------------------------------------- 1 | # Calculates the correct CSS vendor prefix based on the current browser. 2 | prefix = -> 3 | 4 | if "-webkit-transform" of document.body.style 5 | val = "-webkit-" 6 | else if "-moz-transform" of document.body.style 7 | val = "-moz-" 8 | else if "-ms-transform" of document.body.style 9 | val = "-ms-" 10 | else if "-o-transform" of document.body.style 11 | val = "-o-" 12 | else 13 | val = "" 14 | 15 | prefix = -> val 16 | 17 | val 18 | 19 | module.exports = prefix 20 | -------------------------------------------------------------------------------- /src/util/dataURL.coffee: -------------------------------------------------------------------------------- 1 | # Creates a Base-64 Data URL from and Image URL 2 | module.exports = (url, callback) -> 3 | 4 | img = new Image() 5 | img.src = url 6 | img.crossOrigin = "Anonymous" 7 | img.onload = -> 8 | canvas = document.createElement("canvas") 9 | canvas.width = @width 10 | canvas.height = @height 11 | context = canvas.getContext("2d") 12 | context.drawImage this, 0, 0 13 | callback.call this, canvas.toDataURL("image/png") 14 | canvas = null 15 | return 16 | 17 | return 18 | -------------------------------------------------------------------------------- /src/viz/methods/legend.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | 3 | module.exports = 4 | accepted: [Boolean] 5 | align: "middle" 6 | font: 7 | align: "middle" 8 | color: "#444444" 9 | family: family() 10 | size: 10 11 | weight: 200 12 | gradient: 13 | height: 10 14 | order: 15 | accepted: ["color", "id", "size", "text"] 16 | sort: 17 | accepted: ["asc", "desc"] 18 | value: "asc" 19 | value: "color" 20 | size: [8,30] 21 | value: true 22 | -------------------------------------------------------------------------------- /src/util/copy.coffee: -------------------------------------------------------------------------------- 1 | objectMerge = require "../object/merge.coffee" 2 | objectValidate = require "../object/validate.coffee" 3 | 4 | # Clones a variable 5 | copy = (variable) -> 6 | 7 | # Object Logic 8 | if objectValidate(variable) 9 | objectMerge variable 10 | 11 | # Array Logic 12 | else if variable instanceof Array 13 | ret = [] 14 | variable.forEach (o) -> 15 | ret.push copy(o) 16 | ret 17 | 18 | # Everything else just returns itself 19 | else 20 | variable 21 | 22 | module.exports = copy 23 | -------------------------------------------------------------------------------- /src/viz/methods/timeline.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Boolean] 3 | align: "middle" 4 | hover: 5 | accepted: ["all-scroll", "col-resize", "crosshair", "default", "grab", "grabbing", "move", "pointer"] 6 | value: "pointer" 7 | handles: 8 | accepted: [Boolean] 9 | color: "#e5e5e5" 10 | hover: "#cccccc" 11 | opacity: 1 12 | size: 2 13 | stroke: "#818181" 14 | value: true 15 | height: 16 | accepted: [Number] 17 | value: 23 18 | tick: "#818181" 19 | value: true 20 | -------------------------------------------------------------------------------- /src/color/validate.coffee: -------------------------------------------------------------------------------- 1 | # Tests if a string is a valid color 2 | module.exports = (color) -> 3 | color = color + "" 4 | color = color.replace(RegExp(" ", "g"), "") 5 | color = color.split("(")[1].split(")")[0].split(",").slice(0, 3).join(",") if color.indexOf("rgb") is 0 6 | color = color.split(",")[2].split(")")[0] if color.indexOf("hsl") is 0 7 | testColor = d3.rgb(color).toString() 8 | blackColors = [ "black", "#000", "#000000", "0%", "0,0,0" ] 9 | userBlack = blackColors.indexOf(color) >= 0 10 | testColor isnt "#000000" or userBlack 11 | -------------------------------------------------------------------------------- /src/viz/methods/shape.coffee: -------------------------------------------------------------------------------- 1 | rendering = require "../../core/methods/rendering.coffee" 2 | 3 | module.exports = 4 | accepted: (vars) -> 5 | list = vars.types[vars.type.value].shapes 6 | list = [list] if list and !(list instanceof Array) 7 | if list.length then list else ["square"] 8 | interpolate: 9 | accepted: ["basis", "basis-open", "cardinal", "cardinal-open", "linear", "monotone", "step", "step-before", "step-after"] 10 | deprecates: "stack_type" 11 | value: "linear" 12 | rendering: rendering() 13 | value: false 14 | -------------------------------------------------------------------------------- /src/form/types/auto.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Determines form type based on data length. 3 | //------------------------------------------------------------------------------ 4 | module.exports = function( vars ) { 5 | 6 | var dataLength = vars.data.value.length 7 | 8 | if ( dataLength === 1 ) { 9 | vars.self.type("button").draw() 10 | } 11 | else if ( dataLength < 5 ) { 12 | vars.self.type("toggle").draw() 13 | } 14 | else { 15 | vars.self.type("drop").draw() 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /docs/assets/js/yui-prettify.js: -------------------------------------------------------------------------------- 1 | YUI().use('node', function(Y) { 2 | var code = Y.all('.prettyprint.linenums'); 3 | if (code.size()) { 4 | code.each(function(c) { 5 | var lis = c.all('ol li'), 6 | l = 1; 7 | lis.each(function(n) { 8 | n.prepend(''); 9 | l++; 10 | }); 11 | }); 12 | var h = location.hash; 13 | location.hash = ''; 14 | h = h.replace('LINE_', 'LINENUM_'); 15 | location.hash = h; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /src/viz/methods/links.coffee: -------------------------------------------------------------------------------- 1 | decoration = require "../../core/methods/font/decoration.coffee" 2 | family = require "../../core/methods/font/family.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | module.exports = 6 | font: 7 | color: "#444444" 8 | decoration: decoration() 9 | family: family() 10 | transform: transform() 11 | weight: 200 12 | hover: 13 | color: "#444444" 14 | decoration: decoration() 15 | family: family() 16 | transform: transform() 17 | weight: 200 18 | -------------------------------------------------------------------------------- /src/viz/methods/labels.coffee: -------------------------------------------------------------------------------- 1 | decoration = require "../../core/methods/font/decoration.coffee" 2 | family = require "../../core/methods/font/family.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | module.exports = 6 | accepted: [Boolean] 7 | align: "middle" 8 | font: 9 | decoration: decoration() 10 | family: family() 11 | size: 11 12 | transform: transform() 13 | weight: 200 14 | padding: 7 15 | resize: 16 | accepted: [Boolean] 17 | value: true 18 | segments: 2 19 | value: true 20 | -------------------------------------------------------------------------------- /src/array/update.coffee: -------------------------------------------------------------------------------- 1 | # Updates an array, either overwriting it with a new array, removing an entry 2 | module.exports = (arr, x) -> 3 | 4 | # Return an empty array if the user has passed `false` 5 | return [] if x is false 6 | 7 | # If the user has passed an array, just use that. 8 | return x if x instanceof Array 9 | 10 | # Create an empty Array if none has been passed 11 | arr = [] unless arr instanceof Array 12 | 13 | # Remove or add the value 14 | if arr.indexOf(x) >= 0 then arr.splice arr.indexOf(x), 1 else arr.push x 15 | 16 | # Return the array 17 | arr 18 | -------------------------------------------------------------------------------- /src/client/pointer.coffee: -------------------------------------------------------------------------------- 1 | ie = require "./ie.js" 2 | touch = require "./touch.coffee" 3 | 4 | # Creates custom mouse events based on IE and Touch Devices. 5 | if touch 6 | module.exports = 7 | click: "click" 8 | down: "touchstart" 9 | up: "touchend" 10 | over: "touchstart" 11 | out: "touchend" 12 | move: "touchmove" 13 | else 14 | module.exports = 15 | click: "click" 16 | down: "mousedown" 17 | up: "mouseup" 18 | over: if ie then "mouseenter" else "mouseover" 19 | out: if ie then "mouseleave" else "mouseout" 20 | move: "mousemove" 21 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/direction.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (data, vars) -> 2 | 3 | max_depth = vars.id.nesting.length - 1 4 | current_depth = vars.depth.value 5 | restricted = vars.types[vars.type.value].nesting is false 6 | 7 | if restricted 8 | 0 9 | else if data.d3plus.merged or current_depth < max_depth and (not data or vars.id.nesting[vars.depth.value + 1] of data) 10 | 1 11 | else if (current_depth is max_depth or (data and (vars.id.nesting[vars.depth.value + 1] not of data))) and (vars.small or not vars.tooltip.html.value) 12 | -1 13 | else 14 | 0 15 | -------------------------------------------------------------------------------- /src/viz/methods/footer.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | decoration = require "../../core/methods/font/decoration.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | module.exports = 6 | accepted: [false, Number, String] 7 | font: 8 | align: "center" 9 | color: "#444" 10 | decoration: decoration() 11 | family: family() 12 | size: 11 13 | transform: transform() 14 | weight: 200 15 | link: false 16 | padding: 0 17 | position: "bottom" 18 | value: false 19 | -------------------------------------------------------------------------------- /src/core/methods/process/data.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require "../../../util/d3selection.coffee" 2 | 3 | # Function to process data by url or element. 4 | module.exports = (value, vars, method) -> 5 | 6 | if typeof value isnt "string" and not d3selection(value) 7 | value 8 | else 9 | maybeURL = value.indexOf("/") >= 0 10 | if not maybeURL and d3selection(value) 11 | return value 12 | else 13 | if not maybeURL and not d3.selectAll(value).empty() 14 | return d3.selectAll(value) 15 | else 16 | method.url = value 17 | return [] 18 | [] 19 | -------------------------------------------------------------------------------- /src/core/font/tester.coffee: -------------------------------------------------------------------------------- 1 | # Creates an invisible test element to populate 2 | module.exports = (type) -> 3 | 4 | type = "div" if [ "div", "svg" ].indexOf(type) < 0 5 | styles = 6 | position: "absolute" 7 | left: "-9999px" 8 | top: "-9999px" 9 | visibility: "hidden" 10 | display: "block" 11 | 12 | attrs = if type is "div" then {} else 13 | position: "absolute" 14 | 15 | tester = d3.select("body").selectAll(type + ".d3plus_tester").data([0]) 16 | tester.enter().append(type).attr("class", "d3plus_tester") 17 | .style(styles).attr(attrs) 18 | 19 | tester 20 | -------------------------------------------------------------------------------- /docs/api.js: -------------------------------------------------------------------------------- 1 | YUI.add("yuidoc-meta", function(Y) { 2 | Y.YUIDoc = { meta: { 3 | "classes": [ 4 | "d3plus", 5 | "d3plus.array", 6 | "d3plus.client", 7 | "d3plus.color", 8 | "d3plus.data", 9 | "d3plus.font", 10 | "d3plus.form", 11 | "d3plus.geom", 12 | "d3plus.network", 13 | "d3plus.number", 14 | "d3plus.object", 15 | "d3plus.string", 16 | "d3plus.textwrap", 17 | "d3plus.tooltip", 18 | "d3plus.util", 19 | "d3plus.viz" 20 | ], 21 | "modules": [], 22 | "allModules": [] 23 | } }; 24 | }); -------------------------------------------------------------------------------- /src/network/distances.coffee: -------------------------------------------------------------------------------- 1 | # Returns distances of all objects in array 2 | module.exports = (arr, accessor) -> 3 | 4 | distances = [] 5 | checked = [] 6 | 7 | arr.forEach (node1) -> 8 | n1 = (if accessor then accessor(node1) else [ node1.x, node1.y ]) 9 | checked.push node1 10 | arr.forEach (node2) -> 11 | if checked.indexOf(node2) < 0 12 | n2 = (if accessor then accessor(node2) else [ node2.x, node2.y ]) 13 | xx = Math.abs(n1[0] - n2[0]) 14 | yy = Math.abs(n1[1] - n2[1]) 15 | distances.push Math.sqrt((xx * xx) + (yy * yy)) 16 | 17 | distances.sort (a, b) -> a - b 18 | -------------------------------------------------------------------------------- /src/viz/types/deprecated/chart.coffee: -------------------------------------------------------------------------------- 1 | print = require("../../../core/console/print.coffee") 2 | 3 | chart = (vars) -> 4 | 5 | types = 6 | circle: "scatter" 7 | donut: "scatter" 8 | line: "line" 9 | square: "scatter" 10 | area: "stacked" 11 | 12 | type = types[vars.shape.value] 13 | print.warning "The \"chart\" visualization type has been deprecated and will be removed in version 2.0. Please use the \"" + type + "\" visualization type." 14 | vars.self.type(type).draw() 15 | 16 | return 17 | 18 | chart.shapes = ["circle", "donut", "line", "square", "area"] 19 | module.exports = chart 20 | -------------------------------------------------------------------------------- /gulp/server.coffee: -------------------------------------------------------------------------------- 1 | express = require "express" 2 | gulp = require "gulp" 3 | gutil = require "gulp-util" 4 | livereload = require "gulp-livereload" 5 | lr = require("tiny-lr")() 6 | path = require "path" 7 | 8 | gulp.task "server", -> 9 | 10 | app = express() 11 | app.use require("connect-livereload")(hostname: "0.0.0.0") 12 | app.use express.static("./") 13 | app.listen 4000 14 | 15 | gulp.watch ["./tests/**/*.*"], (evt) -> 16 | 17 | fileName = path.relative("./", evt.path) 18 | gutil.log gutil.colors.cyan(fileName), "changed" 19 | gulp.src(evt.path, read: false).pipe livereload(lr) 20 | -------------------------------------------------------------------------------- /src/viz/methods/coords.coffee: -------------------------------------------------------------------------------- 1 | filter = require("../../core/methods/filter.coffee") 2 | process = require("../../core/methods/process/data.coffee") 3 | 4 | module.exports = 5 | accepted: [false, Array, Function, Object, String] 6 | center: [0,0] 7 | filetype: 8 | accepted: ["json"] 9 | value: "json" 10 | fit: 11 | accepted: ["auto", "height", "width"] 12 | value: "auto" 13 | mute: filter false 14 | padding: 20 15 | process: process 16 | projection: 17 | accepted: ["mercator", "equirectangular"] 18 | value: "mercator" 19 | solo: filter false 20 | threshold: 0.1 21 | value: false 22 | -------------------------------------------------------------------------------- /src/tooltip/remove.coffee: -------------------------------------------------------------------------------- 1 | # Destroy Tooltips 2 | module.exports = (id) -> 3 | 4 | # If an ID is specified, only remove that tooltip 5 | if id 6 | 7 | # First remove the background curtain, if the tooltip has one 8 | d3.selectAll("div#d3plus_tooltip_curtain_" + id).remove() 9 | 10 | # Finally, remove the tooltip itself 11 | d3.selectAll("div#d3plus_tooltip_id_" + id).remove() 12 | 13 | # If no ID is given, remove ALL d3plus tooltips 14 | else 15 | 16 | # First remove all background curtains on the page 17 | d3.selectAll("div.d3plus_tooltip_curtain").remove() 18 | 19 | # Finally, remove all tooltip 20 | d3.selectAll("div.d3plus_tooltip").remove() 21 | -------------------------------------------------------------------------------- /docs/assets/vendor/prettify/prettify-min.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /src/textwrap/helpers/getText.coffee: -------------------------------------------------------------------------------- 1 | # Fetches text if not specified, and formats text to array. 2 | module.exports = (vars) -> 3 | 4 | unless vars.text.value 5 | text = vars.container.value.text() 6 | if text 7 | if text.indexOf("tspan") >= 0 8 | text.replace /\<\/tspan\>\/g, " " 9 | text.replace /\<\/tspan\>/g, "" 10 | text.replace /\/g, "" 11 | vars.self.text text 12 | 13 | if vars.text.value instanceof Array 14 | vars.text.phrases = vars.text.value.filter (t) -> ["string", "number"].indexOf(typeof t) >= 0 15 | else 16 | vars.text.phrases = [vars.text.value + ""] 17 | 18 | vars.container.value.text "" 19 | 20 | return 21 | -------------------------------------------------------------------------------- /src/form/types/button/functions/style.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // 3 | //------------------------------------------------------------------------------ 4 | module.exports = function ( elem , vars ) { 5 | 6 | elem 7 | .style("position","relative") 8 | .style("margin",vars.ui.margin+"px") 9 | .style("display",vars.ui.display.value) 10 | .style("border-style","solid") 11 | .style("border-width",vars.ui.border+"px") 12 | .style("font-family",vars.font.family.value) 13 | .style("font-size",vars.font.size+"px") 14 | .style("font-weight",vars.font.weight) 15 | .style("letter-spacing",vars.font.spacing+"px") 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/style.coffee: -------------------------------------------------------------------------------- 1 | color = require "./color.coffee" 2 | 3 | # Fill style for all shapes 4 | module.exports = (nodes, vars) -> 5 | 6 | nodes 7 | .attr "fill", (d) -> 8 | if d.d3plus and d.d3plus.spline then "none" else color d, vars 9 | .style "stroke", (d) -> 10 | if d.d3plus and d.d3plus.stroke 11 | d.d3plus.stroke 12 | else 13 | c = if d.values then color(d.values[0], vars) else color(d, vars) 14 | d3.rgb(c).darker 0.7 15 | .style "stroke-width", (d) -> 16 | mod = if d.d3plus.shape is "line" then 2 else 1 17 | vars.data.stroke.width * mod 18 | .attr "opacity", vars.data.opacity 19 | .attr "vector-effect", "non-scaling-stroke" 20 | -------------------------------------------------------------------------------- /src/viz/methods/size.coffee: -------------------------------------------------------------------------------- 1 | filter = require "../../core/methods/filter.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Function, Number, Object, String] 5 | dataFilter: true 6 | deprecates: ["value", "value_var"] 7 | mute: filter(true) 8 | scale: 9 | accepted: [Function] 10 | deprecates: "size_scale" 11 | max: 12 | accepted: [Function, Number] 13 | value: (vars) -> 14 | Math.floor d3.max [d3.min([vars.width.viz,vars.height.viz])/15, 6] 15 | min: 16 | accepted: [Function, Number] 17 | value: 3 18 | value: d3.scale.sqrt() 19 | solo: filter(true) 20 | threshold: 21 | accepted: [Boolean, Function, Number] 22 | value: true 23 | value: false 24 | -------------------------------------------------------------------------------- /src/form/methods/focus.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [false, Number, String] 3 | deprecates: "highlight" 4 | process: (value, vars) -> 5 | 6 | element = vars.data.element.value 7 | 8 | if element and ["string","number"].indexOf(typeof value) >= 0 9 | 10 | elementTag = element.node().tagName.toLowerCase() 11 | elementType = element.attr("type") 12 | 13 | if elementTag is "select" 14 | for d, i in element.selectAll("option") 15 | element.node().selectedIndex = i if d and d[vars.id.value] is value 16 | else if elementTag is "input" and elementType is "radio" 17 | for d in element 18 | @checked = d and d[vars.id.value] is value 19 | 20 | value 21 | value: false 22 | -------------------------------------------------------------------------------- /src/form/methods/font.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | align = require "../../core/methods/font/align.coffee" 3 | decoration = require "../../core/methods/font/decoration.coffee" 4 | transform = require "../../core/methods/font/transform.coffee" 5 | 6 | module.exports = 7 | align: align() 8 | color: "#444444" 9 | decoration: decoration() 10 | family: family() 11 | secondary: 12 | align: align() 13 | color: "#444444" 14 | decoration: decoration() 15 | family: family() 16 | size: 12 17 | spacing: 0 18 | transform: transform() 19 | weight: 200 20 | size: 12 21 | spacing: 0 22 | transform: transform() 23 | weight: 200 24 | -------------------------------------------------------------------------------- /src/textwrap/methods/format.coffee: -------------------------------------------------------------------------------- 1 | locale = require "../../core/locale/locale.coffee" 2 | mergeObject = require "../../object/merge.coffee" 3 | 4 | module.exports = 5 | accepted: [Function, String] 6 | locale: 7 | accepted: -> d3.keys locale 8 | process: (value) -> 9 | defaultLocale = "en_US" 10 | returnObject = locale[defaultLocale] 11 | returnObject = mergeObject(returnObject, locale[value]) if value isnt defaultLocale 12 | @language = value 13 | returnObject 14 | value: "en_US" 15 | process: (value, vars) -> 16 | if @initialized and typeof value is "string" 17 | vars.self.format locale: value 18 | else return value if typeof value is "function" 19 | @value 20 | value: "en_US" 21 | -------------------------------------------------------------------------------- /src/viz/methods/font.coffee: -------------------------------------------------------------------------------- 1 | align = require "../../core/methods/font/align.coffee" 2 | decoration = require "../../core/methods/font/decoration.coffee" 3 | family = require "../../core/methods/font/family.coffee" 4 | transform = require "../../core/methods/font/transform.coffee" 5 | 6 | module.exports = 7 | align: align() 8 | color: "#444444" 9 | decoration: decoration() 10 | family: family() 11 | secondary: 12 | align: align() 13 | color: "#444444" 14 | decoration: decoration() 15 | family: family() 16 | size: 12 17 | spacing: 0 18 | transform: transform() 19 | weight: 200 20 | size: 12 21 | spacing: 0 22 | transform: transform() 23 | weight: 200 24 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/selector.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Creates and styles the div that holds the search box and item list. 3 | //------------------------------------------------------------------------------ 4 | module.exports = function ( vars ) { 5 | 6 | vars.container.selector = vars.container.ui 7 | .selectAll("div.d3plus_drop_selector") 8 | .data(["selector"]) 9 | 10 | vars.container.selector.enter().append("div") 11 | .attr("class","d3plus_drop_selector") 12 | .style("position","absolute") 13 | .style("top","0px") 14 | .style("z-index","-1") 15 | .style("overflow","hidden") 16 | 17 | vars.container.selector 18 | .style("padding",vars.ui.border+"px") 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/string/title.coffee: -------------------------------------------------------------------------------- 1 | defaultLocale = require "../core/locale/languages/en_US.coffee" 2 | 3 | module.exports = (text, key, vars) -> 4 | 5 | return "" unless text 6 | 7 | locale = if "locale" of this then @locale.value else defaultLocale 8 | 9 | # If it's a sentence, just capitalize the first letter. 10 | return text.charAt(0).toUpperCase() + text.substr(1) if text.charAt(text.length - 1) is "." 11 | 12 | smalls = locale.lowercase 13 | bigs = locale.uppercase 14 | 15 | text.replace /\S*/g, (txt, i) -> 16 | if bigs.indexOf(txt.toLowerCase()) >= 0 17 | return txt.toUpperCase() 18 | else return txt.toLowerCase() if smalls.indexOf(txt.toLowerCase()) >= 0 and i isnt 0 and i isnt text.length - 1 19 | txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase() 20 | -------------------------------------------------------------------------------- /src/form/methods/title.coffee: -------------------------------------------------------------------------------- 1 | decoration = require "../../core/methods/font/decoration.coffee" 2 | family = require "../../core/methods/font/family.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | stringStrip = require "../../string/strip.js" 6 | 7 | module.exports = 8 | accepted: [false, Function, String] 9 | font: 10 | align: "center" 11 | color: "#444444" 12 | decoration: decoration() 13 | family: family() 14 | size: 16 15 | transform: transform() 16 | weight: 400 17 | link: false 18 | process: (value, vars) -> 19 | if vars.container.id.indexOf("default") is 0 and value 20 | id = stringStrip(value).toLowerCase() 21 | vars.self.container id: id 22 | value 23 | value: false 24 | -------------------------------------------------------------------------------- /src/string/list.coffee: -------------------------------------------------------------------------------- 1 | format = require "./format.js" 2 | locale = require("../core/locale/languages/en_US.coffee").ui 3 | 4 | # Converts an array of strings into a string list using commas and "and". 5 | module.exports = (list, andText, max, moreText) -> 6 | unless list instanceof Array 7 | return list 8 | else 9 | list = list.slice(0) 10 | andText = locale.and unless andText 11 | moreText = locale.moreText unless moreText 12 | if list.length is 2 13 | list.join " " + andText + " " 14 | else 15 | if max and list.length > max 16 | amount = list.length - max + 1 17 | list = list.slice(0, max - 1) 18 | list[max - 1] = format(moreText, amount) 19 | list[list.length - 1] = andText + " " + list[list.length - 1] if list.length > 1 20 | list.join ", " 21 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/list.js: -------------------------------------------------------------------------------- 1 | var print = require("../../../../core/console/print.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Creates and populates the dropdown list of items. 4 | //------------------------------------------------------------------------------ 5 | module.exports = function ( vars ) { 6 | 7 | if ( vars.dev.value ) print.time("populating list") 8 | 9 | vars.container.list = vars.container.selector.selectAll("div.d3plus_drop_list") 10 | .data(["list"]) 11 | 12 | vars.container.list.enter().append("div") 13 | .attr("class","d3plus_drop_list") 14 | .attr("id","d3plus_drop_list_"+vars.container.id) 15 | .style("overflow-y","auto") 16 | .style("overflow-x","hidden") 17 | 18 | if ( vars.dev.value ) print.timeEnd("populating list") 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/textwrap/methods/draw.coffee: -------------------------------------------------------------------------------- 1 | print = require "../../core/console/print.coffee" 2 | 3 | module.exports = 4 | accepted: [undefined] 5 | process : (value, vars) -> 6 | 7 | return value if this.initialized is false 8 | 9 | if vars.container.value is false 10 | str = vars.format.locale.value.dev.setContainer 11 | print.warning str, "container" 12 | else if vars.container.value.empty() 13 | str = vars.format.locale.value.dev.noContainer 14 | print.warning stringFormat(str, "\"" + vars.container.value + "\""), "container" 15 | else 16 | if vars.dev.value 17 | if vars.methodGroup 18 | vars.methodGroup = "wait" 19 | print.groupEnd() 20 | print.time "total draw time" 21 | 22 | vars.container.value.call vars.self 23 | 24 | value 25 | value: undefined 26 | -------------------------------------------------------------------------------- /src/font/sizes.coffee: -------------------------------------------------------------------------------- 1 | fontTester = require "../core/font/tester.coffee" 2 | 3 | module.exports = (words, style, parent) -> 4 | 5 | tester = parent or fontTester("svg").append("text") 6 | style = style or {} 7 | sizes = [] 8 | words = [ words ] unless words instanceof Array 9 | tspans = tester.selectAll("tspan").data(words) 10 | attr = 11 | x: 0 12 | y: 0 13 | 14 | tspans.enter().append("tspan") 15 | .text String 16 | .attr "position", "absolute" 17 | .attr "top", "0px" 18 | .attr "left", "0px" 19 | .style style 20 | .attr attr 21 | .each (d) -> 22 | sizes.push 23 | height: @offsetHeight or @getBoundingClientRect().height or @.parentNode.getBBox().height 24 | text: d 25 | width: @getComputedTextLength() 26 | 27 | tspans.remove() 28 | tester.remove() unless parent 29 | sizes 30 | -------------------------------------------------------------------------------- /src/client/scrollbar.coffee: -------------------------------------------------------------------------------- 1 | # Detects scrollbar width for current browser. 2 | scrollbar = -> 3 | 4 | inner = document.createElement "p" 5 | inner.style.width = "100%" 6 | inner.style.height = "200px" 7 | 8 | outer = document.createElement "div" 9 | outer.style.position = "absolute" 10 | outer.style.top = "0px" 11 | outer.style.left = "0px" 12 | outer.style.visibility = "hidden" 13 | outer.style.width = "200px" 14 | outer.style.height = "150px" 15 | outer.style.overflow = "hidden" 16 | 17 | outer.appendChild inner 18 | document.body.appendChild outer 19 | w1 = inner.offsetWidth 20 | outer.style.overflow = "scroll" 21 | w2 = inner.offsetWidth 22 | w2 = outer.clientWidth if w1 is w2 23 | document.body.removeChild outer 24 | val = w1 - w2 25 | 26 | scrollbar = -> val 27 | 28 | val 29 | 30 | module.exports = scrollbar 31 | -------------------------------------------------------------------------------- /src/core/data/group.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../fetch/value.js" 2 | # Groups data into groups to use with D3 layouts. Helps prevent key name mismatches (parent, child, value, etc). 3 | module.exports = (vars, data, nesting) -> 4 | 5 | groupedData = d3.nest() 6 | nesting = vars.id.nesting if nesting is undefined 7 | 8 | for n, i in nesting 9 | if i < vars.depth.value 10 | key = n 11 | groupedData.key (d) -> fetchValue vars, d.d3plus, key 12 | 13 | strippedData = [] 14 | for d in data 15 | 16 | val = if vars.size.value then fetchValue vars, d, vars.size.value else 1 17 | 18 | if val and typeof val is "number" and val > 0 19 | 20 | delete d.d3plus.r 21 | delete d.d3plus.x 22 | delete d.d3plus.y 23 | 24 | strippedData.push 25 | d3plus: d 26 | id: d[vars.id.value] 27 | value: val 28 | 29 | groupedData.entries(strippedData) 30 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/arrow.js: -------------------------------------------------------------------------------- 1 | var print = require("../../../../core/console/print.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Toggles the state of the dropdown menu. 4 | //------------------------------------------------------------------------------ 5 | module.exports = function ( vars ) { 6 | 7 | if ( vars.dev.value ) print.time("rotating arrow") 8 | 9 | var offset = vars.icon.drop.value === "❯" ? 90 : 0 10 | 11 | if (vars.open.value != vars.open.flipped.value) { 12 | var rotate = 180 + offset 13 | } 14 | else { 15 | var rotate = offset 16 | } 17 | 18 | vars.container.button 19 | .icon({ 20 | "select": { 21 | "opacity": vars.open.value ? 0.5 : 1, 22 | "rotate": rotate 23 | } 24 | }) 25 | .draw() 26 | 27 | if ( vars.dev.value ) print.timeEnd("rotating arrow") 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/viz/methods/data.js: -------------------------------------------------------------------------------- 1 | var process = require("../../core/methods/process/data.coffee") 2 | 3 | module.exports = { 4 | "accepted" : [ false , Array , Function , String ], 5 | "cache" : {}, 6 | "delimiter" : { 7 | "accepted" : [ String ], 8 | "value" : "|" 9 | }, 10 | "donut" : { 11 | "size" : 0.35 12 | }, 13 | "filetype" : { 14 | "accepted" : [false, "json", "xml", "html", "csv", "dsv", "tsv", "txt"], 15 | "value" : false 16 | }, 17 | "filters" : [], 18 | "mute" : [], 19 | "large" : 400, 20 | "opacity" : 0.9, 21 | "process" : function(value, vars) { 22 | 23 | if ( vars.container.id === "default" && value.length ) { 24 | vars.self.container({"id": "default"+value.length}) 25 | } 26 | 27 | return process(value, vars, this) 28 | }, 29 | "solo" : [], 30 | "stroke" : { 31 | "width" : 1 32 | }, 33 | "value" : false 34 | } 35 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/active.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Checks to see if a given variable is allowed to be selected. 3 | //------------------------------------------------------------------------------ 4 | module.exports = function ( vars , value , active ) { 5 | 6 | var ret = [] 7 | , active = active || vars.active.value 8 | 9 | if ( active instanceof Array ) { 10 | 11 | for (var i = 0; i < active.length; i++) { 12 | ret.push(this(vars,value,active[i])) 13 | } 14 | 15 | } 16 | else { 17 | 18 | var t = typeof active 19 | 20 | if (t === "number") { 21 | ret.push(vars.depth.value === active) 22 | } 23 | else if (t === "function") { 24 | ret.push(active(value)) 25 | } 26 | else { 27 | ret.push(value === active) 28 | } 29 | 30 | } 31 | 32 | return ret.indexOf(true) >= 0 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/array/comparator.coffee: -------------------------------------------------------------------------------- 1 | colorSort = require "../color/sort.coffee" 2 | 3 | module.exports = (a, b, keys, sort, colors, vars, depth) -> 4 | 5 | sort = "asc" unless sort 6 | colors = [colors] unless colors instanceof Array 7 | keys = [keys] unless keys instanceof Array 8 | depth = vars.id.nesting.indexOf(depth) if vars and depth isnt undefined and typeof depth isnt "number" 9 | 10 | retVal = 0 11 | i = 0 12 | 13 | while i < keys.length 14 | 15 | k = keys[i] 16 | 17 | a = if vars and a.d3plus and a.d3plus.sortKeys then a.d3plus.sortKeys[k] else a[k] 18 | b = if vars and b.d3plus and b.d3plus.sortKeys then b.d3plus.sortKeys[k] else b[k] 19 | 20 | if vars and colors.indexOf(k) >= 0 21 | retVal = colorSort a, b 22 | else 23 | retVal = if a < b then -1 else 1 24 | 25 | break if retVal isnt 0 or i is keys.length - 1 26 | i++ 27 | 28 | if sort is "asc" then retVal else -retVal 29 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/height.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Calculates the height and orientation of the dropdown list, based on 3 | // available screen space. 4 | //------------------------------------------------------------------------------ 5 | module.exports = function ( vars ) { 6 | 7 | var button = vars.container.button.container().node().getBoundingClientRect() 8 | 9 | vars.height.secondary = window.innerHeight - button.bottom - vars.ui.margin 10 | - vars.ui.padding*2 - vars.ui.border*2 11 | 12 | if ( vars.height.secondary < button.height*3 ) { 13 | vars.height.secondary = button.top-10 14 | vars.self.open({"flipped": true}) 15 | } 16 | else { 17 | vars.self.open({"flipped": false}) 18 | } 19 | 20 | var scrolling = false 21 | if (vars.height.secondary > vars.height.max) { 22 | vars.height.secondary = vars.height.max 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/util/uniques.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../core/fetch/value.js" 2 | objectValidate = require "../object/validate.coffee" 3 | 4 | # Returns list of unique values 5 | module.exports = (data, value, vars) -> 6 | 7 | return [] if data is undefined 8 | 9 | if value is undefined 10 | return data.reduce (p, c) -> 11 | p.push c if p.indexOf(c) < 0 12 | p 13 | , [] 14 | 15 | data = [ data ] unless data instanceof Array 16 | vals = [] 17 | lookups = [] 18 | 19 | for d in data 20 | if objectValidate d 21 | if typeof value is "function" 22 | val = value d 23 | else if vars 24 | val = fetchValue vars, d, value 25 | else 26 | val = d[value] 27 | lookup = if [ "number", "string" ].indexOf(typeof val) >= 0 then val else JSON.stringify(val) 28 | if lookup isnt undefined and lookups.indexOf(lookup) < 0 29 | vals.push val 30 | lookups.push lookup 31 | 32 | vals.sort (a, b) -> a - b 33 | -------------------------------------------------------------------------------- /src/viz/methods/tooltip.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | transform = require "../../core/methods/font/transform.coffee" 3 | 4 | module.exports = 5 | accepted: [false, Array, Function, Object, String] 6 | anchor: "top center" 7 | background: "#ffffff" 8 | children: 9 | accepted: [Boolean] 10 | value: true 11 | connections: 12 | accepted: [Boolean] 13 | value: true 14 | curtain: 15 | color: "#ffffff" 16 | opacity: 0.8 17 | deprecates: "tooltip_info" 18 | font: 19 | color: "#444" 20 | family: family() 21 | size: 12 22 | transform: transform() 23 | weight: 200 24 | html: 25 | accepted: [false, Function, String] 26 | deprecates: "click_function" 27 | value: false 28 | large: 250 29 | share: 30 | accepted: [Boolean] 31 | value: true 32 | size: 33 | accepted: [Boolean] 34 | value: true 35 | small: 225 36 | value: false 37 | -------------------------------------------------------------------------------- /src/core/fetch/sort.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "./value.js" 2 | fetchColor = require "./color.coffee" 3 | fetchText = require "./text.js" 4 | 5 | module.exports = (vars, d, keys, colors, depth) -> 6 | 7 | keys = [keys] unless keys instanceof Array 8 | colors = [colors] unless colors instanceof Array 9 | depth = vars.id.nesting.indexOf(depth) if vars and depth isnt undefined and typeof depth isnt "number" 10 | 11 | obj = {} 12 | i = 0 13 | 14 | while i < keys.length 15 | 16 | key = keys[i] 17 | 18 | if vars 19 | if colors.indexOf(key) >= 0 20 | value = fetchColor vars, d, depth 21 | else 22 | value = if key is vars.text.value then fetchText vars, d, depth else fetchValue vars, d, key, depth 23 | else 24 | value = d[key] 25 | 26 | value = value[0] if value instanceof Array 27 | value = if typeof value is "string" then value.toLowerCase() else value 28 | 29 | obj[key] = value 30 | 31 | i++ 32 | 33 | obj 34 | -------------------------------------------------------------------------------- /src/viz/methods/color.coffee: -------------------------------------------------------------------------------- 1 | filter = require("../../core/methods/filter.coffee") 2 | scale = require("../../color/scale.coffee") 3 | 4 | module.exports = 5 | accepted: [false, Array, Function, Object, String] 6 | deprecates: "color_var" 7 | focus: "#444444" 8 | heatmap: ["#282F6B", "#419391", "#AFD5E8", "#EACE3F", "#B35C1E", "#B22200"] 9 | missing: "#eeeeee" 10 | mute: filter true 11 | primary: "#d74b03" 12 | range: ["#B22200", "#FFEE8D", "#759143"] 13 | scale: 14 | accepted: [Array, Function, "d3plus", "category10", "category20", "category20b", "category20c"] 15 | process: (value) -> 16 | if value instanceof Array 17 | d3.scale.ordinal().range value 18 | else if value is "d3plus" 19 | scale 20 | else if typeof value is "string" 21 | d3.scale[value]() 22 | else 23 | value 24 | value: "d3plus" 25 | solo: filter true 26 | secondary: "#e5b3bb" 27 | value: false 28 | -------------------------------------------------------------------------------- /src/string/format.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Formats a string similar to Python's "format" 3 | //------------------------------------------------------------------------------ 4 | module.exports = function() { 5 | 6 | var args = Array.prototype.slice.call(arguments) 7 | , str = args.shift() 8 | 9 | str.unkeyed_index = 0; 10 | return str.replace(/\{(\w*)\}/g, function(match, key) { 11 | if (key === '') { 12 | key = str.unkeyed_index; 13 | str.unkeyed_index++ 14 | } 15 | if (key == +key) { 16 | return args[key] !== 'undefined' 17 | ? args[key] 18 | : match; 19 | } else { 20 | for (var i = 0; i < args.length; i++) { 21 | if (typeof args[i] === 'object' && typeof args[i][key] !== 'undefined') { 22 | return args[i][key]; 23 | } 24 | } 25 | return match; 26 | } 27 | }.bind(str)); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/textwrap/helpers/getDimensions.coffee: -------------------------------------------------------------------------------- 1 | # Checks width and height, and gets it if needed. 2 | module.exports = (vars) -> 3 | 4 | if not vars.width.value or not vars.height.value 5 | 6 | parent = d3.select vars.container.value.node().parentNode 7 | rect = parent.select "rect" 8 | circle = parent.select "circle" 9 | 10 | unless rect.empty() 11 | unless vars.width.value 12 | width = rect.attr "width" or rect.style "width" 13 | vars.self.width parseFloat width, 10 14 | unless vars.height.value 15 | height = rect.attr "height" or rect.style "height" 16 | vars.self.height parseFloat height, 10 17 | else unless circle.empty() 18 | radius = circle.attr "r" 19 | vars.self.width parseFloat radius * 2, 10 unless vars.width.value 20 | vars.self.height parseFloat radius * 2, 10 unless vars.height.value 21 | else 22 | vars.self.width 500 unless vars.width.value 23 | vars.self.height 500 unless vars.height.value 24 | 25 | return 26 | -------------------------------------------------------------------------------- /src/textwrap/helpers/foreign.coffee: -------------------------------------------------------------------------------- 1 | # Flows the text as a foreign element. 2 | module.exports = (vars) -> 3 | 4 | text = vars.container.value 5 | family = text.attr("font-family") or text.style("font-family") 6 | anchor = text.attr("text-anchor") or text.style("text-anchor") 7 | color = text.attr("fill") or text.style("fill") 8 | opacity = text.attr("opacity") or text.style("opacity") 9 | anchor = if anchor is "end" then "right" else (if anchor is "middle" then "center" else "left") 10 | 11 | d3.select(text.node().parentNode).append "foreignObject" 12 | .attr "width" , vars.width.value + "px" 13 | .attr "height", vars.height.value + "px" 14 | .attr "x" , "0px" 15 | .attr "y" , "0px" 16 | .append "xhtml:div" 17 | .style "font-family", family 18 | .style "font-size" , vars.size.value[1]+"px" 19 | .style "color" , color 20 | .style "text-align" , anchor 21 | .style "opacity" , opacity 22 | .text vars.text.current 23 | 24 | return 25 | -------------------------------------------------------------------------------- /src/data/mad.coffee: -------------------------------------------------------------------------------- 1 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | # Finds outliers in 1-dim data by computing the median absolute deviation for each point 3 | # See: 4 | # http://eurekastatistics.com/using-the-median-absolute-deviation-to-find-outliers 5 | # http://en.wikipedia.org/wiki/Median_absolute_deviation 6 | #------------------------------------------------------------------------------ 7 | 8 | # points is an array of numbers (1-dim points). 9 | 10 | # Returns an array of [index, deviation] tuples, where index is the index of the point in the original array 11 | # and deviation is the distance from the median in MAD units for that point. The array is ordered by 12 | # descreasing order of deviation so the outliers are in the beginning of the array. 13 | module.exports = (points) -> 14 | 15 | median = d3.median points 16 | mad = d3.median points.map (p) -> Math.abs(p-median) 17 | result = points.map (p, i) -> [i, Math.abs(p-median)/mad] 18 | 19 | result.sort (a,b) -> b[1] - a[1] 20 | -------------------------------------------------------------------------------- /src/object/merge.coffee: -------------------------------------------------------------------------------- 1 | d3selection = require "../util/d3selection.coffee" 2 | validate = require "./validate.coffee" 3 | 4 | ###* 5 | # Given any two objects, this method will merge the two objects together, returning a new third object. The values of the second object always overwrite the first. 6 | # @method d3plus.object.merge 7 | # @for d3plus.object 8 | # @param obj1 {Object} The primary object. 9 | # @param obj2 {Object} The secondary object to merge into the first. 10 | # @return {Object} 11 | ### 12 | module.exports = (obj1, obj2) -> 13 | 14 | copyObject = (obj, ret) -> 15 | for a of obj 16 | unless typeof obj[a] is "undefined" 17 | if validate(obj[a]) 18 | ret[a] = {} if typeof ret[a] isnt "object" 19 | copyObject obj[a], ret[a] 20 | else if not d3selection(obj[a]) and obj[a] instanceof Array 21 | ret[a] = obj[a].slice(0) 22 | else 23 | ret[a] = obj[a] 24 | 25 | obj3 = {} 26 | 27 | copyObject obj1, obj3 if obj1 28 | copyObject obj2, obj3 if obj2 29 | 30 | obj3 31 | -------------------------------------------------------------------------------- /src/form/methods/ui.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | align = require "../../core/methods/font/align.coffee" 3 | decoration = require "../../core/methods/font/decoration.coffee" 4 | transform = require "../../core/methods/font/transform.coffee" 5 | 6 | module.exports = 7 | align: align("center") 8 | border: 1 9 | color: 10 | primary: 11 | process: (value, vars) -> 12 | primary = @value 13 | secondary = vars.ui.color.secondary.value 14 | vars.ui.color.secondary.value = d3.rgb(value).darker(2).toString() if not secondary or secondary is d3.rgb(primary).darker(2).toString() 15 | value 16 | value: "#ffffff" 17 | secondary: 18 | value: false 19 | display: 20 | acceped: ["block", "inline-block"] 21 | value: "inline-block" 22 | font: 23 | align: align("center") 24 | color: "#444" 25 | decoration: decoration() 26 | family: family() 27 | size: 11 28 | transform: transform() 29 | weight: 200 30 | margin: 5 31 | padding: 5 32 | -------------------------------------------------------------------------------- /src/viz/types/geo_map.coffee: -------------------------------------------------------------------------------- 1 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | # Geo Map 3 | #------------------------------------------------------------------------------ 4 | geo_map = (vars) -> 5 | 6 | topojson.presimplify vars.coords.value 7 | 8 | coords = vars.coords.value 9 | key = d3.keys(coords.objects)[0] 10 | topo = topojson.feature coords, coords.objects[key] 11 | features = topo.features 12 | 13 | solo = vars.coords.solo.value 14 | mute = vars.coords.mute.value 15 | 16 | features = features.filter (f) -> 17 | f[vars.id.value] = f.id 18 | if solo.length then solo.indexOf(f.id) >= 0 else if mute.length then mute.indexOf(f.id) < 0 else true 19 | 20 | features 21 | 22 | 23 | # Visualization Settings and Helper Functions 24 | geo_map.libs = ["topojson"] 25 | geo_map.nesting = false 26 | geo_map.requirements = ["color", "coords"] 27 | geo_map.scale = 1 28 | geo_map.shapes = ["coordinates"] 29 | geo_map.tooltip = "follow" 30 | geo_map.zoom = true 31 | 32 | module.exports = geo_map 33 | -------------------------------------------------------------------------------- /gulp/rebuild.coffee: -------------------------------------------------------------------------------- 1 | browserify = require "browserify" 2 | error = require "./error.coffee" 3 | gulp = require "gulp" 4 | livereload = require "gulp-livereload" 5 | lr = require("tiny-lr")() 6 | notify = require "gulp-notify" 7 | source = require "vinyl-source-stream" 8 | timer = require "gulp-duration" 9 | watchify = require "watchify" 10 | 11 | gulp.task "rebuild", -> 12 | 13 | # fileList = glob.sync files, {nosort: true} 14 | 15 | bundler = browserify watchify.args 16 | .add "./src/init.coffee" 17 | .transform "coffeeify" 18 | 19 | bundler = watchify(bundler) 20 | 21 | rebundle = -> 22 | bundler.bundle() 23 | .on("error", notify.onError(error)) 24 | .pipe(source("d3plus.js")) 25 | .pipe(gulp.dest("./")) 26 | .pipe(timer("Total Build Time")) 27 | .pipe(notify( 28 | title: "D3plus" 29 | message: "New Build Compiled" 30 | icon: __dirname + "/../icon.png" 31 | )) 32 | .pipe(livereload(lr)) 33 | .on "error", notify.onError(error) 34 | 35 | bundler.on "update", rebundle 36 | 37 | rebundle() 38 | -------------------------------------------------------------------------------- /src/geom/path2poly.coffee: -------------------------------------------------------------------------------- 1 | offset = require "../geom/offset.coffee" 2 | 3 | module.exports = (path) -> 4 | 5 | path = path.slice(1).slice(0,-1).split(/L|A/) 6 | poly = [] 7 | 8 | for p in path 9 | p = p.split(" ") 10 | if p.length is 1 11 | poly.push p[0].split(",").map (d) -> parseFloat d 12 | else 13 | prev = poly[poly.length-1] 14 | last = p.pop().split(",").map (d) -> parseFloat d 15 | radius = parseFloat p.shift().split(",")[0] 16 | width = Math.sqrt( Math.pow(last[0]-prev[0],2) + Math.pow(last[1]-prev[1],2) ) 17 | angle = Math.acos((radius*radius+radius*radius-width*width)/(2*radius*radius)) 18 | obtuse = p[1].split(",")[0] is "1" 19 | angle = Math.PI*2 - angle if obtuse 20 | length = angle/(Math.PI*2) * (radius*Math.PI*2) 21 | segments = length/5 22 | start = Math.atan2(-prev[1],-prev[0]) - Math.PI 23 | step = angle/segments 24 | i = step 25 | while i < angle 26 | o = offset start + i, radius 27 | poly.push [o.x,o.y] 28 | i += step 29 | poly.push last 30 | 31 | poly 32 | -------------------------------------------------------------------------------- /src/form/methods/icon.coffee: -------------------------------------------------------------------------------- 1 | process = require "../../core/methods/process/icon.coffee" 2 | 3 | module.exports = 4 | accepted: [false, Array, Function, Object, String] 5 | back: 6 | accepted: [false, String] 7 | fallback: "❮" 8 | opacity: 1 9 | process: process 10 | rotate: 0 11 | value: "fa-angle-left" 12 | button: 13 | accepted: [false, String] 14 | fallback: false 15 | opacity: 1 16 | process: process 17 | rotate: 0 18 | value: false 19 | drop: 20 | accepted: [false, String] 21 | fallback: "❯" 22 | opacity: 1 23 | process: process 24 | rotate: 0 25 | value: "fa-angle-down" 26 | next: 27 | accepted: [false, String] 28 | fallback: "❯" 29 | opacity: 1 30 | process: process 31 | rotate: 0 32 | value: "fa-angle-right" 33 | select: 34 | accepted: [false, String] 35 | fallback: "✓" 36 | opacity: 1 37 | process: process 38 | rotate: 0 39 | value: "fa-check" 40 | style: 41 | accepted: [Object, String] 42 | value: "default" 43 | value: "icon" 44 | -------------------------------------------------------------------------------- /src/viz/helpers/types/run.coffee: -------------------------------------------------------------------------------- 1 | print = require "../../../core/console/print.coffee" 2 | 3 | module.exports = (vars) -> 4 | 5 | # Set vars.group to the app's specific group element 6 | vars.group = vars.g.apps[vars.type.value] 7 | 8 | # Reset mouse events for the app to use 9 | vars.mouse = {} 10 | 11 | visualization = vars.types[vars.type.value] 12 | requirements = visualization.requirements or [] 13 | dataRequired = requirements.indexOf("data") >= 0 14 | drawable = not dataRequired or (dataRequired and vars.data.viz.length) 15 | 16 | if not vars.internal_error and drawable 17 | app = vars.format.locale.value.visualization[vars.type.value] 18 | print.time "running " + app if vars.dev.value 19 | returned = visualization(vars) 20 | print.timeEnd "running " + app if vars.dev.value 21 | else 22 | returned = null 23 | 24 | vars.returned = 25 | nodes: [] 26 | edges: null 27 | 28 | if returned instanceof Array 29 | vars.returned.nodes = returned 30 | else if returned 31 | vars.returned.nodes = returned.nodes if returned.nodes 32 | vars.returned.edges = returned.edges if returned.edges 33 | 34 | return 35 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/labels.js: -------------------------------------------------------------------------------- 1 | var print = require("../../../core/console/print.coffee") 2 | 3 | // Sets label opacity based on zoom 4 | module.exports = function(vars) { 5 | 6 | var max_scale = vars.zoom.behavior.scaleExtent()[1] 7 | 8 | if ( vars.dev.value ) print.time("determining label visibility") 9 | 10 | if (vars.draw.timing) { 11 | 12 | vars.g.viz.selectAll("text.d3plus_label") 13 | .transition().duration(vars.draw.timing) 14 | .attr("opacity",function(d){ 15 | if (!d) var d = {"scale": max_scale} 16 | var size = parseFloat(d3.select(this).attr("font-size"),10) 17 | d.visible = size/d.scale*vars.zoom.scale >= 7 18 | return d.visible ? 1 : 0 19 | }) 20 | 21 | } 22 | else { 23 | 24 | vars.g.viz.selectAll("text.d3plus_label") 25 | .attr("opacity",function(d){ 26 | if (!d) var d = {"scale": max_scale} 27 | var size = parseFloat(d3.select(this).attr("font-size"),10) 28 | d.visible = size/d.scale*vars.zoom.scale >= 7 29 | return d.visible ? 1 : 0 30 | }) 31 | 32 | } 33 | 34 | if ( vars.dev.value ) print.timeEnd("determining label visibility") 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/element.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Overrides keyboard behavior of the original input element. 3 | //------------------------------------------------------------------------------ 4 | module.exports = function ( vars ) { 5 | 6 | if (vars.data.element.value) { 7 | 8 | vars.data.element.value.on("focus."+vars.container.id,function(){ 9 | vars.self.draw({"update":false}).draw() 10 | }) 11 | 12 | vars.data.element.value.on("blur."+vars.container.id,function(){ 13 | 14 | var search = vars.search.enabled 15 | ? d3.event.relatedTarget != vars.container.value.select("input").node() 16 | : true 17 | 18 | if (search) { 19 | vars.self.draw({"update":false}).draw() 20 | } 21 | 22 | }) 23 | 24 | vars.data.element.value.on("change."+vars.container.id,function(){ 25 | vars.self.focus(this.value).draw() 26 | }) 27 | 28 | vars.data.element.value.on("keydown.cancel_"+vars.container.id,function(){ 29 | var key = d3.event.keyCode 30 | if (key != 9) { 31 | d3.event.preventDefault() 32 | } 33 | }) 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/viz/methods/ui.coffee: -------------------------------------------------------------------------------- 1 | family = require "../../core/methods/font/family.coffee" 2 | align = require "../../core/methods/font/align.coffee" 3 | decoration = require "../../core/methods/font/decoration.coffee" 4 | transform = require "../../core/methods/font/transform.coffee" 5 | 6 | module.exports = 7 | accepted: [Array, Boolean] 8 | align: align("center") 9 | border: 1 10 | color: 11 | primary: 12 | process: (value, vars) -> 13 | primary = @value 14 | secondary = vars.ui.color.secondary.value 15 | vars.ui.color.secondary.value = d3.rgb(value).darker(2).toString() if not secondary or secondary is d3.rgb(primary).darker(2).toString() 16 | value 17 | value: "#ffffff" 18 | secondary: 19 | value: false 20 | display: 21 | acceped: ["block", "inline-block"] 22 | value: "inline-block" 23 | font: 24 | align: "center" 25 | color: "#444" 26 | decoration: decoration() 27 | family: family() 28 | size: 11 29 | transform: transform() 30 | weight: 200 31 | margin: 5 32 | padding: 5 33 | position: 34 | accepted: ["top", "right", "bottom", "left"] 35 | value: "bottom" 36 | value: false 37 | -------------------------------------------------------------------------------- /src/core/data/keys.js: -------------------------------------------------------------------------------- 1 | var validObject = require("../../object/validate.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Get Key Types from Data 4 | //------------------------------------------------------------------------------ 5 | module.exports = function( vars , type ) { 6 | 7 | if ( vars.dev.value ) { 8 | var timerString = type + " key analysis" 9 | console.time( timerString ) 10 | } 11 | 12 | vars[type].keys = {} 13 | 14 | function get_keys( arr ) { 15 | if (arr instanceof Array) { 16 | arr.forEach(function(d) { 17 | get_keys( d ) 18 | }) 19 | } 20 | else if ( validObject(arr) ) { 21 | for (var d in arr) { 22 | if ( validObject(arr[d]) ) { 23 | get_keys( arr[d] ) 24 | } 25 | else if (!(d in vars[type].keys) && d in arr) { 26 | vars[type].keys[d] = typeof arr[d] 27 | } 28 | } 29 | } 30 | } 31 | 32 | if ( validObject(vars[type].value) ) { 33 | for ( var a in vars[type].value ) { 34 | get_keys(vars[type].value[a]) 35 | } 36 | } 37 | else { 38 | get_keys(vars[type].value) 39 | } 40 | 41 | if ( vars.dev.value ) console.time( timerString ) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/form/types/button/functions/mouseevents.js: -------------------------------------------------------------------------------- 1 | var events = require("../../../../client/pointer.coffee"), 2 | ie = require("../../../../client/ie.js") 3 | 4 | module.exports = function ( elem , vars , color ) { 5 | 6 | elem 7 | .on(events.over,function(d,i){ 8 | 9 | vars.self.hover(d[vars.id.value]) 10 | 11 | if ( ie || !vars.draw.timing ) { 12 | 13 | d3.select(this).style("cursor","pointer") 14 | .call( color , vars ) 15 | 16 | } 17 | else { 18 | 19 | d3.select(this).style("cursor","pointer") 20 | .transition().duration(vars.timing.mouseevents) 21 | .call( color , vars ) 22 | } 23 | 24 | }) 25 | .on(events.out,function(d){ 26 | 27 | vars.self.hover(false) 28 | 29 | if ( ie || !vars.draw.timing ) { 30 | d3.select(this).style("cursor","auto") 31 | .call( color , vars ) 32 | } 33 | else { 34 | d3.select(this).style("cursor","auto") 35 | .transition().duration(vars.timing.mouseevents) 36 | .call( color , vars ) 37 | } 38 | 39 | }) 40 | .on(events.click,function(d){ 41 | 42 | if ( vars.id.value in d ) { 43 | 44 | vars.self.focus(d[vars.id.value]).draw() 45 | 46 | } 47 | 48 | }) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/textwrap/textwrap.coffee: -------------------------------------------------------------------------------- 1 | attach = require "../core/methods/attach.coffee" 2 | dimensions = require "./helpers/getDimensions.coffee" 3 | size = require "./helpers/getSize.coffee" 4 | text = require "./helpers/getText.coffee" 5 | wrap = require "./helpers/wrap.coffee" 6 | 7 | # Word wraps SVG text 8 | module.exports = -> 9 | 10 | # Main drawing function 11 | vars = 12 | self: (selection) -> 13 | 14 | selection.each -> 15 | 16 | dimensions vars 17 | size vars 18 | 19 | if vars.size.value[0] <= vars.height.value 20 | text vars 21 | wrap vars 22 | 23 | return 24 | 25 | vars.self 26 | 27 | 28 | # Define methods and expose public variables. 29 | attach vars, 30 | container: require "./methods/container.coffee" 31 | dev: require "./methods/dev.coffee" 32 | draw: require "./methods/draw.coffee" 33 | format: require "./methods/format.coffee" 34 | height: require "./methods/height.coffee" 35 | resize: require "./methods/resize.coffee" 36 | text: require "./methods/text.coffee" 37 | shape: require "./methods/shape.coffee" 38 | size: require "./methods/size.coffee" 39 | width: require "./methods/width.coffee" 40 | 41 | vars.self 42 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/color.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../../core/fetch/value.js" 2 | fetchColor = require "../../../core/fetch/color.coffee" 3 | lighter = require "../../../color/lighter.coffee" 4 | 5 | # Returns the correct fill color for a node 6 | module.exports = (d, vars) -> 7 | 8 | shape = d.d3plus.shape or vars.shape.value 9 | 10 | if vars.shape.value is "line" and shape isnt "circle" 11 | return "none" 12 | else if vars.shape.value is "area" or shape is "active" or vars.shape.value is "line" 13 | return fetchColor(vars, d) 14 | else if shape is "temp" 15 | return "url(#d3plus_hatch_" + d.d3plus.id + ")" 16 | else if d.d3plus.static 17 | return lighter fetchColor(vars, d), .75 18 | 19 | active = if vars.active.value then fetchValue(vars, d, vars.active.value) else d.d3plus.active 20 | temp = if vars.temp.value then fetchValue(vars, d, vars.temp.value) else d.d3plus.temp 21 | total = if vars.total.value then fetchValue(vars, d, vars.total.value) else d.d3plus.total 22 | 23 | if (not vars.active.value and not vars.temp.value) or active is true or (active and total and active is total and not temp) or (active and not total) 24 | fetchColor vars, d 25 | else if vars.active.spotlight.value 26 | "#eee" 27 | else 28 | lighter fetchColor(vars, d), .75 29 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/window.js: -------------------------------------------------------------------------------- 1 | var child = require("../../../../util/child.coffee") 2 | 3 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 | // Recursive function that applies a click event to all parent windows that 5 | // will close the dropdown if it is open. 6 | //------------------------------------------------------------------------------ 7 | var windowEvents = function ( vars , elem ) { 8 | 9 | if ( elem === undefined ) { 10 | var elem = window 11 | } 12 | 13 | d3.select(elem).on("click."+vars.container.id,function(){ 14 | 15 | var element = d3.event.target || d3.event.toElement 16 | , parent = element.parentNode 17 | 18 | if ( parent && ["d3plus_node","d3plus_drop_title"].indexOf(parent.className) >= 0 ) { 19 | element = parent.parentNode 20 | } 21 | 22 | if (element && parent && !child(vars.container.ui, element) && vars.open.value) { 23 | vars.self.open(!vars.open.value).draw() 24 | } 25 | 26 | }) 27 | 28 | try { 29 | var same_origin = window.parent.location.host === window.location.host; 30 | } 31 | catch (e) { 32 | var same_origin = false 33 | } 34 | 35 | if (same_origin) { 36 | if (elem.self !== window.top) { 37 | windowEvents( vars , elem.parent ) 38 | } 39 | } 40 | 41 | } 42 | 43 | module.exports = windowEvents 44 | -------------------------------------------------------------------------------- /src/string/strip.js: -------------------------------------------------------------------------------- 1 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | // Removes all non ASCII characters 3 | //------------------------------------------------------------------------------ 4 | module.exports = function(str) { 5 | 6 | var removed = [ "!","@","#","$","%","^","&","*","(",")", 7 | "[","]","{","}",".",",","/","\\","|", 8 | "'","\"",";",":","<",">","?","=","+"] 9 | 10 | var diacritics = [ 11 | [/[\300-\306]/g, "A"], 12 | [/[\340-\346]/g, "a"], 13 | [/[\310-\313]/g, "E"], 14 | [/[\350-\353]/g, "e"], 15 | [/[\314-\317]/g, "I"], 16 | [/[\354-\357]/g, "i"], 17 | [/[\322-\330]/g, "O"], 18 | [/[\362-\370]/g, "o"], 19 | [/[\331-\334]/g, "U"], 20 | [/[\371-\374]/g, "u"], 21 | [/[\321]/g, "N"], 22 | [/[\361]/g, "n"], 23 | [/[\307]/g, "C"], 24 | [/[\347]/g, "c"], 25 | ]; 26 | 27 | str += "" 28 | 29 | return ""+str.replace(/[^A-Za-z0-9\-_]/g, function(chr) { 30 | 31 | if (" " == chr) { 32 | return "_" 33 | } 34 | else if (removed.indexOf(chr) >= 0) { 35 | return "" 36 | } 37 | 38 | var ret = "" 39 | 40 | for ( var d in diacritics ) { 41 | 42 | if (diacritics[d][0].test(chr)) { 43 | ret = diacritics[d][1] 44 | break; 45 | } 46 | 47 | } 48 | 49 | return ret; 50 | 51 | }); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /gulp/compile.coffee: -------------------------------------------------------------------------------- 1 | browserify = require "browserify" 2 | error = require "./error.coffee" 3 | es = require "event-stream" 4 | gulp = require "gulp" 5 | notify = require "gulp-notify" 6 | rename = require "gulp-rename" 7 | source = require "vinyl-source-stream" 8 | streamify = require "gulp-streamify" 9 | timer = require "gulp-duration" 10 | uglify = require "gulp-uglify" 11 | 12 | gulp.task "compile", -> 13 | 14 | normal = browserify(["./src/init.coffee"]) 15 | .transform("coffeeify") 16 | .bundle() 17 | .on("error", notify.onError(error)) 18 | .pipe(source("d3plus.js")) 19 | .pipe(gulp.dest("./")) 20 | .pipe(rename("d3plus.min.js")) 21 | .pipe(streamify(uglify())) 22 | .pipe(gulp.dest("./")) 23 | .on("error", notify.onError(error)) 24 | 25 | full = browserify(["./src/libs.coffee", "./src/init.coffee"]) 26 | .transform("coffeeify") 27 | .bundle() 28 | .on("error", notify.onError(error)) 29 | .pipe(source("d3plus.full.js")) 30 | .pipe(gulp.dest("./")) 31 | .pipe(rename("d3plus.full.min.js")) 32 | .pipe(streamify(uglify())) 33 | .pipe(gulp.dest("./")) 34 | .pipe(timer("Total Build Time")) 35 | .pipe(notify( 36 | title: "D3plus" 37 | message: "Production Builds Compiled" 38 | icon: __dirname + "/../icon.png" 39 | )) 40 | .on("error", notify.onError(error)) 41 | 42 | es.merge normal, full 43 | -------------------------------------------------------------------------------- /src/viz/methods/margin.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Number, Object, String] 3 | process: (value) -> 4 | 5 | self = this 6 | sides = ["top", "right", "bottom", "left"] 7 | 8 | value = self.value if value is undefined 9 | userValue = value 10 | 11 | if typeof value is "string" 12 | 13 | value = value.split(" ") 14 | 15 | for v, i in value 16 | value[i] = parseFloat(v, 10) 17 | 18 | if value.length is 1 19 | value = value[0] 20 | else if value.length is 2 21 | value = 22 | top: value[0] 23 | right: value[1] 24 | bottom: value[0] 25 | left: value[1] 26 | else if value.length is 3 27 | value = 28 | top: value[0] 29 | right: value[1] 30 | bottom: value[2] 31 | left: value[1] 32 | else if value.length is 4 33 | value = 34 | top: value[0] 35 | right: value[1] 36 | bottom: value[2] 37 | left: value[3] 38 | else 39 | value = 0 40 | 41 | if typeof value is "number" 42 | for side in sides 43 | self[side] = value 44 | else 45 | for side of value 46 | sideIndex = sides.indexOf(side) 47 | if sideIndex >= 0 48 | sides.splice sideIndex, 1 49 | self[side] = value[side] 50 | for k in sides 51 | self[k] = 0 52 | 53 | userValue 54 | value: 0 55 | -------------------------------------------------------------------------------- /src/core/parse/nodes.js: -------------------------------------------------------------------------------- 1 | var print = require("../console/print.coffee") 2 | 3 | // Calculates node positions, if needed for network. 4 | module.exports = function(vars) { 5 | 6 | if ( vars.dev.value ) { 7 | var timerString = "analyzing node positions" 8 | print.time( timerString ) 9 | } 10 | 11 | var set = vars.nodes.value.filter(function(n){ 12 | return typeof n.x == "number" && typeof n.y == "number" 13 | }).length 14 | 15 | if (set == vars.nodes.value.length) { 16 | vars.nodes.positions = true 17 | } 18 | else { 19 | 20 | var force = d3.layout.force() 21 | .size([vars.width.viz,vars.height.viz]) 22 | .nodes(vars.nodes.value) 23 | .links(vars.edges.value) 24 | 25 | var strength = vars.edges.strength.value 26 | if (strength) { 27 | if (typeof strength === "string") { 28 | force.linkStrength(function(e){ 29 | return e[strength] 30 | }) 31 | } 32 | else { 33 | force.linkStrength(strength) 34 | } 35 | } 36 | 37 | var iterations = 50, 38 | threshold = 0.01; 39 | 40 | force.start(); // Defaults to alpha = 0.1 41 | for (var i = iterations; i > 0; --i) { 42 | force.tick(); 43 | if(force.alpha() < threshold) { 44 | break; 45 | } 46 | } 47 | force.stop(); 48 | 49 | vars.nodes.positions = true 50 | 51 | } 52 | 53 | if ( vars.dev.value ) print.timeEnd( timerString ) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/form/methods/margin.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | accepted: [Number, Object, String] 3 | process: (value) -> 4 | 5 | self = this 6 | sides = ["top", "right", "bottom", "left"] 7 | 8 | value = self.value if value is undefined 9 | userValue = value 10 | 11 | if typeof value is "string" 12 | 13 | value = value.split(" ") 14 | 15 | for v, i in value 16 | value[i] = parseFloat(v, 10) 17 | 18 | if value.length is 1 19 | value = value[0] 20 | else if value.length is 2 21 | value = 22 | top: value[0] 23 | right: value[1] 24 | bottom: value[0] 25 | left: value[1] 26 | else if value.length is 3 27 | value = 28 | top: value[0] 29 | right: value[1] 30 | bottom: value[2] 31 | left: value[1] 32 | else if value.length is 4 33 | value = 34 | top: value[0] 35 | right: value[1] 36 | bottom: value[2] 37 | left: value[3] 38 | else 39 | value = 0 40 | 41 | if typeof value is "number" 42 | for side in sides 43 | self[side] = value 44 | else 45 | for side of value 46 | sideIndex = sides.indexOf(side) 47 | if sideIndex >= 0 48 | sides.splice sideIndex, 1 49 | self[side] = value[side] 50 | for k in sides 51 | self[k] = 0 52 | 53 | userValue 54 | value: 0 55 | -------------------------------------------------------------------------------- /src/core/methods/rejected.coffee: -------------------------------------------------------------------------------- 1 | contains = require "../../array/contains.coffee" 2 | format = require "../../string/format.js" 3 | list = require "../../string/list.coffee" 4 | print = require "../console/print.coffee" 5 | 6 | module.exports = (vars, accepted, value, method, text) -> 7 | 8 | accepted = accepted(vars) if typeof accepted is "function" 9 | accepted = [accepted] if accepted not instanceof Array 10 | 11 | # Check to see if the given value is allowed. 12 | allowed = contains accepted, value 13 | 14 | # If value is not allowed, show an error message in the console. 15 | if allowed is false and value isnt undefined 16 | 17 | recs = [] 18 | val = JSON.stringify(value) 19 | val = "\"" + val + "\"" if typeof value isnt "string" 20 | 21 | for a in accepted 22 | if typeof a is "string" 23 | recs.push "\"" + a + "\"" 24 | else if typeof a is "function" 25 | recs.push a.toString().split("()")[0].substring(9) 26 | else 27 | recs.push a.toString() 28 | 29 | recs = list recs, vars.format.locale.value.ui.or 30 | 31 | if vars.type and ["mode", "shape"].indexOf(method) >= 0 32 | str = vars.format.locale.value.error.accepted 33 | app = vars.format.locale.value.visualization[vars.type.value] || vars.type.value 34 | print.warning format(str, val, method, app, recs), method 35 | else 36 | str = vars.format.locale.value.dev.accepted 37 | print.warning format(str, val, text, recs), method 38 | 39 | not allowed 40 | -------------------------------------------------------------------------------- /src/viz/types/line.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../core/fetch/value.js" 2 | graph = require "./helpers/graph/draw.coffee" 3 | dataTicks = require "./helpers/graph/dataTicks.coffee" 4 | nest = require "./helpers/graph/nest.coffee" 5 | stack = require "./helpers/graph/stack.coffee" 6 | 7 | # Line Plot 8 | line = (vars) -> 9 | 10 | graph vars, 11 | buffer: vars.axes.opposite 12 | mouse: true 13 | 14 | data = nest vars 15 | 16 | # Assign x and y to each data point 17 | for point in data 18 | for d in point.values 19 | d.d3plus.x = vars.x.scale.viz fetchValue(vars, d, vars.x.value) 20 | d.d3plus.x += vars.axes.margin.left 21 | 22 | d.d3plus.y = vars.y.scale.viz fetchValue(vars, d, vars.y.value) 23 | d.d3plus.y += vars.axes.margin.top 24 | 25 | d.d3plus.r = 2 26 | 27 | dataTicks vars 28 | 29 | if vars.axes.stacked then stack vars, data else data 30 | 31 | # Visualization Settings and Helper Functions 32 | line.requirements = ["data", "x", "y"] 33 | line.setup = (vars) -> 34 | vars.self.x scale: "discrete" unless vars.axes.discrete 35 | y = vars[vars.axes.opposite].value 36 | size = vars.size 37 | if (not y.value and size.value) or (size.changed and size.previous is y.value) 38 | vars.self[vars.axes.opposite] size.value 39 | else if (not size.value and y.value) or (y.changed and y.previous is size.value) 40 | vars.self.size y.value 41 | return 42 | line.shapes = ["line"] 43 | line.tooltip = "static" 44 | 45 | module.exports = line 46 | -------------------------------------------------------------------------------- /src/viz/types/helpers/graph/stack.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../../../core/fetch/value.js" 2 | 3 | module.exports = (vars, data) -> 4 | 5 | stacked = vars.axes.stacked 6 | flip = vars[stacked].scale.viz 0 7 | scale = vars[stacked].scale.value 8 | opposite = if stacked is "x" then "y" else "x" 9 | margin = if stacked is "y" then vars.axes.margin.top else vars.axes.margin.left 10 | offset = if scale is "share" then "expand" else "zero" 11 | 12 | stack = d3.layout.stack() 13 | .values (d) -> d.values 14 | .offset offset 15 | .x (d) -> d.d3plus[opposite] 16 | .y (d) -> flip - vars[stacked].scale.viz fetchValue vars, d, vars[stacked].value 17 | .out (d, y0, y) -> 18 | 19 | value = fetchValue vars, d, vars[stacked].value 20 | negative = value < 0 21 | 22 | if scale is "share" 23 | d.d3plus[stacked+"0"] = (1 - y0) * flip 24 | d.d3plus[stacked] = d.d3plus[stacked+"0"] - (y * flip) 25 | else 26 | d.d3plus[stacked+"0"] = flip - y0 27 | d.d3plus[stacked] = d.d3plus[stacked+"0"] - y 28 | 29 | d.d3plus[stacked] += margin 30 | d.d3plus[stacked+"0"] += margin 31 | 32 | positiveData = data.filter (d) -> 33 | fetchValue(vars, d, vars[stacked].value) > 0 34 | negativeData = data.filter (d) -> 35 | fetchValue(vars, d, vars[stacked].value) < 0 36 | 37 | positiveData = stack positiveData if positiveData.length 38 | negativeData = stack negativeData if negativeData.length 39 | 40 | positiveData.concat(negativeData) 41 | -------------------------------------------------------------------------------- /src/font/validate.coffee: -------------------------------------------------------------------------------- 1 | fontTester = require("../core/font/tester.coffee") 2 | 3 | # Given a single font or a list of font, determines which can be rendered 4 | validate = (fontList) -> 5 | 6 | fontList = fontList.split(",") unless fontList instanceof Array 7 | font.trim() for font in fontList 8 | 9 | # Check if the fontList has already been validated. 10 | fontString = fontList.join(", ") 11 | completed = validate.complete 12 | return completed[fontString] if fontString of completed 13 | 14 | testElement = (font) -> 15 | tester.append("span") 16 | .style "font-family", font 17 | .style "font-size", "32px" 18 | .style "padding", "0px" 19 | .style "margin", "0px" 20 | .text "abcdefghiABCDEFGHI_!@#$%^&*()_+1234567890" 21 | 22 | testWidth = (font, control) -> 23 | elem = testElement(font) 24 | width1 = elem.node().offsetWidth 25 | width2 = control.node().offsetWidth 26 | elem.remove() 27 | width1 isnt width2 28 | 29 | tester = fontTester("div") 30 | monospace = testElement("monospace") 31 | proportional = testElement("sans-serif") 32 | 33 | for family in fontList 34 | 35 | valid = testWidth(family + ",monospace", monospace) 36 | valid = testWidth(family + ",sans-serif", proportional) unless valid 37 | 38 | if valid 39 | valid = family 40 | break 41 | 42 | valid = "sans-serif" unless valid 43 | 44 | monospace.remove() 45 | proportional.remove() 46 | 47 | completed[fontString] = valid 48 | valid 49 | 50 | validate.complete = {} 51 | 52 | module.exports = validate 53 | -------------------------------------------------------------------------------- /src/form/methods/format.coffee: -------------------------------------------------------------------------------- 1 | formatNumber = require "../../number/format.js" 2 | locale = require "../../core/locale/locale.coffee" 3 | mergeObject = require "../../object/merge.coffee" 4 | titleCase = require "../../string/title.coffee" 5 | 6 | module.exports = 7 | accepted: [Function, String] 8 | deprecates: ["number_format", "text_format"] 9 | locale: 10 | accepted: -> d3.keys locale 11 | process: (value) -> 12 | defaultLocale = "en_US" 13 | returnObject = locale[defaultLocale] 14 | returnObject = mergeObject(returnObject, locale[value]) if value isnt defaultLocale 15 | @language = value 16 | returnObject 17 | value: "en_US" 18 | number: 19 | accepted: [false, Function] 20 | value: false 21 | process: (value, vars) -> 22 | if typeof value is "string" 23 | vars.self.format locale: value 24 | else return value if typeof value is "function" 25 | @value 26 | text: 27 | accepted: [false, Function] 28 | value: false 29 | value: (value, key, vars) -> 30 | vars = {} unless vars 31 | if vars.time and vars.time.value and key is vars.time.value 32 | f = vars.time.format.value or vars.data.time.format 33 | v = (if value.constructor is Date then value else new Date(value)) 34 | f v 35 | else if typeof value is "number" 36 | f = @number.value or formatNumber 37 | f value, key, vars 38 | else if typeof value is "string" 39 | f = @text.value or titleCase 40 | f value, key, vars 41 | else 42 | JSON.stringify value 43 | -------------------------------------------------------------------------------- /src/viz/methods/format.coffee: -------------------------------------------------------------------------------- 1 | formatNumber = require "../../number/format.js" 2 | locale = require "../../core/locale/locale.coffee" 3 | mergeObject = require "../../object/merge.coffee" 4 | titleCase = require "../../string/title.coffee" 5 | 6 | module.exports = 7 | accepted: [Function, String] 8 | deprecates: ["number_format", "text_format"] 9 | locale: 10 | accepted: -> d3.keys locale 11 | process: (value) -> 12 | defaultLocale = "en_US" 13 | returnObject = locale[defaultLocale] 14 | returnObject = mergeObject(returnObject, locale[value]) if value isnt defaultLocale 15 | @language = value 16 | returnObject 17 | value: "en_US" 18 | number: 19 | accepted: [false, Function] 20 | value: false 21 | process: (value, vars) -> 22 | if typeof value is "string" 23 | vars.self.format locale: value 24 | else return value if typeof value is "function" 25 | @value 26 | text: 27 | accepted: [false, Function] 28 | value: false 29 | value: (value, key, vars) -> 30 | vars = {} unless vars 31 | if vars.time and vars.time.value and key is vars.time.value 32 | f = vars.time.format.value or vars.data.time.format 33 | v = (if value.constructor is Date then value else new Date(value)) 34 | f v 35 | else if typeof value is "number" 36 | f = @number.value or formatNumber 37 | f value, key, vars 38 | else if typeof value is "string" 39 | f = @text.value or titleCase 40 | f value, key, vars 41 | else 42 | JSON.stringify value 43 | -------------------------------------------------------------------------------- /src/viz/types/helpers/graph/nest.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../../../core/fetch/value.js" 2 | stringStrip = require "../../../../string/strip.js" 3 | uniqueValues = require "../../../../util/uniques.coffee" 4 | 5 | module.exports = (vars, data) -> 6 | 7 | data = vars.data.viz unless data 8 | discrete = vars[vars.axes.discrete] 9 | opposite = vars[vars.axes.opposite] 10 | ticks = discrete.ticks.values 11 | offsets = 12 | x: vars.axes.margin.left 13 | y: vars.axes.margin.top 14 | 15 | d3.nest() 16 | .key (d) -> 17 | id = fetchValue vars, d, vars.id.value 18 | depth = if "depth" of d.d3plus then d.d3plus.depth else vars.depth.value 19 | "line_"+stringStrip(id)+"_"+depth 20 | .rollup (leaves) -> 21 | 22 | availables = uniqueValues leaves, discrete.value 23 | timeVar = availables[0].constructor is Date 24 | availables = availables.map((t) -> t.getTime()) if timeVar 25 | 26 | for tick, i in ticks 27 | 28 | tester = if timeVar then tick.getTime() else tick 29 | 30 | if availables.indexOf(tester) < 0 and discrete.zerofill.value 31 | 32 | obj = {d3plus: {}} 33 | obj[vars.id.value] = leaves[0][vars.id.value] 34 | obj[discrete.value] = tick 35 | obj[opposite.value] = opposite.scale.viz.domain()[1] 36 | 37 | leaves.push obj 38 | 39 | return leaves.sort (a, b) -> 40 | xsort = a[discrete.value] - b[discrete.value] 41 | ysort = a[opposite.value] - b[opposite.value] 42 | if xsort then xsort else ysort 43 | 44 | .entries data 45 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3plus", 3 | "main": "d3plus.js", 4 | "version": "1.6.2", 5 | "moduleType": ["node"], 6 | "homepage": "https://github.com/alexandersimoes/d3plus", 7 | "description": "Data visualization made easy. A javascript library that extends the popular D3.js to enable fast and beautiful visualizations.", 8 | "authors": [ 9 | "Dave Landry ", 10 | "Alexander Simoes ", 11 | "Daniel Smilkov " 12 | ], 13 | "dependencies": { 14 | "d3": "^3.4.12", 15 | "heap": "^0.2.4", 16 | "numeric": "^1.2.6", 17 | "simplify-js": "git@github.com:mourner/simplify-js.git" 18 | "static-kdtree": "git@github.com:mikolalysenko/static-kdtree.git#ce6e639c333fbab310fa44a3587b4bfdf10dbd4b" 19 | "topojson": "^1.6.18" 20 | }, 21 | "devDependencies": { 22 | "browserify": "^6.0.2", 23 | "coffee-script": "^1.8.0", 24 | "coffeeify": "^0.7.0", 25 | "connect-livereload": "^0.4.0", 26 | "event-stream": "^3.1.7", 27 | "express": "^4.9.5", 28 | "gulp": "^3.8.7", 29 | "gulp-duration": "^0.0.0", 30 | "gulp-livereload": "^2.1.0", 31 | "gulp-notify": "^2.0.0", 32 | "gulp-rename": "^1.2.0", 33 | "gulp-rimraf": "^0.1.0", 34 | "gulp-streamify": "^0.0.5", 35 | "gulp-uglify": "^1.0.1", 36 | "gulp-util": "^3.0.0", 37 | "gulp-yuidoc": "^0.1.2", 38 | "require-dir": "^0.1.0", 39 | "tiny-lr": "^0.1.4", 40 | "vinyl-source-stream": "^1.0.0", 41 | "watchify": "^2.0.0" 42 | }, 43 | "keywords": ["charts", "d3", "d3plus", "data", "visualization"], 44 | "license": "MIT" 45 | } 46 | -------------------------------------------------------------------------------- /src/viz/helpers/focus/tooltip.coffee: -------------------------------------------------------------------------------- 1 | createTooltip = require "../tooltip/create.js" 2 | fetchValue = require "../../../core/fetch/value.js" 3 | print = require "../../../core/console/print.coffee" 4 | removeTooltip = require "../../../tooltip/remove.coffee" 5 | 6 | # Creates focus tooltip, if applicable 7 | module.exports = (vars) -> 8 | 9 | focus = vars.focus 10 | 11 | if not vars.internal_error and focus.value.length is 1 and focus.value.length and not vars.small and focus.tooltip.value 12 | 13 | print.time "drawing focus tooltip" if vars.dev.value 14 | data = vars.data.pool.filter (d) -> 15 | fetchValue(vars, d, vars.id.value) is focus.value[0] 16 | 17 | if data.length >= 1 18 | data = data[0] 19 | else 20 | data = {} 21 | data[vars.id.value] = focus.value[0] 22 | 23 | offset = vars.labels.padding 24 | 25 | createTooltip 26 | anchor: "top left" 27 | arrow: false 28 | data: data 29 | fullscreen: false 30 | id: "visualization_focus" 31 | length: "long" 32 | maxheight: vars.height.viz - offset * 2 33 | mouseevents: true 34 | offset: 0 35 | vars: vars 36 | width: vars.tooltip.large 37 | x: vars.width.value - vars.margin.right - offset 38 | y: vars.margin.top + offset 39 | 40 | vars.width.viz -= (vars.tooltip.large + offset * 2) unless d3.select("div#d3plus_tooltip_id_visualization_focus").empty() 41 | 42 | print.timeEnd "drawing focus tooltip" if vars.dev.value 43 | 44 | else 45 | removeTooltip "visualization_focus" 46 | 47 | return 48 | -------------------------------------------------------------------------------- /docs/assets/js/api-filter.js: -------------------------------------------------------------------------------- 1 | YUI.add('api-filter', function (Y) { 2 | 3 | Y.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], { 4 | // -- Initializer ---------------------------------------------------------- 5 | initializer: function () { 6 | this._bindUIACBase(); 7 | this._syncUIACBase(); 8 | }, 9 | getDisplayName: function(name) { 10 | 11 | Y.each(Y.YUIDoc.meta.allModules, function(i) { 12 | if (i.name === name && i.displayName) { 13 | name = i.displayName; 14 | } 15 | }); 16 | 17 | return name; 18 | } 19 | 20 | }, { 21 | // -- Attributes ----------------------------------------------------------- 22 | ATTRS: { 23 | resultHighlighter: { 24 | value: 'phraseMatch' 25 | }, 26 | 27 | // May be set to "classes" or "modules". 28 | queryType: { 29 | value: 'classes' 30 | }, 31 | 32 | source: { 33 | valueFn: function() { 34 | var self = this; 35 | return function(q) { 36 | var data = Y.YUIDoc.meta[self.get('queryType')], 37 | out = []; 38 | Y.each(data, function(v) { 39 | if (v.toLowerCase().indexOf(q.toLowerCase()) > -1) { 40 | out.push(v); 41 | } 42 | }); 43 | return out; 44 | }; 45 | } 46 | } 47 | } 48 | }); 49 | 50 | }, '3.4.0', {requires: [ 51 | 'autocomplete-base', 'autocomplete-highlighters', 'autocomplete-sources' 52 | ]}); 53 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/mouse.coffee: -------------------------------------------------------------------------------- 1 | labels = require "./labels.js" 2 | transform = require "./transform.coffee" 3 | 4 | module.exports = (vars) -> 5 | 6 | translate = d3.event.translate 7 | scale = d3.event.scale 8 | limits = vars.zoom.bounds 9 | xoffset = (vars.width.viz - (vars.zoom.size.width * scale)) / 2 10 | xmin = (if xoffset > 0 then xoffset else 0) 11 | xmax = (if xoffset > 0 then vars.width.viz - xoffset else vars.width.viz) 12 | yoffset = (vars.height.viz - (vars.zoom.size.height * scale)) / 2 13 | ymin = (if yoffset > 0 then yoffset else 0) 14 | ymax = (if yoffset > 0 then vars.height.viz - yoffset else vars.height.viz) 15 | 16 | # Auto center visualization 17 | if translate[0] + limits[0][0] * scale > xmin 18 | translate[0] = -limits[0][0] * scale + xmin 19 | else if translate[0] + limits[1][0] * scale < xmax 20 | translate[0] = xmax - (limits[1][0] * scale) 21 | 22 | if translate[1] + limits[0][1] * scale > ymin 23 | translate[1] = -limits[0][1] * scale + ymin 24 | else if translate[1] + limits[1][1] * scale < ymax 25 | translate[1] = ymax - (limits[1][1] * scale) 26 | 27 | vars.zoom.behavior.translate(translate).scale scale 28 | 29 | vars.zoom.translate = translate 30 | vars.zoom.scale = scale 31 | 32 | if d3.event.sourceEvent.type is "wheel" 33 | delay = (if vars.draw.timing then 100 else 250) 34 | clearTimeout vars.zoom.wheel 35 | vars.zoom.wheel = setTimeout( -> 36 | labels vars 37 | , delay) 38 | else 39 | labels vars 40 | 41 | if d3.event.sourceEvent.type is "dblclick" 42 | transform vars, vars.timing.transitions 43 | else 44 | transform vars, 0 45 | -------------------------------------------------------------------------------- /src/viz/types/pie.coffee: -------------------------------------------------------------------------------- 1 | comparator = require "../../array/comparator.coffee" 2 | dataThreshold = require("../../core/data/threshold.js") 3 | fetchValue = require("../../core/fetch/value.js") 4 | groupData = require("../../core/data/group.coffee") 5 | 6 | order = {} 7 | 8 | pie = (vars) -> 9 | 10 | pieLayout = d3.layout.pie() 11 | .value (d) -> d.value 12 | .sort (a, b) -> 13 | if vars.order.value 14 | comparator a.d3plus, b.d3plus, [vars.order.value], vars.order.sort.value, [], vars 15 | else 16 | aID = fetchValue vars, a.d3plus, vars.id.value 17 | order[aID] = a.value if order[aID] is undefined 18 | bID = fetchValue vars, b.d3plus, vars.id.value 19 | order[bID] = b.value if order[bID] is undefined 20 | if order[bID] < order[aID] then -1 else 1 21 | 22 | groupedData = groupData vars, vars.data.viz, [] 23 | pieData = pieLayout groupedData 24 | returnData = [] 25 | 26 | radius = d3.min([vars.width.viz, vars.height.viz])/2 - vars.labels.padding * 2 27 | 28 | for d in pieData 29 | 30 | item = d.data.d3plus 31 | item.d3plus.startAngle = d.startAngle 32 | item.d3plus.endAngle = d.endAngle 33 | item.d3plus.r = radius 34 | item.d3plus.x = vars.width.viz/2 35 | item.d3plus.y = vars.height.viz/2 36 | 37 | returnData.push item 38 | 39 | returnData 40 | 41 | # Visualization Settings and Helper Functions 42 | pie.filter = dataThreshold 43 | pie.requirements = ["data", "size"] 44 | pie.shapes = ["arc"] 45 | pie.threshold = (vars) -> (40 * 40) / (vars.width.viz * vars.height.viz) 46 | pie.tooltip = "follow" 47 | module.exports = pie 48 | -------------------------------------------------------------------------------- /src/viz/types/scatter.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../core/fetch/value.js" 2 | graph = require "./helpers/graph/draw.coffee" 3 | print = require "../../core/console/print.coffee" 4 | sort = require "../../array/sort.coffee" 5 | ticks = require "./helpers/graph/dataTicks.coffee" 6 | 7 | # Scatterplot 8 | scatter = (vars) -> 9 | 10 | # Calculate X and Y domains, using "size" as a buffer 11 | graph vars, 12 | buffer: "size" 13 | mouse: true 14 | 15 | # Assign x, y, and radius to each data point 16 | for d in vars.data.viz 17 | d.d3plus.x = vars.x.scale.viz fetchValue(vars, d, vars.x.value) 18 | d.d3plus.x += vars.axes.margin.left 19 | 20 | d.d3plus.y = vars.y.scale.viz fetchValue(vars, d, vars.y.value) 21 | d.d3plus.y += vars.axes.margin.top 22 | 23 | if typeof vars.size.value is "number" or !vars.size.value 24 | d.d3plus.r = vars.axes.scale 0 25 | else 26 | d.d3plus.r = vars.axes.scale fetchValue(vars, d, vars.size.value) 27 | 28 | # Create data ticks 29 | ticks vars 30 | 31 | # Return the data, sorted 32 | sort vars.data.viz, vars.order.value or vars.size.value or vars.id.value, 33 | if vars.order.sort.value is "desc" then "asc" else "desc", 34 | vars.color.value or [], vars 35 | 36 | # Visualization Settings and Helper Functions 37 | scatter.fill = true 38 | scatter.requirements = ["data", "x", "y"] 39 | scatter.scale = 1.1 40 | scatter.setup = (vars) -> 41 | vars.self.x scale: "discrete" if vars.x.value is vars.time.value 42 | vars.self.y scale: "discrete" if vars.y.value is vars.time.value 43 | scatter.shapes = ["circle", "square", "donut"] 44 | scatter.tooltip = "static" 45 | 46 | module.exports = scatter 47 | -------------------------------------------------------------------------------- /src/viz/methods/draw.js: -------------------------------------------------------------------------------- 1 | var print = require("../../core/console/print.coffee"), 2 | stringFormat = require("../../string/format.js") 3 | 4 | module.exports = { 5 | "accepted" : [ undefined , Function ], 6 | "first" : true, 7 | "frozen" : false, 8 | "process" : function (value, vars) { 9 | 10 | if ( this.initialized === false ) { 11 | this.initialized = true 12 | return value 13 | } 14 | 15 | if ( value === undefined && typeof this.value === "function" ) { 16 | value = this.value 17 | } 18 | 19 | if ( vars.container.value === false ) { 20 | 21 | var str = vars.format.locale.value.dev.setContainer 22 | print.warning( str , "container" ) 23 | 24 | } 25 | else if ( vars.container.value.empty() ) { 26 | 27 | var str = vars.format.locale.value.dev.noContainer 28 | print.warning( stringFormat(str,"\""+vars.container.value+"\"") , "container" ) 29 | 30 | } 31 | else { 32 | 33 | if ( vars.dev.value ) { 34 | if ( vars.methodGroup ) { 35 | vars.methodGroup = "wait" 36 | print.groupEnd() 37 | } 38 | print.time("total draw time") 39 | } 40 | 41 | vars.container.value.call(vars.self) 42 | 43 | } 44 | 45 | if ( typeof value === "function" && vars.history.chain.length ) { 46 | 47 | var changesObject = {} 48 | changes.forEach(function(c){ 49 | var method = c.method 50 | delete c.method 51 | changesObject[method] = c 52 | }) 53 | 54 | value(changesObject) 55 | 56 | vars.history.chain = [] 57 | 58 | } 59 | 60 | return value 61 | 62 | }, 63 | "update" : true, 64 | "value" : undefined 65 | } 66 | -------------------------------------------------------------------------------- /src/viz/methods/title.coffee: -------------------------------------------------------------------------------- 1 | decoration = require "../../core/methods/font/decoration.coffee" 2 | family = require "../../core/methods/font/family.coffee" 3 | transform = require "../../core/methods/font/transform.coffee" 4 | 5 | stringStrip = require "../../string/strip.js" 6 | 7 | module.exports = 8 | accepted: [false, Function, String] 9 | font: 10 | align: "center" 11 | color: "#444444" 12 | decoration: decoration() 13 | family: family() 14 | size: 16 15 | transform: transform() 16 | weight: 400 17 | height: false 18 | link: false 19 | padding: 2 20 | position: "top" 21 | process: (value, vars) -> 22 | if vars.container.id.indexOf("default") is 0 and value 23 | id = stringStrip(value).toLowerCase() 24 | vars.self.container id: id 25 | value 26 | sub: 27 | accepted: [false, String] 28 | deprecates: "sub_title" 29 | font: 30 | align: "center" 31 | color: "#444444" 32 | decoration: decoration() 33 | family: family() 34 | size: 12 35 | transform: transform() 36 | weight: 200 37 | link: false 38 | padding: 1 39 | position: "top" 40 | value: false 41 | total: 42 | accepted: [Boolean, Object] 43 | deprecates: "total_bar" 44 | font: 45 | align: "center" 46 | color: "#444444" 47 | decoration: decoration() 48 | family: family() 49 | size: 12 50 | transform: transform() 51 | weight: 200 52 | value: false 53 | link: false 54 | padding: 1 55 | position: "top" 56 | value: false 57 | width: false 58 | value: false 59 | -------------------------------------------------------------------------------- /src/number/format.js: -------------------------------------------------------------------------------- 1 | var defaultLocale = require("../core/locale/languages/en_US.coffee") 2 | 3 | // Formats numbers to look "pretty" 4 | module.exports = function( number , key , vars ) { 5 | 6 | if ( vars && key && vars.x && vars.y && ( 7 | ( key === vars.x.value && vars.x.scale.value === "log" ) || 8 | ( key === vars.y.value && vars.y.scale.value === "log" ) ) ) { 9 | 10 | var superscript = "⁰¹²³⁴⁵⁶⁷⁸⁹" 11 | , formatPower = function(d) { 12 | return (d + "").split("").map(function(c) { 13 | return superscript[c] 14 | }).join("") 15 | } 16 | 17 | return 10 + " " + formatPower( Math.round(Math.log(number) / Math.LN10) ) 18 | 19 | } 20 | 21 | if ( "locale" in this ) { 22 | var time = this.locale.value.time 23 | } 24 | else { 25 | var time = defaultLocale.time 26 | } 27 | 28 | if ( vars && vars.time && typeof vars.time.value === "string") { 29 | time.push(vars.time.value) 30 | } 31 | 32 | if (typeof key === "string" && time.indexOf(key.toLowerCase()) >= 0) { 33 | return number 34 | } 35 | else if (number < 10 && number > -10) { 36 | return d3.round(number,2) 37 | } 38 | else if (number.toString().split(".")[0].length > 4) { 39 | var symbol = d3.formatPrefix(number).symbol 40 | symbol = symbol.replace("G", "B") // d3 uses G for giga 41 | 42 | // Format number to precision level using proper scale 43 | number = d3.formatPrefix(number).scale(number) 44 | number = parseFloat(d3.format(".3g")(number)) 45 | return number + symbol; 46 | } 47 | else if (key == "share") { 48 | return d3.format(".2f")(number) 49 | } 50 | else { 51 | return d3.format(",f")(number) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/core/fetch/color.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "./value.js" 2 | randomColor = require "../../color/random.coffee" 3 | validColor = require "../../color/validate.coffee" 4 | validObject = require "../../object/validate.coffee" 5 | 6 | # Finds an object's color and returns random if it cannot be found 7 | module.exports = (vars, id, level) -> 8 | 9 | return id.d3plus.color if id.d3plus and id.d3plus.color 10 | 11 | getRandom = (c) -> 12 | c = fetchValue(vars, c, level) if validObject(c) 13 | c = c[0] if c instanceof Array 14 | randomColor c, vars.color.scale.value 15 | 16 | level = vars.id.value unless level 17 | level = vars.id.nesting[level] if typeof level is "number" 18 | 19 | unless vars.color.value 20 | getRandom id 21 | else 22 | 23 | colors = [] 24 | i = vars.id.nesting.indexOf(level) 25 | getColor = (color) -> 26 | unless color 27 | return vars.color.valueScale(0) if vars.color.value and typeof vars.color.valueScale is "function" 28 | getRandom id 29 | else unless vars.color.valueScale 30 | if validColor(color) then color else getRandom(color) 31 | else 32 | vars.color.valueScale color 33 | 34 | while i >= 0 35 | colorLevel = vars.id.nesting[i] 36 | if validObject(id) 37 | o = (unless (colorLevel of id) then fetchValue(vars, id, colorLevel) else id) 38 | value = fetchValue(vars, o, vars.color.value, colorLevel) 39 | else 40 | value = id 41 | if value isnt undefined and value isnt null 42 | color = getColor(value) 43 | colors.push color if colors.indexOf(color) < 0 44 | i-- 45 | 46 | if colors.length is 1 then colors[0] else vars.color.missing 47 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/bounds.js: -------------------------------------------------------------------------------- 1 | var transform = require("./transform.coffee") 2 | 3 | module.exports = function( vars , b , timing ) { 4 | 5 | if (!b) { 6 | var b = vars.zoom.bounds 7 | } 8 | 9 | if (typeof timing !== "number") { 10 | var timing = vars.timing.transitions 11 | } 12 | 13 | vars.zoom.size = { 14 | "height": b[1][1]-b[0][1], 15 | "width": b[1][0]-b[0][0] 16 | } 17 | 18 | var fit = vars.coords.fit.value 19 | if (fit == "auto" || vars.types[vars.type.value].requirements.indexOf("coords") < 0) { 20 | var aspect = d3.max([vars.zoom.size.width/vars.width.viz,vars.zoom.size.height/vars.height.viz]) 21 | } 22 | else { 23 | var aspect = vars.zoom.size[fit]/vars["app_"+fit] 24 | } 25 | 26 | var min = d3.min([vars.width.viz,vars.height.viz]) 27 | 28 | var padding = vars.types[vars.type.value].zoom ? vars.coords.padding*2 : 0 29 | 30 | var scale = ((min-padding) / min) / aspect 31 | 32 | var extent = vars.zoom.behavior.scaleExtent() 33 | 34 | if (extent[0] == extent[1] || b == vars.zoom.bounds) { 35 | vars.zoom.behavior.scaleExtent([scale,scale*16]) 36 | } 37 | 38 | var max_scale = vars.zoom.behavior.scaleExtent()[1] 39 | if (scale > max_scale) { 40 | scale = max_scale 41 | } 42 | vars.zoom.scale = scale 43 | 44 | var translate = [] 45 | 46 | translate[0] = vars.width.viz/2-(vars.zoom.size.width*scale)/2-(b[0][0]*scale) 47 | translate[1] = vars.height.viz/2-(vars.zoom.size.height*scale)/2-(b[0][1]*scale) 48 | 49 | vars.zoom.translate = translate 50 | vars.zoom.behavior.translate(translate).scale(scale) 51 | 52 | vars.zoom.size = { 53 | "height": vars.zoom.bounds[1][1]-vars.zoom.bounds[0][1], 54 | "width": vars.zoom.bounds[1][0]-vars.zoom.bounds[0][0] 55 | } 56 | 57 | transform(vars,timing) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/viz/types/tree_map.coffee: -------------------------------------------------------------------------------- 1 | dataThreshold = require("../../core/data/threshold.js") 2 | groupData = require("../../core/data/group.coffee") 3 | mergeObject = require("../../object/merge.coffee") 4 | 5 | tree_map = (vars) -> 6 | 7 | groupedData = groupData(vars, vars.data.viz) 8 | 9 | # Pass data through the D3js .treemap() layout. 10 | data = d3.layout.treemap() 11 | .mode vars.type.mode.value 12 | .round true 13 | .size [vars.width.viz, vars.height.viz] 14 | .children (d) -> d.values 15 | .padding 1 16 | .sort (a, b) -> 17 | sizeDiff = a.value - b.value 18 | if sizeDiff is 0 then a.id < b.id else sizeDiff 19 | .nodes 20 | name: "root" 21 | values: groupedData 22 | .filter (d) -> not d.values and d.area 23 | 24 | # If the "data" array has entries... 25 | if data.length 26 | 27 | # Create the "root" node to use when calculating share percentage. 28 | root = data[0] 29 | root = root.parent while root.parent 30 | 31 | # Calculate the position, size, and share percentage of each square. 32 | returnData = [] 33 | for d in data 34 | 35 | d.d3plus.d3plus = mergeObject d.d3plus.d3plus, 36 | x: d.x + d.dx / 2 37 | y: d.y + d.dy / 2 38 | width: d.dx 39 | height: d.dy 40 | share: d.value / root.value 41 | 42 | returnData.push d.d3plus 43 | 44 | # Return the data array. 45 | returnData 46 | 47 | # Visualization Settings and Helper Functions 48 | tree_map.filter = dataThreshold 49 | tree_map.modes = ["squarify", "slice", "dice", "slice-dice"] 50 | tree_map.requirements = ["data", "size"] 51 | tree_map.shapes = ["square"] 52 | tree_map.threshold = (vars) -> (40 * 40) / (vars.width.viz * vars.height.viz) 53 | tree_map.tooltip = "follow" 54 | 55 | module.exports = tree_map 56 | -------------------------------------------------------------------------------- /src/form/methods/data.js: -------------------------------------------------------------------------------- 1 | var d3selection = require("../../util/d3selection.coffee"), 2 | process = require("../../core/methods/process/data.coffee") 3 | 4 | module.exports = { 5 | "accepted" : [ false , Array , Function , String ], 6 | "delimiter" : { 7 | "accepted" : [ String ], 8 | "value" : "|" 9 | }, 10 | "element": { 11 | "process": function(value, vars) { 12 | 13 | if ( d3selection(value) ) { 14 | var element = value 15 | } 16 | else if (typeof value === "string" && !d3.select(value).empty()) { 17 | var element = d3.select(value) 18 | } 19 | else { 20 | var element = false 21 | } 22 | 23 | if (element) { 24 | 25 | vars.self.container(d3.select(element.node().parentNode)) 26 | 27 | element 28 | .style("position","absolute","important") 29 | .style("clip","rect(1px 1px 1px 1px)","important") 30 | .style("clip","rect(1px, 1px, 1px, 1px)","important") 31 | .style("width","1px","important") 32 | .style("height","1px","important") 33 | .style("margin","-1px","important") 34 | .style("padding","0","important") 35 | .style("border","0","important") 36 | .style("overflow","hidden","important") 37 | 38 | } 39 | 40 | return element 41 | 42 | }, 43 | "value": false 44 | }, 45 | "filetype" : { 46 | "accepted" : [false, "json", "xml", "html", "csv", "dsv", "tsv", "txt"], 47 | "value" : false 48 | }, 49 | "filters" : [], 50 | "mute" : [], 51 | "process" : function(value, vars) { 52 | 53 | if ( vars.container.id === "default" && value.length ) { 54 | vars.self.container({"id": "default"+value.length}) 55 | } 56 | 57 | return process(value, vars, this) 58 | }, 59 | "solo" : [], 60 | "value" : false 61 | } 62 | -------------------------------------------------------------------------------- /src/viz/methods/csv.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../core/fetch/value.js" 2 | ie = require "../../client/ie.js" 3 | stringStrip = require "../../string/strip.js" 4 | 5 | module.exports = 6 | accepted: [undefined, Array, String] 7 | chainable: false 8 | data: [] 9 | process: (value, vars) -> 10 | 11 | return [] if vars.returned is undefined 12 | 13 | value = value or vars.cols.value 14 | 15 | if value instanceof Array 16 | columns = value 17 | else if typeof value is "string" 18 | columns = [value] 19 | 20 | csv_to_return = [] 21 | titles = [] 22 | title = stringStrip vars.title.value or "My D3plus App Data" 23 | 24 | unless columns 25 | columns = [vars.id.value] 26 | columns.push vars.time.value if vars.time.value 27 | columns.push vars.size.value if vars.size.value 28 | columns.push vars.text.value if vars.text.value 29 | 30 | for c in columns 31 | titles.push vars.format.value(c) 32 | 33 | csv_to_return.push titles 34 | for n in vars.returned.nodes.forEach 35 | arr = [] 36 | for c in columns 37 | arr.push fetchValue(vars, n, c) 38 | csv_to_return.push arr 39 | 40 | csv_data = "data:text/csv;charset=utf-8," 41 | for c, i in csv_to_return 42 | dataString = c.join(",") 43 | csv_data += (if i < csv_to_return.length then dataString + "\n" else dataString) 44 | 45 | if ie 46 | blob = new Blob [csv_data], {type: "text/csv;charset=utf-8;"} 47 | navigator.msSaveBlob blob, title + ".csv" 48 | else 49 | encodedUri = encodeURI(csv_data) 50 | link = document.createElement("a") 51 | link.setAttribute "href", encodedUri 52 | link.setAttribute "download", title + ".csv" 53 | link.click() 54 | 55 | @data = csv_to_return 56 | columns 57 | value: undefined 58 | -------------------------------------------------------------------------------- /src/core/data/color.js: -------------------------------------------------------------------------------- 1 | var buckets = require("../../util/buckets.coffee"), 2 | fetchValue = require("../fetch/value.js"), 3 | print = require("../console/print.coffee") 4 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | // Sets color range of data, if applicable 6 | //------------------------------------------------------------------- 7 | module.exports = function(vars) { 8 | 9 | if ( vars.dev.value ) print.time("getting color data range") 10 | 11 | var data_range = [] 12 | vars.data.pool.forEach(function(d){ 13 | var val = parseFloat(fetchValue(vars,d,vars.color.value)) 14 | if (typeof val == "number" && !isNaN(val) && data_range.indexOf(val) < 0) data_range.push(val) 15 | }) 16 | 17 | if ( vars.dev.value ) print.timeEnd("getting color data range") 18 | 19 | if (data_range.length > 1) { 20 | 21 | var data_domain = null 22 | 23 | if ( vars.dev.value ) print.time("calculating color scale") 24 | 25 | data_range = d3.extent(data_range) 26 | 27 | if (data_range[0] < 0 && data_range[1] > 0) { 28 | var color_range = vars.color.range 29 | if (color_range.length == 3) { 30 | data_range.push(data_range[1]) 31 | data_range[1] = 0 32 | } 33 | } 34 | else if (data_range[1] > 0 && data_range[0] >= 0) { 35 | var color_range = vars.color.heatmap 36 | data_range = buckets(data_range,color_range.length) 37 | } 38 | else { 39 | var color_range = vars.color.range.slice(0) 40 | if (data_range[0] < 0) { 41 | color_range.pop() 42 | } 43 | else { 44 | color_range.shift() 45 | } 46 | } 47 | 48 | vars.color.valueScale = d3.scale.sqrt() 49 | .domain(data_range) 50 | .range(color_range) 51 | .interpolate(d3.interpolateRgb) 52 | 53 | if ( vars.dev.value ) print.timeEnd("calculating color scale") 54 | 55 | } 56 | else { 57 | vars.color.valueScale = null 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/core/console/wiki.coffee: -------------------------------------------------------------------------------- 1 | module.exports = 2 | active: "Segmenting-Data#active" 3 | aggs: "Custom-Aggregations" 4 | alt: "Alt-Text-Parameters" 5 | attrs: "Attribute-Data#axes" 6 | axes: "Axis-Parameters" 7 | background: "Background" 8 | color: "Color-Parameters" 9 | container: "Container-Element" 10 | coords: "Geography-Data" 11 | csv: "CSV-Export" 12 | data: "Data-Points" 13 | depth: "Visible-Depth" 14 | descs: "Value-Definitions" 15 | dev: "Verbose-Mode" 16 | draw: "Draw" 17 | edges: "Edges-List" 18 | error: "Custom-Error-Message" 19 | focus: "Focus-Element" 20 | font: "Font-Styles" 21 | footer: "Custom-Footer" 22 | format: "Value-Formatting" 23 | height: "Height" 24 | history: "User-History" 25 | hover: "Hover-Element" 26 | icon: "Icon-Parameters" 27 | id: "Unique-ID" 28 | keywords: "Keyword-Parameters" 29 | labels: "Data-Labels" 30 | legend: "Legend" 31 | links: "Link-Styles" 32 | margin: "Outer-Margins" 33 | messages: "Status-Messages" 34 | method: "Methods" 35 | nodes: "Node-Positions" 36 | open: "Open" 37 | order: "Data-Ordering" 38 | remove: "Remove" 39 | search: "Search-Box" 40 | select: "Selecting-Elements#select" 41 | selectAll: "Selecting-Elements#selectall" 42 | shape: "Data-Shapes" 43 | size: "Size-Parameters" 44 | temp: "Segmenting-Data#temp" 45 | text: "Text-Parameters" 46 | time: "Time-Parameters" 47 | timeline: "Timeline" 48 | timing: "Animation-Timing" 49 | title: "Custom-Titles" 50 | tooltip: "Tooltip-Parameters" 51 | total: "Segmenting-Data#total" 52 | type: "Output-Type" 53 | ui: "Custom-Interface" 54 | width: "Width" 55 | x: "Axis-Parameters" 56 | y: "Axis-Parameters" 57 | zoom: "Zooming" 58 | -------------------------------------------------------------------------------- /src/data/lof.coffee: -------------------------------------------------------------------------------- 1 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | # Finds outliers in n-dim data using the Local Outlier Factor algorithm 3 | # See: 4 | # http://en.wikipedia.org/wiki/Local_outlier_factor 5 | #------------------------------------------------------------------------------ 6 | 7 | kdtree = require 'static-kdtree' 8 | 9 | # points is an array of n-dimensional points. Each point is an array of length n 10 | 11 | # K is the number of nearest neighbors to look for when comparing densities. Default value is 10 12 | 13 | # Returns an array of [index, lof] tuples, where index is the index of the point in the original array 14 | # and lof is the local outlier factor for that point. The array is ordered by descreasing order of LOF 15 | # so the outliers are in the beginning of the array. 16 | 17 | module.exports = (points, K=10) -> 18 | tree = kdtree points # construct a kd-tree 19 | neighbors = (tree.knn(p, K+1)[1...] for p in points) # get the k nearest neighbors for each point 20 | 21 | # calculate the squared euclidean distance between points p1 and p2 22 | sqDist = (i, j) -> 23 | A = points[i] 24 | B = points[j] 25 | dist = 0 26 | for i in [0...A.length] 27 | delta = A[i] - B[i] 28 | dist += delta * delta 29 | return dist 30 | 31 | # pre-compute kdist for all points 32 | kdists = (sqDist i, neighbors[i][K-1] for i in [0...points.length]) 33 | 34 | # reachability distance 35 | reachDist = (i, j) -> Math.max sqDist(i, j), kdists[j] 36 | 37 | # local reachability density 38 | ldr = (i) -> 39 | rDist = 0 40 | rDist += reachDist i, j for j in neighbors[i] 41 | return K / rDist 42 | 43 | # pre-compute lrd for all points 44 | ldrs = (ldr i for i in [0...points.length]) 45 | 46 | result = for i in [0...points.length] 47 | avg_lrd = 0 48 | avg_lrd += ldrs[j] for j in neighbors[i] 49 | avg_lrd /= K 50 | [i, avg_lrd / ldrs[i]] 51 | 52 | result.sort (a,b) -> b[1] - a[1] 53 | -------------------------------------------------------------------------------- /src/form/methods/draw.js: -------------------------------------------------------------------------------- 1 | var d3selection = require("../../util/d3selection.coffee"), 2 | parseElement = require("../../core/parse/element.js"), 3 | print = require("../../core/console/print.coffee"), 4 | stringFormat = require("../../string/format.js") 5 | 6 | module.exports = { 7 | "accepted" : [ undefined , Function ], 8 | "first" : true, 9 | "frozen" : false, 10 | "process" : function (value, vars) { 11 | 12 | if ( this.initialized === false ) { 13 | this.initialized = true 14 | return value 15 | } 16 | 17 | if (vars.data.value && (!(vars.data.value instanceof Array) || d3selection(vars.data.value))) { 18 | vars.data.value = parseElement( vars ) 19 | } 20 | 21 | if ( value === undefined && typeof this.value === "function" ) { 22 | value = this.value 23 | } 24 | 25 | if ( vars.container.value === false ) { 26 | 27 | var str = vars.format.locale.value.dev.setContainer 28 | print.warning( str , "container" ) 29 | 30 | } 31 | else if ( vars.container.value.empty() ) { 32 | 33 | var str = vars.format.locale.value.dev.noContainer 34 | print.warning( stringFormat(str,"\""+vars.container.value+"\"") , "container" ) 35 | 36 | } 37 | else { 38 | 39 | if ( vars.dev.value ) { 40 | if ( vars.methodGroup ) { 41 | vars.methodGroup = "wait" 42 | print.groupEnd() 43 | } 44 | print.time("total draw time") 45 | } 46 | 47 | vars.container.value.call(vars.self) 48 | 49 | } 50 | 51 | if ( typeof value === "function" && vars.history.chain.length ) { 52 | 53 | var changesObject = {} 54 | changes.forEach(function(c){ 55 | var method = c.method 56 | delete c.method 57 | changesObject[method] = c 58 | }) 59 | 60 | value(changesObject) 61 | 62 | vars.history.chain = [] 63 | 64 | } 65 | 66 | return value 67 | 68 | }, 69 | "update" : true, 70 | "value" : undefined 71 | } 72 | -------------------------------------------------------------------------------- /src/geom/offset.coffee: -------------------------------------------------------------------------------- 1 | # Gives X and Y offset based off angle and shape 2 | module.exports = (radians, distance, shape) -> 3 | 4 | coords = 5 | x: 0 6 | y: 0 7 | 8 | radians = Math.PI * 2 + radians if radians < 0 9 | 10 | if shape is "square" 11 | diagonal = 45 * (Math.PI / 180) 12 | if radians <= Math.PI 13 | if radians < (Math.PI / 2) 14 | if radians < diagonal 15 | coords.x += distance 16 | oppositeLegLength = Math.tan(radians) * distance 17 | coords.y += oppositeLegLength 18 | else 19 | coords.y += distance 20 | adjacentLegLength = distance / Math.tan(radians) 21 | coords.x += adjacentLegLength 22 | else 23 | if radians < (Math.PI - diagonal) 24 | coords.y += distance 25 | adjacentLegLength = distance / Math.tan(Math.PI - radians) 26 | coords.x -= adjacentLegLength 27 | else 28 | coords.x -= distance 29 | oppositeLegLength = Math.tan(Math.PI - radians) * distance 30 | coords.y += oppositeLegLength 31 | else 32 | if radians < (3 * Math.PI / 2) 33 | if radians < (diagonal + Math.PI) 34 | coords.x -= distance 35 | oppositeLegLength = Math.tan(radians - Math.PI) * distance 36 | coords.y -= oppositeLegLength 37 | else 38 | coords.y -= distance 39 | adjacentLegLength = distance / Math.tan(radians - Math.PI) 40 | coords.x -= adjacentLegLength 41 | else 42 | if radians < (2 * Math.PI - diagonal) 43 | coords.y -= distance 44 | adjacentLegLength = distance / Math.tan(2 * Math.PI - radians) 45 | coords.x += adjacentLegLength 46 | else 47 | coords.x += distance 48 | oppositeLegLength = Math.tan(2 * Math.PI - radians) * distance 49 | coords.y -= oppositeLegLength 50 | else 51 | coords.x += distance * Math.cos(radians) 52 | coords.y += distance * Math.sin(radians) 53 | 54 | coords 55 | -------------------------------------------------------------------------------- /src/form/types/button/functions/color.js: -------------------------------------------------------------------------------- 1 | var legible = require("../../../../color/legible.coffee"), 2 | lighter = require("../../../../color/lighter.coffee"), 3 | textColor = require("../../../../color/text.coffee") 4 | 5 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | // Defines button color 7 | //------------------------------------------------------------------------------ 8 | module.exports = function ( elem , vars ) { 9 | 10 | elem 11 | .style("background-color",function(d){ 12 | 13 | if ( vars.focus.value !== d[vars.id.value] ) { 14 | 15 | if ( vars.hover.value === d[vars.id.value] ) { 16 | return lighter(vars.ui.color.secondary.value,.25) 17 | } 18 | else { 19 | return vars.ui.color.secondary.value 20 | } 21 | 22 | } 23 | else { 24 | 25 | if ( vars.hover.value === d[vars.id.value] ) { 26 | return d3.rgb(vars.ui.color.primary.value).darker(0.15).toString() 27 | } 28 | else { 29 | return vars.ui.color.primary.value 30 | } 31 | 32 | } 33 | 34 | }) 35 | .style("color",function(d){ 36 | 37 | var image = d[vars.icon.value] && vars.data.viz.length < vars.data.large 38 | 39 | if ( vars.focus.value === d[vars.id.value] ) { 40 | var opacity = 1 41 | } 42 | else { 43 | var opacity = 0.75 44 | } 45 | 46 | if ( vars.focus.value === d[vars.id.value] && d[vars.color.value] && !image ) { 47 | var color = legible(d[vars.color.value]) 48 | } 49 | else if ( vars.focus.value === d[vars.id.value] ) { 50 | var color = textColor(vars.ui.color.primary.value) 51 | } 52 | else { 53 | var color = textColor(vars.ui.color.secondary.value) 54 | } 55 | 56 | var color = d3.rgb(color) 57 | 58 | return "rgba("+color.r+","+color.g+","+color.b+","+opacity+")" 59 | 60 | }) 61 | .style("border-color",vars.ui.color.secondary.value) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/viz/types/helpers/graph/dataTicks.coffee: -------------------------------------------------------------------------------- 1 | color = require "../../../../core/fetch/color.coffee" 2 | legible = require "../../../../color/legible.coffee" 3 | 4 | module.exports = (vars) -> 5 | 6 | data = if vars.axes.stacked then [] else vars.data.viz 7 | 8 | style = (line, axis) -> 9 | line 10 | .attr "x1", (d) -> 11 | if axis is "y" then -2 else d.d3plus.x - vars.axes.margin.left 12 | .attr "x2", (d) -> 13 | if axis is "y" then -8 else d.d3plus.x - vars.axes.margin.left 14 | .attr "y1", (d) -> 15 | if axis is "x" then vars.axes.height + 2 else d.d3plus.y - vars.axes.margin.top 16 | .attr "y2", (d) -> 17 | if axis is "x" then vars.axes.height + 8 else d.d3plus.y - vars.axes.margin.top 18 | .style "stroke", (d) -> legible color vars, d 19 | .style "stroke-width", vars.data.stroke.width 20 | .attr "shape-rendering", vars.shape.rendering.value 21 | 22 | ticks = vars.group.select("g#d3plus_graph_plane").selectAll "g.d3plus_data_tick" 23 | .data data, (d) -> 24 | mod = if vars.axes.discrete then "_"+d.d3plus[vars.axes.discrete] else "" 25 | "tick_" + d[vars.id.value] + "_" + d.d3plus.depth + mod 26 | 27 | ticks.enter().append "g" 28 | .attr "class", "d3plus_data_tick" 29 | .attr "opacity", 0 30 | 31 | for axis in ["x","y"] 32 | 33 | axisData = if axis isnt vars.axes.discrete then data else [] 34 | 35 | tick = ticks.selectAll "line.d3plus_data_"+axis 36 | .data axisData, (d) -> 37 | mod = if vars.axes.discrete then "_"+d.d3plus[vars.axes.discrete] else "" 38 | "tick_" + d[vars.id.value] + "_" + d.d3plus.depth + mod 39 | 40 | tick.enter().append("line") 41 | .attr "class","d3plus_data_"+axis 42 | .call style, axis 43 | 44 | tick.transition().duration vars.draw.timing 45 | .call style, axis 46 | 47 | ticks.transition().duration vars.draw.timing 48 | .attr("opacity",1) 49 | 50 | ticks.exit().transition().duration vars.draw.timing 51 | .attr("opacity",0).remove() 52 | 53 | return 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3plus", 3 | "version": "1.6.2", 4 | "description": "Data visualization made easy. A javascript library that extends the popular D3.js to enable fast and beautiful visualizations.", 5 | "main": "d3plus.js", 6 | "devDependencies": { 7 | "browserify": "^6.0.2", 8 | "coffee-script": "^1.8.0", 9 | "coffeeify": "^0.7.0", 10 | "connect-livereload": "^0.4.0", 11 | "event-stream": "^3.1.7", 12 | "express": "^4.9.5", 13 | "gulp": "^3.8.7", 14 | "gulp-duration": "^0.0.0", 15 | "gulp-livereload": "^2.1.0", 16 | "gulp-notify": "^2.0.0", 17 | "gulp-rename": "^1.2.0", 18 | "gulp-rimraf": "^0.1.0", 19 | "gulp-streamify": "^0.0.5", 20 | "gulp-uglify": "^1.0.1", 21 | "gulp-util": "^3.0.0", 22 | "gulp-yuidoc": "^0.1.2", 23 | "require-dir": "^0.1.0", 24 | "tiny-lr": "^0.1.4", 25 | "vinyl-source-stream": "^1.0.0", 26 | "watchify": "^2.0.0" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/alexandersimoes/d3plus.git" 31 | }, 32 | "keywords": [ 33 | "charts", 34 | "d3", 35 | "d3plus", 36 | "data", 37 | "visualization" 38 | ], 39 | "author": { 40 | "name": "Dave Landry", 41 | "email": "landry.dave@gmail.com", 42 | "url": "http://www.dave-landry.com" 43 | }, 44 | "contributors": [ 45 | { 46 | "name": "Alexander Simoes", 47 | "email": "alexandersimoes@gmail.com", 48 | "url": "http://www.alexandersimoes.com" 49 | }, 50 | { 51 | "name": "Daniel Smilkov", 52 | "email": "dsmilkov@gmail.com", 53 | "url": "http://smilkov.com" 54 | } 55 | ], 56 | "license": "MIT", 57 | "bugs": { 58 | "url": "https://github.com/alexandersimoes/d3plus/issues", 59 | "email": "landry.dave@gmail.com" 60 | }, 61 | "homepage": "http://www.d3plus.org", 62 | "dependencies": { 63 | "d3": "^3.4.12", 64 | "heap": "^0.2.4", 65 | "numeric": "^1.2.6", 66 | "simplify-js": "^1.2.1", 67 | "static-kdtree": "^1.0.1", 68 | "topojson": "^1.6.18" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/viz/methods/edges.js: -------------------------------------------------------------------------------- 1 | var process = require("../../core/methods/process/data.coffee") 2 | 3 | module.exports = { 4 | "accepted": [false, Array, Function, String], 5 | "arrows": { 6 | "accepted": [ Boolean , Number ], 7 | "direction": { 8 | "accepted": [ "source" , "target" ], 9 | "value": "target" 10 | }, 11 | "value": false 12 | }, 13 | "color": "#d0d0d0", 14 | "connections": function(focus,id,objects) { 15 | 16 | var self = this 17 | 18 | if (!self.value) { 19 | return [] 20 | } 21 | 22 | if (!id) var id = "id" 23 | 24 | var edges = self.restricted || self.value, 25 | targets = [] 26 | 27 | if (!focus) { 28 | return edges 29 | } 30 | 31 | var connections = edges.filter(function(edge){ 32 | 33 | var match = false 34 | 35 | if (edge[self.source][id] == focus) { 36 | match = true 37 | if (objects) { 38 | targets.push(edge[self.target]) 39 | } 40 | } 41 | else if (edge[self.target][id] == focus) { 42 | match = true 43 | if (objects) { 44 | targets.push(edge[self.source]) 45 | } 46 | } 47 | 48 | return match 49 | 50 | }) 51 | 52 | return objects ? targets : connections 53 | 54 | }, 55 | "delimiter": { 56 | "accepted": [ String ], 57 | "value": "|" 58 | }, 59 | "filetype": { 60 | "accepted": [false, "json", "xml","html", "csv", "dsv", "tsv", "txt"], 61 | "value": false 62 | }, 63 | "interpolate": { 64 | "accepted": ["basis", "cardinal", "linear", "monotone", "step"], 65 | "value": "basis" 66 | }, 67 | "label": false, 68 | "large": 100, 69 | "limit": { 70 | "accepted": [false, Function, Number], 71 | "value": false 72 | }, 73 | "opacity": 1, 74 | "process": process, 75 | "size": false, 76 | "source": "source", 77 | "strength": { 78 | "accepted": [false, Function, Number, String], 79 | "value": false 80 | }, 81 | "target": "target", 82 | "value": false, 83 | "width": 1 84 | } 85 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/cross.js: -------------------------------------------------------------------------------- 1 | var shapeStyle = require("./style.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Draws "square" and "circle" shapes using svg:rect 4 | //------------------------------------------------------------------------------ 5 | module.exports = function(vars,selection,enter,exit) { 6 | 7 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8 | // Initialize check scale on enter and exit. 9 | //---------------------------------------------------------------------------- 10 | function init(paths){ 11 | paths.attr("d", d3.svg.symbol().type("cross").size(10)) 12 | } 13 | 14 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | // Change scale of check on update. 16 | //--------------------------------------------------------------------------- 17 | function update(paths){ 18 | paths.attr("d", d3.svg.symbol().type("cross").size(function(d){ 19 | var smaller_dim = Math.min(d.d3plus.width, d.d3plus.height); 20 | return d3.scale.pow().exponent(2)(smaller_dim/2); 21 | })) 22 | } 23 | 24 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 25 | // "paths" Enter 26 | //---------------------------------------------------------------------------- 27 | enter.append("path").attr("class","d3plus_data") 28 | .call(init) 29 | .call(shapeStyle,vars) 30 | 31 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 32 | // "paths" Update 33 | //---------------------------------------------------------------------------- 34 | selection.selectAll("path.d3plus_data") 35 | .data(function(d) { 36 | return [d]; 37 | }) 38 | 39 | if (vars.draw.timing) { 40 | selection.selectAll("path.d3plus_data") 41 | .transition().duration(vars.draw.timing) 42 | .call(update) 43 | .call(shapeStyle,vars) 44 | } 45 | else { 46 | selection.selectAll("path.d3plus_data") 47 | .call(update) 48 | .call(shapeStyle,vars) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/core/data/load.coffee: -------------------------------------------------------------------------------- 1 | print = require "../console/print.coffee" 2 | validObject = require "../../object/validate.coffee" 3 | 4 | # Load Data using JSON 5 | module.exports = (vars, key, next) -> 6 | 7 | print.time "loading " + key if vars.dev.value 8 | 9 | url = vars[key].url 10 | 11 | unless vars[key].filetype.value 12 | 13 | fileType = url.slice(url.length - 5).split(".") 14 | 15 | if fileType.length > 1 16 | fileType = fileType[1] 17 | else 18 | fileType = false 19 | 20 | if fileType 21 | fileType = "text" if fileType is "txt" 22 | fileType = "json" if vars[key].filetype.accepted.indexOf(fileType) < 0 23 | else 24 | fileType = "json" 25 | 26 | else 27 | fileType = vars[key].filetype.value 28 | 29 | if fileType is "dsv" 30 | parser = d3.dsv(vars[key].delimiter.value, "text/plain") 31 | else 32 | parser = d3[fileType] 33 | 34 | parser url, (error, data) -> 35 | 36 | if not error and data 37 | 38 | if typeof vars[key].callback is "function" 39 | ret = vars[key].callback(data) 40 | if ret 41 | if validObject(ret) and key of ret 42 | for k of ret 43 | vars[k].value = ret[k] if k of vars 44 | else 45 | vars[key].value = ret 46 | else 47 | vars[key].value = data 48 | 49 | if [ "json" ].indexOf(fileType) < 0 50 | vars[key].value.forEach (d) -> 51 | for k of d 52 | unless isNaN(d[k]) 53 | d[k] = parseFloat(d[k]) 54 | else if d[k].toLowerCase() is "false" 55 | d[k] = false 56 | else if d[k].toLowerCase() is "true" 57 | d[k] = true 58 | else if d[k].toLowerCase() is "null" 59 | d[k] = null 60 | else d[k] = undefined if d[k].toLowerCase() is "undefined" 61 | 62 | vars[key].changed = true 63 | vars[key].loaded = true 64 | 65 | else 66 | vars.internal_error = "Could not load data from: \"" + url + "\"" 67 | 68 | print.time "loading " + key if vars.dev.value 69 | next() 70 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/diamond.js: -------------------------------------------------------------------------------- 1 | var shapeStyle = require("./style.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Draws "square" and "circle" shapes using svg:rect 4 | //------------------------------------------------------------------------------ 5 | module.exports = function(vars,selection,enter,exit) { 6 | 7 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8 | // Initialize check scale on enter and exit. 9 | //---------------------------------------------------------------------------- 10 | function init(paths){ 11 | paths.attr("d", d3.svg.symbol().type("diamond").size(10)) 12 | } 13 | 14 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | // Change scale of check on update. 16 | //--------------------------------------------------------------------------- 17 | function update(paths){ 18 | paths.attr("d", d3.svg.symbol().type("diamond").size(function(d){ 19 | var smaller_dim = Math.min(d.d3plus.width, d.d3plus.height); 20 | return d3.scale.pow().exponent(2)(smaller_dim/2); 21 | })) 22 | } 23 | 24 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 25 | // "paths" Enter 26 | //---------------------------------------------------------------------------- 27 | enter.append("path").attr("class","d3plus_data") 28 | .call(init) 29 | .call(shapeStyle,vars) 30 | 31 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 32 | // "paths" Update 33 | //---------------------------------------------------------------------------- 34 | selection.selectAll("path.d3plus_data") 35 | .data(function(d) { 36 | return [d]; 37 | }) 38 | 39 | if (vars.draw.timing) { 40 | selection.selectAll("path.d3plus_data") 41 | .transition().duration(vars.draw.timing) 42 | .call(update) 43 | .call(shapeStyle,vars) 44 | } 45 | else { 46 | selection.selectAll("path.d3plus_data") 47 | .call(update) 48 | .call(shapeStyle,vars) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/triangle_up.js: -------------------------------------------------------------------------------- 1 | var shapeStyle = require("./style.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Draws "square" and "circle" shapes using svg:rect 4 | //------------------------------------------------------------------------------ 5 | module.exports = function(vars,selection,enter,exit) { 6 | 7 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8 | // Initialize check scale on enter and exit. 9 | //---------------------------------------------------------------------------- 10 | function init(paths){ 11 | paths.attr("d", d3.svg.symbol().type("triangle-up").size(10)) 12 | } 13 | 14 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | // Change scale of check on update. 16 | //--------------------------------------------------------------------------- 17 | function update(paths){ 18 | paths.attr("d", d3.svg.symbol().type("triangle-up").size(function(d){ 19 | var smaller_dim = Math.min(d.d3plus.width, d.d3plus.height); 20 | return d3.scale.pow().exponent(2)(smaller_dim/2); 21 | })) 22 | } 23 | 24 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 25 | // "paths" Enter 26 | //---------------------------------------------------------------------------- 27 | enter.append("path").attr("class","d3plus_data") 28 | .call(init) 29 | .call(shapeStyle,vars) 30 | 31 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 32 | // "paths" Update 33 | //---------------------------------------------------------------------------- 34 | selection.selectAll("path.d3plus_data") 35 | .data(function(d) { 36 | return [d]; 37 | }) 38 | 39 | if (vars.draw.timing) { 40 | selection.selectAll("path.d3plus_data") 41 | .transition().duration(vars.draw.timing) 42 | .call(update) 43 | .call(shapeStyle,vars) 44 | } 45 | else { 46 | selection.selectAll("path.d3plus_data") 47 | .call(update) 48 | .call(shapeStyle,vars) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/triangle_down.js: -------------------------------------------------------------------------------- 1 | var shapeStyle = require("./style.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Draws "square" and "circle" shapes using svg:rect 4 | //------------------------------------------------------------------------------ 5 | module.exports = function(vars,selection,enter,exit) { 6 | 7 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 8 | // Initialize check scale on enter and exit. 9 | //---------------------------------------------------------------------------- 10 | function init(paths){ 11 | paths.attr("d", d3.svg.symbol().type("triangle-down").size(10)) 12 | } 13 | 14 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | // Change scale of check on update. 16 | //--------------------------------------------------------------------------- 17 | function update(paths){ 18 | paths.attr("d", d3.svg.symbol().type("triangle-down").size(function(d){ 19 | var smaller_dim = Math.min(d.d3plus.width, d.d3plus.height); 20 | return d3.scale.pow().exponent(2)(smaller_dim/2); 21 | })) 22 | } 23 | 24 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 25 | // "paths" Enter 26 | //---------------------------------------------------------------------------- 27 | enter.append("path").attr("class","d3plus_data") 28 | .call(init) 29 | .call(shapeStyle,vars) 30 | 31 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 32 | // "paths" Update 33 | //---------------------------------------------------------------------------- 34 | selection.selectAll("path.d3plus_data") 35 | .data(function(d) { 36 | return [d]; 37 | }) 38 | 39 | if (vars.draw.timing) { 40 | selection.selectAll("path.d3plus_data") 41 | .transition().duration(vars.draw.timing) 42 | .call(update) 43 | .call(shapeStyle,vars) 44 | } 45 | else { 46 | selection.selectAll("path.d3plus_data") 47 | .call(update) 48 | .call(shapeStyle,vars) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/textwrap/helpers/wrap.coffee: -------------------------------------------------------------------------------- 1 | flow = require "./flow.coffee" 2 | fontSizes = require "../../font/sizes.coffee" 3 | flow = require "./flow.coffee" 4 | 5 | # Flows the text into the container 6 | wrap = (vars) -> 7 | 8 | if vars.text.phrases.length 9 | 10 | vars.text.current = vars.text.phrases.shift() + "" 11 | vars.text.words = vars.text.current.match vars.text.break 12 | 13 | if vars.resize.value then resize vars else flow vars 14 | 15 | return 16 | 17 | module.exports = wrap 18 | 19 | # Logic to determine the best size for text 20 | resize = (vars) -> 21 | 22 | words = [] 23 | i = 0 24 | 25 | while i < vars.text.words.length 26 | addon = (if i is vars.text.words.length - 1 then "" else " ") 27 | words.push vars.text.words[i] + addon 28 | i++ 29 | 30 | # Start by trying the largest font size 31 | sizeMax = Math.floor(vars.size.value[1]) 32 | lineWidth = if vars.shape.value is "circle" then vars.width.value * 0.785 else vars.width.value 33 | sizes = fontSizes words, {"font-size": sizeMax + "px"}, vars.container.value 34 | maxWidth = d3.max sizes, (d) -> d.width 35 | areaMod = 1.165 + (vars.width.value / vars.height.value * 0.037) 36 | textArea = d3.sum(sizes, (d) -> d.width * d.height) * areaMod 37 | 38 | if vars.shape.value is "circle" 39 | boxArea = Math.PI * Math.pow(vars.width.value / 2, 2) 40 | else 41 | boxArea = lineWidth * vars.height.value 42 | 43 | if maxWidth > lineWidth or textArea > boxArea 44 | areaRatio = Math.sqrt(boxArea / textArea) 45 | widthRatio = lineWidth / maxWidth 46 | sizeRatio = d3.min [areaRatio, widthRatio] 47 | sizeMax = d3.max [vars.size.value[0], Math.floor(sizeMax * sizeRatio)] 48 | 49 | heightMax = Math.floor(vars.height.value * 0.8) 50 | sizeMax = heightMax if sizeMax > heightMax 51 | 52 | if maxWidth * (sizeMax / vars.size.value[1]) <= lineWidth 53 | if sizeMax isnt vars.size.value[1] 54 | vars.self.size [vars.size.value[0], sizeMax] 55 | vars.container.value.attr "font-size", vars.size.value[1] + "px" 56 | flow vars 57 | else 58 | wrap vars 59 | 60 | return 61 | -------------------------------------------------------------------------------- /src/viz/helpers/container.coffee: -------------------------------------------------------------------------------- 1 | # If placing into a new container, remove it's contents 2 | # and check text direction. 3 | # 4 | # Also initialized app width and height. 5 | module.exports = (vars) -> 6 | 7 | vars.container.value 8 | .style "position", () -> 9 | current = d3.select(this).style("position") 10 | remain = ["absolute","fixed"].indexOf(current) >= 0 11 | if remain then current else "relative" 12 | .html "" 13 | 14 | # Get overall width and height, if not defined 15 | for s in ["width","height"] 16 | 17 | unless vars[s].value 18 | 19 | checkParent = (element) -> 20 | 21 | if element.tagName is undefined or ["BODY","HTML"].indexOf(element.tagName) >= 0 22 | 23 | val = window["inner"+s.charAt(0).toUpperCase()+s.slice(1)] 24 | elem = if document isnt element then d3.select(element) else false 25 | 26 | if elem 27 | if s is "width" 28 | val -= parseFloat elem.style("margin-left"), 10 29 | val -= parseFloat elem.style("margin-right"), 10 30 | val -= parseFloat elem.style("padding-left"), 10 31 | val -= parseFloat elem.style("padding-right"), 10 32 | else 33 | val -= parseFloat elem.style("margin-top"), 10 34 | val -= parseFloat elem.style("margin-bottom"), 10 35 | val -= parseFloat elem.style("padding-top"), 10 36 | val -= parseFloat elem.style("padding-bottom"), 10 37 | 38 | vars[s].value = if val <= 20 then vars[s].small else val 39 | 40 | else 41 | 42 | val = parseFloat d3.select(element).style(s), 10 43 | if typeof val is "number" and val > 0 44 | vars[s].value = val 45 | else if element.tagName isnt "BODY" 46 | checkParent element.parentNode 47 | 48 | checkParent vars.container.value.node() 49 | 50 | d3.select("body").style("overflow","hidden") if d3.selectAll("body > *:not(script)").size() is 1 51 | 52 | vars.container.value 53 | .style "width", vars.width.value+"px" 54 | .style "height", vars.height.value+"px" 55 | 56 | return 57 | -------------------------------------------------------------------------------- /src/data/bestRegress.coffee: -------------------------------------------------------------------------------- 1 | #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 | # Finds the best regression model that fits the data using Bayesian Information Criteria 3 | #--------------------------------------------------------------------------------------- 4 | 5 | # data is an array of two-dimensional arrays in the format of [x, y] 6 | 7 | # options is a dictionary of options with attributes 8 | # maxDegree; maximum possible degree of the polynomial. Default is 10. 9 | 10 | # Returns the model with the best BIC score as a triple [degrees, betaHat, yHat] 11 | # where degrees is an array containing the degrees of each term in the polynomial. 12 | # and betaHat contains the coefficients for each term 13 | # and yHat contains the regressed output for each input term. 14 | 15 | numeric = require 'numeric' 16 | 17 | module.exports = (data, options) -> 18 | if not options? then options = {} 19 | if not options.maxDegree? then options.maxDegree = 5 # try to fit a polynomial up to this degree 20 | N = data.length 21 | # choose the model that has minimum BIC (penalty) 22 | prevBIC = Number.MAX_VALUE 23 | bestResult = null 24 | 25 | # construct the matrix X 26 | Xfulltr = ((Math.pow(point[0], degree) for point in data) for degree in [1...options.maxDegree+1]) 27 | y = (point[1] for point in data) 28 | for i in [0...1< 0 33 | Xtr.push Xfulltr[j] 34 | degrees.push j+1 35 | #console.log Xtr 36 | X = numeric.transpose Xtr 37 | k = degrees.length # degrees of freedom 38 | beta_hat = numeric.dot(numeric.dot(numeric.inv(numeric.dot(Xtr, X)), Xtr), y) 39 | y_hat = numeric.dot(X, beta_hat) 40 | residual = numeric.sub y, y_hat 41 | sse = numeric.dot residual, residual 42 | # compute sigma2 43 | sigma2 = sse / (N - k) 44 | # compute log-likelihood 45 | loglike = -0.5*N*Math.log(2*Math.PI)-0.5*N*Math.log(sigma2)-sse/(2*sigma2) 46 | bic = -2*loglike + k*(Math.log(N)-Math.log(2*Math.PI)) 47 | if bic < prevBIC 48 | prevBIC = bic 49 | bestResult = [degrees, beta_hat, y_hat] 50 | bestResult 51 | -------------------------------------------------------------------------------- /src/viz/helpers/svg/update.js: -------------------------------------------------------------------------------- 1 | var print = require("../../../core/console/print.coffee") 2 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | // Updating Elements 4 | //------------------------------------------------------------------------------ 5 | module.exports = function(vars) { 6 | 7 | if ( vars.dev.value ) print.time("updating SVG elements") 8 | 9 | if ( vars.draw.timing ) { 10 | 11 | // Update Parent Element 12 | vars.container.value.transition().duration(vars.draw.timing) 13 | .style("width",vars.width.value+"px") 14 | .style("height",vars.height.value+"px") 15 | 16 | // Update SVG 17 | vars.svg.transition().duration(vars.draw.timing) 18 | .attr("width",vars.width.value) 19 | .attr("height",vars.height.value) 20 | 21 | // Update Background Rectangle 22 | vars.g.bg.transition().duration(vars.draw.timing) 23 | .attr("width",vars.width.value) 24 | .attr("height",vars.height.value) 25 | 26 | // Update App Clipping Rectangle 27 | vars.g.clipping.select("rect").transition().duration(vars.draw.timing) 28 | .attr("width",vars.width.viz) 29 | .attr("height",vars.height.viz) 30 | 31 | // Update Container Groups 32 | vars.g.container.transition().duration(vars.draw.timing) 33 | .attr("transform","translate("+vars.margin.left+","+vars.margin.top+")") 34 | 35 | } 36 | else { 37 | 38 | // Update Parent Element 39 | vars.container.value 40 | .style("width",vars.width.value+"px") 41 | .style("height",vars.height.value+"px") 42 | 43 | // Update SVG 44 | vars.svg 45 | .attr("width",vars.width.value) 46 | .attr("height",vars.height.value) 47 | 48 | // Update Background Rectangle 49 | vars.g.bg 50 | .attr("width",vars.width.value) 51 | .attr("height",vars.height.value) 52 | 53 | // Update App Clipping Rectangle 54 | vars.g.clipping.select("rect") 55 | .attr("width",vars.width.viz) 56 | .attr("height",vars.height.viz) 57 | 58 | // Update Container Groups 59 | vars.g.container 60 | .attr("transform","translate("+vars.margin.left+","+vars.margin.top+")") 61 | 62 | } 63 | 64 | if ( vars.dev.value ) print.timeEnd("updating SVG elements") 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/viz/helpers/zoom/controls.js: -------------------------------------------------------------------------------- 1 | var events = require("../../../client/pointer.coffee") 2 | 3 | module.exports = function() { 4 | 5 | d3.select("#d3plus.utilsts.zoom_controls").remove() 6 | 7 | if (!vars.small) { 8 | // Create Zoom Controls 9 | var zoom_enter = vars.container.value.append("div") 10 | .attr("id","d3plus.utilsts.zoom_controls") 11 | .style("top",(vars.margin.top+5)+"px") 12 | 13 | zoom_enter.append("div") 14 | .attr("id","zoom_in") 15 | .attr("unselectable","on") 16 | .on(events.click,function(){ vars.zoom("in") }) 17 | .text("+") 18 | 19 | zoom_enter.append("div") 20 | .attr("id","zoom_out") 21 | .attr("unselectable","on") 22 | .on(events.click,function(){ vars.zoom("out") }) 23 | .text("-") 24 | 25 | zoom_enter.append("div") 26 | .attr("id","zoom_reset") 27 | .attr("unselectable","on") 28 | .on(events.click,function(){ 29 | vars.zoom("reset") 30 | vars.draw.update() 31 | }) 32 | .html("\↺") 33 | } 34 | 35 | /* Old Styles 36 | 37 | #zoom_controls { 38 | position: absolute; 39 | top: 5px; 40 | left: 5px; 41 | z-index: 50; 42 | } 43 | 44 | #zoom_in, #zoom_out, #zoom_reset { 45 | background-color: #ffffff; 46 | background-position: 50% 50%; 47 | background-repeat: no-repeat; 48 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 49 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 50 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); 51 | color: #333333; 52 | display: block; 53 | height: 18px; 54 | margin-bottom: 5px; 55 | opacity: 0.75; 56 | text-align: center; 57 | width: 18px; 58 | -webkit-text-size-adjust: none; 59 | -webkit-user-select: none; 60 | -moz-user-select: none; 61 | } 62 | 63 | #zoom_in:hover, #zoom_out:hover, #zoom_reset:hover { 64 | opacity: 1; 65 | } 66 | 67 | #zoom_in { 68 | cursor: pointer; 69 | font: normal 18px/20px Arial, Helvetica, sans-serif; 70 | } 71 | 72 | #zoom_out { 73 | cursor: pointer; 74 | font: normal 22px/16px Tahoma, Verdana, sans-serif; 75 | } 76 | 77 | #zoom_reset { 78 | cursor: pointer; 79 | font: bold 15px/19px Arial, Helvetica, sans-serif; 80 | } 81 | 82 | */ 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/viz/types/stacked.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../core/fetch/value.js" 2 | graph = require "./helpers/graph/draw.coffee" 3 | nest = require "./helpers/graph/nest.coffee" 4 | sort = require "../../array/sort.coffee" 5 | stack = require "./helpers/graph/stack.coffee" 6 | threshold = require "../../core/data/threshold.js" 7 | 8 | # Stacked Area Chart 9 | stacked = (vars) -> 10 | 11 | graph vars, 12 | buffer: vars.axes.opposite 13 | 14 | data = nest vars 15 | 16 | # Assign x and y to each data point 17 | for point in data 18 | point.d3plus = {} unless point.d3plus 19 | for d in point.values 20 | 21 | d.d3plus.x = vars.x.scale.viz fetchValue vars, d, vars.x.value 22 | d.d3plus.x += vars.axes.margin.left 23 | 24 | d.d3plus.y = vars.y.scale.viz fetchValue vars, d, vars.y.value 25 | d.d3plus.y += vars.axes.margin.top 26 | 27 | if d.d3plus.merged instanceof Array 28 | point.d3plus.merged = [] unless point.d3plus.merged 29 | point.d3plus.merged = point.d3plus.merged.concat(d.d3plus.merged) 30 | point.d3plus.text = d.d3plus.text if d.d3plus.text and !point.d3plus.text 31 | 32 | data = stack vars, data 33 | order = vars.order.value or vars.size.value or vars.id.value 34 | sortOrder = if vars.order.sort.value is "desc" then "asc" else "desc" 35 | 36 | # Return the data, sorted 37 | sort data, order, sortOrder, vars.color.value or [], vars 38 | 39 | # Visualization Settings and Helper Functions 40 | stacked.filter = (vars, data) -> 41 | threshold vars, data, vars.x.value 42 | stacked.requirements = ["data", "x", "y"] 43 | stacked.setup = (vars) -> 44 | 45 | vars.self.x scale: "discrete" unless vars.axes.discrete 46 | 47 | vars.self[vars.axes.discrete] 48 | zerofill: true 49 | vars.self[vars.axes.opposite] 50 | stacked: true 51 | 52 | y = vars[vars.axes.opposite] 53 | size = vars.size 54 | 55 | if (not y.value and size.value) or (size.changed and size.previous is y.value) 56 | vars.self[vars.axes.opposite] size.value 57 | else if (not size.value and y.value) or (y.changed and y.previous is size.value) 58 | vars.self.size y.value 59 | return 60 | 61 | stacked.shapes = ["area"] 62 | stacked.threshold = (vars) -> 20 / vars.height.viz 63 | stacked.tooltip = "static" 64 | module.exports = stacked 65 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/check.js: -------------------------------------------------------------------------------- 1 | var fetchText = require("../../../core/fetch/text.js"), 2 | fontSizes = require("../../../font/sizes.coffee"), 3 | largestRect = require("../../../geom/largestRect.coffee"), 4 | shapeStyle = require("./style.coffee") 5 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | // Draws "square" and "circle" shapes using svg:rect 7 | //------------------------------------------------------------------------------ 8 | module.exports = function(vars,selection,enter,exit) { 9 | 10 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 11 | // Initialize check scale on enter and exit. 12 | //---------------------------------------------------------------------------- 13 | function init(paths){ 14 | paths.attr("transform", "scale(1)") 15 | } 16 | 17 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 18 | // Change scale of check on update. 19 | //--------------------------------------------------------------------------- 20 | function update(paths){ 21 | paths.attr("transform", function(d){ 22 | var smaller_dim = Math.min(d.d3plus.width, d.d3plus.height); 23 | var scale = Math.floor(smaller_dim / 16); 24 | return "scale("+scale+")"; 25 | }) 26 | } 27 | 28 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 29 | // "paths" Enter 30 | //---------------------------------------------------------------------------- 31 | enter.append("path").attr("class","d3plus_data") 32 | .attr("d", "M5-6.844L3.594-5.407L-2,0.188l-1.594-1.594L-5-2.844L-7.844,0l1.438,1.406l3,3L-2,5.843l1.406-1.438l7-7L7.844-4L5-6.844z") 33 | .call(init) 34 | .call(shapeStyle,vars) 35 | 36 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 37 | // "paths" Update 38 | //---------------------------------------------------------------------------- 39 | selection.selectAll("path.d3plus_data") 40 | .data(function(d) { 41 | return [d]; 42 | }) 43 | 44 | if (vars.draw.timing) { 45 | selection.selectAll("path.d3plus_data") 46 | .transition().duration(vars.draw.timing) 47 | .call(update) 48 | .call(shapeStyle,vars) 49 | } 50 | else { 51 | selection.selectAll("path.d3plus_data") 52 | .call(update) 53 | .call(shapeStyle,vars) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/core/fetch/text.js: -------------------------------------------------------------------------------- 1 | var fetchValue = require("./value.js"), 2 | validObject = require("../../object/validate.coffee"), 3 | uniqueValues = require("../../util/uniques.coffee") 4 | 5 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | // Get array of available text values 7 | //------------------------------------------------------------------------------ 8 | module.exports = function(vars,obj,depth) { 9 | 10 | if ( typeof depth !== "number" ) var depth = vars.depth.value 11 | 12 | var key = vars.id.nesting[depth] 13 | 14 | if ( vars.text.nesting && validObject(vars.text.nesting) ) { 15 | if ( vars.text.nesting[key] ) { 16 | var textKeys = vars.text.nesting[key] 17 | } 18 | else { 19 | var textKeys = vars.text.value 20 | } 21 | } 22 | else { 23 | var textKeys = [] 24 | if (vars.text.value && depth === vars.depth.value) textKeys.push(vars.text.value) 25 | textKeys.push(key) 26 | } 27 | 28 | if ( !(textKeys instanceof Array) ) { 29 | textKeys = [ textKeys ] 30 | } 31 | 32 | var names = [] 33 | 34 | if (validObject(obj) && "d3plus" in obj && obj.d3plus.text) { 35 | names.push(obj.d3plus.text.toString()) 36 | names.push(vars.format.value(obj.d3plus.text.toString(), undefined, vars)) 37 | } 38 | else { 39 | 40 | var ids = validObject(obj) && key in obj ? obj[key] : fetchValue(vars, obj, key) 41 | if (!(ids instanceof Array)) ids = [ids] 42 | else if (validObject(ids[0])) { 43 | ids = uniqueValues(ids,key) 44 | } 45 | 46 | textKeys.forEach(function( t ){ 47 | 48 | var name = [] 49 | ids.forEach(function(i){ 50 | var n = fetchValue(vars,i,t,key) 51 | if (n) { 52 | if (n instanceof Array && validObject(n[0])) { 53 | n = uniqueValues(n,t) 54 | } 55 | name = name.concat(n) 56 | } 57 | }) 58 | 59 | if ( name.length ) { 60 | name = name.map(function(n){ 61 | if (n instanceof Array) { 62 | return n.map(function(nn){ 63 | return vars.format.value(nn.toString(),t, vars) 64 | }) 65 | } 66 | else if (n) { 67 | return vars.format.value(n.toString(),t, vars) 68 | } 69 | }) 70 | if (name.length === 1) name = name[0] 71 | names.push(name) 72 | } 73 | 74 | }) 75 | 76 | } 77 | 78 | return names 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/form/types/toggle.js: -------------------------------------------------------------------------------- 1 | var form = require("../form.js") 2 | 3 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 4 | // Creates a set of Toggle Buttons 5 | //------------------------------------------------------------------------------ 6 | module.exports = function( vars ) { 7 | 8 | if ( !("buttons" in vars.container) ) { 9 | 10 | vars.container.buttons = form() 11 | .container(vars.container.ui) 12 | .type("button") 13 | 14 | } 15 | 16 | var dataLength = vars.data.viz.length 17 | , buttonWidth = vars.width.value 18 | ? vars.width.value/dataLength 19 | : false 20 | 21 | var toggles = vars.container.ui.selectAll("div.d3plus_toggle") 22 | .data(vars.data.viz,function(d){ 23 | return d[vars.id.value] 24 | }) 25 | 26 | toggles.enter().append("div") 27 | .attr("class","d3plus_toggle") 28 | .style("display","inline-block") 29 | .style("vertical-align","top") 30 | 31 | toggles.order() 32 | .each(function(d){ 33 | 34 | if (!("form" in d.d3plus)) { 35 | d.d3plus.form = form().container(d3.select(this)) 36 | } 37 | 38 | var id = vars.id.nesting.length > vars.depth.value ? vars.id.nesting[vars.depth.value+1] : vars.id.value 39 | 40 | if (d[id] instanceof Array) { 41 | d.d3plus.form 42 | .container({"id": vars.container.id+"_"+d[vars.id.value]}) 43 | .data(d[id]) 44 | .id(vars.id.nesting.slice(1)) 45 | .type("drop") 46 | } 47 | else { 48 | d.d3plus.form 49 | .data([d]) 50 | .id(vars.id.value) 51 | .type("button") 52 | } 53 | 54 | d.d3plus.form 55 | .color(vars.color) 56 | .focus(vars.focus.value,function(value){ 57 | 58 | if (value !== vars.focus.value) { 59 | vars.self.focus(value).draw() 60 | } 61 | 62 | }) 63 | .icon({ 64 | "select": false, 65 | "value": vars.icon.value 66 | }) 67 | .font(vars.font) 68 | .format(vars.format) 69 | .order(vars.order) 70 | .text(vars.text.value) 71 | .ui({ 72 | "border": vars.ui.border, 73 | "color": vars.ui.color, 74 | "display": "inline-block", 75 | "margin": 0, 76 | "padding": vars.ui.padding 77 | }) 78 | .width(buttonWidth) 79 | .draw() 80 | 81 | }) 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/core/parse/edges.js: -------------------------------------------------------------------------------- 1 | var print = require("../console/print.coffee"), 2 | stringFormat = require("../../string/format.js") 3 | 4 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 5 | // Cleans edges list and populates nodes list if needed 6 | //------------------------------------------------------------------- 7 | module.exports = function( vars ) { 8 | 9 | if ( vars.dev.value ) { 10 | var timerString = "analyzing edges list" 11 | print.time( timerString ) 12 | } 13 | 14 | var appReqs = vars.types[vars.type.value].requirements 15 | if (!(appReqs instanceof Array)) appReqs = [appReqs] 16 | var createNodes = appReqs.indexOf("nodes") >= 0 && !vars.nodes.value 17 | 18 | if ( createNodes ) { 19 | vars.nodes.value = [] 20 | var placed = [] 21 | vars.nodes.changed = true 22 | } 23 | 24 | vars.edges.value.forEach(function(e){ 25 | 26 | if (typeof e[vars.edges.source] !== "object") { 27 | var obj = {} 28 | obj[vars.id.value] = e[vars.edges.source] 29 | e[vars.edges.source] = obj 30 | } 31 | if (typeof e[vars.edges.target] !== "object") { 32 | var obj = {} 33 | obj[vars.id.value] = e[vars.edges.target] 34 | e[vars.edges.target] = obj 35 | } 36 | 37 | if (!("keys" in vars.data)) { 38 | vars.data.keys = {} 39 | } 40 | 41 | if (!(vars.id.value in vars.data.keys)) { 42 | vars.data.keys[vars.id.value] = typeof e[vars.edges.source][vars.id.value] 43 | } 44 | 45 | if ( createNodes ) { 46 | if (placed.indexOf(e[vars.edges.source][vars.id.value]) < 0) { 47 | placed.push(e[vars.edges.source][vars.id.value]) 48 | vars.nodes.value.push(e[vars.edges.source]) 49 | } 50 | if (placed.indexOf(e[vars.edges.target][vars.id.value]) < 0) { 51 | placed.push(e[vars.edges.target][vars.id.value]) 52 | vars.nodes.value.push(e[vars.edges.target]) 53 | } 54 | } 55 | 56 | }) 57 | 58 | vars.edges.value = vars.edges.value.filter(function(e){ 59 | 60 | var source = e[vars.edges.source][vars.id.value] 61 | , target = e[vars.edges.target][vars.id.value] 62 | 63 | if ( source === target ) { 64 | var str = vars.format.locale.value.dev.sameEdge 65 | print.warning(stringFormat(str,"\""+source+"\"") , "edges" ) 66 | return false 67 | } 68 | else { 69 | return true 70 | } 71 | 72 | }) 73 | 74 | vars.edges.linked = true 75 | 76 | if ( vars.dev.value ) print.timeEnd( timerString ) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/button.js: -------------------------------------------------------------------------------- 1 | var copy = require("../../../../util/copy.coffee"), 2 | events = require("../../../../client/pointer.coffee"), 3 | form = require("../../../form.js"), 4 | print = require("../../../../core/console/print.coffee") 5 | 6 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7 | // Creates and styles the main drop button. 8 | //------------------------------------------------------------------------------ 9 | module.exports = function ( vars ) { 10 | 11 | if ( !("button" in vars.container) ) { 12 | 13 | if ( vars.dev.value ) print.time("creating main button") 14 | 15 | vars.container.button = form() 16 | .container(vars.container.ui) 17 | .type("button") 18 | .ui({ 19 | "margin": 0 20 | }) 21 | 22 | if ( vars.dev.value ) print.timeEnd("creating main button") 23 | 24 | } 25 | 26 | if ( vars.focus.changed || vars.data.changed || vars.depth.changed ) { 27 | 28 | var depth = vars.depth.value 29 | 30 | var buttonData = copy(vars.data.value.filter(function(d){ 31 | var match = false 32 | for ( var i = 0 ; i < vars.id.nesting.length ; i++ ) { 33 | var level = vars.id.nesting[i] 34 | match = level in d && d[level] === vars.focus.value 35 | if (match) { 36 | depth = i 37 | break 38 | } 39 | } 40 | return match 41 | })[0]) 42 | 43 | if ( !buttonData ) { 44 | buttonData = vars.container.button.data()[0] || vars.data.viz[0] 45 | } 46 | 47 | vars.container.button 48 | .data([buttonData]) 49 | .id( vars.id.nesting ) 50 | .depth(depth) 51 | 52 | } 53 | 54 | vars.container.button 55 | .draw({ 56 | "update": vars.draw.update 57 | }) 58 | .focus(vars.focus.value) 59 | .font( vars.font ) 60 | .icon({ 61 | "button": vars.icon.drop.value, 62 | "select": vars.icon.drop.value, 63 | "value": vars.icon.value 64 | }) 65 | .text( vars.text.value ) 66 | .timing({ 67 | "ui": vars.draw.timing 68 | }) 69 | .ui({ 70 | "color": vars.ui.color, 71 | "padding": vars.ui.padding 72 | }) 73 | .width(vars.width.value) 74 | .draw() 75 | 76 | var button = vars.container.button.container(Object).ui 77 | 78 | vars.margin.top += button.node().offsetHeight || button.node().getBoundingClientRect().height 79 | 80 | button.on(events.click,function(){ 81 | vars.self.open(!vars.open.value).draw() 82 | }) 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/viz/types/bar.coffee: -------------------------------------------------------------------------------- 1 | fetchValue = require "../../core/fetch/value.js" 2 | graph = require "./helpers/graph/draw.coffee" 3 | nest = require "./helpers/graph/nest.coffee" 4 | stack = require "./helpers/graph/stack.coffee" 5 | 6 | # Line Plot 7 | bar = (vars) -> 8 | 9 | discrete = vars.axes.discrete 10 | h = if discrete is "x" then "height" else "width" 11 | w = if discrete is "x" then "width" else "height" 12 | opposite = vars.axes.opposite 13 | cMargin = if discrete is "x" then "left" else "top" 14 | oMargin = if discrete is "x" then "top" else "left" 15 | 16 | data = vars.data.viz.filter (d) -> fetchValue vars, d, vars[opposite].value 17 | 18 | return [] unless data.length 19 | 20 | graph vars, 21 | buffer: true 22 | zero: vars.axes.opposite 23 | 24 | nested = nest vars, data 25 | 26 | stack vars, nested if vars.axes.stacked 27 | 28 | space = vars.axes[w] / vars[vars.axes.discrete].ticks.values.length 29 | 30 | if vars.axes.stacked 31 | maxSize = space - vars.labels.padding * 4 32 | else 33 | maxSize = space / nested.length 34 | maxSize -= vars.labels.padding * 2 35 | offset = space/2 - maxSize/2 - vars.labels.padding * 2 36 | 37 | x = d3.scale.linear() 38 | .domain [0, nested.length-1] 39 | .range [-offset, offset] 40 | 41 | for point, i in nested 42 | mod = if vars.axes.stacked then 0 else x(i) 43 | for d in point.values 44 | 45 | d.d3plus[discrete] = vars[discrete].scale.viz fetchValue(vars, d, vars[discrete].value) 46 | d.d3plus[discrete] += vars.axes.margin[cMargin] + mod 47 | 48 | if vars.axes.stacked 49 | base = d.d3plus[opposite+"0"] 50 | value = d.d3plus[opposite] 51 | length = base - value 52 | else 53 | base = vars[opposite].scale.viz(0) 54 | value = vars[opposite].scale.viz fetchValue(vars, d, vars[opposite].value) 55 | length = base - value 56 | 57 | d.d3plus[opposite] = base - length/2 58 | d.d3plus[opposite] += vars.axes.margin[oMargin] unless vars.axes.stacked 59 | 60 | d.d3plus[w] = maxSize 61 | d.d3plus[h] = Math.abs length 62 | d.d3plus.init = {} 63 | d.d3plus.init[opposite] = vars[opposite].scale.viz(0) - d.d3plus[opposite] + vars.axes.margin[oMargin] 64 | d.d3plus.init[w] = d.d3plus[w] 65 | 66 | d.d3plus.label = false 67 | 68 | data 69 | 70 | # Visualization Settings and Helper Functions 71 | bar.requirements = ["data", "x", "y"] 72 | bar.setup = (vars) -> vars.self.x scale: "discrete" unless vars.axes.discrete 73 | bar.shapes = ["square"] 74 | bar.tooltip = "static" 75 | 76 | module.exports = bar 77 | -------------------------------------------------------------------------------- /src/core/console/print.coffee: -------------------------------------------------------------------------------- 1 | ie = require "../../client/ie.js" 2 | wiki = require "./wiki.coffee" 3 | 4 | # Custom styling and behavior for browser console statements. 5 | print = (type, message, style) -> 6 | style = style or "" 7 | if ie or typeof InstallTrigger isnt 'undefined' 8 | console.log "[ D3plus ] " + message 9 | else if type is "groupCollapsed" 10 | if window.chrome and navigator.onLine 11 | console[type] "%c%c " + message, "padding:3px 10px;line-height:25px;background-size:20px;background-position:top left;background-image:url('http://d3plus.org/assets/img/favicon.ico');", "font-weight:200;" + style 12 | else 13 | console[type] "%cD3plus%c " + message, "line-height:25px;font-weight:800;color:#b35c1e;margin-left:0px;", "font-weight:200;" + style 14 | else 15 | console[type] "%c" + message, style + "font-weight:200;" 16 | return 17 | 18 | print.comment = (message) -> 19 | this "log", message, "color:#aaa;" 20 | return 21 | 22 | print.error = (message, url) -> 23 | this "groupCollapsed", "ERROR: " + message, "font-weight:800;color:#D74B03;" 24 | @stack() 25 | @wiki url 26 | @groupEnd() 27 | return 28 | 29 | print.group = (message) -> 30 | this "group", message, "color:#888;" 31 | return 32 | 33 | print.groupCollapsed = (message) -> 34 | this "groupCollapsed", message, "color:#888;" 35 | return 36 | 37 | print.groupEnd = -> 38 | console.groupEnd() unless ie 39 | return 40 | 41 | print.log = (message) -> 42 | this "log", message, "color:#444444;" 43 | return 44 | 45 | print.stack = -> 46 | unless ie 47 | err = new Error() 48 | if err.stack 49 | stack = err.stack.split("\n") 50 | stack = stack.filter((e) -> 51 | e.indexOf("Error") isnt 0 and e.indexOf("d3plus.js:") < 0 and e.indexOf("d3plus.min.js:") < 0 52 | ) 53 | if stack.length and stack[0].length 54 | splitter = (if window.chrome then "at " else "@") 55 | url = stack[0].split(splitter)[1] 56 | stack = url.split(":") 57 | stack.pop() if stack.length is 3 58 | line = stack.pop() 59 | page = stack.join(":").split("/") 60 | page = page[page.length - 1] 61 | message = "line " + line + " of " + page + ": " + url 62 | this "log", message, "color:#D74B03;" 63 | return 64 | 65 | print.time = (message) -> 66 | console.time message unless ie 67 | return 68 | 69 | print.timeEnd = (message) -> 70 | console.timeEnd message unless ie 71 | return 72 | 73 | print.warning = (message, url) -> 74 | this "groupCollapsed", message, "color:#888;" 75 | @stack() 76 | @wiki url 77 | @groupEnd() 78 | return 79 | 80 | print.wiki = (url) -> 81 | if url 82 | if url of wiki 83 | url = d3plus.repo + "wiki/" + wiki[url] 84 | this "log", "documentation: " + url, "color:#aaa;" 85 | return 86 | 87 | module.exports = print 88 | -------------------------------------------------------------------------------- /src/viz/helpers/shapes/arc.coffee: -------------------------------------------------------------------------------- 1 | shapeStyle = require "./style.coffee" 2 | largestRect = require "../../../geom/largestRect.coffee" 3 | path2poly = require "../../../geom/path2poly.coffee" 4 | 5 | module.exports = (vars, selection, enter, exit) -> 6 | 7 | arc = d3.svg.arc() 8 | .innerRadius 0 9 | .outerRadius (d) -> d.d3plus.r 10 | .startAngle (d) -> d.d3plus.startAngle 11 | .endAngle (d) -> d.d3plus.endAngle 12 | 13 | # Calculate label position and pass data from parent. 14 | data = (d) -> 15 | if vars.labels.value 16 | if d.d3plus.label 17 | d.d3plus_label = d.d3plus.label 18 | else 19 | poly = path2poly(arc(d)) 20 | rect = largestRect poly, 21 | angle: 0 22 | if rect[0] 23 | d.d3plus_label = 24 | w: rect[0].width 25 | h: rect[0].height 26 | x: rect[0].cx 27 | y: rect[0].cy 28 | else 29 | delete d.d3plus_label 30 | [d] 31 | 32 | if vars.draw.timing 33 | 34 | newarc = d3.svg.arc() 35 | .innerRadius 0 36 | .outerRadius (d) -> d.d3plus.r 37 | .startAngle (d) -> 38 | d.d3plus.startAngleCurrent = 0 if d.d3plus.startAngleCurrent is undefined 39 | d.d3plus.startAngleCurrent = d.d3plus.startAngle if isNaN(d.d3plus.startAngleCurrent) 40 | d.d3plus.startAngleCurrent 41 | .endAngle (d) -> 42 | d.d3plus.endAngleCurrent = 0 if d.d3plus.endAngleCurrent is undefined 43 | d.d3plus.endAngleCurrent = d.d3plus.endAngle if isNaN(d.d3plus.endAngleCurrent) 44 | d.d3plus.endAngleCurrent 45 | 46 | arcTween = (arcs, newAngle) -> 47 | arcs.attrTween "d", (d) -> 48 | 49 | if newAngle is undefined 50 | s = d.d3plus.startAngle 51 | e = d.d3plus.endAngle 52 | else if newAngle is 0 53 | s = 0 54 | e = 0 55 | 56 | interpolateS = d3.interpolate(d.d3plus.startAngleCurrent, s) 57 | interpolateE = d3.interpolate(d.d3plus.endAngleCurrent, e) 58 | (t) -> 59 | d.d3plus.startAngleCurrent = interpolateS(t) 60 | d.d3plus.endAngleCurrent = interpolateE(t) 61 | newarc d 62 | 63 | enter.append("path") 64 | .attr "class", "d3plus_data" 65 | .call shapeStyle, vars 66 | .attr "d", newarc 67 | 68 | selection.selectAll("path.d3plus_data").data data 69 | .transition().duration vars.draw.timing 70 | .call shapeStyle, vars 71 | .call arcTween 72 | 73 | exit.selectAll("path.d3plus_data") 74 | .transition().duration vars.draw.timing 75 | .call arcTween, 0 76 | 77 | else 78 | 79 | enter.append("path").attr "class", "d3plus_data" 80 | 81 | selection.selectAll("path.d3plus_data").data data 82 | .call shapeStyle, vars 83 | .attr "d", arc 84 | 85 | return 86 | -------------------------------------------------------------------------------- /src/viz/types/helpers/graph/includes/buffer.coffee: -------------------------------------------------------------------------------- 1 | closest = require "../../../../../util/closest.coffee" 2 | 3 | module.exports = (vars, axis, buffer) -> 4 | 5 | if vars[axis].scale.value isnt "share" and !vars[axis].range.value 6 | 7 | if axis is vars.axes.discrete 8 | 9 | domain = vars[axis].scale.viz.domain() 10 | domain = domain.slice().reverse() if axis is "y" 11 | 12 | if vars[axis].ticks.values.length is 1 13 | if vars[axis].value is vars.time.value and vars.data.time.ticks.length isnt 1 14 | closestTime = closest(vars.data.time.ticks, domain[0]) 15 | timeIndex = vars.data.time.ticks.indexOf(closestTime) 16 | if timeIndex > 0 17 | domain[0] = vars.data.time.ticks[timeIndex - 1] 18 | else 19 | diff = vars.data.time.ticks[timeIndex + 1] - closestTime 20 | domain[0] = new Date(closestTime.getTime() - diff) 21 | if timeIndex < vars.data.time.ticks.length - 1 22 | domain[1] = vars.data.time.ticks[timeIndex + 1] 23 | else 24 | diff = closestTime - vars.data.time.ticks[timeIndex - 1] 25 | domain[1] = new Date(closestTime.getTime() + diff) 26 | else 27 | domain[0] -= 1 28 | domain[1] += 1 29 | else 30 | difference = Math.abs domain[1] - domain[0] 31 | additional = difference / (vars[axis].ticks.values.length - 1) 32 | additional = additional / 2 33 | 34 | domain[0] = domain[0] - additional 35 | domain[1] = domain[1] + additional 36 | 37 | domain = domain.reverse() if axis is "y" 38 | vars[axis].scale.viz.domain(domain) 39 | 40 | else if (buffer is "x" and axis is "x") or (buffer is "y" and axis is "y") or (buffer is true) 41 | 42 | domain = vars[axis].scale.viz.domain() 43 | domain = domain.slice().reverse() if axis is "y" 44 | 45 | allPositive = domain[0] >= 0 and domain[1] >= 0 46 | allNegative = domain[0] <= 0 and domain[1] <= 0 47 | 48 | additional = Math.abs(domain[1] - domain[0]) * 0.05 49 | 50 | domain[0] = domain[0] - additional 51 | domain[1] = domain[1] + additional 52 | 53 | domain[0] = 0 if (allPositive and domain[0] < 0) or (allNegative and domain[0] > 0) 54 | domain[1] = 0 if (allPositive and domain[1] < 0) or (allNegative and domain[1] > 0) 55 | 56 | domain = domain.reverse() if axis is "y" 57 | 58 | vars[axis].scale.viz.domain(domain) 59 | 60 | else if vars.axes.scale 61 | 62 | rangeMax = vars[axis].scale.viz.range()[1] 63 | maxSize = vars.axes.scale.range()[1] 64 | 65 | domainHigh = vars[axis].scale.viz.invert -maxSize * 2 66 | domainLow = vars[axis].scale.viz.invert rangeMax + maxSize * 2 67 | 68 | if domainHigh is domainLow 69 | domainHigh += 1 70 | domainLow -= 1 71 | 72 | vars[axis].scale.viz.domain([domainHigh,domainLow]) 73 | -------------------------------------------------------------------------------- /src/form/types/button/button.js: -------------------------------------------------------------------------------- 1 | var print = require("../../../core/console/print.coffee"), 2 | color = require("./functions/color.js"), 3 | icons = require("./functions/icons.js"), 4 | mouseevents = require("./functions/mouseevents.js"), 5 | style = require("./functions/style.js") 6 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7 | // Creates a Button 8 | //------------------------------------------------------------------------------ 9 | module.exports = function( vars ) { 10 | 11 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | // Bind Data to Buttons 13 | //---------------------------------------------------------------------------- 14 | var button = vars.container.ui.selectAll("div.d3plus_node") 15 | .data(vars.data.viz,function(d){ 16 | return d[vars.id.value] 17 | }) 18 | 19 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | // Enter Buttons 21 | //---------------------------------------------------------------------------- 22 | if ( vars.dev.value ) print.time("enter") 23 | 24 | button.enter().append("div") 25 | .attr("class","d3plus_node") 26 | .call( color , vars ) 27 | .call( style , vars ) 28 | .call( icons , vars ) 29 | .call( mouseevents , vars , color ) 30 | 31 | if ( vars.dev.value ) print.timeEnd("enter") 32 | 33 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 34 | // Update Buttons 35 | //---------------------------------------------------------------------------- 36 | if (vars.draw.update || vars.draw.timing) { 37 | 38 | if ( vars.dev.value ) print.time("ordering") 39 | button.order() 40 | if ( vars.dev.value ) print.timeEnd("ordering") 41 | 42 | var updatedButtons = button 43 | 44 | } 45 | else { 46 | 47 | var checks = [ vars.focus.previous 48 | , vars.focus.value 49 | , vars.hover.previous 50 | , vars.hover.value ].filter(function(c){ return c }) 51 | 52 | var updatedButtons = button.filter(function(b){ 53 | return checks.indexOf(b[vars.id.value]) >= 0 54 | }) 55 | 56 | } 57 | 58 | if ( vars.dev.value ) print.time("update") 59 | if (vars.draw.timing) { 60 | updatedButtons 61 | .transition().duration(vars.draw.timing) 62 | .call( color , vars ) 63 | .call( style , vars ) 64 | } 65 | else { 66 | updatedButtons 67 | .call( color , vars ) 68 | .call( style , vars ) 69 | } 70 | 71 | updatedButtons 72 | .call( icons , vars ) 73 | .call( mouseevents , vars , color ) 74 | if ( vars.dev.value ) print.timeEnd("update") 75 | 76 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 77 | // Exit Buttons 78 | //---------------------------------------------------------------------------- 79 | button.exit().remove() 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/items.coffee: -------------------------------------------------------------------------------- 1 | active = require("./active.js") 2 | copy = require("../../../../util/copy.coffee") 3 | form = require("../../../form.js") 4 | print = require("../../../../core/console/print.coffee") 5 | 6 | # Populates item list based on filtered data. 7 | module.exports = (vars) -> 8 | 9 | if vars.open.value 10 | 11 | print.time "updating list items" if vars.dev.value 12 | 13 | unless "items" of vars.container 14 | vars.container.items = form() 15 | .container vars.container.list 16 | .type "button" 17 | .ui 18 | border: 0 19 | display: "block" 20 | margin: 0 21 | .width(false) 22 | 23 | large = if vars.draw.timing then vars.data.large else 1 24 | order = copy vars.order 25 | order.value = (if vars.text.solo.value.length and vars.text.solo.value[0] isnt "" then "d3plus_order" else vars.order.value) 26 | deepest = vars.depth.value is vars.id.nesting.length - 1 27 | 28 | if vars.focus.changed or not vars.container.items.focus().length 29 | 30 | vars.container.items 31 | .focus vars.focus.value, (value) -> 32 | 33 | change = value isnt vars.focus.value 34 | change = active(vars, value) if change and vars.active.value 35 | 36 | vars.self.focus value if change 37 | 38 | data = vars.data.filtered.filter((f) -> 39 | f[vars.id.value] is value 40 | )[0] 41 | 42 | if vars.depth.value < vars.id.nesting.length - 1 and vars.id.nesting[vars.depth.value + 1] of data 43 | depth = vars.depth.value 44 | solo = vars.id.solo.value 45 | vars.history.states.push -> vars.self.depth(depth).id(solo: solo).draw() 46 | vars.self.depth(vars.depth.value + 1).id(solo: [value]).draw() 47 | else unless vars.depth.changed 48 | vars.self.open(false).draw() 49 | else vars.self.draw() if change 50 | 51 | return 52 | 53 | if vars.data.changed 54 | vars.container.items 55 | .data 56 | large: large 57 | value: vars.data.filtered 58 | 59 | vars.container.items 60 | .active vars.active.value 61 | .draw 62 | update: vars.draw.update 63 | .font vars.font.secondary 64 | .id vars.id.value 65 | .icon 66 | button: (if deepest then false else vars.icon.next) 67 | select: (if deepest then vars.icon.select else false) 68 | .order order 69 | .text vars.text.secondary.value or vars.text.value 70 | .timing 71 | ui: vars.draw.timing 72 | .ui 73 | color: 74 | primary: (if vars.id.nesting.length is 1 then vars.ui.color.primary.value else vars.ui.color.secondary.value) 75 | secondary: vars.ui.color.secondary.value 76 | padding: vars.ui.padding 77 | .draw() 78 | 79 | print.timeEnd "updating list items" if vars.dev.value 80 | 81 | return 82 | -------------------------------------------------------------------------------- /src/form/types/drop/functions/width.js: -------------------------------------------------------------------------------- 1 | var copy = require("../../../../util/copy.coffee"), 2 | fontTester = require("../../../../core/font/tester.coffee"), 3 | form = require("../../../form.js"), 4 | print = require("../../../../core/console/print.coffee"), 5 | validObject = require("../../../../object/validate.coffee") 6 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 7 | // If no widths are defined, then this calculates the width needed to fit the 8 | // longest entry in the list. 9 | //------------------------------------------------------------------------------ 10 | module.exports = function ( vars ) { 11 | 12 | var data = [], buffer = 0 13 | for ( var level in vars.data.nested.all ) { 14 | var newData = vars.data.nested.all[level] 15 | , key = validObject(vars.text.nesting) && level in vars.text.nesting 16 | ? vars.text.nesting[level][0] : level 17 | 18 | if ( [vars.id.value,vars.text.value].indexOf(key) < 0 ) { 19 | newData = copy(newData) 20 | newData.forEach(function(d){ 21 | d[vars.text.value || vars.id.value] = d[key] 22 | }) 23 | } 24 | data = data.concat( newData ) 25 | } 26 | 27 | function getWidth( type ) { 28 | 29 | var key = type === "primary" ? "value" : type 30 | , icon = key === "value" ? vars.icon.drop.value 31 | : vars.icon.select.value || vars.icon.drop.value 32 | , text = key === "value" ? vars.text.value 33 | : vars.text.secondary.value || vars.text.value 34 | , font = key === "value" ? vars.font : vars.font.secondary 35 | 36 | if ( vars.dev.value ) print.time("calculating "+type+" width") 37 | 38 | var button = form() 39 | .container( fontTester() ) 40 | .data({ 41 | "large": 9999, 42 | "value": data 43 | }) 44 | .draw({ "update": false }) 45 | .font( font ) 46 | .icon({ "button": icon, "value": vars.icon.value }) 47 | .id(vars.id.value) 48 | .timing({ 49 | "ui": 0 50 | }) 51 | .text( text || vars.id.value ) 52 | .type( "button" ) 53 | .ui({ 54 | "border": type === "primary" ? vars.ui.border : 0, 55 | "display": "inline-block", 56 | "margin": 0, 57 | "padding": vars.ui.padding 58 | }) 59 | .width(false) 60 | .draw() 61 | 62 | var w = [] 63 | button.selectAll("div.d3plus_node").each(function(o){ 64 | w.push(this.offsetWidth) 65 | }).remove() 66 | 67 | var dropWidth = {} 68 | dropWidth[key] = d3.max(w) 69 | 70 | vars.self.width( dropWidth ) 71 | 72 | if ( vars.dev.value ) print.timeEnd("calculating "+type+" width") 73 | 74 | } 75 | 76 | if ( typeof vars.width.value !== "number" ) { 77 | 78 | getWidth( "primary" ) 79 | 80 | } 81 | 82 | if ( typeof vars.width.secondary !== "number" ) { 83 | 84 | if ( !vars.text.secondary.value || vars.text.value === vars.text.secondary.value ) { 85 | vars.self.width({"secondary": vars.width.value}) 86 | } 87 | else { 88 | getWidth( "secondary" ) 89 | } 90 | 91 | } 92 | 93 | } 94 | --------------------------------------------------------------------------------