├── js ├── analytics.js ├── filters.js ├── app.js ├── services.js ├── controllers.js └── directives.js ├── favicon.ico ├── .gitignore ├── favicon-l.png ├── imgs ├── binning.png ├── treemap.png ├── voronoi.png ├── alluvial.png ├── bumpChart.png ├── convexHull.png ├── delaunay.png ├── dendrogram.png ├── clusterForce.png ├── scatterPlot.png ├── streamgraph.png ├── circlePacking.png ├── forcedirected.png ├── reingoldTilford.png ├── smallMultiples.png ├── simplescatteplot.png ├── circularDendrogram.png └── parallelCoordinates.png ├── templates ├── dimensions.html └── colors.html ├── LICENSE ├── bower.json ├── data ├── dispersions.csv ├── correlations.csv ├── flows.csv └── multivariate.csv ├── charts ├── delaunay.js ├── convexHull.js ├── voronoi.js ├── chart.js ├── circularDendrogram.js ├── reingoldTilford.js ├── clusterDendrogram.js ├── treemap.js ├── packing.js ├── hexagonalBinning.js ├── parallelCoordinates.js ├── scatterPlot.js ├── smallMultiplesArea.js ├── alluvial.js ├── clusterForce.js ├── streamgraph.js └── bumpChart.js ├── README.md ├── index.html ├── COPYING.LESSER ├── partials └── main.html ├── lib └── raw.js └── css └── raw.css /js/analytics.js: -------------------------------------------------------------------------------- 1 | // Put here your GA code 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | node_modules/ 3 | bower_components/ 4 | components/ -------------------------------------------------------------------------------- /favicon-l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/favicon-l.png -------------------------------------------------------------------------------- /imgs/binning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/binning.png -------------------------------------------------------------------------------- /imgs/treemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/treemap.png -------------------------------------------------------------------------------- /imgs/voronoi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/voronoi.png -------------------------------------------------------------------------------- /imgs/alluvial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/alluvial.png -------------------------------------------------------------------------------- /imgs/bumpChart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/bumpChart.png -------------------------------------------------------------------------------- /imgs/convexHull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/convexHull.png -------------------------------------------------------------------------------- /imgs/delaunay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/delaunay.png -------------------------------------------------------------------------------- /imgs/dendrogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/dendrogram.png -------------------------------------------------------------------------------- /imgs/clusterForce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/clusterForce.png -------------------------------------------------------------------------------- /imgs/scatterPlot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/scatterPlot.png -------------------------------------------------------------------------------- /imgs/streamgraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/streamgraph.png -------------------------------------------------------------------------------- /imgs/circlePacking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/circlePacking.png -------------------------------------------------------------------------------- /imgs/forcedirected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/forcedirected.png -------------------------------------------------------------------------------- /imgs/reingoldTilford.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/reingoldTilford.png -------------------------------------------------------------------------------- /imgs/smallMultiples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/smallMultiples.png -------------------------------------------------------------------------------- /imgs/simplescatteplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/simplescatteplot.png -------------------------------------------------------------------------------- /imgs/circularDendrogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/circularDendrogram.png -------------------------------------------------------------------------------- /imgs/parallelCoordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tscanlin/raw/master/imgs/parallelCoordinates.png -------------------------------------------------------------------------------- /js/filters.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Filters */ 4 | 5 | angular.module('raw.filters', []) 6 | 7 | .filter('categoryFilter', [function () { 8 | return function (charts, category) { 9 | return charts.filter(function (chart){ 10 | return !chart.category() && category == 'Others' || chart.category() == category; 11 | }); 12 | }; 13 | }]); -------------------------------------------------------------------------------- /templates/dimensions.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /js/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('raw', [ 4 | 'ngRoute', 5 | 'ngAnimate', 6 | 'ngSanitize', 7 | 'raw.filters', 8 | 'raw.services', 9 | 'raw.directives', 10 | 'raw.controllers', 11 | 'mgcrea.ngStrap', 12 | 'ui', 13 | 'colorpicker.module' 14 | ]) 15 | 16 | .config(['$routeProvider','$locationProvider', function ($routeProvider,$locationProvider) { 17 | $routeProvider.when('/', {templateUrl: 'partials/main.html', controller: 'RawCtrl'}); 18 | $routeProvider.otherwise({redirectTo: '/'}); 19 | $locationProvider.html5Mode(true); 20 | }]); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c), 2013-2014 DensityDesign Lab, Giorgio Caviglia, Michele Mauri, Giorgio Uboldi, Matteo Azzi 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU Lesser General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public License 20 | along with this program. If not, see . 21 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Raw", 3 | "version": "1.0.0", 4 | "authors": [ 5 | "DensityDesign Lab" 6 | ], 7 | "description": "The missing link between spreadsheet and vector graphics", 8 | "main": "index.html", 9 | "keywords": [ 10 | "Raw" 11 | ], 12 | "license": "LGPL v.3", 13 | "homepage": "raw.densitydesign.org", 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ], 21 | "dependencies": { 22 | "angular": "1.2.14", 23 | "d3": "~3.4.3", 24 | "bootstrap": "3.1.1", 25 | "angular-route": "1.2.14", 26 | "angular-strap": "2.0.0-rc.4", 27 | "angular-animate": "1.2.14", 28 | "jquery-ui": "1.10.4", 29 | "angular-sanitize": "1.2.14", 30 | "angular-bootstrap-colorpicker": "1.0", 31 | "bootstrap-colorpicker": "*", 32 | "d3-plugins": "*", 33 | "FileSaver": "*", 34 | "angular-ui": "0.4.0", 35 | "zeroclipboard": "1.3.2", 36 | "canvas-toBlob.js": "https://github.com/eligrey/canvas-toBlob.js.git", 37 | "jqueryui-touch-punch": "*", 38 | "codemirror": "~4.5.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /templates/colors.html: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 |
11 | 12 | 13 |
14 | 15 | 16 | 17 | 20 | 30 | 31 | 32 |
18 |

{{color.key}}

19 |
21 | 28 |
29 |
33 |
34 | -------------------------------------------------------------------------------- /js/services.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Services */ 4 | 5 | angular.module('raw.services', []) 6 | 7 | .factory('dataService', function ($http, $q, $timeout) { 8 | 9 | return { 10 | 11 | loadSample : function(sample){ 12 | var deferred = $q.defer(); 13 | $http.get(sample) 14 | .then(function(response){ 15 | deferred.resolve(response.data); 16 | }, 17 | function(){ 18 | deferred.reject("An error occured while getting sample (" + sample.title + ")"); 19 | }); 20 | 21 | return deferred.promise; 22 | }, 23 | 24 | debounce : function (func, wait, immediate) { 25 | var timeout; 26 | var deferred = $q.defer(); 27 | return function() { 28 | var context = this, args = arguments; 29 | var later = function() { 30 | timeout = null; 31 | if(!immediate) { 32 | deferred.resolve(func.apply(context, args)); 33 | deferred = $q.defer(); 34 | } 35 | }; 36 | var callNow = immediate && !timeout; 37 | if ( timeout ) { 38 | $timeout.cancel(timeout); 39 | } 40 | timeout = $timeout(later, wait); 41 | if (callNow) { 42 | deferred.resolve(func.apply(context,args)); 43 | deferred = $q.defer(); 44 | } 45 | return deferred.promise; 46 | }; 47 | } 48 | 49 | } 50 | }) 51 | -------------------------------------------------------------------------------- /data/dispersions.csv: -------------------------------------------------------------------------------- 1 | Movie,Genre,Production Budget,Total Domestic Box Office,Rating IMDB 2 | Avatar,Action,425000000,760507625, 8.0 3 | The Blind Side,Drama,35000000,255959475, 7.6 4 | "The Chronicles of Narnia: The Lion, the Witch and the Wardrobe",Adventure,180000000,291710957, 6.9 5 | The Dark Knight,Action,185000000,533345358, 9.0 6 | ET: The Extra-Terrestrial,Drama,10500000,435110554, 7.9 7 | Finding Nemo,Adventure,94000000,380529370, 8.1 8 | Ghostbusters,Comedy,30000000,238632124, 7.8 9 | The Hunger Games,Thriller/Suspense,80000000,408010692, 7.2 10 | Iron Man 3,Action,200000000,396702239, 7.6 11 | Jurassic Park,Action,63000000,395708305, 8.0 12 | King Kong,Adventure,207000000,218080025, 7.3 13 | The Lion King,Adventure,79300000,422780140, 8.4 14 | "Monsters, Inc.",Adventure,115000000,289423425, 8.0 15 | The Twilight Saga: New Moon,Drama,50000000,296623634, 4.5 16 | Oz the Great and Powerful,Adventure,200000000,233671832, 6.6 17 | Pirates of the Caribbean: Dead Man's Chest,Adventure,225000000,423315812, 7.3 18 | Quantum of Solace,Action,230000000,169368427, 6.7 19 | Raiders of the Lost Ark,Adventure,20000000,248159971, 8.7 20 | Star Wars Ep. I: The Phantom Menace,Adventure,115000000,474544677, 6.5 21 | Titanic,Thriller/Suspense,200000000,658672302, 7.6 22 | Up,Adventure,175000000,293004164, 8.3 23 | The Vow,Drama,30000000,125014030, 6.7 24 | The War of the Worlds,Action,132000000,234280354, 6.5 25 | X-Men: The Last Stand,Action,210000000,234362462, 6.8 26 | You've Got Mail,Drama,65000000,115821495, 6.3 27 | Zookeeper,Romantic Comedy,80000000,80360866, 5.0 -------------------------------------------------------------------------------- /charts/delaunay.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var points = raw.models.points(); 4 | 5 | points.dimensions().remove('size'); 6 | points.dimensions().remove('label'); 7 | points.dimensions().remove('color'); 8 | 9 | var chart = raw.chart() 10 | .title('Delaunay Triangulation') 11 | .description( 12 | "The Delaunay triangulation, the dual of Voronoi tesselation, creates a planar, triangular mesh for a given set of points.
Based on http://bl.ocks.org/mbostock/4341156") 13 | .thumbnail("imgs/delaunay.png") 14 | .model(points) 15 | 16 | var width = chart.number() 17 | .title("Width") 18 | .defaultValue(1000) 19 | .fitToWidth(true) 20 | 21 | var height = chart.number() 22 | .title("Height") 23 | .defaultValue(500) 24 | 25 | chart.draw(function (selection, data){ 26 | 27 | var x = d3.scale.linear().range([0,+width()]).domain(d3.extent(data, function (d){ return d.x; })), 28 | y = d3.scale.linear().range([+height(), 0]).domain(d3.extent(data, function (d){ return d.y; })); 29 | 30 | var delaunay = d3.geom.voronoi() 31 | .x(function (d){ return x(d.x); }) 32 | .y(function (d){ return y(d.y); }) 33 | .clipExtent([ [ 0, 0 ], [+width(), +height()] ]); 34 | 35 | var g = selection 36 | .attr("width", +width()) 37 | .attr("height", +height()) 38 | .append("g"); 39 | 40 | var path = g.selectAll("path") 41 | .data(delaunay.triangles(data), polygon) 42 | .enter().append("path") 43 | .style("fill", "#bbb") 44 | .style("stroke","#fff") 45 | .attr("d", polygon); 46 | 47 | function polygon(d) { 48 | if(!d) return; 49 | var s = d.map(function (a){ return [x(a.x), y(a.y)] } ) 50 | return "M" + s.join("L") + "Z"; 51 | } 52 | 53 | }) 54 | })(); 55 | -------------------------------------------------------------------------------- /data/correlations.csv: -------------------------------------------------------------------------------- 1 | Cocktail,Parts,Ingredient 2 | Bloody Mary,9,vodka 3 | Bloody Mary,18,Tomato juice 4 | Bloody Mary,3,lemon juice 5 | Gin and Tonic,12,Gin 6 | Gin and Tonic,29,Tonic Water 7 | Screwdriver,10,vodka 8 | Screwdriver,20,orange juice 9 | White Russian,10,vodka 10 | White Russian,4,coffee liqueur 11 | White Russian,6,cream 12 | Cosmopolitan,8,vodka 13 | Cosmopolitan,3,cointreau 14 | Cosmopolitan,3,lime juice 15 | Cosmopolitan,6,cranberry juice 16 | Apple Martini,8,vodka 17 | Apple Martini,3,apple schnapps 18 | Apple Martini,3,cointreau 19 | Long Island Iced Tea,3,vodka 20 | Long Island Iced Tea,3,tequila 21 | Long Island Iced Tea,3,rum 22 | Long Island Iced Tea,3,triple sec 23 | Long Island Iced Tea,3,Gin 24 | Long Island Iced Tea,5,lemon juice 25 | Long Island Iced Tea,6,gomme syrup 26 | Mudslide,6,vodka 27 | Mudslide,6,coffee liqueur 28 | Mudslide,6,bailey's 29 | Mudslide,6,cream 30 | Margarita,7,tequila 31 | Margarita,4,cointreau 32 | Margarita,3,lime juice 33 | Kamikaze,6,vodka 34 | Kamikaze,6,triple sec 35 | Kamikaze,6,lime juice 36 | Mojito,8,rum 37 | Mojito,6,lime juice 38 | Mojito,1,sugar 39 | Mojito,1,mint 40 | Mojito,12,soda 41 | Caribou Lou,6,rum 42 | Caribou Lou,3,pineapple juice 43 | Cuba Libre,12,Cola 44 | Cuba Libre,6,rum 45 | Jager Monster,9,Jagermeister 46 | Jager Monster,6,orange juice 47 | Daiquiri,9,rum 48 | Daiquiri,4,lime juice 49 | Daiquiri,1,syrup 50 | Whiskey Sour,3,whiskey 51 | Whiskey Sour,2,lemon juice 52 | Whiskey Sour,1,syrup 53 | Mint Julep,18,whiskey 54 | Mint Julep,1,mint 55 | Mint Julep,1,sugar 56 | Pina Colada,6,rum 57 | Pina Colada,6,cream 58 | Pina Colada,6,pineapple juice 59 | Sex on the Beach,8,vodka 60 | Sex on the Beach,4,peach schnapps 61 | Sex on the Beach,8,orange juice 62 | Sex on the Beach,8,cranberry juice 63 | B-52,4,coffee liqueur 64 | B-52,4,bailey's 65 | B-52,4,cointreau -------------------------------------------------------------------------------- /charts/convexHull.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var points = raw.models.points(); 4 | 5 | points.dimensions().remove('size'); 6 | points.dimensions().remove('label'); 7 | points.dimensions().remove('color'); 8 | 9 | var chart = raw.chart() 10 | .title('Convex Hull') 11 | .description( 12 | "In mathematics, the convex hull is the smallest convex shape containing a set o points. Applied to a scatterplot, it is useful to identify points belonging to the same category.

Based on http://bl.ocks.org/mbostock/4341699") 13 | .thumbnail("imgs/convexHull.png") 14 | .model(points) 15 | 16 | var width = chart.number() 17 | .title("Width") 18 | .defaultValue(1000) 19 | .fitToWidth(true) 20 | 21 | var height = chart.number() 22 | .title("Height") 23 | .defaultValue(500) 24 | 25 | var stroke = chart.number() 26 | .title("Stroke Width") 27 | .defaultValue(32) 28 | 29 | chart.draw(function (selection, data){ 30 | 31 | var x = d3.scale.linear().range([0,+width()-stroke()]).domain(d3.extent(data, function (d){ return d.x; })), 32 | y = d3.scale.linear().range([+height()-stroke(), 0]).domain(d3.extent(data, function (d){ return d.y; })); 33 | 34 | var vertices = data.map(function (d){ 35 | return [ x(d.x), y(d.y) ] 36 | }) 37 | 38 | var g = selection 39 | .attr("width", +width()) 40 | .attr("height", +height()) 41 | .append("g") 42 | .attr("transform","translate(" + stroke()/2 + "," + stroke()/2 + ")") 43 | 44 | g.append("path") 45 | .datum(d3.geom.hull(vertices)) 46 | .style("fill", "#bbb") 47 | .style("stroke","#bbb") 48 | .style("stroke-width", +stroke()) 49 | .style("stroke-linejoin","round") 50 | .attr("d", function (d) { return "M" + d.join("L") + "Z"; }); 51 | 52 | g.selectAll("circle") 53 | .data(vertices) 54 | .enter().append("circle") 55 | .attr("r", 2) 56 | .attr("transform", function (d) { return "translate(" + d + ")"; }) 57 | }) 58 | })(); -------------------------------------------------------------------------------- /charts/voronoi.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var points = raw.models.points(); 4 | 5 | points.dimensions().remove('size'); 6 | points.dimensions().remove('label'); 7 | 8 | var chart = raw.chart() 9 | .title('Voronoi Tessellation') 10 | .description( 11 | "It creates the minimum area around each point defined by two variables. When applied to a scatterplot, it is useful to show the distance between points.
Based on http://bl.ocks.org/mbostock/4060366") 12 | .thumbnail("imgs/voronoi.png") 13 | .category('Distributions') 14 | .model(points) 15 | 16 | var width = chart.number() 17 | .title("Width") 18 | .defaultValue(1000) 19 | .fitToWidth(true) 20 | 21 | var height = chart.number() 22 | .title("Height") 23 | .defaultValue(500) 24 | 25 | var colors = chart.color() 26 | .title("Color scale") 27 | 28 | var showPoints = chart.checkbox() 29 | .title("Show points") 30 | .defaultValue(true) 31 | 32 | chart.draw(function (selection, data){ 33 | 34 | var x = d3.scale.linear().range([0,+width()]).domain(d3.extent(data, function (d){ return d.x; })), 35 | y = d3.scale.linear().range([+height(), 0]).domain(d3.extent(data, function (d){ return d.y; })); 36 | 37 | var voronoi = d3.geom.voronoi() 38 | .x(function (d){ return x(d.x); }) 39 | .y(function (d){ return y(d.y); }) 40 | .clipExtent([ [ 0, 0 ], [+width(), +height()] ]); 41 | 42 | var g = selection 43 | .attr("width", +width()) 44 | .attr("height", +height()) 45 | .append("g"); 46 | 47 | colors.domain(data, function (d){ return d.color; }); 48 | 49 | var path = g.selectAll("path") 50 | .data(voronoi(data), polygon) 51 | .enter().append("path") 52 | .style("fill",function (d){ return d && colors()? colors()(d.point.color) : "#dddddd"; }) 53 | .style("stroke","#fff") 54 | .attr("d", polygon); 55 | 56 | path.order(); 57 | 58 | g.selectAll("circle") 59 | .data(data.filter(function(){ return showPoints() })) 60 | .enter().append("circle") 61 | .style("fill","#000000") 62 | .style("pointer-events","none") 63 | .attr("transform", function (d) { return "translate(" + x(d.x) + ", " + y(d.y) + ")"; }) 64 | .attr("r", 1.5); 65 | 66 | function polygon(d) { 67 | if(!d) return; 68 | return "M" + d.join("L") + "Z"; 69 | } 70 | 71 | }) 72 | })(); 73 | -------------------------------------------------------------------------------- /charts/chart.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | // A simple scatterplot for APIs demo 4 | 5 | // The Model 6 | 7 | var model = raw.model(); 8 | 9 | // X axis dimension 10 | // Adding a title to be displayed in the UI 11 | // and limiting the type of data to Numbers only 12 | var x = model.dimension() 13 | .title('X Axis') 14 | .types(Number) 15 | 16 | // Y axis dimension 17 | // Same as X 18 | var y = model.dimension() 19 | .title('Y Axis') 20 | .types(Number) 21 | 22 | // Mapping function 23 | // For each record in the data returns the values 24 | // for the X and Y dimensions and casts them as numbers 25 | model.map(function (data){ 26 | return data.map(function (d){ 27 | return { 28 | x : +x(d), 29 | y : +y(d) 30 | } 31 | }) 32 | }) 33 | 34 | 35 | // The Chart 36 | 37 | var chart = raw.chart() 38 | .title("Simple Scatter Plot") 39 | .description("A simple chart for test") 40 | .model(model) 41 | 42 | // Some options we want to expose to the users 43 | // For each of them a GUI component will be created 44 | // Options can be use within the Draw function 45 | // by simply calling them (i.e. witdh()) 46 | // the current value of the options will be returned 47 | 48 | // Width 49 | var width = chart.number() 50 | .title('Width') 51 | .defaultValue(900) 52 | 53 | // Height 54 | var height = chart.number() 55 | .title('Height') 56 | .defaultValue(600) 57 | 58 | // A simple margin 59 | var margin = chart.number() 60 | .title('margin') 61 | .defaultValue(10) 62 | 63 | // Drawing function 64 | // selection represents the d3 selection (svg) 65 | // data is not the original set of records 66 | // but the result of the model map function 67 | chart.draw(function (selection, data){ 68 | 69 | // svg size 70 | selection 71 | .attr("width", width()) 72 | .attr("height", height()) 73 | 74 | // x and y scale 75 | var xScale = d3.scale.linear().domain([0, d3.max(data, function (d){ return d.x; })]).range([margin(), width()-margin()]); 76 | var yScale = d3.scale.linear().domain([0, d3.max(data, function (d){ return d.y; })]).range([height()-margin(), margin()]); 77 | 78 | // let's plot the dots! 79 | selection.selectAll("circle") 80 | .data(data) 81 | .enter().append("circle") 82 | .attr("cx", function(d) { return xScale(d.x); }) 83 | .attr("cy", function(d) { return yScale(d.y); }) 84 | .attr("r", 5) 85 | 86 | }) 87 | })(); -------------------------------------------------------------------------------- /charts/circularDendrogram.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var tree = raw.models.tree(); 4 | 5 | tree.dimensions().remove('size'); 6 | tree.dimensions().remove('color'); 7 | tree.dimensions().remove('label'); 8 | 9 | var chart = raw.chart() 10 | .title('Circular Dendrogram') 11 | .description( 12 | "Dendrograms are tree-like diagrams used to represent the distribution of a hierarchical clustering. The different depth levels represented by each node are visualized on the horizontal axes and it is useful to visualize a non-weighted hierarchy.
Based on
http://bl.ocks.org/mbostock/4063570") 13 | .thumbnail("imgs/circularDendrogram.png") 14 | .category('Hierarchies') 15 | .model(tree) 16 | 17 | var diameter = chart.number () 18 | .title("Radius") 19 | .defaultValue(1000) 20 | .fitToWidth(true) 21 | 22 | chart.draw(function (selection, data){ 23 | 24 | var g = selection 25 | .attr("width", +diameter() ) 26 | .attr("height", +diameter() ) 27 | .append("g") 28 | .attr("transform", "translate(" + diameter()/2 + "," + diameter()/2 + ")"); 29 | 30 | var cluster = d3.layout.cluster() 31 | .size([360, diameter()/2-120]); 32 | 33 | var diagonal = d3.svg.diagonal.radial() 34 | .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; }); 35 | 36 | var nodes = cluster.nodes(data); 37 | 38 | var link = g.selectAll("path.link") 39 | .data(cluster.links(nodes)) 40 | .enter().append("path") 41 | .attr("class", "link") 42 | .style("fill","none") 43 | .style("stroke","#cccccc") 44 | .style("stroke-width","1px") 45 | .attr("d", diagonal); 46 | 47 | var node = g.selectAll("g.node") 48 | .data(nodes) 49 | .enter().append("g") 50 | .attr("class", "node") 51 | .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; }) 52 | 53 | node.append("circle") 54 | .attr("r", 4.5) 55 | .style("fill", "#eeeeee") 56 | .style("stroke","#999999") 57 | .style("stroke-width","1px"); 58 | 59 | node.append("text") 60 | .attr("dy", ".31em") 61 | .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) 62 | .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; }) 63 | .text(function(d) { return d.name; }) 64 | .style("font-size","11px") 65 | .style("font-family","Arial, Helvetica") 66 | 67 | }) 68 | })(); 69 | -------------------------------------------------------------------------------- /charts/reingoldTilford.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var tree = raw.models.tree(); 4 | 5 | tree.dimensions().remove('size'); 6 | tree.dimensions().remove('color'); 7 | tree.dimensions().remove('label'); 8 | 9 | var chart = raw.chart() 10 | .title('Reingold–Tilford Tree') 11 | .description( 12 | "The tree layout implements the Reingold-Tilford algorithm for efficient, tidy arrangement of layered nodes. The depth of nodes is computed by distance from the root, leading to a ragged appearance.
Based on http://bl.ocks.org/mbostock/4339184") 13 | .thumbnail("imgs/reingoldTilford.png") 14 | .category('Hierarchies') 15 | .model(tree) 16 | 17 | var width = chart.number() 18 | .title("Width") 19 | .defaultValue(1000) 20 | .fitToWidth(true) 21 | 22 | var height = chart.number() 23 | .title("Height") 24 | .defaultValue(500) 25 | 26 | chart.draw(function (selection, data){ 27 | 28 | var g = selection 29 | .attr("width", +width() ) 30 | .attr("height", +height() ) 31 | .append("g") 32 | .attr("transform", "translate(40,0)"); 33 | 34 | var layout = d3.layout.tree() 35 | .size([+height(), +width() -160]); 36 | 37 | var diagonal = d3.svg.diagonal() 38 | .projection(function (d) { return [d.y, d.x]; }); 39 | 40 | var nodes = layout.nodes(data), 41 | links = layout.links(nodes); 42 | 43 | var link = g.selectAll("path.link") 44 | .data(links) 45 | .enter().append("path") 46 | .attr("class", "link") 47 | .style("fill","none") 48 | .style("stroke","#cccccc") 49 | .style("stroke-width","1px") 50 | .attr("d", diagonal); 51 | 52 | var node = g.selectAll("g.node") 53 | .data(nodes) 54 | .enter().append("g") 55 | .attr("class", "node") 56 | .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }) 57 | 58 | node.append("circle") 59 | .style("fill", "#eeeeee") 60 | .style("stroke","#999999") 61 | .style("stroke-width","1px") 62 | .attr("r", 4.5); 63 | 64 | node.append("text") 65 | .attr("dx", function(d) { return d.children ? -8 : 8; }) 66 | .attr("dy", 3) 67 | .style("font-size","11px") 68 | .style("font-family","Arial, Helvetica") 69 | .attr("text-anchor", function(d) { return d.children ? "end" : "start"; }) 70 | .text(function (d){ return d.name; }); 71 | 72 | }) 73 | })(); 74 | -------------------------------------------------------------------------------- /charts/clusterDendrogram.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var tree = raw.models.tree(); 4 | 5 | tree.dimensions().remove('size'); 6 | tree.dimensions().remove('color'); 7 | tree.dimensions().remove('label'); 8 | 9 | var chart = raw.chart() 10 | .title('Cluster Dendrogram') 11 | .description( 12 | "Dendrograms are tree-like diagrams used to represent the distribution of a hierarchical clustering. The different depth levels represented by each node are visualized on the horizontal axes and it is useful to visualize a non-weighted hierarchy.
Based on
http://bl.ocks.org/mbostock/4063570") 13 | .thumbnail("imgs/dendrogram.png") 14 | .category('Hierarchies') 15 | .model(tree) 16 | 17 | var width = chart.number() 18 | .title("Width") 19 | .defaultValue(1000) 20 | .fitToWidth(true) 21 | 22 | var height = chart.number() 23 | .title("Height") 24 | .defaultValue(500) 25 | 26 | chart.draw(function (selection, data){ 27 | 28 | var g = selection 29 | .attr("width", +width() ) 30 | .attr("height", +height() ) 31 | .append("g") 32 | .attr("transform", "translate(40,0)"); 33 | 34 | var cluster = d3.layout.cluster() 35 | .size([+height(), +width() - 160]); 36 | 37 | var diagonal = d3.svg.diagonal() 38 | .projection(function (d) { return [d.y, d.x]; }); 39 | 40 | var nodes = cluster.nodes(data), 41 | links = cluster.links(nodes); 42 | 43 | var link = g.selectAll(".link") 44 | .data(links) 45 | .enter().append("path") 46 | .attr("class", "link") 47 | .style("fill","none") 48 | .style("stroke","#cccccc") 49 | .style("stroke-width","1px") 50 | .attr("d", diagonal); 51 | 52 | var node = g.selectAll(".node") 53 | .data(nodes) 54 | .enter().append("g") 55 | .attr("class", "node") 56 | .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }) 57 | 58 | node.append("circle") 59 | .attr("r", 4.5) 60 | .style("fill", "#eeeeee") 61 | .style("stroke","#999999") 62 | .style("stroke-width","1px") 63 | 64 | node.append("text") 65 | .style("font-size","11px") 66 | .style("font-family","Arial, Helvetica") 67 | .attr("dx", function(d) { return d.children ? -8 : 8; }) 68 | .attr("dy", 3) 69 | .style("text-anchor", function(d) { return d.children ? "end" : "start"; }) 70 | .text(function(d) { return d.name; }); 71 | 72 | }) 73 | })(); -------------------------------------------------------------------------------- /charts/treemap.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var tree = raw.models.tree(); 4 | 5 | var chart = raw.chart() 6 | .title('Treemap') 7 | .description( 8 | "A space filling visualization of data hierarchies and proportion between elements. The different hierarchical levels create visual clusters through the subdivision into rectangles proportionally to each element's value. Treemaps are useful to represent the different proportion of nested hierarchical data structures.
Based on http://bl.ocks.org/mbostock/4063582") 9 | .thumbnail("imgs/treemap.png") 10 | .category('Hierarchies') 11 | .model(tree) 12 | 13 | var width = chart.number() 14 | .title('Width') 15 | .defaultValue(100) 16 | .fitToWidth(true) 17 | 18 | var height = chart.number() 19 | .title("Height") 20 | .defaultValue(500) 21 | 22 | var padding = chart.number() 23 | .title("Padding") 24 | .defaultValue(5) 25 | 26 | var colors = chart.color() 27 | .title("Color scale") 28 | 29 | chart.draw(function (selection, data){ 30 | 31 | var format = d3.format(",d"); 32 | 33 | var layout = d3.layout.treemap() 34 | .sticky(true) 35 | .padding(+padding()) 36 | .size([+width(), +height()]) 37 | .value(function(d) { return d.size; }) 38 | 39 | var g = selection 40 | .attr("width", +width()) 41 | .attr("height", +height()) 42 | .append("g") 43 | .attr("transform", "translate(.5,.5)"); 44 | 45 | var nodes = layout.nodes(data) 46 | .filter(function(d) { return !d.children; }); 47 | 48 | colors.domain(nodes, function (d){ return d.color; }); 49 | 50 | var cell = g.selectAll("g") 51 | .data(nodes) 52 | .enter().append("g") 53 | .attr("class", "cell") 54 | .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 55 | 56 | cell.append("svg:rect") 57 | .attr("width", function (d) { return d.dx; }) 58 | .attr("height", function (d) { return d.dy; }) 59 | .style("fill", function (d) { return colors()(d.color); }) 60 | .style("fill-opacity", function (d) { return d.children ? 0 : 1; }) 61 | .style("stroke","#fff") 62 | 63 | cell.append("svg:title") 64 | .text(function(d) { return d.name + ": " + format(d.size); }); 65 | 66 | cell.append("svg:text") 67 | .attr("x", function(d) { return d.dx / 2; }) 68 | .attr("y", function(d) { return d.dy / 2; }) 69 | .attr("dy", ".35em") 70 | .attr("text-anchor", "middle") 71 | // .attr("fill", function (d) { return raw.foreground(color()(d.color)); }) 72 | .style("font-size","11px") 73 | .style("font-family","Arial, Helvetica") 74 | .text(function(d) { return d.label ? d.label.join(", ") : d.name; }); 75 | 76 | }) 77 | })(); -------------------------------------------------------------------------------- /charts/packing.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var tree = raw.models.tree(); 4 | 5 | var chart = raw.chart() 6 | .title('Circle Packing') 7 | .description( 8 | "Nested circles allow to represent hierarchies and compare values. This visualization is particularly effective to show the proportion between elements through their areas and their position inside a hierarchical structure.
Based on http://bl.ocks.org/mbostock/4063530") 9 | .thumbnail("imgs/circlePacking.png") 10 | .category('Hierarchies') 11 | .model(tree) 12 | 13 | var diameter = chart.number() 14 | .title("Diameter") 15 | .defaultValue(800) 16 | .fitToWidth(true) 17 | 18 | var padding = chart.number() 19 | .title("Padding") 20 | .defaultValue(5) 21 | 22 | var sort = chart.checkbox() 23 | .title("Sort by size") 24 | .defaultValue(false) 25 | 26 | var colors = chart.color() 27 | .title("Color scale") 28 | 29 | var showLabels = chart.checkbox() 30 | .title("Show labels") 31 | .defaultValue(true) 32 | 33 | chart.draw(function (selection, data){ 34 | 35 | if (!data.children.length) return; 36 | 37 | var margin = 10, 38 | outerDiameter = +diameter(), 39 | innerDiameter = outerDiameter - margin - margin; 40 | 41 | var x = d3.scale.linear() 42 | .range([0, innerDiameter]); 43 | 44 | var y = d3.scale.linear() 45 | .range([0, innerDiameter]); 46 | 47 | var pack = d3.layout.pack() 48 | .padding(+padding()) 49 | .sort(function (a,b){ return sort() ? a.value-b.value : null; }) 50 | .size([innerDiameter, innerDiameter]) 51 | .value(function(d) { return +d.size; }) 52 | 53 | var g = selection 54 | .attr("width", outerDiameter) 55 | .attr("height", outerDiameter) 56 | .append("g") 57 | .attr("transform", "translate(" + margin + "," + margin + ")"); 58 | 59 | var focus = data, 60 | nodes = pack.nodes(data); 61 | 62 | colors.domain(nodes.filter(function (d){ return !d.children; }), function (d){ return d.color; }); 63 | 64 | g.append("g").selectAll("circle") 65 | .data(nodes) 66 | .enter().append("circle") 67 | .attr("class", function (d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; }) 68 | .attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; }) 69 | .attr("r", function (d) { return d.r; }) 70 | .style("fill", function (d) { return !d.children ? colors()(d.color) : ''; }) 71 | .style("fill-opacity", function (d){ return !d.children ? 1 : 0; }) 72 | .style("stroke", '#ddd') 73 | .style("stroke-opacity", function (d) { return !d.children ? 0 : 1 }) 74 | 75 | g.append("g").selectAll("text") 76 | .data(nodes.filter(function (d){ return showLabels(); })) 77 | .enter().append("text") 78 | .attr("text-anchor", "middle") 79 | .style("font-size","11px") 80 | .style("font-family","Arial, Helvetica") 81 | .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 82 | .text(function (d) { return d.label ? d.label.join(", ") : d.name; }); 83 | 84 | }) 85 | })(); -------------------------------------------------------------------------------- /charts/hexagonalBinning.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var points = raw.models.points(); 4 | 5 | points.dimensions().remove('size'); 6 | points.dimensions().remove('label'); 7 | points.dimensions().remove('color'); 8 | 9 | var chart = raw.chart() 10 | .title('Hexagonal Binning') 11 | .description( 12 | "Visually clusters the most populated areas on a scatterplot. Useful to make more readable a scatterplot when plotting hundreds of points.
Based on http://bl.ocks.org/mbostock/4248145") 13 | .thumbnail("imgs/binning.png") 14 | .category('Distributions') 15 | .model(points) 16 | 17 | var width = chart.number() 18 | .title("Width") 19 | .defaultValue(1000) 20 | .fitToWidth(true) 21 | 22 | var height = chart.number() 23 | .title("Height") 24 | .defaultValue(500) 25 | 26 | var radius = chart.number() 27 | .title("Radius") 28 | .defaultValue(20) 29 | 30 | var useZero = chart.checkbox() 31 | .title("set origin at (0,0)") 32 | .defaultValue(false) 33 | 34 | var colors = chart.color() 35 | .title("Color scale") 36 | 37 | var showPoints = chart.checkbox() 38 | .title("show points") 39 | .defaultValue(true) 40 | 41 | chart.draw(function (selection, data){ 42 | 43 | // Retrieving dimensions from model 44 | var x = points.dimensions().get('x'), 45 | y = points.dimensions().get('y'); 46 | 47 | var g = selection 48 | .attr("width", +width() ) 49 | .attr("height", +height() ) 50 | .append("g") 51 | 52 | var marginLeft = d3.max(data, function (d) { return (Math.log(d.y) / 2.302585092994046) + 1; }) * 9, 53 | marginBottom = 20, 54 | w = width() - marginLeft, 55 | h = height() - marginBottom; 56 | 57 | var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })], 58 | yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })]; 59 | 60 | var xScale = x.type() == "Date" 61 | ? d3.time.scale().range([marginLeft,width()]).domain(xExtent) 62 | : d3.scale.linear().range([marginLeft,width()]).domain(xExtent), 63 | yScale = y.type() == "Date" 64 | ? d3.time.scale().range([h, 0]).domain(yExtent) 65 | : d3.scale.linear().range([h, 0]).domain(yExtent), 66 | xAxis = d3.svg.axis().scale(xScale).tickSize(-h).orient("bottom"), 67 | yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w).orient("left"); 68 | 69 | var hexbin = d3.hexbin() 70 | .size([w, h]) 71 | .x(function(d){ return xScale(d.x); }) 72 | .y(function(d){ return yScale(d.y); }) 73 | .radius(+radius()); 74 | 75 | var xAxis = d3.svg.axis() 76 | .scale(xScale) 77 | .orient("bottom") 78 | .tickSize(6, -h); 79 | 80 | var yAxis = d3.svg.axis() 81 | .scale(yScale) 82 | .orient("left") 83 | .tickSize(6, -w); 84 | 85 | g.append("clipPath") 86 | .attr("id", "clip") 87 | .append("rect") 88 | .attr("class", "mesh") 89 | .attr("width", w) 90 | .attr("height", h) 91 | .attr("transform", "translate(" + marginLeft + ",1)"); 92 | 93 | colors.domain(hexbin(data), function (d){ return d.length; }); 94 | 95 | g.append("g") 96 | .attr("clip-path", "url(#clip)") 97 | .selectAll(".hexagon") 98 | .data(hexbin(data)) 99 | .enter().append("path") 100 | .attr("class", "hexagon") 101 | .attr("d", hexbin.hexagon()) 102 | .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 103 | .style("fill", function(d) { return colors()(d.length); }) 104 | .attr("stroke","#000") 105 | .attr("stroke-width",".5px") 106 | 107 | var point = g.selectAll("g.point") 108 | .data(data) 109 | .enter().append("g") 110 | .attr("class","point") 111 | 112 | point.append("circle") 113 | .filter(function(){ return showPoints(); }) 114 | .style("fill", "#000") 115 | .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; }) 116 | .attr("r", 1); 117 | 118 | g.append("g") 119 | .attr("class", "y axis") 120 | .attr("transform", "translate(" + marginLeft + ",0)") 121 | .call(yAxis); 122 | 123 | g.append("g") 124 | .attr("class", "x axis") 125 | .attr("transform", "translate(0," + h + ")") 126 | .call(xAxis); 127 | 128 | g.selectAll(".axis") 129 | .selectAll("text") 130 | .style("font","10px Arial, Helvetica") 131 | 132 | g.selectAll(".axis") 133 | .selectAll("path") 134 | .style("fill","none") 135 | .style("stroke","#000000") 136 | .style("shape-rendering","crispEdges") 137 | 138 | g.selectAll(".axis") 139 | .selectAll("line") 140 | .style("fill","none") 141 | .style("stroke","#000000") 142 | .style("shape-rendering","crispEdges") 143 | }) 144 | })(); 145 | -------------------------------------------------------------------------------- /charts/parallelCoordinates.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var model = raw.model(); 4 | 5 | var list = model.dimension() 6 | .title('Dimensions') 7 | .multiple(true) 8 | .types(Number) 9 | .required(2); 10 | 11 | var color = model.dimension() 12 | .title("Color") 13 | 14 | model.map(function (data){ 15 | if (!list()) return; 16 | return data.map(function (d){ 17 | var obj = { dimensions: {}, color: color(d) }; 18 | list().forEach(function (l){ 19 | obj.dimensions[l] = d[l]; 20 | }) 21 | return obj; 22 | }) 23 | }) 24 | 25 | var chart = raw.chart() 26 | .title('Parallel Coordinates') 27 | .description( 28 | "Parallel coordinates is a common way of visualizing high-dimensional geometry and analyzing multivariate data.To show a set of points in an n-dimensional space, a backdrop is drawn consisting of n parallel lines, typically vertical and equally spaced. A point in n-dimensional space is represented as a polyline with vertices on the parallel axes; the position of the vertex on the ith axis corresponds to the ith coordinate of the point.
Based on http://bl.ocks.org/jasondavies/1341281") 29 | .thumbnail("imgs/parallelCoordinates.png") 30 | .category('Distributions') 31 | .model(model) 32 | 33 | var width = chart.number() 34 | .title("Width") 35 | .defaultValue(1000) 36 | .fitToWidth(true) 37 | 38 | var height = chart.number() 39 | .title("Height") 40 | .defaultValue(500) 41 | 42 | var colors = chart.color() 43 | .title("Color scale") 44 | 45 | chart.draw(function (selection, data){ 46 | 47 | var m = [30, 40, 10, 40], 48 | w = +width() - m[1] - m[3], 49 | h = +height() - m[0] - m[2]; 50 | 51 | var x = d3.scale.ordinal().rangePoints([0, w], 0), 52 | y = {}, 53 | dragging = {}; 54 | 55 | var line = d3.svg.line(), 56 | axis = d3.svg.axis().orient("left"), 57 | background, 58 | foreground; 59 | 60 | var svg = selection 61 | .attr("width", +width()) 62 | .attr("height", +height()) 63 | .append("g") 64 | .attr("width", w + m[1] + m[3]) 65 | .attr("height", h + m[0] + m[2]) 66 | .style("font-size","10px") 67 | .style("font-family","Arial, Helvetica") 68 | .append("svg:g") 69 | .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); 70 | 71 | x.domain(dimensions = d3.keys(data[0].dimensions).filter(function (d) { 72 | return d != "name" && (y[d] = d3.scale.linear() 73 | .domain(d3.extent(data, function(p) { return +p.dimensions[d]; })) 74 | .range([h, 0])); 75 | })); 76 | 77 | colors.domain(data, function (d){ return d.color; }); 78 | 79 | background = svg.append("svg:g") 80 | .attr("class", "background") 81 | .selectAll("path") 82 | .data(data) 83 | .enter().append("svg:path") 84 | .style('fill','none') 85 | .style('stroke', function (d){ return colors()(d.color); }) 86 | .style('stroke-opacity','.4') 87 | .attr("d", path); 88 | 89 | var g = svg.selectAll(".dim") 90 | .data(dimensions) 91 | .enter().append("svg:g") 92 | .attr("class", "dim") 93 | .attr("transform", function(d) { return "translate(" + x(d) + ")"; }); 94 | 95 | g.append("svg:g") 96 | .attr("class", "axis") 97 | .each(function(d) { d3.select(this).call(axis.scale(y[d])); }) 98 | .append("svg:text") 99 | .attr("text-anchor", "middle") 100 | .style("font-size","10px") 101 | .style("font-family","Arial, Helvetica") 102 | .attr("y", -9) 103 | .text(String); 104 | 105 | d3.selectAll('text') 106 | .style("font-size","10px") 107 | .style("font-family","Arial, Helvetica") 108 | 109 | d3.selectAll(".axis line, .axis path") 110 | .style('fill', 'none') 111 | .style('stroke', '#000') 112 | .style('stroke-width', '1px') 113 | .style('shape-rendering','crispEdges') 114 | 115 | function position(d) { 116 | var v = dragging[d]; 117 | return v == null ? x(d) : v; 118 | } 119 | 120 | function path(d) { 121 | return line(dimensions.map(function(p) { return [position(p), y[p](d.dimensions[p])]; })); 122 | } 123 | 124 | }); 125 | 126 | })(); -------------------------------------------------------------------------------- /charts/scatterPlot.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var points = raw.models.points(); 4 | 5 | var chart = raw.chart() 6 | .title('Scatter Plot') 7 | .description( 8 | "A scatter plot, scatterplot, or scattergraph is a type of mathematical diagram using Cartesian coordinates to display values for two variables for a set of data. The data is displayed as a collection of points, each having the value of one variable determining the position on the horizontal axis and the value of the other variable determining the position on the vertical axis. This kind of plot is also called a scatter chart, scattergram, scatter diagram, or scatter graph.") 9 | .thumbnail("imgs/scatterPlot.png") 10 | .category('Distributions') 11 | .model(points) 12 | 13 | var width = chart.number() 14 | .title("Width") 15 | .defaultValue(1000) 16 | .fitToWidth(true) 17 | 18 | var height = chart.number() 19 | .title("Height") 20 | .defaultValue(500) 21 | 22 | var maxRadius = chart.number() 23 | .title("max radius") 24 | .defaultValue(20) 25 | 26 | var useZero = chart.checkbox() 27 | .title("set origin at (0,0)") 28 | .defaultValue(false) 29 | 30 | var colors = chart.color() 31 | .title("Color scale") 32 | 33 | var showPoints = chart.checkbox() 34 | .title("show points") 35 | .defaultValue(true) 36 | 37 | chart.draw(function (selection, data){ 38 | 39 | // Retrieving dimensions from model 40 | var x = points.dimensions().get('x'), 41 | y = points.dimensions().get('y'); 42 | 43 | var g = selection 44 | .attr("width", +width() ) 45 | .attr("height", +height() ) 46 | .append("g") 47 | 48 | var marginLeft = d3.max([maxRadius(),(d3.max(data, function (d) { return (Math.log(d.y) / 2.302585092994046) + 1; }) * 9)]), 49 | marginBottom = 20, 50 | w = width() - marginLeft, 51 | h = height() - marginBottom; 52 | 53 | var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })], 54 | yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })]; 55 | 56 | var xScale = x.type() == "Date" 57 | ? d3.time.scale().range([marginLeft,width()-maxRadius()]).domain(xExtent) 58 | : d3.scale.linear().range([marginLeft,width()-maxRadius()]).domain(xExtent), 59 | yScale = y.type() == "Date" 60 | ? d3.time.scale().range([h-maxRadius(), maxRadius()]).domain(yExtent) 61 | : d3.scale.linear().range([h-maxRadius(), maxRadius()]).domain(yExtent), 62 | sizeScale = d3.scale.linear().range([1, Math.pow(+maxRadius(),2)*Math.PI]).domain([0, d3.max(data, function (d){ return d.size; })]), 63 | xAxis = d3.svg.axis().scale(xScale).tickSize(-h+maxRadius()*2).orient("bottom")//.tickSubdivide(true), 64 | yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w+maxRadius()).orient("left"); 65 | 66 | 67 | g.append("g") 68 | .attr("class", "x axis") 69 | .style("stroke-width", "1px") 70 | .style("font-size","10px") 71 | .style("font-family","Arial, Helvetica") 72 | .attr("transform", "translate(" + 0 + "," + (h-maxRadius()) + ")") 73 | .call(xAxis); 74 | 75 | g.append("g") 76 | .attr("class", "y axis") 77 | .style("stroke-width", "1px") 78 | .style("font-size","10px") 79 | .style("font-family","Arial, Helvetica") 80 | .attr("transform", "translate(" + marginLeft + "," + 0 + ")") 81 | .call(yAxis); 82 | 83 | d3.selectAll(".y.axis line, .x.axis line, .y.axis path, .x.axis path") 84 | .style("shape-rendering","crispEdges") 85 | .style("fill","none") 86 | .style("stroke","#ccc") 87 | 88 | var circle = g.selectAll("g.circle") 89 | .data(data) 90 | .enter().append("g") 91 | .attr("class","circle") 92 | 93 | var point = g.selectAll("g.point") 94 | .data(data) 95 | .enter().append("g") 96 | .attr("class","point") 97 | 98 | colors.domain(data, function(d){ return d.color; }); 99 | 100 | circle.append("circle") 101 | .style("fill", function(d) { return colors() ? colors()(d.color) : "#eeeeee"; }) 102 | .style("fill-opacity", .9) 103 | .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; }) 104 | .attr("r", function (d){ return Math.sqrt(sizeScale(d.size)/Math.PI); }); 105 | 106 | point.append("circle") 107 | .filter(function(){ return showPoints(); }) 108 | .style("fill", "#000") 109 | .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; }) 110 | .attr("r", 1); 111 | 112 | circle.append("text") 113 | .attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; }) 114 | .attr("text-anchor", "middle") 115 | .style("font-size","10px") 116 | .attr("dy", 15) 117 | .style("font-family","Arial, Helvetica") 118 | .text(function (d){ return d.label? d.label.join(", ") : ""; }); 119 | 120 | }) 121 | 122 | })(); -------------------------------------------------------------------------------- /charts/smallMultiplesArea.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var stream = raw.model(); 4 | 5 | var group = stream.dimension() 6 | .title('Group') 7 | .required(1) 8 | 9 | var date = stream.dimension() 10 | .title('Date') 11 | .types(Date) 12 | .accessor(function (d){ return this.type() == "Date" ? new Date(d) : +d; }) 13 | .required(1) 14 | 15 | var size = stream.dimension() 16 | .title('Size') 17 | .types(Number) 18 | .required(1) 19 | 20 | stream.map(function (data){ 21 | if (!group()) return []; 22 | 23 | var dates = d3.set(data.map(function (d){ return +date(d); })).values(); 24 | 25 | var groups = d3.nest() 26 | .key(group) 27 | .rollup(function (g){ 28 | var singles = d3.nest() 29 | .key(function(d){ return +date(d); }) 30 | .rollup(function (d){ 31 | return { 32 | group : group(d[0]), 33 | date : date(d[0]), 34 | size : size() ? d3.sum(d,size) : d.length 35 | } 36 | }) 37 | .map(g); 38 | 39 | return d3.values(singles); 40 | }) 41 | .map(data) 42 | 43 | return d3.values(groups).map(function(d){ return d.sort(function(a,b){ return a.date - b.date; }) }); 44 | 45 | }) 46 | 47 | var chart = raw.chart() 48 | .title('Small Multiples (Area)') 49 | .thumbnail("imgs/smallMultiples.png") 50 | .description("A small multiple is a series of small similar graphics or charts, allowing them to be easily compared.
Based on http://bl.ocks.org/mbostock/9490313") 51 | .category('Time Series') 52 | .model(stream) 53 | 54 | var width = chart.number() 55 | .title("Width") 56 | .defaultValue(1000) 57 | .fitToWidth(true) 58 | 59 | var height = chart.number() 60 | .title("Height") 61 | .defaultValue(500) 62 | 63 | var padding = chart.number() 64 | .title("Padding") 65 | .defaultValue(10) 66 | 67 | var scale = chart.checkbox() 68 | .title("Use same scale") 69 | .defaultValue(false) 70 | 71 | var colors = chart.color() 72 | .title("Color scale") 73 | 74 | chart.draw(function (selection, data){ 75 | 76 | var w = +width(), 77 | h = (+height() - (+padding()*(data.length-1))) / (data.length); 78 | 79 | var svg = selection 80 | .attr("width", +width()) 81 | .attr("height", +height()) 82 | 83 | var x = d3.time.scale() 84 | .range([0, w]); 85 | 86 | var y = d3.scale.linear() 87 | .range([h, 0]); 88 | 89 | var area = d3.svg.area() 90 | .x(function(d) { return x(d.date); }) 91 | .y0(h) 92 | .y1(function(d) { return y(d.size); }); 93 | 94 | var line = d3.svg.line() 95 | .x(function(d) { return x(d.date); }) 96 | .y(function(d) { return y(d.size); }); 97 | 98 | x.domain([ 99 | d3.min(data, function(layer) { return d3.min(layer, function(d) { return d.date; }); }), 100 | d3.max(data, function(layer) { return d3.max(layer, function(d) { return d.date; }); }) 101 | ]) 102 | 103 | colors.domain(data, function (d){ return d[0].group; }) 104 | 105 | svg.selectAll("g") 106 | .data(data) 107 | .enter().append("g") 108 | .attr("title", function(d) { return d[0].group; }) 109 | .attr("transform", function(d,i) { return "translate(0," + ((h+padding())*i) + ")"}) 110 | .each(multiple); 111 | 112 | svg.selectAll("g") 113 | .append("text") 114 | .attr("x", w - 6) 115 | .attr("y", h - 6) 116 | .style("font-size","10px") 117 | .style("fill", function(d){ return raw.foreground(colors()(d[0].group)) }) 118 | .style("font-family","Arial, Helvetica") 119 | .style("text-anchor", "end") 120 | .text(function(d) { return d[0].group; }); 121 | 122 | function multiple(single) { 123 | 124 | var g = d3.select(this); 125 | 126 | if (scale()) y.domain([0, d3.max(data, function(layer) { return d3.max(layer, function(d) { return d.size; }); })]) 127 | else y.domain([0, d3.max(single, function(d) { return d.size; })]); 128 | 129 | g.append("path") 130 | .attr("class", "area") 131 | .style("fill", function(d){ return colors()(d[0].group); }) 132 | .attr("d", area(single)); 133 | 134 | /*g.append("path") 135 | .attr("class", "line") 136 | .style("fill","none") 137 | .style("stroke","#666") 138 | .style("stroke-width","1.5px") 139 | .attr("d", line(single));*/ 140 | 141 | } 142 | 143 | }) 144 | 145 | })(); -------------------------------------------------------------------------------- /js/controllers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Controllers */ 4 | 5 | angular.module('raw.controllers', []) 6 | 7 | .controller('RawCtrl', function ($scope, dataService) { 8 | 9 | $scope.samples = [ 10 | { title : 'Cars (multivariate)', url : 'data/multivariate.csv' }, 11 | { title : 'Movies (dispersions)', url : 'data/dispersions.csv' }, 12 | { title : 'Music (flows)', url : 'data/flows.csv' }, 13 | { title : 'Cocktails (correlations)', url : 'data/correlations.csv' } 14 | ] 15 | 16 | $scope.$watch('sample', function (sample){ 17 | if (!sample) return; 18 | dataService.loadSample(sample.url).then( 19 | function(data){ 20 | $scope.text = data; 21 | }, 22 | function(error){ 23 | $scope.error = error; 24 | } 25 | ); 26 | }); 27 | 28 | // init 29 | $scope.raw = raw; 30 | $scope.data = []; 31 | $scope.metadata = []; 32 | $scope.error = false; 33 | $scope.loading = true; 34 | 35 | $scope.categories = ['Correlations', 'Distributions', 'Time Series', 'Hierarchies', 'Others']; 36 | 37 | $scope.parse = function(text){ 38 | 39 | if ($scope.model) $scope.model.clear(); 40 | 41 | $scope.data = []; 42 | $scope.metadata = []; 43 | $scope.error = false; 44 | $scope.$apply(); 45 | 46 | try { 47 | var parser = raw.parser(); 48 | $scope.data = parser(text); 49 | $scope.metadata = parser.metadata(text); 50 | $scope.error = false; 51 | } catch(e){ 52 | $scope.data = []; 53 | $scope.metadata = []; 54 | $scope.error = e.name == "ParseError" ? +e.message : false; 55 | } 56 | if (!$scope.data.length && $scope.model) $scope.model.clear(); 57 | $scope.loading = false; 58 | } 59 | 60 | $scope.delayParse = dataService.debounce($scope.parse, 500, false); 61 | 62 | $scope.$watch("text", function (text){ 63 | $scope.loading = true; 64 | $scope.delayParse(text); 65 | }); 66 | 67 | $scope.charts = raw.charts.values().sort(function (a,b){ return a.title() < b.title() ? -1 : a.title() > b.title() ? 1 : 0; }); 68 | $scope.chart = $scope.charts[0]; 69 | $scope.model = $scope.chart ? $scope.chart.model() : null; 70 | 71 | $scope.$watch('error', function (error){ 72 | if (!$('.CodeMirror')[0]) return; 73 | var cm = $('.CodeMirror')[0].CodeMirror; 74 | if (!error) { 75 | cm.removeLineClass($scope.lastError,'wrap','line-error'); 76 | return; 77 | } 78 | cm.addLineClass(error, 'wrap', 'line-error'); 79 | cm.scrollIntoView(error); 80 | $scope.lastError = error; 81 | 82 | }) 83 | 84 | $('body').mousedown(function (e,ui){ 85 | if ($(e.target).hasClass("dimension-info-toggle")) return; 86 | $('.dimensions-wrapper').each(function (e){ 87 | angular.element(this).scope().open = false; 88 | angular.element(this).scope().$apply(); 89 | }) 90 | }) 91 | 92 | $scope.codeMirrorOptions = { 93 | lineNumbers : true, 94 | lineWrapping : true, 95 | placeholder : 'Paste your text or drop a file here. No data on hand? Try one of our sample datasets!' 96 | } 97 | 98 | $scope.selectChart = function(chart){ 99 | if (chart == $scope.chart) return; 100 | $scope.model.clear(); 101 | $scope.chart = chart; 102 | $scope.model = $scope.chart.model(); 103 | } 104 | 105 | function refreshScroll(){ 106 | $('[data-spy="scroll"]').each(function () { 107 | $(this).scrollspy('refresh'); 108 | }); 109 | } 110 | 111 | $(window).scroll(function(){ 112 | 113 | // check for mobile 114 | if ($(window).width() < 760 || $('#mapping').height() < 300) return; 115 | 116 | var scrollTop = $(window).scrollTop() + 0, 117 | mappingTop = $('#mapping').offset().top + 10, 118 | mappingHeight = $('#mapping').height(), 119 | isBetween = scrollTop > mappingTop + 50 && scrollTop <= mappingTop + mappingHeight - $(".sticky").height() - 20, 120 | isOver = scrollTop > mappingTop + mappingHeight - $(".sticky").height() - 20, 121 | mappingWidth = mappingWidth ? mappingWidth : $('.col-lg-9').width(); 122 | 123 | if (mappingHeight-$('.dimensions-list').height() > 90) return; 124 | //console.log(mappingHeight-$('.dimensions-list').height()) 125 | if (isBetween) { 126 | $(".sticky") 127 | .css("position","fixed") 128 | .css("width", mappingWidth+"px") 129 | .css("top","20px") 130 | } 131 | 132 | if(isOver) { 133 | $(".sticky") 134 | .css("position","fixed") 135 | .css("width", mappingWidth+"px") 136 | .css("top", (mappingHeight - $(".sticky").height() + 0 - scrollTop+mappingTop) + "px"); 137 | return; 138 | } 139 | 140 | if (isBetween) return; 141 | 142 | $(".sticky") 143 | .css("position","relative") 144 | .css("top","") 145 | .css("width", ""); 146 | 147 | }) 148 | 149 | $(document).ready(refreshScroll); 150 | 151 | 152 | }) -------------------------------------------------------------------------------- /charts/alluvial.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var graph = raw.models.graph(); 4 | 5 | var chart = raw.chart() 6 | .title('Alluvial Diagram') 7 | .description( 8 | "Alluvial diagrams allow to represent flows and to see correlations between categorical dimensions, visually linking to the number of elements sharing the same categories. It is useful to see the evolution of cluster (such as the number of people belonging to a specific group). It can also be used to represent bipartite graphs, using each node group as dimensions.
Mainly based on our previous work with Fineo, it is inspired by http://bost.ocks.org/mike/sankey/") 9 | .thumbnail("imgs/alluvial.png") 10 | .category("Correlations") 11 | .model(graph) 12 | 13 | var width = chart.number() 14 | .title("Width") 15 | .defaultValue(1000) 16 | .fitToWidth(true) 17 | 18 | var height = chart.number() 19 | .title("Height") 20 | .defaultValue(500) 21 | 22 | var nodeWidth = chart.number() 23 | .title("Node Width") 24 | .defaultValue(5) 25 | 26 | var sortBy = chart.list() 27 | .title("Sort by") 28 | .values(['size','name','automatic']) 29 | .defaultValue('size') 30 | 31 | var colors = chart.color() 32 | .title("Color scale") 33 | 34 | chart.draw(function (selection, data){ 35 | 36 | var formatNumber = d3.format(",.0f"), 37 | format = function(d) { return formatNumber(d); }; 38 | 39 | var g = selection 40 | .attr("width", +width() ) 41 | .attr("height", +height() + 20 ) 42 | .append("g") 43 | .attr("transform", "translate(" + 0 + "," + 10 + ")"); 44 | 45 | // Calculating the best nodePadding 46 | 47 | var nested = d3.nest() 48 | .key(function (d){ return d.group; }) 49 | .rollup(function (d){ return d.length; }) 50 | .entries(data.nodes) 51 | 52 | var maxNodes = d3.max(nested, function (d){ return d.values; }); 53 | 54 | var sankey = d3.sankey() 55 | .nodeWidth(+nodeWidth()) 56 | .nodePadding(d3.min([10,(height()-maxNodes)/maxNodes])) 57 | .size([+width(), +height()]); 58 | 59 | var path = sankey.link(), 60 | nodes = data.nodes, 61 | links = data.links; 62 | 63 | sankey 64 | .nodes(nodes) 65 | .links(links) 66 | .layout(32); 67 | 68 | // Re-sorting nodes 69 | 70 | nested = d3.nest() 71 | .key(function(d){ return d.group; }) 72 | .map(nodes) 73 | 74 | d3.values(nested) 75 | .forEach(function (d){ 76 | var y = ( height() - d3.sum(d,function(n){ return n.dy+sankey.nodePadding();}) ) / 2 + sankey.nodePadding()/2; 77 | d.sort(function (a,b){ 78 | if (sortBy() == "automatic") return b.y - a.y; 79 | if (sortBy() == "size") return b.dy - a.dy; 80 | if (sortBy() == "name") return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; 81 | }) 82 | d.forEach(function (node){ 83 | node.y = y; 84 | y += node.dy +sankey.nodePadding(); 85 | }) 86 | }) 87 | 88 | // Resorting links 89 | 90 | d3.values(nested).forEach(function (d){ 91 | 92 | d.forEach(function (node){ 93 | 94 | var ly = 0; 95 | node.sourceLinks 96 | .sort(function (a,b){ 97 | return a.target.y - b.target.y; 98 | }) 99 | .forEach(function (link){ 100 | link.sy = ly; 101 | ly += link.dy; 102 | }) 103 | 104 | ly = 0; 105 | 106 | node.targetLinks 107 | .sort(function(a,b){ 108 | return a.source.y - b.source.y; 109 | }) 110 | .forEach(function (link){ 111 | link.ty = ly; 112 | ly += link.dy; 113 | }) 114 | }) 115 | }) 116 | 117 | colors.domain(links, function (d){ return d.source.name; }); 118 | 119 | var link = g.append("g").selectAll(".link") 120 | .data(links) 121 | .enter().append("path") 122 | .attr("class", "link") 123 | .attr("d", path ) 124 | .style("stroke-width", function(d) { return Math.max(1, d.dy); }) 125 | .style("fill","none") 126 | .style("stroke", function (d){ return colors()(d.source.name); }) 127 | .style("stroke-opacity",".4") 128 | .sort(function(a, b) { return b.dy - a.dy; }); 129 | 130 | var node = g.append("g").selectAll(".node") 131 | .data(nodes) 132 | .enter().append("g") 133 | .attr("class", "node") 134 | .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }) 135 | 136 | node.append("rect") 137 | .attr("height", function(d) { return d.dy; }) 138 | .attr("width", sankey.nodeWidth()) 139 | .style("fill", function (d) { return d.sourceLinks.length ? colors(d.name) : "#666"; }) 140 | .append("title") 141 | .text(function(d) { return d.name + "\n" + format(d.value); }); 142 | 143 | node.append("text") 144 | .attr("x", -6) 145 | .attr("y", function (d) { return d.dy / 2; }) 146 | .attr("dy", ".35em") 147 | .attr("text-anchor", "end") 148 | .attr("transform", null) 149 | .text(function(d) { return d.name; }) 150 | .style("font-size","11px") 151 | .style("font-family","Arial, Helvetica") 152 | .style("pointer-events","none") 153 | .filter(function(d) { return d.x < +width() / 2; }) 154 | .attr("x", 6 + sankey.nodeWidth()) 155 | .attr("text-anchor", "start"); 156 | 157 | }) 158 | 159 | })(); -------------------------------------------------------------------------------- /charts/clusterForce.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var nodes = raw.model(); 4 | 5 | var cluster = nodes.dimension() 6 | .title("Clusters") 7 | .required(1); 8 | 9 | var size = nodes.dimension() 10 | .title("Size") 11 | .types(Number) 12 | 13 | var label = nodes.dimension() 14 | .title("Label") 15 | 16 | var color = nodes.dimension() 17 | .title("Color") 18 | 19 | nodes.map(function (data){ 20 | 21 | var nodeClusters = d3.nest() 22 | .key(function (d) { return cluster(d); }) 23 | .rollup(function (d){ 24 | return { 25 | type: 'cluster', 26 | cluster: cluster(d[0]), 27 | size: 0, 28 | } 29 | }) 30 | .map(data); 31 | 32 | var nodeElements = data.map(function (d) { 33 | return { 34 | type : 'node', 35 | label : label(d), 36 | cluster: cluster(d), 37 | clusterObject : nodeClusters[cluster(d)], 38 | size: size() ? +size(d) : 1, 39 | color: color(d) 40 | }; 41 | }); 42 | 43 | return nodeElements.concat(d3.values(nodeClusters)); 44 | 45 | }) 46 | 47 | 48 | var chart = raw.chart() 49 | .title('Clustered Force Layout') 50 | .description( 51 | "Nested circles allow to represent hierarchies and compare values. This visualization is particularly effective to show the proportion between elements through their areas and their position inside a hierarchical structure.
Based on http://bl.ocks.org/mbostock/7882658") 52 | .thumbnail("imgs/clusterForce.png") 53 | .model(nodes) 54 | 55 | var width = chart.number() 56 | .title("Width") 57 | .defaultValue(1000) 58 | .fitToWidth(true) 59 | 60 | var height = chart.number() 61 | .title("Height") 62 | .defaultValue(500) 63 | 64 | var nodePadding = chart.number() 65 | .title("node padding") 66 | .defaultValue(2) 67 | 68 | var clusterPadding = chart.number() 69 | .title("cluster padding") 70 | .defaultValue(10) 71 | 72 | var colors = chart.color() 73 | .title("Color scale") 74 | 75 | chart.draw(function (selection, data){ 76 | 77 | d3.layout.pack() 78 | .sort(null) 79 | .size([+width(), +height()]) 80 | .padding(d3.max([nodePadding(),clusterPadding()])) 81 | .children(function (d) { return d.values; }) 82 | .value(function (d) { return +d.size; }) 83 | .nodes({ 84 | values: d3.nest() 85 | .key(function (d) { return d.cluster; }) 86 | .entries(data) 87 | } 88 | ); 89 | 90 | var force = d3.layout.force() 91 | .nodes(data) 92 | .size([+width(), +height()]) 93 | .gravity(.01) 94 | .charge(0) 95 | .on("tick", tick) 96 | .start(); 97 | 98 | var g = selection 99 | .attr("width", width) 100 | .attr("height", height); 101 | 102 | colors.domain(data.filter(function (d){ return d.type == "node"; }), function (d){ return d.color; }); 103 | 104 | var node = g.selectAll("circle") 105 | .data(data.filter(function (d){ return d.type == "node"; })) 106 | .enter().append("circle") 107 | .style("fill", function(d) { return d.color ? colors()(d.color) : colors()(null); }) 108 | .call(force.drag); 109 | 110 | node.transition() 111 | .delay(function(d, i) { return i * 5; }) 112 | .attrTween("r", function(d) { 113 | var i = d3.interpolate(0, +d.r); 114 | return function(t) { return d.radius = i(t); }; 115 | }); 116 | 117 | var text = g.selectAll("text") 118 | .data(data.filter(function (d){ return d.type == "node"; })) 119 | .enter().append("text") 120 | .text(function (d){ return d.label; }) 121 | .attr("text-anchor", "middle") 122 | .attr("dy","4") 123 | .style("font-size","11px") 124 | .style("font-family","Arial, Helvetica") 125 | .call(force.drag); 126 | 127 | function tick(e) { 128 | node 129 | .each(cluster(10 * e.alpha * e.alpha)) 130 | .each(collide(.5)) 131 | .attr("cx", function(d) { return d.x; }) 132 | .attr("cy", function(d) { return d.y; }); 133 | text 134 | .each(cluster(10 * e.alpha * e.alpha)) 135 | .each(collide(.5)) 136 | .attr("x", function(d) { return d.x; }) 137 | .attr("y", function(d) { return d.y; }); 138 | } 139 | 140 | function cluster(alpha) { 141 | return function(d) { 142 | if (d.type != "node") return; 143 | var cluster = d.clusterObject; 144 | var x = d.x - cluster.x, 145 | y = d.y - cluster.y, 146 | l = Math.sqrt(x * x + y * y), 147 | r = d.r + cluster.r; 148 | if (l != r) { 149 | l = (l - r) / l * alpha; 150 | d.x -= x *= l; 151 | d.y -= y *= l; 152 | cluster.x += x; 153 | cluster.y += y; 154 | } 155 | }; 156 | } 157 | 158 | function collide(alpha) { 159 | var quadtree = d3.geom.quadtree(data); 160 | return function(d) { 161 | var r = d.r + Math.max(+nodePadding(), +clusterPadding()), 162 | nx1 = d.x - r, 163 | nx2 = d.x + r, 164 | ny1 = d.y - r, 165 | ny2 = d.y + r; 166 | 167 | quadtree.visit(function(quad, x1, y1, x2, y2) { 168 | if (quad.point && (quad.point !== d)) { 169 | var x = d.x - quad.point.x, 170 | y = d.y - quad.point.y, 171 | l = Math.sqrt(x * x + y * y), 172 | r = d.r + quad.point.radius + (d.cluster === quad.point.cluster ? +nodePadding() : +clusterPadding()); 173 | if (l < r) { 174 | l = (l - r) / l * alpha; 175 | d.x -= x *= l; 176 | d.y -= y *= l; 177 | quad.point.x += x; 178 | quad.point.y += y; 179 | } 180 | } 181 | return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; 182 | }); 183 | }; 184 | } 185 | 186 | }) 187 | 188 | })(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | ##About 5 | 6 | **RAW** is an open web tool developed at the [DensityDesign Research Lab](http://www.densitydesign.org) (Politecnico di Milano) to create custom vector-based visualizations on top of the amazing [d3.js](https://github.com/mbostock/d3) library by [Mike Bostock](http://bost.ocks.org/mike/). 7 | Primarily conceived as a tool for designers and vis geeks, RAW aims at providing a missing link between spreadsheet applications (e.g. Microsoft Excel, Apple Numbers, Google Docs, OpenRefine, …) and vector graphics editors (e.g. Adobe Illustrator, Inkscape, …). 8 | 9 | RAW works with [delimiter-separated values](http://en.wikipedia.org/wiki/Delimiter-separated_values) (i.e. csv and tsv files) as well as with copied-and-pasted texts from other applications (e.g. Microsoft Excel, TextWrangler, TextEdit, …). Based on the [svg](http://en.wikipedia.org/wiki/Svg) format, visualizations can be easily edited with vector graphics applications for further refinements, or directly embedded into web pages. 10 | 11 | Knowing the need of working with sensitive information, the data uploaded to RAW is processed only by the web browser: **no server-side operations or storages are performed** and no one will see, touch or copy your data! 12 | 13 | RAW is also highly customizable and extensible, accepting new custom layouts defined by users. For more information about how to add or edit layouts, see the [Developer Guide](https://github.com/densitydesign/raw/wiki/Developer-Guide). 14 | 15 | - App page: [app.raw.densitydesign.org](http://app.raw.densitydesign.org) 16 | - Project official page: [raw.densitydesign.org](http://raw.densitydesign.org) 17 | - Documentation: [github.com/densitydesign/raw/wiki](https://github.com/densitydesign/raw/wiki) 18 | - Google group: [groups.google.com/forum/#!forum/densitydesign-raw](https://groups.google.com/forum/#!forum/densitydesign-raw) 19 | 20 | 21 | ##Usage 22 | The easiest way to use RAW is by accessing the most updated version on the **[official app page](http://app.raw.densitydesign.org)**. However, RAW can also run locally on your machine: see the installation instructions below to know how. 23 | 24 | ##Installation 25 | If you want to run your instance of RAW locally on your machine, be sure you have the following requirements installed. 26 | 27 | ###Requirements 28 | 29 | - [git](http://git-scm.com/book/en/Getting-Started-Installing-Git) 30 | - [Bower](http://bower.io/#installing-bower) 31 | 32 | ###Instructions 33 | 34 | Clone RAW from the command line: 35 | 36 | ``` sh 37 | $ git clone git://github.com/densitydesign/raw.git 38 | ``` 39 | 40 | browse to RAW root folder: 41 | 42 | ``` sh 43 | $ cd raw 44 | ``` 45 | 46 | install client-side dependencies: 47 | 48 | ``` sh 49 | $ bower install 50 | ``` 51 | 52 | You can now run RAW from your local web server. For example, you can run Python's built-in server: 53 | 54 | ``` sh 55 | $ python -m SimpleHTTPServer 4000 56 | ``` 57 | 58 | or for Python 3+ 59 | 60 | ``` sh 61 | $ python -m http.server 4000 62 | ``` 63 | 64 | Once this is running, go to [http://localhost:4000/](http://localhost:4000/). 65 | 66 | Troubles with the installation? Maybe a look at the [issues](https://github.com/densitydesign/raw/issues) page can solve your problem, otherwise join the [Google group](https://groups.google.com/forum/#!forum/densitydesign-raw). 67 | 68 | 69 | ##Documentation and Support 70 | 71 | Documentation and FAQs about how to use RAW can be found on the [wiki](https://github.com/densitydesign/raw/wiki/). 72 | 73 | ##Charts 74 | 75 | Information about the available charts can be found [here](https://github.com/densitydesign/raw/wiki/Available-Charts). Adding new charts is very easy in RAW, see how [here](https://github.com/densitydesign/raw/wiki/Adding-New-Charts)! 76 | 77 | If you have any suggestion or request about new layouts to include, please let us know! If you have already created new charts and you would like to see them included into Raw, please send us a [pull request](https://github.com/densitydesign/raw/pulls). 78 | 79 | ##Libraries 80 | 81 | **RAW** has been developed using a lot of cool stuff found out there: 82 | 83 | [angular.js](https://github.com/angular/angular.js) 84 | [angular-bootstrap-colorpicker](https://github.com/buberdds/angular-bootstrap-colorpicker) 85 | [angular-ui](https://github.com/angular-ui) 86 | [bootstrap](https://github.com/twbs/bootstrap) 87 | [bootstrap-colorpicker](http://www.eyecon.ro/bootstrap-colorpicker/) 88 | [Bower](https://github.com/bower/bower) 89 | [canvas-toBlob.js](https://github.com/eligrey/canvas-toBlob.js) 90 | [CodeMirror](https://github.com/marijnh/codemirror) 91 | [d3.js](https://github.com/mbostock/d3) 92 | [FileSaver.js](https://github.com/eligrey/FileSaver.js) 93 | [jQuery](https://github.com/jquery/jquery) 94 | [jQuery UI Touch Punch](https://github.com/furf/jquery-ui-touch-punch/) 95 | [ZeroClipboard](https://github.com/zeroclipboard/zeroclipboard) 96 | 97 | ##Roadmap 98 | 99 | - ~~Refactoring using [reusable charts](http://bost.ocks.org/mike/chart/) as layouts~~ 100 | - ~~Introducing continuous color scales (for numeric values)~~ 101 | - ~~Mobile support~~ 102 | - Improving documentation and API Reference 103 | - Creating and exporting legends 104 | - PDF export 105 | 106 | ##Team and Contacts 107 | 108 | **RAW** has been developed and maintained at DensityDesign Research Lab by: 109 | 110 | Giorgio Caviglia 111 | Michele Mauri 112 | Giorgio Uboldi 113 | Matteo Azzi 114 | 115 | If you want to know more about RAW, how it works and future developments, please visit the [official website](http://raw.densitydesign.org). For any specific request or comment we suggest you to use Github or the [Google group](https://groups.google.com/forum/#!forum/densitydesign-raw). If none of these worked for you, you can write us at . 116 | 117 | ##Contributing 118 | 119 | Want to contribute to RAW's development? You are more than welcome! Start by forking the repository (the "Fork" button at the top-right corner of this page) and follow the instructions above to clone it and install dependencies. Then you can use Github's issues and pull requests to discuss and share your work. 120 | 121 | 122 | ##License 123 | 124 | RAW is provided under the [LGPL (Lesser General Public License)](https://github.com/densitydesign/raw/blob/master/COPYING.LESSER) v.3: 125 | 126 | Copyright (c), 2013-2014 DensityDesign Lab, Giorgio Caviglia, Michele Mauri, 127 | Giorgio Uboldi, Matteo Azzi 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | This program is free software: you can redistribute it and/or modify 136 | it under the terms of the GNU Lesser General Public License as published by 137 | the Free Software Foundation, either version 3 of the License, or 138 | (at your option) any later version. 139 | 140 | This program is distributed in the hope that it will be useful, 141 | but WITHOUT ANY WARRANTY; without even the implied warranty of 142 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 143 | GNU Lesser General Public License for more details. 144 | 145 | You should have received a copy of the GNU Lesser General Public License 146 | along with this program. If not, see . 147 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RAW 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 54 | 55 |
56 | 57 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /charts/streamgraph.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var stream = raw.model(); 4 | 5 | var group = stream.dimension() 6 | .title('Group') 7 | .required(1) 8 | 9 | var date = stream.dimension() 10 | .title('Date') 11 | .types(Number, Date, String) 12 | .accessor(function (d){ return this.type() == "Date" ? new Date(d) : this.type() == "String" ? d : +d; }) 13 | .required(1) 14 | 15 | var size = stream.dimension() 16 | .title('Size') 17 | .types(Number) 18 | .required(1) 19 | 20 | stream.map(function (data){ 21 | if (!group()) return []; 22 | 23 | var dates = d3.set(data.map(function (d){ return date(d); })).values(); 24 | 25 | var groups = d3.nest() 26 | .key(group) 27 | .rollup(function (g){ 28 | 29 | var singles = d3.nest() 30 | .key(function(d){ return date(d); }) 31 | .rollup(function (d){ 32 | return { 33 | group : group(d[0]), 34 | x : date(d[0]), 35 | y : size() ? d3.sum(d,size) : d.length 36 | } 37 | }) 38 | .map(g); 39 | 40 | // let's create the empty ones 41 | dates.forEach(function(d){ 42 | if (!singles.hasOwnProperty(d)) { 43 | //console.log(singles, d); 44 | singles[d] = { group : group(g[0]), x : d, y : 0 } 45 | } 46 | }) 47 | 48 | return d3.values(singles); 49 | }) 50 | .map(data) 51 | 52 | return d3.values(groups).map(function(d){ return d.sort(function(a,b){ return a.x - b.x; }) }); 53 | 54 | }) 55 | 56 | var chart = raw.chart() 57 | .title('Streamgraph') 58 | .thumbnail("imgs/streamgraph.png") 59 | .description( 60 | "For continuous data such as time series, a streamgraph can be used in place of stacked bars.
Based on http://bl.ocks.org/mbostock/4060954") 61 | .category('Time Series') 62 | .model(stream) 63 | 64 | var width = chart.number() 65 | .title("Width") 66 | .defaultValue(1000) 67 | .fitToWidth(true) 68 | 69 | var height = chart.number() 70 | .title("Height") 71 | .defaultValue(500) 72 | 73 | var offset = chart.list() 74 | .title("Offset") 75 | .values(['silhouette','wiggle','expand','zero']) 76 | .defaultValue('silhouette') 77 | 78 | var curve = chart.list() 79 | .title("Interpolation") 80 | .values(['Sankey curves','Linear']) 81 | .defaultValue('Sankey curves') 82 | 83 | var showLabels = chart.checkbox() 84 | .title("show labels") 85 | .defaultValue(true) 86 | 87 | var colors = chart.color() 88 | .title("Color scale") 89 | 90 | chart.draw(function (selection, data){ 91 | 92 | var g = selection 93 | .attr("width", +width() ) 94 | .attr("height", +height() ) 95 | .append("g") 96 | 97 | var curves = { 98 | 'Sankey curves' : interpolate, 99 | 'Linear' : 'linear' 100 | } 101 | 102 | var stack = d3.layout.stack() 103 | .offset(offset()); 104 | 105 | var layers = stack(data); 106 | 107 | var x = date.type() == "Date" 108 | // Date 109 | ? d3.time.scale() 110 | .domain( [ d3.min(layers, function(layer) { return d3.min(layer, function(d) { return d.x; }); }), d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.x; }); }) ]) 111 | .range([0, +width()]) 112 | : date && date.type() == "String" 113 | // String 114 | ? d3.scale.ordinal() 115 | .domain(layers[0].map(function(d){ return d.x; }) ) 116 | .rangePoints([0, +width()],0) 117 | // Number 118 | : d3.scale.linear() 119 | .domain( [ d3.min(layers, function(layer) { return d3.min(layer, function(d) { return d.x; }); }), d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.x; }); }) ]) 120 | .range([0, +width()]); 121 | 122 | var y = d3.scale.linear() 123 | .domain([0, d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); })]) 124 | .range([+height()-20, 0]); 125 | 126 | var xAxis = d3.svg.axis().scale(x).tickSize(-height()+20).orient("bottom")//.tickFormat(d3.format("d")) 127 | 128 | g.append("g") 129 | .attr("class", "x axis") 130 | .style("stroke-width", "1px") 131 | .style("font-size","10px") 132 | .style("font-family","Arial, Helvetica") 133 | .attr("transform", "translate(" + 0 + "," + (height()-20) + ")") 134 | .call(xAxis); 135 | 136 | d3.selectAll(".x.axis line, .x.axis path") 137 | .style("shape-rendering","crispEdges") 138 | .style("fill","none") 139 | .style("stroke","#ccc") 140 | 141 | colors.domain(layers, function (d){ return d[0].group; }) 142 | 143 | var area = d3.svg.area() 144 | .interpolate(curves[curve()]) 145 | .x(function(d) { return x(d.x); }) 146 | .y0(function(d) { return y(d.y0); }) 147 | .y1(function(d) { return y(d.y0 + d.y); }); 148 | 149 | var line = d3.svg.line() 150 | .interpolate(curves[curve()]) 151 | .x(function(d) { return x(d.x); }) 152 | .y(function(d) { 153 | var y0 = y(d.y0), y1 = y(d.y0 + d.y); 154 | return y0 + (y1 - y0) * 0.5; 155 | }); 156 | 157 | 158 | g.selectAll("path.layer") 159 | .data(layers) 160 | .enter().append("path") 161 | .attr("class","layer") 162 | .attr("d", area) 163 | .attr("title", function (d){ return d[0].group; }) 164 | .style("fill", function (d) { return colors()(d[0].group); }); 165 | 166 | if (!showLabels()) return; 167 | 168 | g.append('defs'); 169 | 170 | g.select('defs') 171 | .selectAll('path') 172 | .data(layers) 173 | .enter().append('path') 174 | .attr('id', function(d,i) { return 'path-' + i; }) 175 | .attr('d', line); 176 | 177 | g.selectAll("text.label") 178 | .data(layers) 179 | .enter().append('text') 180 | .attr('dy', '0.5ex') 181 | .attr("class","label") 182 | .append('textPath') 183 | .attr('xlink:xlink:href', function(d,i) { return '#path-' + i; }) 184 | .attr('startOffset', function(d) { 185 | var maxYr = 0, maxV = 0; 186 | d3.range(layers[0].length).forEach(function(i) { 187 | if (d[i].y > maxV) { 188 | maxV = d[i].y; 189 | maxYr = i; 190 | } 191 | }); 192 | d.maxVal = d[maxYr].y; 193 | d.offset = Math.round(x(d[maxYr].x) / x.range()[1] * 100); 194 | return Math.min(95, Math.max(5, d.offset))+'%'; 195 | }) 196 | .attr('text-anchor', function(d) { 197 | return d.offset > 90 ? 'end' : d.offset < 10 ? 'start' : 'middle'; 198 | }) 199 | .text(function(d){ return d[0].group; }) 200 | .style("font-size","11px") 201 | .style("font-family","Arial, Helvetica") 202 | .style("font-weight","normal") 203 | 204 | /*g.selectAll("text.label") 205 | .data(labels(layers)) 206 | .enter().append("text") 207 | .attr("x", function(d){ return x(d.x); }) 208 | .attr("y", function(d){ return y(d.y0 + d.y/2); }) 209 | .text(function(d){ return d.group; }) 210 | .style("font-size","11px") 211 | .style("font-family","Arial, Helvetica") 212 | 213 | 214 | 215 | function labels(layers){ 216 | return layers.map(function(layer){ 217 | var l = layer[0], max = 0; 218 | layer.forEach(function(d){ 219 | if ( d.y > max ) { 220 | max = d.y; 221 | l = d; 222 | } 223 | }) 224 | return l; 225 | }) 226 | 227 | }*/ 228 | 229 | function interpolate(points) { 230 | var x0 = points[0][0], y0 = points[0][1], x1, y1, x2, 231 | path = [x0, ",", y0], 232 | i = 0, 233 | n = points.length; 234 | 235 | while (++i < n) { 236 | x1 = points[i][0], y1 = points[i][1], x2 = (x0 + x1) / 2; 237 | path.push("C", x2, ",", y0, " ", x2, ",", y1, " ", x1, ",", y1); 238 | x0 = x1, y0 = y1; 239 | } 240 | return path.join(""); 241 | } 242 | 243 | }) 244 | 245 | })(); -------------------------------------------------------------------------------- /charts/bumpChart.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var stream = raw.model(); 4 | 5 | var group = stream.dimension() 6 | .title('Group') 7 | .required(1) 8 | 9 | var date = stream.dimension() 10 | .title('Date') 11 | .types(Number, Date, String) 12 | .accessor(function (d){ return this.type() == "Date" ? new Date(d) : this.type() == "String" ? d : +d; }) 13 | .required(1) 14 | 15 | var size = stream.dimension() 16 | .title('Size') 17 | .types(Number) 18 | .required(1) 19 | 20 | stream.map(function (data){ 21 | if (!group()) return []; 22 | 23 | var dates = d3.set(data.map(function (d){ return date(d); })).values(); 24 | 25 | var groups = d3.nest() 26 | .key(group) 27 | .rollup(function (g){ 28 | 29 | var singles = d3.nest() 30 | .key(function(d){ return date(d); }) 31 | .rollup(function (d){ 32 | return { 33 | group : group(d[0]), 34 | x : date(d[0]), 35 | y : size() ? d3.sum(d,size) : d.length 36 | } 37 | }) 38 | .map(g); 39 | 40 | // let's create the empty ones 41 | dates.forEach(function(d){ 42 | if (!singles.hasOwnProperty(d)) { 43 | singles[d] = { group : group(g[0]), x : d, y : 0 } 44 | } 45 | }) 46 | 47 | return d3.values(singles); 48 | }) 49 | .map(data) 50 | 51 | return d3.values(groups).map(function(d){ return d.sort(function(a,b){ return a.x - b.x; }) }); 52 | 53 | }) 54 | 55 | var chart = raw.chart() 56 | .title('Bump Chart') 57 | .thumbnail("imgs/bumpChart.png") 58 | .description( 59 | "For continuous data such as time series, a bump chart can be used in place of stacked bars. Based on New York Times's interactive visualization.") 60 | .category('Time Series') 61 | .model(stream) 62 | 63 | var width = chart.number() 64 | .title("Width") 65 | .defaultValue(1000) 66 | .fitToWidth(true) 67 | 68 | var height = chart.number() 69 | .title("Height") 70 | .defaultValue(500) 71 | 72 | var padding = chart.number() 73 | .title("Padding") 74 | .defaultValue(1) 75 | 76 | var normalize = chart.checkbox() 77 | .title("normalize") 78 | .defaultValue(false) 79 | 80 | var curve = chart.list() 81 | .title("Interpolation") 82 | .values(['Basis spline','Sankey','Linear']) 83 | .defaultValue('Sankey') 84 | 85 | var sort = chart.list() 86 | .title("sort by") 87 | .values(['value (descending)', 'value (ascending)', 'group']) 88 | .defaultValue('value (descending)') 89 | 90 | var showLabels = chart.checkbox() 91 | .title("show labels") 92 | .defaultValue(true) 93 | 94 | var colors = chart.color() 95 | .title("Color scale") 96 | 97 | chart.draw(function (selection, data){ 98 | 99 | var g = selection 100 | .attr("width", +width() ) 101 | .attr("xmlns:xmlns:xlink", "http://www.w3.org/1999/xlink") 102 | .attr("height", +height() ) 103 | .append("g") 104 | 105 | var layers = data; 106 | 107 | var curves = { 108 | 'Basis spline' : 'basis', 109 | 'Sankey' : interpolate, 110 | 'Linear' : 'linear' 111 | } 112 | 113 | layers[0].forEach(function(d,i){ 114 | 115 | var values = layers.map(function(layer){ 116 | return layer[i]; 117 | }) 118 | .sort(sortBy); 119 | 120 | var sum = d3.sum(values, function(layer){ return layer.y; }); 121 | var y0 = 0; 122 | values.forEach(function(layer){ 123 | layer.y *= normalize() ? 100 / sum : 1; 124 | layer.y0 = y0; 125 | y0 += layer.y + padding(); 126 | }) 127 | 128 | }) 129 | 130 | var x = date && date.type() == "Date" 131 | // Date 132 | ? d3.time.scale() 133 | .domain( [ d3.min(layers, function(layer) { return d3.min(layer, function(d) { return d.x; }); }), d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.x; }); }) ]) 134 | .range([0, +width()]) 135 | : date && date.type() == "String" 136 | // String 137 | ? d3.scale.ordinal() 138 | .domain(layers[0].map(function(d){ return d.x; }) ) 139 | .rangePoints([0, +width()],0) 140 | // Number 141 | : d3.scale.linear() 142 | .domain( [ d3.min(layers, function(layer) { return d3.min(layer, function(d) { return d.x; }); }), d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.x; }); }) ]) 143 | .range([0, +width()]); 144 | 145 | var y = d3.scale.linear() 146 | .domain([0, d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); })]) 147 | .range([+height()-20, 0]); 148 | 149 | // to be improved 150 | layers[0].forEach(function(d,i){ 151 | 152 | var values = layers.map(function(layer){ 153 | return layer[i]; 154 | }) 155 | .sort(sortBy); 156 | 157 | var sum = d3.sum(values, function(layer){ return layer.y; }); 158 | var y0 = normalize() ? 0 : -sum/2 + y.invert( (+height()-20)/2 ) - padding()*(values.length-1)/2; 159 | 160 | values.forEach(function(layer){ 161 | layer.y *= normalize() ? 100 / sum : 1; 162 | layer.y0 = y0; 163 | y0 += layer.y + padding(); 164 | }) 165 | 166 | }) 167 | 168 | var xAxis = d3.svg.axis().scale(x).tickSize(-height()+20).orient("bottom"); 169 | 170 | g.append("g") 171 | .attr("class", "x axis") 172 | .style("stroke-width", "1px") 173 | .style("font-size","10px") 174 | .style("font-family","Arial, Helvetica") 175 | .attr("transform", "translate(" + 0 + "," + (height()-20) + ")") 176 | .call(xAxis); 177 | 178 | d3.selectAll(".x.axis line, .x.axis path") 179 | .style("shape-rendering","crispEdges") 180 | .style("fill","none") 181 | .style("stroke","#ccc") 182 | 183 | colors.domain(layers, function (d){ return d[0].group; }) 184 | 185 | var area = d3.svg.area() 186 | .interpolate(curves[curve()]) 187 | .x(function(d) { return x(d.x); }) 188 | .y0(function(d) { return y(d.y0); }) 189 | .y1(function(d) { return Math.min(y(d.y0)-1, y(d.y0 + d.y)); }); 190 | 191 | var line = d3.svg.line() 192 | .interpolate(curves[curve()]) 193 | .x(function(d) { return x(d.x); }) 194 | .y(function(d) { 195 | var y0 = y(d.y0), y1 = y(d.y0 + d.y); 196 | return y0 + (y1 - y0) * 0.5; 197 | }); 198 | 199 | g.selectAll("path.layer") 200 | .data(layers) 201 | .enter().append("path") 202 | .attr("class","layer") 203 | .attr("d", area) 204 | .attr("title", function (d){ return d[0].group; }) 205 | .style("fill-opacity",.9) 206 | .style("fill", function (d) { return colors()(d[0].group); }); 207 | 208 | if (!showLabels()) return; 209 | 210 | g.append('defs'); 211 | 212 | g.select('defs') 213 | .selectAll('path') 214 | .data(layers) 215 | .enter().append('path') 216 | .attr('id', function(d,i) { return 'path-' + i; }) 217 | .attr('d', line); 218 | 219 | g.selectAll("text.label") 220 | .data(layers) 221 | .enter().append('text') 222 | .attr('dy', '0.5ex') 223 | .attr("class","label") 224 | .append('textPath') 225 | .attr('xlink:xlink:href', function(d,i) { return '#path-' + i; }) 226 | .attr('startOffset', function(d) { 227 | var maxYr = 0, maxV = 0; 228 | d3.range(layers[0].length).forEach(function(i) { 229 | if (d[i].y > maxV) { 230 | maxV = d[i].y; 231 | maxYr = i; 232 | } 233 | }); 234 | d.maxVal = d[maxYr].y; 235 | d.offset = Math.round(x(d[maxYr].x) / x.range()[1] * 100); 236 | return Math.min(95, Math.max(5, d.offset))+'%'; 237 | }) 238 | .attr('text-anchor', function(d) { 239 | return d.offset > 90 ? 'end' : d.offset < 10 ? 'start' : 'middle'; 240 | }) 241 | .text(function(d){ return d[0].group; }) 242 | .style("font-size","11px") 243 | .style("font-family","Arial, Helvetica") 244 | .style("font-weight","normal") 245 | 246 | function sortBy(a,b){ 247 | if (sort() == 'value (descending)') return a.y - b.y; 248 | if (sort() == 'value (ascending)') return b.y - a.y; 249 | if (sort() == 'group') return a.group - b.group; 250 | } 251 | 252 | function interpolate(points) { 253 | var x0 = points[0][0], y0 = points[0][1], x1, y1, x2, 254 | path = [x0, ",", y0], 255 | i = 0, 256 | n = points.length; 257 | 258 | while (++i < n) { 259 | x1 = points[i][0], y1 = points[i][1], x2 = (x0 + x1) / 2; 260 | path.push("C", x2, ",", y0, " ", x2, ",", y1, " ", x1, ",", y1); 261 | x0 = x1, y0 = y1; 262 | } 263 | return path.join(""); 264 | } 265 | }) 266 | 267 | })(); -------------------------------------------------------------------------------- /partials/main.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |

Insert your data 8 | 14 | 15 | 16 | 20 | 24 | 25 | 26 |

27 | 28 |
29 | 31 |
32 | 33 |
34 | 35 |
36 |
Not sure how it works? Take a look at this video or visit our FAQs
37 |
{{data.length}} records in your data have been successfully parsed!
38 |
Whoops! Please, check line {{error+1}}
39 |
Loading your data. Please wait.
40 |
41 | 42 |
43 | 44 |
45 | 46 |
47 | 48 |
49 |

Ouch. It seems like RAW encountered some problems while parsing your data. Please, be sure everything is ok with your data. Often this is due to some missing delimiters. If you want to use a delimiter char as string literal, please include it in double quotes. See our FAQs for more information.

50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |

61 | Choose a Chart 62 |

63 | 64 | 65 |
66 | 67 |
68 |
69 |

{{chart.title()}}

70 |
71 |

72 |

No description given

73 |
74 |
75 | 76 |
77 | 78 |
79 |

{{category}}

80 |
81 |
82 |
83 |
84 |
85 |

86 | {{c.title()}} 87 |

88 |
89 |
90 | 91 | 103 | 104 |
105 | 106 |
107 | 108 | 109 | 110 |
111 | 112 |
113 | 114 | 115 |
116 | 117 |
118 | 119 |
120 | 121 |
122 | 123 |
124 | 125 |
126 | 127 |
128 |

Map your Dimensions 129 | 132 | 133 |

134 |
135 | 136 | 137 |
138 | 139 |
140 |
141 |
    142 |
  • 143 | {{ dimension.key }} 144 | {{dimension.type}} 145 | 146 |
  • 147 |
148 |
149 |
150 | 151 |
152 |
153 |
157 | 158 |
161 | 162 |
163 | 164 | 176 | 177 | 181 | 182 | 188 | 189 |

{{dimension.title()}}

190 |
    197 |
198 | 199 |
200 | 201 | 204 | 205 |
206 | 207 |
208 |
209 | 210 | 211 | 212 |
213 | 214 |
215 | 216 |
217 | 218 | 219 |
220 | 221 |
222 | 223 |
224 | 225 |
226 | 227 |

228 | Customize your Visualization 229 |

230 | 231 |
232 | 233 |
234 |
    235 |
  • 236 |

    237 | {{option.title()}} 238 | 242 |

    243 | 244 |
    245 | 246 | 247 |
    248 | 251 |
    252 | 253 |
    254 | 255 | 263 | 264 | 265 | 266 |
    267 | 268 |
  • 269 |
270 |
271 | 272 |
273 |
274 |
275 |
276 |
277 | 278 |

279 |
280 | 281 |
282 | 283 |
284 |
285 | 286 |
287 | 288 |
289 | 290 |
291 | 292 |
293 | 294 |
295 | 296 |
297 |

Download

298 | 299 |
300 | 301 |
302 |

Embed Code

303 | 304 |

Copy the code above into your HTML to embed the visualization 305 | 306 |

307 |
308 | 309 |
310 |
311 | 312 |
313 |
314 |
-------------------------------------------------------------------------------- /data/flows.csv: -------------------------------------------------------------------------------- 1 | Year,Media,Market Share 2 | 1980,8-track,14.3 3 | 1981,8-track,7.9 4 | 1982,8-track,1.0 5 | 1983,8-track,0 6 | 1984,8-track,0 7 | 1985,8-track,0 8 | 1986,8-track,0 9 | 1987,8-track,0 10 | 1988,8-track,0 11 | 1989,8-track,0 12 | 1990,8-track,0 13 | 1991,8-track,0 14 | 1992,8-track,0 15 | 1993,8-track,0 16 | 1994,8-track,0 17 | 1995,8-track,0 18 | 1996,8-track,0 19 | 1997,8-track,0 20 | 1998,8-track,0 21 | 1999,8-track,0 22 | 2000,8-track,0 23 | 2001,8-track,0 24 | 2002,8-track,0 25 | 2003,8-track,0 26 | 2004,8-track,0 27 | 2005,8-track,0 28 | 2006,8-track,0 29 | 2007,8-track,0 30 | 2008,8-track,0 31 | 2009,8-track,0 32 | 2010,8-track,0 33 | 1980,Cassete,19.1 34 | 1981,Cassete,26.7 35 | 1982,Cassete,38.2 36 | 1983,Cassete,47.8 37 | 1984,Cassete,55 38 | 1985,Cassete,55.3 39 | 1986,Cassete,53.9 40 | 1987,Cassete,53.2 41 | 1988,Cassete,54.1 42 | 1989,Cassete,50.8 43 | 1990,Cassete,46 44 | 1991,Cassete,38.5 45 | 1992,Cassete,34.5 46 | 1993,Cassete,29 47 | 1994,Cassete,24.7 48 | 1995,Cassete,18.7 49 | 1996,Cassete,15.2 50 | 1997,Cassete,12.4 51 | 1998,Cassete,7.3 52 | 1999,Cassete,7.3 53 | 2000,Cassete,4.4 54 | 2001,Cassete,2.6 55 | 2002,Cassete,1.7 56 | 2003,Cassete,0.9 57 | 2004,Cassete,0.2 58 | 2005,Cassete,0.1 59 | 2006,Cassete,0 60 | 2007,Cassete,0 61 | 2008,Cassete,0 62 | 2009,Cassete,0 63 | 2010,Cassete,0 64 | 1980,Cassete single,0 65 | 1981,Cassete single,0 66 | 1982,Cassete single,0 67 | 1983,Cassete single,0 68 | 1984,Cassete single,0 69 | 1985,Cassete single,0 70 | 1986,Cassete single,0 71 | 1987,Cassete single,0.3 72 | 1988,Cassete single,0.9 73 | 1989,Cassete single,3 74 | 1990,Cassete single,3.4 75 | 1991,Cassete single,2.9 76 | 1992,Cassete single,3.3 77 | 1993,Cassete single,3 78 | 1994,Cassete single,2.3 79 | 1995,Cassete single,1.9 80 | 1996,Cassete single,1.5 81 | 1997,Cassete single,1.1 82 | 1998,Cassete single,0.3 83 | 1999,Cassete single,0.3 84 | 2000,Cassete single,0 85 | 2001,Cassete single,0 86 | 2002,Cassete single,0 87 | 2003,Cassete single,0 88 | 2004,Cassete single,0 89 | 2005,Cassete single,0 90 | 2006,Cassete single,0 91 | 2007,Cassete single,0 92 | 2008,Cassete single,0 93 | 2009,Cassete single,0 94 | 2010,Cassete single,0 95 | 1980,CD,0 96 | 1981,CD,0 97 | 1982,CD,0 98 | 1983,CD,0.5 99 | 1984,CD,2.4 100 | 1985,CD,8.9 101 | 1986,CD,20 102 | 1987,CD,28.5 103 | 1988,CD,33.4 104 | 1989,CD,39.3 105 | 1990,CD,45.8 106 | 1991,CD,55.5 107 | 1992,CD,59.2 108 | 1993,CD,64.8 109 | 1994,CD,70.1 110 | 1995,CD,76.1 111 | 1996,CD,79.2 112 | 1997,CD,81.1 113 | 1998,CD,87.9 114 | 1999,CD,87.9 115 | 2000,CD,92.3 116 | 2001,CD,94 117 | 2002,CD,95.3 118 | 2003,CD,94.7 119 | 2004,CD,92.7 120 | 2005,CD,85.6 121 | 2006,CD,79.7 122 | 2007,CD,70 123 | 2008,CD,62.4 124 | 2009,CD,55.6 125 | 2010,CD,49.1 126 | 1980,CD single,0 127 | 1981,CD single,0 128 | 1982,CD single,0 129 | 1983,CD single,0 130 | 1984,CD single,0 131 | 1985,CD single,0 132 | 1986,CD single,0 133 | 1987,CD single,0 134 | 1988,CD single,0.2 135 | 1989,CD single,0 136 | 1990,CD single,0.1 137 | 1991,CD single,0.4 138 | 1992,CD single,0.5 139 | 1993,CD single,0.5 140 | 1994,CD single,0.5 141 | 1995,CD single,0.9 142 | 1996,CD single,1.5 143 | 1997,CD single,2.2 144 | 1998,CD single,1.5 145 | 1999,CD single,1.5 146 | 2000,CD single,1 147 | 2001,CD single,0.6 148 | 2002,CD single,0.2 149 | 2003,CD single,0.3 150 | 2004,CD single,0.1 151 | 2005,CD single,0.1 152 | 2006,CD single,0.1 153 | 2007,CD single,0.1 154 | 2008,CD single,0 155 | 2009,CD single,0 156 | 2010,CD single,0 157 | 1980,Download Album,0 158 | 1981,Download Album,0 159 | 1982,Download Album,0 160 | 1983,Download Album,0 161 | 1984,Download Album,0 162 | 1985,Download Album,0 163 | 1986,Download Album,0 164 | 1987,Download Album,0 165 | 1988,Download Album,0 166 | 1989,Download Album,0 167 | 1990,Download Album,0 168 | 1991,Download Album,0 169 | 1992,Download Album,0 170 | 1993,Download Album,0 171 | 1994,Download Album,0 172 | 1995,Download Album,0 173 | 1996,Download Album,0 174 | 1997,Download Album,0 175 | 1998,Download Album,0 176 | 1999,Download Album,0 177 | 2000,Download Album,0 178 | 2001,Download Album,0 179 | 2002,Download Album,0 180 | 2003,Download Album,0 181 | 2004,Download Album,0.4 182 | 2005,Download Album,1.2 183 | 2006,Download Album,2.5 184 | 2007,Download Album,4.9 185 | 2008,Download Album,7.9 186 | 2009,Download Album,11 187 | 2010,Download Album,14.8 188 | 1980,Download Music Video,0 189 | 1981,Download Music Video,0 190 | 1982,Download Music Video,0 191 | 1983,Download Music Video,0 192 | 1984,Download Music Video,0 193 | 1985,Download Music Video,0 194 | 1986,Download Music Video,0 195 | 1987,Download Music Video,0 196 | 1988,Download Music Video,0 197 | 1989,Download Music Video,0 198 | 1990,Download Music Video,0 199 | 1991,Download Music Video,0 200 | 1992,Download Music Video,0 201 | 1993,Download Music Video,0 202 | 1994,Download Music Video,0 203 | 1995,Download Music Video,0 204 | 1996,Download Music Video,0 205 | 1997,Download Music Video,0 206 | 1998,Download Music Video,0 207 | 1999,Download Music Video,0 208 | 2000,Download Music Video,0 209 | 2001,Download Music Video,0 210 | 2002,Download Music Video,0 211 | 2003,Download Music Video,0 212 | 2004,Download Music Video,0 213 | 2005,Download Music Video,0 214 | 2006,Download Music Video,0.2 215 | 2007,Download Music Video,0.3 216 | 2008,Download Music Video,0.5 217 | 2009,Download Music Video,0.5 218 | 2010,Download Music Video,0.5 219 | 1980,Download Single,0 220 | 1981,Download Single,0 221 | 1982,Download Single,0 222 | 1983,Download Single,0 223 | 1984,Download Single,0 224 | 1985,Download Single,0 225 | 1986,Download Single,0 226 | 1987,Download Single,0 227 | 1988,Download Single,0 228 | 1989,Download Single,0 229 | 1990,Download Single,0 230 | 1991,Download Single,0 231 | 1992,Download Single,0 232 | 1993,Download Single,0 233 | 1994,Download Single,0 234 | 1995,Download Single,0 235 | 1996,Download Single,0 236 | 1997,Download Single,0 237 | 1998,Download Single,0 238 | 1999,Download Single,0 239 | 2000,Download Single,0 240 | 2001,Download Single,0 241 | 2002,Download Single,0 242 | 2003,Download Single,0 243 | 2004,Download Single,1.1 244 | 2005,Download Single,3.1 245 | 2006,Download Single,5.1 246 | 2007,Download Single,7.8 247 | 2008,Download Single,12.5 248 | 2009,Download Single,16.9 249 | 2010,Download Single,21 250 | 1980,DVD Audio,0 251 | 1981,DVD Audio,0 252 | 1982,DVD Audio,0 253 | 1983,DVD Audio,0 254 | 1984,DVD Audio,0 255 | 1985,DVD Audio,0 256 | 1986,DVD Audio,0 257 | 1987,DVD Audio,0 258 | 1988,DVD Audio,0 259 | 1989,DVD Audio,0 260 | 1990,DVD Audio,0 261 | 1991,DVD Audio,0 262 | 1992,DVD Audio,0 263 | 1993,DVD Audio,0 264 | 1994,DVD Audio,0 265 | 1995,DVD Audio,0 266 | 1996,DVD Audio,0 267 | 1997,DVD Audio,0 268 | 1998,DVD Audio,0 269 | 1999,DVD Audio,0 270 | 2000,DVD Audio,0 271 | 2001,DVD Audio,0 272 | 2002,DVD Audio,0.1 273 | 2003,DVD Audio,0.1 274 | 2004,DVD Audio,0.1 275 | 2005,DVD Audio,0.1 276 | 2006,DVD Audio,0 277 | 2007,DVD Audio,0 278 | 2008,DVD Audio,0 279 | 2009,DVD Audio,0 280 | 2010,DVD Audio,0 281 | 1980,Kiosk,0 282 | 1981,Kiosk,0 283 | 1982,Kiosk,0 284 | 1983,Kiosk,0 285 | 1984,Kiosk,0 286 | 1985,Kiosk,0 287 | 1986,Kiosk,0 288 | 1987,Kiosk,0 289 | 1988,Kiosk,0 290 | 1989,Kiosk,0 291 | 1990,Kiosk,0 292 | 1991,Kiosk,0 293 | 1992,Kiosk,0 294 | 1993,Kiosk,0 295 | 1994,Kiosk,0 296 | 1995,Kiosk,0 297 | 1996,Kiosk,0 298 | 1997,Kiosk,0 299 | 1998,Kiosk,0 300 | 1999,Kiosk,0 301 | 2000,Kiosk,0 302 | 2001,Kiosk,0 303 | 2002,Kiosk,0 304 | 2003,Kiosk,0 305 | 2004,Kiosk,0 306 | 2005,Kiosk,0 307 | 2006,Kiosk,0 308 | 2007,Kiosk,0 309 | 2008,Kiosk,0 310 | 2009,Kiosk,0.1 311 | 2010,Kiosk,0.1 312 | 1980,LP/EP,59.8 313 | 1981,LP/EP,58.9 314 | 1982,LP/EP,53.1 315 | 1983,LP/EP,44.6 316 | 1984,LP/EP,35.7 317 | 1985,LP/EP,29.4 318 | 1986,LP/EP,21.2 319 | 1987,LP/EP,14.3 320 | 1988,LP/EP,8.5 321 | 1989,LP/EP,3.3 322 | 1990,LP/EP,1.1 323 | 1991,LP/EP,0.4 324 | 1992,LP/EP,0.1 325 | 1993,LP/EP,0.1 326 | 1994,LP/EP,0.1 327 | 1995,LP/EP,0.2 328 | 1996,LP/EP,0.3 329 | 1997,LP/EP,0.3 330 | 1998,LP/EP,0.2 331 | 1999,LP/EP,0.2 332 | 2000,LP/EP,0.2 333 | 2001,LP/EP,0.2 334 | 2002,LP/EP,0.2 335 | 2003,LP/EP,0.2 336 | 2004,LP/EP,0.2 337 | 2005,LP/EP,0.1 338 | 2006,LP/EP,0.1 339 | 2007,LP/EP,0.2 340 | 2008,LP/EP,0.6 341 | 2009,LP/EP,0.8 342 | 2010,LP/EP,1.3 343 | 1980,Mobile,0 344 | 1981,Mobile,0 345 | 1982,Mobile,0 346 | 1983,Mobile,0 347 | 1984,Mobile,0 348 | 1985,Mobile,0 349 | 1986,Mobile,0 350 | 1987,Mobile,0 351 | 1988,Mobile,0 352 | 1989,Mobile,0 353 | 1990,Mobile,0 354 | 1991,Mobile,0 355 | 1992,Mobile,0 356 | 1993,Mobile,0 357 | 1994,Mobile,0 358 | 1995,Mobile,0 359 | 1996,Mobile,0 360 | 1997,Mobile,0 361 | 1998,Mobile,0 362 | 1999,Mobile,0 363 | 2000,Mobile,0 364 | 2001,Mobile,0 365 | 2002,Mobile,0 366 | 2003,Mobile,0 367 | 2004,Mobile,0 368 | 2005,Mobile,3.4 369 | 2006,Mobile,6.6 370 | 2007,Mobile,9.9 371 | 2008,Mobile,11.1 372 | 2009,Mobile,9.5 373 | 2010,Mobile,7.7 374 | 1980,Music video,0 375 | 1981,Music video,0 376 | 1982,Music video,0 377 | 1983,Music video,0 378 | 1984,Music video,0 379 | 1985,Music video,0 380 | 1986,Music video,0 381 | 1987,Music video,0 382 | 1988,Music video,0 383 | 1989,Music video,1.8 384 | 1990,Music video,2.3 385 | 1991,Music video,1.5 386 | 1992,Music video,1.7 387 | 1993,Music video,2.1 388 | 1994,Music video,1.9 389 | 1995,Music video,1.8 390 | 1996,Music video,1.9 391 | 1997,Music video,2.6 392 | 1998,Music video,2.6 393 | 1999,Music video,2.6 394 | 2000,Music video,2.0 395 | 2001,Music video,2.4 396 | 2002,Music video,2.3 397 | 2003,Music video,3.4 398 | 2004,Music video,4.9 399 | 2005,Music video,4.9 400 | 2006,Music video,3.8 401 | 2007,Music video,4.6 402 | 2008,Music video,2.5 403 | 2009,Music video,2.8 404 | 2010,Music video,2.6 405 | 1980,SACD,0 406 | 1981,SACD,0 407 | 1982,SACD,0 408 | 1983,SACD,0 409 | 1984,SACD,0 410 | 1985,SACD,0 411 | 1986,SACD,0 412 | 1987,SACD,0 413 | 1988,SACD,0 414 | 1989,SACD,0 415 | 1990,SACD,0 416 | 1991,SACD,0 417 | 1992,SACD,0 418 | 1993,SACD,0 419 | 1994,SACD,0 420 | 1995,SACD,0 421 | 1996,SACD,0 422 | 1997,SACD,0 423 | 1998,SACD,0 424 | 1999,SACD,0 425 | 2000,SACD,0 426 | 2001,SACD,0 427 | 2002,SACD,0 428 | 2003,SACD,0.2 429 | 2004,SACD,0.1 430 | 2005,SACD,0.1 431 | 2006,SACD,0 432 | 2007,SACD,0 433 | 2008,SACD,0 434 | 2009,SACD,0 435 | 2010,SACD,0 436 | 1980,Subscription,0 437 | 1981,Subscription,0 438 | 1982,Subscription,0 439 | 1983,Subscription,0 440 | 1984,Subscription,0 441 | 1985,Subscription,0 442 | 1986,Subscription,0 443 | 1987,Subscription,0 444 | 1988,Subscription,0 445 | 1989,Subscription,0 446 | 1990,Subscription,0 447 | 1991,Subscription,0 448 | 1992,Subscription,0 449 | 1993,Subscription,0 450 | 1994,Subscription,0 451 | 1995,Subscription,0 452 | 1996,Subscription,0 453 | 1997,Subscription,0 454 | 1998,Subscription,0 455 | 1999,Subscription,0 456 | 2000,Subscription,0 457 | 2001,Subscription,0 458 | 2002,Subscription,0 459 | 2003,Subscription,0 460 | 2004,Subscription,0 461 | 2005,Subscription,1.2 462 | 2006,Subscription,1.8 463 | 2007,Subscription,2.2 464 | 2008,Subscription,2.5 465 | 2009,Subscription,2.8 466 | 2010,Subscription,2.9 467 | 1980,vinyl single,6.8 468 | 1981,vinyl single,6.5 469 | 1982,vinyl single,7.7 470 | 1983,vinyl single,7.1 471 | 1984,vinyl single,6.9 472 | 1985,vinyl single,6.4 473 | 1986,vinyl single,4.9 474 | 1987,vinyl single,3.7 475 | 1988,vinyl single,2.9 476 | 1989,vinyl single,1.8 477 | 1990,vinyl single,1.3 478 | 1991,vinyl single,0.8 479 | 1992,vinyl single,0.7 480 | 1993,vinyl single,0.5 481 | 1994,vinyl single,0.4 482 | 1995,vinyl single,0.4 483 | 1996,vinyl single,0.4 484 | 1997,vinyl single,0.3 485 | 1998,vinyl single,0.2 486 | 1999,vinyl single,0.2 487 | 2000,vinyl single,0.2 488 | 2001,vinyl single,0.2 489 | 2002,vinyl single,0.2 490 | 2003,vinyl single,0.2 491 | 2004,vinyl single,0.2 492 | 2005,vinyl single,0.1 493 | 2006,vinyl single,0.1 494 | 2007,vinyl single,0 495 | 2008,vinyl single,0 496 | 2009,vinyl single,0 497 | 2010,vinyl single,0 -------------------------------------------------------------------------------- /data/multivariate.csv: -------------------------------------------------------------------------------- 1 | name,economy (mpg),cylinders,displacement (cc),power (hp),weight (lb),0-60 mph (s),year 2 | AMC Ambassador Brougham,13,8,360,175,3821,11,73 3 | AMC Ambassador DPL,15,8,390,190,3850,8.5,70 4 | AMC Ambassador SST,17,8,304,150,3672,11.5,72 5 | AMC Concord DL 6,20.2,6,232,90,3265,18.2,79 6 | AMC Concord DL,18.1,6,258,120,3410,15.1,78 7 | AMC Concord DL,23,4,151,,3035,20.5,82 8 | AMC Concord,19.4,6,232,90,3210,17.2,78 9 | AMC Concord,24.3,4,151,90,3003,20.1,80 10 | AMC Gremlin,18,6,232,100,2789,15,73 11 | AMC Gremlin,19,6,232,100,2634,13,71 12 | AMC Gremlin,20,6,232,100,2914,16,75 13 | AMC Gremlin,21,6,199,90,2648,15,70 14 | AMC Hornet Sportabout (Wagon),18,6,258,110,2962,13.5,71 15 | AMC Hornet,18,6,199,97,2774,15.5,70 16 | AMC Hornet,18,6,232,100,2945,16,73 17 | AMC Hornet,19,6,232,100,2901,16,74 18 | AMC Hornet,22.5,6,232,90,3085,17.6,76 19 | AMC Matador (Wagon),14,8,304,150,4257,15.5,74 20 | AMC Matador (Wagon),15,8,304,150,3892,12.5,72 21 | AMC Matador,14,8,304,150,3672,11.5,73 22 | AMC Matador,15,6,258,110,3730,19,75 23 | AMC Matador,15.5,8,304,120,3962,13.9,76 24 | AMC Matador,16,6,258,110,3632,18,74 25 | AMC Matador,18,6,232,100,3288,15.5,71 26 | AMC Pacer D/L,17.5,6,258,95,3193,17.8,76 27 | AMC Pacer,19,6,232,90,3211,17,75 28 | AMC Rebel SST (Wagon),,8,360,175,3850,11,70 29 | AMC Rebel SST,16,8,304,150,3433,12,70 30 | AMC Spirit DL,27.4,4,121,80,2670,15,79 31 | Audi 100 LS,20,4,114,91,2582,14,73 32 | Audi 100 LS,23,4,115,95,2694,15,75 33 | Audi 100 LS,24,4,107,90,2430,14.5,70 34 | Audi 4000,34.3,4,97,78,2188,15.8,80 35 | Audi 5000,20.3,5,131,103,2830,15.9,78 36 | Audi 5000S (Diesel),36.4,5,121,67,2950,19.9,80 37 | Audi Fox,29,4,98,83,2219,16.5,74 38 | BMW 2002,26,4,121,113,2234,12.5,70 39 | BMW 320i,21.5,4,121,110,2600,12.8,77 40 | Buick Century 350,13,8,350,175,4100,13,73 41 | Buick Century Limited,25,6,181,110,2945,16.4,82 42 | Buick Century Luxus (Wagon),13,8,350,150,4699,14.5,74 43 | Buick Century Special,20.6,6,231,105,3380,15.8,78 44 | Buick Century,17,6,231,110,3907,21,75 45 | Buick Century,22.4,6,231,110,3415,15.8,81 46 | Buick Electra 225 Custom,12,8,455,225,4951,11,73 47 | Buick Estate Wagon (Wagon),14,8,455,225,3086,10,70 48 | Buick Estate Wagon (Wagon),16.9,8,350,155,4360,14.9,79 49 | Buick Lesabre Custom,13,8,350,155,4502,13.5,72 50 | Buick Opel Isuzu Deluxe,30,4,111,80,2155,14.8,77 51 | Buick Regal Sport Coupe (Turbo),17.7,6,231,165,3445,13.4,78 52 | Buick Skyhawk,21,6,231,110,3039,15,75 53 | Buick Skylark 320,15,8,350,165,3693,11.5,70 54 | Buick Skylark Limited,28.4,4,151,90,2670,16,79 55 | Buick Skylark,20.5,6,231,105,3425,16.9,77 56 | Buick Skylark,26.6,4,151,84,2635,16.4,81 57 | Cadillac Eldorado,23,8,350,125,3900,17.4,79 58 | Cadillac Seville,16.5,8,350,180,4380,12.1,76 59 | Chevroelt Chevelle Malibu,16,6,250,105,3897,18.5,75 60 | Chevrolet Bel Air,15,8,350,145,4440,14,75 61 | Chevrolet Camaro,27,4,151,90,2950,17.3,82 62 | Chevrolet Caprice Classic,13,8,400,150,4464,12,73 63 | Chevrolet Caprice Classic,17,8,305,130,3840,15.4,79 64 | Chevrolet Caprice Classic,17.5,8,305,145,3880,12.5,77 65 | Chevrolet Cavalier 2-Door,34,4,112,88,2395,18,82 66 | Chevrolet Cavalier Wagon,27,4,112,88,2640,18.6,82 67 | Chevrolet Cavalier,28,4,112,88,2605,19.6,82 68 | Chevrolet Chevelle Concours (Wagon),,8,350,165,4142,11.5,70 69 | Chevrolet Chevelle Concours (Wagon),13,8,307,130,4098,14,72 70 | Chevrolet Chevelle Malibu Classic,16,6,250,100,3781,17,74 71 | Chevrolet Chevelle Malibu Classic,17.5,8,305,140,4215,13,76 72 | Chevrolet Chevelle Malibu,17,6,250,100,3329,15.5,71 73 | Chevrolet Chevelle Malibu,18,8,307,130,3504,12,70 74 | Chevrolet Chevette,29,4,85,52,2035,22.2,76 75 | Chevrolet Chevette,30,4,98,68,2155,16.5,78 76 | Chevrolet Chevette,30.5,4,98,63,2051,17,77 77 | Chevrolet Chevette,32.1,4,98,70,2120,15.5,80 78 | Chevrolet Citation,23.5,6,173,110,2725,12.6,81 79 | Chevrolet Citation,28,4,151,90,2678,16.5,80 80 | Chevrolet Citation,28.8,6,173,115,2595,11.3,79 81 | Chevrolet Concours,17.5,6,250,110,3520,16.4,77 82 | Chevrolet Impala,11,8,400,150,4997,14,73 83 | Chevrolet Impala,13,8,350,165,4274,12,72 84 | Chevrolet Impala,14,8,350,165,4209,12,71 85 | Chevrolet Impala,14,8,454,220,4354,9,70 86 | Chevrolet Malibu Classic (Wagon),19.2,8,267,125,3605,15,79 87 | Chevrolet Malibu,13,8,350,145,3988,13,73 88 | Chevrolet Malibu,20.5,6,200,95,3155,18.2,78 89 | Chevrolet Monte Carlo Landau,15.5,8,350,170,4165,11.4,77 90 | Chevrolet Monte Carlo Landau,19.2,8,305,145,3425,13.2,78 91 | Chevrolet Monte Carlo S,15,8,350,145,4082,13,73 92 | Chevrolet Monte Carlo,15,8,400,150,3761,9.5,70 93 | Chevrolet Monza 2+2,20,8,262,110,3221,13.5,75 94 | Chevrolet Nova Custom,16,6,250,100,3278,18,73 95 | Chevrolet Nova,15,6,250,100,3336,17,74 96 | Chevrolet Nova,18,6,250,105,3459,16,75 97 | Chevrolet Nova,22,6,250,105,3353,14.5,76 98 | Chevrolet Vega (Wagon),22,4,140,72,2408,19,71 99 | Chevrolet Vega 2300,28,4,140,90,2264,15.5,71 100 | Chevrolet Vega,20,4,140,90,2408,19.5,72 101 | Chevrolet Vega,21,4,140,72,2401,19.5,73 102 | Chevrolet Vega,25,4,140,75,2542,17,74 103 | Chevrolet Woody,24.5,4,98,60,2164,22.1,76 104 | Chevy C10,13,8,350,145,4055,12,76 105 | Chevy C20,10,8,307,200,4376,15,70 106 | Chevy S-10,31,4,119,82,2720,19.4,82 107 | Chrysler Cordoba,15.5,8,400,190,4325,12.2,77 108 | Chrysler Lebaron Medallion,26,4,156,92,2585,14.5,82 109 | Chrysler Lebaron Salon,17.6,6,225,85,3465,16.6,81 110 | Chrysler Lebaron Town & Country (Wagon),18.5,8,360,150,3940,13,79 111 | Chrysler New Yorker Brougham,13,8,440,215,4735,11,73 112 | Chrysler Newport Royal,13,8,400,190,4422,12.5,72 113 | Citroen DS-21 Pallas,,4,133,115,3090,17.5,70 114 | Datsun 1200,35,4,72,69,1613,18,71 115 | Datsun 200SX,23.9,4,119,97,2405,14.9,78 116 | Datsun 200SX,32.9,4,119,100,2615,14.8,81 117 | Datsun 210,31.8,4,85,65,2020,19.2,79 118 | Datsun 210,37,4,85,65,1975,19.4,81 119 | Datsun 210,40.8,4,85,65,2110,19.2,80 120 | Datsun 280ZX,32.7,6,168,132,2910,11.4,80 121 | Datsun 310 GX,38,4,91,67,1995,16.2,82 122 | Datsun 310,37.2,4,86,65,2019,16.4,80 123 | Datsun 510 (Wagon),28,4,97,92,2288,17,72 124 | Datsun 510 Hatchback,37,4,119,92,2434,15,80 125 | Datsun 510,27.2,4,119,97,2300,14.7,78 126 | Datsun 610,22,4,108,94,2379,16.5,73 127 | Datsun 710,24,4,119,97,2545,17,75 128 | Datsun 710,32,4,83,61,2003,19,74 129 | Datsun 810 Maxima,24.2,6,146,120,2930,13.8,81 130 | Datsun 810,22,6,146,97,2815,14.5,77 131 | Datsun B-210,32,4,85,70,1990,17,76 132 | Datsun B210 GX,39.4,4,85,70,2070,18.6,78 133 | Datsun B210,31,4,79,67,1950,19,74 134 | Datsun F-10 Hatchback,33.5,4,85,70,1945,16.8,77 135 | Datsun PL510,27,4,97,88,2130,14.5,70 136 | Datsun PL510,27,4,97,88,2130,14.5,71 137 | Dodge Aries SE,29,4,135,84,2525,16,82 138 | Dodge Aries Wagon (Wagon),25.8,4,156,92,2620,14.4,81 139 | Dodge Aspen 6,20.6,6,225,110,3360,16.6,79 140 | Dodge Aspen SE,20,6,225,100,3651,17.7,76 141 | Dodge Aspen,18.6,6,225,110,3620,18.7,78 142 | Dodge Aspen,19.1,6,225,90,3381,18.7,80 143 | Dodge Challenger SE,15,8,383,170,3563,10,70 144 | Dodge Charger 2.2,36,4,135,84,2370,13,82 145 | Dodge Colt (Wagon),28,4,98,80,2164,15,72 146 | Dodge Colt Hardtop,25,4,97.5,80,2126,17,72 147 | Dodge Colt Hatchback Custom,35.7,4,98,80,1915,14.4,79 148 | Dodge Colt M/M,33.5,4,98,83,2075,15.9,77 149 | Dodge Colt,26,4,98,79,2255,17.7,76 150 | Dodge Colt,27.9,4,156,105,2800,14.4,80 151 | Dodge Colt,28,4,90,75,2125,14.5,74 152 | Dodge Coronet Brougham,16,8,318,150,4190,13,76 153 | Dodge Coronet Custom (Wagon),14,8,318,150,4457,13.5,74 154 | Dodge Coronet Custom,15,8,318,150,3777,12.5,73 155 | Dodge D100,13,8,318,150,3755,14,76 156 | Dodge D200,11,8,318,210,4382,13.5,70 157 | Dodge Dart Custom,15,8,318,150,3399,11,73 158 | Dodge Diplomat,19.4,8,318,140,3735,13.2,78 159 | Dodge Magnum XE,17.5,8,318,140,4080,13.7,78 160 | Dodge Monaco (Wagon),12,8,383,180,4955,11.5,71 161 | Dodge Monaco Brougham,15.5,8,318,145,4140,13.7,77 162 | Dodge Omni,30.9,4,105,75,2230,14.5,78 163 | Dodge Rampage,32,4,135,84,2295,11.6,82 164 | Dodge St. Regis,18.2,8,318,135,3830,15.2,79 165 | Fiat 124 Sport Coupe,26,4,98,90,2265,15.5,73 166 | Fiat 124 TC,26,4,116,75,2246,14,74 167 | Fiat 124B,30,4,88,76,2065,14.5,71 168 | Fiat 128,24,4,90,75,2108,15.5,74 169 | Fiat 128,29,4,68,49,1867,19.5,73 170 | Fiat 131,28,4,107,86,2464,15.5,76 171 | Fiat Strada Custom,37.3,4,91,69,2130,14.7,79 172 | Fiat X1.9,31,4,79,67,2000,16,74 173 | Ford Capri II,25,4,140,92,2572,14.9,76 174 | Ford Country Squire (Wagon),13,8,400,170,4746,12,71 175 | Ford Country Squire (Wagon),15.5,8,351,142,4054,14.3,79 176 | Ford Country,12,8,400,167,4906,12.5,73 177 | Ford Escort 2H,29.9,4,98,65,2380,20.7,81 178 | Ford Escort 4W,34.4,4,98,65,2045,16.2,81 179 | Ford F108,13,8,302,130,3870,15,76 180 | Ford F250,10,8,360,215,4615,14,70 181 | Ford Fairmont (Auto),20.2,6,200,85,2965,15.8,78 182 | Ford Fairmont (Man),25.1,4,140,88,2720,15.4,78 183 | Ford Fairmont 4,22.3,4,140,88,2890,17.3,79 184 | Ford Fairmont Futura,24,4,140,92,2865,16.4,82 185 | Ford Fairmont,26.4,4,140,88,2870,18.1,80 186 | Ford Fiesta,36.1,4,98,66,1800,14.4,78 187 | Ford Futura,18.1,8,302,139,3205,11.2,78 188 | Ford Galaxie 500,14,8,351,153,4129,13,72 189 | Ford Galaxie 500,14,8,351,153,4154,13.5,71 190 | Ford Galaxie 500,15,8,429,198,4341,10,70 191 | Ford Gran Torino (Wagon),13,8,302,140,4294,16,72 192 | Ford Gran Torino (Wagon),14,8,302,140,4638,16,74 193 | Ford Gran Torino,14,8,302,137,4042,14.5,73 194 | Ford Gran Torino,14.5,8,351,152,4215,12.8,76 195 | Ford Gran Torino,16,8,302,140,4141,14,74 196 | Ford Granada Ghia,18,6,250,78,3574,21,76 197 | Ford Granada GL,20.2,6,200,88,3060,17.1,81 198 | Ford Granada L,22,6,232,112,2835,14.7,82 199 | Ford Granada,18.5,6,250,98,3525,19,77 200 | Ford LTD Landau,17.6,8,302,129,3725,13.4,79 201 | Ford LTD,13,8,351,158,4363,13,73 202 | Ford LTD,14,8,351,148,4657,13.5,75 203 | Ford Maverick,15,6,250,72,3158,19.5,75 204 | Ford Maverick,18,6,250,88,3021,16.5,73 205 | Ford Maverick,21,6,200,,2875,17,74 206 | Ford Maverick,21,6,200,85,2587,16,70 207 | Ford Maverick,24,6,200,81,3012,17.6,76 208 | Ford Mustang Boss 302,,8,302,140,3353,8,70 209 | Ford Mustang Cobra,23.6,4,140,,2905,14.3,80 210 | Ford Mustang GL,27,4,140,86,2790,15.6,82 211 | Ford Mustang II 2+2,25.5,4,140,89,2755,15.8,77 212 | Ford Mustang II,13,8,302,129,3169,12,75 213 | Ford Mustang,18,6,250,88,3139,14.5,71 214 | Ford Pinto (Wagon),22,4,122,86,2395,16,72 215 | Ford Pinto Runabout,21,4,122,86,2226,16.5,72 216 | Ford Pinto,18,6,171,97,2984,14.5,75 217 | Ford Pinto,19,4,122,85,2310,18.5,73 218 | Ford Pinto,23,4,140,83,2639,17,75 219 | Ford Pinto,25,4,98,,2046,19,71 220 | Ford Pinto,26,4,122,80,2451,16.5,74 221 | Ford Pinto,26.5,4,140,72,2565,13.6,76 222 | Ford Ranger,28,4,120,79,2625,18.6,82 223 | Ford Thunderbird,16,8,351,149,4335,14.5,77 224 | Ford Torino (Wagon),,8,351,153,4034,11,70 225 | Ford Torino 500,19,6,250,88,3302,15.5,71 226 | Ford Torino,17,8,302,140,3449,10.5,70 227 | Hi 1200D,9,8,304,193,4732,18.5,70 228 | Honda Accord CVCC,31.5,4,98,68,2045,18.5,77 229 | Honda Accord LX,29.5,4,98,68,2135,16.6,78 230 | Honda Accord,32.4,4,107,72,2290,17,80 231 | Honda Accord,36,4,107,75,2205,14.5,82 232 | Honda Civic (Auto),32,4,91,67,1965,15.7,82 233 | Honda Civic 1300,35.1,4,81,60,1760,16.1,81 234 | Honda Civic 1500 GL,44.6,4,91,67,1850,13.8,80 235 | Honda Civic CVCC,33,4,91,53,1795,17.5,75 236 | Honda Civic CVCC,36.1,4,91,60,1800,16.4,78 237 | Honda Civic,24,4,120,97,2489,15,74 238 | Honda Civic,33,4,91,53,1795,17.4,76 239 | Honda Civic,38,4,91,67,1965,15,82 240 | Honda Prelude,33.7,4,107,75,2210,14.4,81 241 | Maxda GLC Deluxe,34.1,4,86,65,1975,15.2,79 242 | Maxda RX-3,18,3,70,90,2124,13.5,73 243 | Mazda 626,31.3,4,120,75,2542,17.5,80 244 | Mazda 626,31.6,4,120,74,2635,18.3,81 245 | Mazda GLC 4,34.1,4,91,68,1985,16,81 246 | Mazda GLC Custom L,37,4,91,68,2025,18.2,82 247 | Mazda GLC Custom,31,4,91,68,1970,17.6,82 248 | Mazda GLC Deluxe,32.8,4,78,52,1985,19.4,78 249 | Mazda GLC,46.6,4,86,65,2110,17.9,80 250 | Mazda RX-2 Coupe,19,3,70,97,2330,13.5,72 251 | Mazda RX-4,21.5,3,80,110,2720,13.5,77 252 | Mazda RX-7 Gs,23.7,3,70,100,2420,12.5,80 253 | Mercedes-Benz 240D,30,4,146,67,3250,21.8,80 254 | Mercedes-Benz 280S,16.5,6,168,120,3820,16.7,76 255 | Mercedes-Benz 300D,25.4,5,183,77,3530,20.1,79 256 | Mercury Capri 2000,23,4,122,86,2220,14,71 257 | Mercury Capri V6,21,6,155,107,2472,14,73 258 | Mercury Cougar Brougham,15,8,302,130,4295,14.9,77 259 | Mercury Grand Marquis,16.5,8,351,138,3955,13.2,79 260 | Mercury Lynx L,36,4,98,70,2125,17.3,82 261 | Mercury Marquis Brougham,12,8,429,198,4952,11.5,73 262 | Mercury Marquis,11,8,429,208,4633,11,72 263 | Mercury Monarch Ghia,20.2,8,302,139,3570,12.8,78 264 | Mercury Monarch,15,6,250,72,3432,21,75 265 | Mercury Zephyr 6,19.8,6,200,85,2990,18.2,79 266 | Mercury Zephyr,20.8,6,200,85,3070,16.7,78 267 | Nissan Stanza XE,36,4,120,88,2160,14.5,82 268 | Oldsmobile Cutlass Ciera (Diesel),38,6,262,85,3015,17,82 269 | Oldsmobile Cutlass LS,26.6,8,350,105,3725,19,81 270 | Oldsmobile Cutlass Salon Brougham,19.9,8,260,110,3365,15.5,78 271 | Oldsmobile Cutlass Salon Brougham,23.9,8,260,90,3420,22.2,79 272 | Oldsmobile Cutlass Supreme,17,8,260,110,4060,19,77 273 | Oldsmobile Delta 88 Royale,12,8,350,160,4456,13.5,72 274 | Oldsmobile Omega Brougham,26.8,6,173,115,2700,12.9,79 275 | Oldsmobile Omega,11,8,350,180,3664,11,73 276 | Oldsmobile Starfire SX,23.8,4,151,85,2855,17.6,78 277 | Oldsmobile Vista Cruiser,12,8,350,180,4499,12.5,73 278 | Opel 1900,25,4,116,81,2220,16.9,76 279 | Opel 1900,28,4,116,90,2123,14,71 280 | Opel Manta,24,4,116,75,2158,15.5,73 281 | Opel Manta,26,4,97,78,2300,14.5,74 282 | Peugeot 304,30,4,79,70,2074,19.5,71 283 | Peugeot 504 (Wagon),21,4,120,87,2979,19.5,72 284 | Peugeot 504,19,4,120,88,3270,21.9,76 285 | Peugeot 504,23,4,120,88,2957,17,75 286 | Peugeot 504,25,4,110,87,2672,17.5,70 287 | Peugeot 504,27.2,4,141,71,3190,24.8,79 288 | Peugeot 505S Turbo Diesel,28.1,4,141,80,3230,20.4,81 289 | Peugeot 604SL,16.2,6,163,133,3410,15.8,78 290 | Plymouth Arrow GS,25.5,4,122,96,2300,15.5,77 291 | Plymouth Barracuda 340,14,8,340,160,3609,8,70 292 | Plymouth Champ,39,4,86,64,1875,16.4,81 293 | Plymouth Cricket,26,4,91,70,1955,20.5,71 294 | Plymouth Custom Suburb,13,8,360,170,4654,13,73 295 | Plymouth Duster,20,6,198,95,3102,16.5,74 296 | Plymouth Duster,22,6,198,95,2833,15.5,70 297 | Plymouth Duster,23,6,198,95,2904,16,73 298 | Plymouth Fury Gran Sedan,14,8,318,150,4237,14.5,73 299 | Plymouth Fury III,14,8,318,150,4096,13,71 300 | Plymouth Fury III,14,8,440,215,4312,8.5,70 301 | Plymouth Fury III,15,8,318,150,4135,13.5,72 302 | Plymouth Fury,18,6,225,95,3785,19,75 303 | Plymouth Grand Fury,16,8,318,150,4498,14.5,75 304 | Plymouth Horizon 4,34.7,4,105,63,2215,14.9,81 305 | Plymouth Horizon Miser,38,4,105,63,2125,14.7,82 306 | Plymouth Horizon TC3,34.5,4,105,70,2150,14.9,79 307 | Plymouth Horizon,34.2,4,105,70,2200,13.2,79 308 | Plymouth Reliant,27.2,4,135,84,2490,15.7,81 309 | Plymouth Reliant,30,4,135,84,2385,12.9,81 310 | Plymouth Sapporo,23.2,4,156,105,2745,16.7,78 311 | Plymouth Satellite (Wagon),,8,383,175,4166,10.5,70 312 | Plymouth Satellite Custom (Wagon),14,8,318,150,4077,14,72 313 | Plymouth Satellite Custom,16,6,225,105,3439,15.5,71 314 | Plymouth Satellite Sebring,18,6,225,105,3613,16.5,74 315 | Plymouth Satellite,18,8,318,150,3436,11,70 316 | Plymouth Valiant Custom,19,6,225,95,3264,16,75 317 | Plymouth Valiant,18,6,225,105,3121,16.5,73 318 | Plymouth Valiant,22,6,225,100,3233,15.4,76 319 | Plymouth Volare Custom,19,6,225,100,3630,17.7,77 320 | Plymouth Volare Premier V8,13,8,318,150,3940,13.2,76 321 | Plymouth Volare,20.5,6,225,100,3430,17.2,78 322 | Pontiac Astro,23,4,140,78,2592,18.5,75 323 | Pontiac Catalina Brougham,14,8,400,175,4464,11.5,71 324 | Pontiac Catalina,14,8,400,175,4385,12,72 325 | Pontiac Catalina,14,8,455,225,4425,10,70 326 | Pontiac Catalina,16,8,400,170,4668,11.5,75 327 | Pontiac Firebird,19,6,250,100,3282,15,71 328 | Pontiac Grand Prix Lj,16,8,400,180,4220,11.1,77 329 | Pontiac Grand Prix,16,8,400,230,4278,9.5,73 330 | Pontiac J2000 Se Hatchback,31,4,112,85,2575,16.2,82 331 | Pontiac Lemans V6,21.5,6,231,115,3245,15.4,79 332 | Pontiac Phoenix LJ,19.2,6,231,105,3535,19.2,78 333 | Pontiac Phoenix,27,4,151,90,2735,18,82 334 | Pontiac Phoenix,33.5,4,151,90,2556,13.2,79 335 | Pontiac Safari (Wagon),13,8,400,175,5140,12,71 336 | Pontiac Sunbird Coupe,24.5,4,151,88,2740,16,77 337 | Pontiac Ventura Sj,18.5,6,250,110,3645,16.2,76 338 | Renault 12 (Wagon),26,4,96,69,2189,18,72 339 | Renault 12TL,27,4,101,83,2202,15.3,76 340 | Renault 18I,34.5,4,100,,2320,15.8,81 341 | Renault 5 Gtl,36,4,79,58,1825,18.6,77 342 | Renault Lecar Deluxe,40.9,4,85,,1835,17.3,80 343 | Saab 900S,,4,121,110,2800,15.4,81 344 | Saab 99E,25,4,104,95,2375,17.5,70 345 | Saab 99GLE,21.6,4,121,115,2795,15.7,78 346 | Saab 99LE,24,4,121,110,2660,14,73 347 | Saab 99LE,25,4,121,115,2671,13.5,75 348 | Subaru DL,30,4,97,67,1985,16.4,77 349 | Subaru DL,33.8,4,97,67,2145,18,80 350 | Subaru,26,4,108,93,2391,15.5,74 351 | Subaru,32.3,4,97,67,2065,17.8,81 352 | Toyota Carina,20,4,97,88,2279,19,73 353 | Toyota Celica GT Liftback,21.1,4,134,95,2515,14.8,78 354 | Toyota Celica GT,32,4,144,96,2665,13.9,82 355 | Toyota Corolla 1200,31,4,71,65,1773,19,71 356 | Toyota Corolla 1200,32,4,71,65,1836,21,74 357 | Toyota Corolla 1600 (Wagon),27,4,97,88,2100,16.5,72 358 | Toyota Corolla Liftback,26,4,97,75,2265,18.2,77 359 | Toyota Corolla Tercel,38.1,4,89,60,1968,18.8,80 360 | Toyota Corolla,28,4,97,75,2155,16.4,76 361 | Toyota Corolla,29,4,97,75,2171,16,75 362 | Toyota Corolla,32.2,4,108,75,2265,15.2,80 363 | Toyota Corolla,32.4,4,108,75,2350,16.8,81 364 | Toyota Corolla,34,4,108,70,2245,16.9,82 365 | Toyota Corona Hardtop,24,4,113,95,2278,15.5,72 366 | Toyota Corona Liftback,29.8,4,134,90,2711,15.5,80 367 | Toyota Corona Mark II,24,4,113,95,2372,15,70 368 | Toyota Corona,24,4,134,96,2702,13.5,75 369 | Toyota Corona,25,4,113,95,2228,14,71 370 | Toyota Corona,27.5,4,134,95,2560,14.2,78 371 | Toyota Corona,31,4,76,52,1649,16.5,74 372 | Toyota Cressida,25.4,6,168,116,2900,12.6,81 373 | Toyota Mark II,19,6,156,108,2930,15.5,76 374 | Toyota Mark II,20,6,156,122,2807,13.5,73 375 | Toyota Starlet,39.1,4,79,58,1755,16.9,81 376 | Toyota Tercel,37.7,4,89,62,2050,17.3,81 377 | Toyouta Corona Mark II (Wagon),23,4,120,97,2506,14.5,72 378 | Triumph TR7 Coupe,35,4,122,88,2500,15.1,80 379 | Vokswagen Rabbit,29.8,4,89,62,1845,15.3,80 380 | Volkswagen 1131 Deluxe Sedan,26,4,97,46,1835,20.5,70 381 | Volkswagen 411 (Wagon),22,4,121,76,2511,18,72 382 | Volkswagen Dasher (Diesel),43.4,4,90,48,2335,23.7,80 383 | Volkswagen Dasher,25,4,90,71,2223,16.5,75 384 | Volkswagen Dasher,26,4,79,67,1963,15.5,74 385 | Volkswagen Dasher,30.5,4,97,78,2190,14.1,77 386 | Volkswagen Jetta,33,4,105,74,2190,14.2,81 387 | Volkswagen Model 111,27,4,97,60,1834,19,71 388 | Volkswagen Pickup,44,4,97,52,2130,24.6,82 389 | Volkswagen Rabbit C (Diesel),44.3,4,90,48,2085,21.7,80 390 | Volkswagen Rabbit Custom Diesel,43.1,4,90,48,1985,21.5,78 391 | Volkswagen Rabbit Custom,29,4,97,78,1940,14.5,77 392 | Volkswagen Rabbit Custom,31.9,4,89,71,1925,14,79 393 | Volkswagen Rabbit L,36,4,105,74,1980,15.3,82 394 | Volkswagen Rabbit,29,4,90,70,1937,14,75 395 | Volkswagen Rabbit,29,4,90,70,1937,14.2,76 396 | Volkswagen Rabbit,29.5,4,97,71,1825,12.2,76 397 | Volkswagen Rabbit,41.5,4,98,76,2144,14.7,80 398 | Volkswagen Scirocco,31.5,4,89,71,1990,14.9,78 399 | Volkswagen Super Beetle 117,,4,97,48,1978,20,71 400 | Volkswagen Super Beetle,26,4,97,46,1950,21,73 401 | Volkswagen Type 3,23,4,97,54,2254,23.5,72 402 | Volvo 144EA,19,4,121,112,2868,15.5,73 403 | Volvo 145E (Wagon),18,4,121,112,2933,14.5,72 404 | Volvo 244DL,22,4,121,98,2945,14.5,75 405 | Volvo 245,20,4,130,102,3150,15.7,76 406 | Volvo 264GL,17,6,163,125,3140,13.6,78 407 | Volvo Diesel,30.7,6,145,76,3160,19.6,81 -------------------------------------------------------------------------------- /js/directives.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Directives */ 4 | 5 | angular.module('raw.directives', []) 6 | 7 | .directive('chart', function ($rootScope, dataService) { 8 | return { 9 | restrict: 'A', 10 | link: function postLink(scope, element, attrs) { 11 | 12 | function update(){ 13 | 14 | $('*[data-toggle="tooltip"]').tooltip({ container:'body' }); 15 | 16 | d3.select(element[0]).select("*").remove(); 17 | 18 | if (!scope.chart || !scope.data.length) return; 19 | if (!scope.model.isValid()) return; 20 | 21 | d3.select(element[0]) 22 | .append("svg") 23 | .datum(scope.data) 24 | .call(scope.chart) 25 | 26 | scope.svgCode = d3.select(element[0]) 27 | .select('svg') 28 | .attr("xmlns", "http://www.w3.org/2000/svg") 29 | .node().parentNode.innerHTML; 30 | 31 | $rootScope.$broadcast("completeGraph"); 32 | 33 | } 34 | 35 | scope.delayUpdate = dataService.debounce(update, 300, false); 36 | 37 | scope.$watch('chart', update); 38 | scope.$on('update', update); 39 | //scope.$watch('data', update) 40 | scope.$watch(function(){ if (scope.model) return scope.model(scope.data); }, update, true); 41 | scope.$watch(function(){ if (scope.chart) return scope.chart.options().map(function (d){ return d.value }); }, scope.delayUpdate, true); 42 | 43 | } 44 | }; 45 | }) 46 | 47 | .directive('chartOption', function () { 48 | return { 49 | restrict: 'A', 50 | link: function postLink(scope, element, attrs) { 51 | 52 | var firstTime = false; 53 | 54 | element.find('.option-fit').click(function(){ 55 | scope.$apply(fitWidth); 56 | }); 57 | 58 | scope.$watch('chart', fitWidth); 59 | 60 | function fitWidth(chart, old){ 61 | if (chart == old) return; 62 | if(!scope.option.fitToWidth || !scope.option.fitToWidth()) return; 63 | scope.option.value = $('.col-lg-9').width(); 64 | } 65 | 66 | $(document).ready(fitWidth); 67 | 68 | } 69 | }; 70 | }) 71 | 72 | .directive('colors', function ($rootScope) { 73 | return { 74 | restrict: 'A', 75 | templateUrl : 'templates/colors.html', 76 | link: function postLink(scope, element, attrs) { 77 | 78 | scope.scales = [ 79 | 80 | { 81 | type : 'Ordinal (categories)', 82 | value : d3.scale.ordinal().range(raw.divergingRange(1)), 83 | reset : function(domain){ this.value.range(raw.divergingRange(domain.length || 1)); }, 84 | update : ordinalUpdate 85 | }, 86 | /*{ 87 | type : 'Ordinal (max 20 categories)', 88 | value : d3.scale.category20(), 89 | reset : function(){ this.value.range(d3.scale.category20().range().map(function (d){ return d; })); }, 90 | update : ordinalUpdate 91 | }, 92 | { 93 | type : 'Ordinal B (max 20 categories)', 94 | value : d3.scale.category20b(), 95 | reset : function(){ this.value.range(d3.scale.category20b().range().map(function (d){ return d; })); }, 96 | update : ordinalUpdate 97 | }, 98 | { 99 | type : 'Ordinal C (max 20 categories)', 100 | value : d3.scale.category20c(), 101 | reset : function(){ this.value.range(d3.scale.category20c().range().map(function (d){ return d; })); }, 102 | update : ordinalUpdate 103 | }, 104 | { 105 | type : 'Ordinal (max 10 categories)', 106 | value : d3.scale.category10(), 107 | reset : function(){ this.value.range(d3.scale.category10().range().map(function (d){ return d; })); }, 108 | update : ordinalUpdate 109 | },*/ 110 | { 111 | type : 'Linear (numeric)', 112 | value : d3.scale.linear().range(["#f7fbff", "#08306b"]), 113 | reset : function(){ this.value.range(["#f7fbff", "#08306b"]); }, 114 | update : linearUpdate 115 | } 116 | ]; 117 | 118 | function ordinalUpdate(domain) { 119 | if (!domain.length) domain = [null]; 120 | this.value.domain(domain); 121 | listColors(); 122 | } 123 | 124 | function linearUpdate(domain) { 125 | domain = d3.extent(domain, function (d){return +d; }); 126 | if (domain[0]==domain[1]) domain = [null]; 127 | this.value.domain(domain).interpolate(d3.interpolateLab); 128 | listColors(); 129 | } 130 | 131 | scope.setScale = function(){ 132 | scope.option.value = scope.colorScale.value; 133 | scope.colorScale.reset(scope.colorScale.value.domain()); 134 | $rootScope.$broadcast("update"); 135 | } 136 | 137 | function addListener(){ 138 | scope.colorScale.reset(scope.colorScale.value.domain()); 139 | scope.option.on('change', function (domain){ 140 | scope.option.value = scope.colorScale.value; 141 | scope.colorScale.update(domain); 142 | }) 143 | } 144 | 145 | scope.colorScale = scope.scales[0]; 146 | 147 | scope.$watch('chart', addListener) 148 | scope.$watch('colorScale.value.domain()',function (domain){ 149 | scope.colorScale.reset(domain); 150 | listColors(); 151 | }, true); 152 | 153 | function listColors(){ 154 | scope.colors = scope.colorScale.value.domain().map(function (d){ 155 | return { key: d, value: scope.colorScale.value(d)} 156 | }).sort(function (a,b){ 157 | if (raw.isNumber(a.key) && raw.isNumber(b.key)) return a.key - b.key; 158 | return a.key < b.key ? -1 : a.key > b.key ? 1 : 0; 159 | }) 160 | } 161 | 162 | scope.setColor = function(key, color) { 163 | var domain = scope.colorScale.value.domain(), 164 | index = domain.indexOf(key), 165 | range = scope.colorScale.value.range(); 166 | range[index] = color; 167 | scope.option.value.range(range); 168 | $rootScope.$broadcast("update"); 169 | } 170 | 171 | scope.foreground = function(color){ 172 | return d3.hsl(color).l > .5 ? "#000000" : "#ffffff"; 173 | } 174 | 175 | scope.$watch('option.value', function (value){ 176 | if(!value) scope.setScale(); 177 | }) 178 | 179 | 180 | } 181 | }; 182 | }) 183 | 184 | .directive('sortable', function ($rootScope) { 185 | return { 186 | restrict: 'A', 187 | scope : { 188 | title : "=", 189 | value : "=", 190 | types : "=", 191 | multiple : "=" 192 | }, 193 | template:'
{{messageText}}
', 194 | link: function postLink(scope, element, attrs) { 195 | 196 | var removeLast = false; 197 | 198 | element.sortable({ 199 | items : '> li', 200 | connectWith: '.dimensions-container', 201 | placeholder:'drop', 202 | start: onStart, 203 | update: onUpdate, 204 | receive : onReceive, 205 | remove: onRemove, 206 | over: over, 207 | tolerance:'intersect' 208 | }) 209 | 210 | function over(e,ui){ 211 | var dimension = ui.item.data().dimension, 212 | html = isValidType(dimension) ? 'Drop here' : 'Don\'t drop here' 213 | element.find('.drop').html(html); 214 | } 215 | 216 | function onStart(e,ui){ 217 | var dimension = ui.item.data().dimension, 218 | html = isValidType(dimension) ? 'Drop here' : 'Don\'t drop here' 219 | element.find('.drop').html(html); 220 | element.parent().css("overflow","visible"); 221 | angular.element(element).scope().open=false; 222 | } 223 | 224 | function onUpdate(e,ui){ 225 | 226 | ui.item.find('.dimension-icon').remove(); 227 | 228 | if (ui.item.find('span.remove').length == 0) { 229 | ui.item.append("×") 230 | } 231 | ui.item.find('span.remove').click(function(){ ui.item.remove(); onRemove(); }); 232 | 233 | if (removeLast) { 234 | ui.item.remove(); 235 | removeLast = false; 236 | } 237 | 238 | scope.value = values(); 239 | scope.$apply(); 240 | 241 | element.parent().css("overflow","hidden"); 242 | 243 | var dimension = ui.item.data().dimension; 244 | ui.item.toggleClass("invalid", !isValidType(dimension)) 245 | message(); 246 | 247 | $rootScope.$broadcast("update"); 248 | } 249 | 250 | scope.$watch('value', function (value){ 251 | if (!value.length) { 252 | element.find('li').remove(); 253 | } 254 | message(); 255 | }) 256 | 257 | function onReceive(e,ui) { 258 | var dimension = ui.item.data().dimension; 259 | 260 | removeLast = hasValue(dimension); 261 | 262 | if (!scope.multiple && scope.value.length) { 263 | var found = false; 264 | element.find('li').each(function (i,d) { 265 | if ($(d).data().dimension.key == scope.value[0].key && !found) { 266 | $(d).remove(); 267 | found = true; 268 | removeLast=false; 269 | } 270 | }) 271 | } 272 | scope.value = values(); 273 | ui.item.find('span.remove').click(function(){ ui.item.remove(); onRemove(); }) 274 | } 275 | 276 | function onRemove(e,ui) { 277 | scope.value = values(); 278 | scope.$apply(); 279 | } 280 | 281 | function values(){ 282 | if (!element.find('li').length) return []; 283 | var v = []; 284 | element.find('li').map(function (i,d){ 285 | v.push($(d).data().dimension); 286 | }) 287 | return v; 288 | } 289 | 290 | function hasValue(dimension){ 291 | 292 | for (var i=0; i 0; 308 | scope.messageText = hasInvalidType 309 | ? "You should only use " + scope.types.map(function (d){ return d.name.toLowerCase() + "s"; }).join(" or ") + " here" 310 | : "Drag " + scope.types.map(function (d){ return d.name.toLowerCase() + "s"; }).join(", ") + " here"; 311 | //element.parent().find('.msg').html(messageText); 312 | } 313 | 314 | } 315 | } 316 | }) 317 | 318 | .directive('draggable', function () { 319 | return { 320 | restrict: 'A', 321 | scope:false, 322 | // templateUrl : 'templates/dimensions.html', 323 | link: function postLink(scope, element, attrs) { 324 | 325 | scope.$watch('metadata', function(metadata){ 326 | if(!metadata.length) element.find('li').remove(); 327 | element.find('li').draggable({ 328 | connectToSortable:'.dimensions-container', 329 | helper : 'clone', 330 | revert: 'invalid', 331 | start : onStart 332 | }) 333 | }) 334 | 335 | function onStart(e,ui){ 336 | ui.helper.width($(e.currentTarget).width()) 337 | ui.helper.css('z-index','100000'); 338 | } 339 | 340 | } 341 | } 342 | }) 343 | 344 | .directive('group', function () { 345 | return { 346 | restrict: 'A', 347 | link: function postLink(scope, element, attrs) { 348 | scope.$watch(attrs.watch, function (watch){ 349 | var last = element; 350 | element.children().each(function(i, o){ 351 | if( (i) && (i) % attrs.every == 0) { 352 | var oldLast = last; 353 | last = element.clone().empty(); 354 | last.insertAfter(oldLast); 355 | } 356 | $(o).appendTo(last) 357 | }) 358 | 359 | },true) 360 | 361 | } 362 | }; 363 | }) 364 | 365 | 366 | .directive('rawTable', function () { 367 | return { 368 | restrict: 'A', 369 | link: function postLink(scope, element, attrs) { 370 | 371 | var sortBy, 372 | descending = true; 373 | 374 | function update(){ 375 | 376 | d3.select(element[0]).selectAll("*").remove(); 377 | 378 | if(!scope.data|| !scope.data.length) { 379 | d3.select(element[0]).append("span").text("Please, review your data") 380 | return; 381 | } 382 | 383 | var table = d3.select(element[0]) 384 | .append('table') 385 | .attr("class","table table-striped table-condensed") 386 | 387 | if (!sortBy) sortBy = scope.metadata[0].key; 388 | 389 | var headers = table.append("thead") 390 | .append("tr") 391 | .selectAll("th") 392 | .data(scope.metadata) 393 | .enter().append("th") 394 | .text( function(d){ return d.key; } ) 395 | .on('click', function (d){ 396 | descending = sortBy == d.key ? !descending : descending; 397 | sortBy = d.key; 398 | update(); 399 | }) 400 | 401 | headers.append("i") 402 | .attr("class", function (d){ return descending ? "fa fa-sort-desc pull-right" : "fa fa-sort-asc pull-right"}) 403 | .style("opacity", function (d){ return d.key == sortBy ? 1 : 0; }) 404 | 405 | var rows = table.append("tbody") 406 | .selectAll("tr") 407 | .data(scope.data.sort(sort)) 408 | .enter().append("tr"); 409 | 410 | var cells = rows.selectAll("td") 411 | .data(d3.values) 412 | .enter().append("td"); 413 | cells.text(String); 414 | 415 | } 416 | 417 | function sort(a,b) { 418 | if (raw.isNumber(a[sortBy]) && raw.isNumber(b[sortBy])) return descending ? a[sortBy] - b[sortBy] : b[sortBy] - a[sortBy]; 419 | return descending ? a[sortBy] < b[sortBy] ? -1 : a[sortBy] > b[sortBy] ? 1 : 0 : a[sortBy] < b[sortBy] ? 1 : a[sortBy] > b[sortBy] ? -1 : 0; 420 | } 421 | 422 | scope.$watch('data', update); 423 | scope.$watch('metadata', function(){ 424 | sortBy = null; 425 | update(); 426 | }); 427 | 428 | } 429 | }; 430 | }) 431 | 432 | .directive('copyButton', function () { 433 | return { 434 | restrict: 'A', 435 | link: function postLink(scope, element, attrs) { 436 | 437 | ZeroClipboard.config({ moviePath: "bower_components/zeroclipboard/ZeroClipboard.swf" }); 438 | 439 | var client = new ZeroClipboard( element ); 440 | 441 | client.on( "load", function (client) { 442 | client.on( "complete", function (client, args) { 443 | element.tooltip('destroy'); 444 | element.tooltip({ title:'Copied!'}); 445 | element.tooltip('show') 446 | } ); 447 | }); 448 | 449 | client.on( 'mouseover', function ( client, args ) { 450 | element.tooltip({title:'Copy to clipboard'}); 451 | element.tooltip('show'); 452 | }); 453 | 454 | client.on( 'mouseout', function ( client, args ) { 455 | element.tooltip('destroy'); 456 | }); 457 | 458 | } 459 | }; 460 | }) 461 | 462 | .directive('coder', function () { 463 | return { 464 | restrict: 'EA', 465 | template : '', 466 | link: function postLink(scope, element, attrs) { 467 | 468 | scope.$on('completeGraph',function(){ 469 | element.find('textarea').val(scope.svgCode) 470 | }) 471 | 472 | /*function asHTML(){ 473 | if (!$('#chart > svg').length) return ""; 474 | return d3.select('#chart > svg') 475 | .attr("xmlns", "http://www.w3.org/2000/svg") 476 | .node().parentNode.innerHTML; 477 | } 478 | 479 | scope.$watch(asHTML, function(){ 480 | scope.html = asHTML(); 481 | },true) 482 | scope.$on('update', function(){ 483 | scope.html = asHTML(); 484 | })*/ 485 | } 486 | }; 487 | }) 488 | 489 | .directive('downloader', function () { 490 | return { 491 | restrict: 'E', 492 | replace:true, 493 | template : '
' + 494 | '' + 501 | '
', 502 | 503 | link: function postLink(scope, element, attrs) { 504 | 505 | var source = "#chart > svg"; 506 | 507 | var getBlob = function() { 508 | return window.Blob || window.WebKitBlob || window.MozBlob; 509 | } 510 | 511 | // Removing HTML entities from svg 512 | function decodeHtml(html) { 513 | var txt = document.createElement("textarea"); 514 | txt.innerHTML = html; 515 | return txt.value; 516 | } 517 | 518 | function downloadSvg(){ 519 | var BB = getBlob(); 520 | 521 | var html = d3.select(source) 522 | .attr("version", 1.1) 523 | .attr("xmlns", "http://www.w3.org/2000/svg") 524 | .node().parentNode.innerHTML; 525 | 526 | html = decodeHtml(html); 527 | 528 | var isSafari = (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1); 529 | 530 | if (isSafari) { 531 | var img = "data:image/svg+xml;utf8," + html; 532 | var newWindow = window.open(img, 'download'); 533 | } else { 534 | var blob = new BB([html], { type: "data:image/svg+xml" }); 535 | saveAs(blob, (element.find('input').val() || element.find('input').attr("placeholder")) + ".svg") 536 | } 537 | 538 | } 539 | 540 | function downloadPng(){ 541 | 542 | var content = d3.select("body").append("canvas") 543 | .attr("id", "canvas") 544 | .style("display","none") 545 | 546 | var html = d3.select(source) 547 | .node().parentNode.innerHTML; 548 | 549 | var image = new Image; 550 | image.src = 'data:image/svg+xml;base64,' + window.btoa(html); 551 | 552 | var canvas = document.getElementById("canvas"); 553 | canvas.width = image.width; 554 | canvas.height = image.height; 555 | var context = canvas.getContext("2d"); 556 | 557 | image.onload = function() { 558 | context.drawImage(image, 0, 0); 559 | 560 | var isSafari = (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1); 561 | 562 | if (isSafari) { 563 | var img = canvas.toDataURL("image/png;base64"); 564 | var newWindow = window.open(img, 'download'); 565 | window.location = img; 566 | } else { 567 | var a = document.createElement("a"); 568 | a.download = (scope.filename || element.find('input').attr("placeholder")) + ".png"; 569 | a.href = canvas.toDataURL("image/png;base64"); 570 | var event = document.createEvent("MouseEvents"); 571 | event.initMouseEvent( 572 | "click", true, false, window, 0, 0, 0, 0, 0 573 | , false, false, false, false, 0, null 574 | ); 575 | a.dispatchEvent(event); 576 | } 577 | }; 578 | 579 | 580 | 581 | d3.select("#canvas").remove(); 582 | } 583 | 584 | var downloadData = function() { 585 | var json = JSON.stringify(scope.model(scope.data)); 586 | var blob = new Blob([json], { type: "data:text/json;charset=utf-8" }); 587 | saveAs(blob, (scope.filename || element.find('input').attr("placeholder")) + ".json") 588 | } 589 | 590 | scope.modes = [ 591 | { label : 'Vector graphics (svg)', download : downloadSvg }, 592 | { label : 'Image (png)', download : downloadPng }, 593 | { label : 'Data model (json)', download : downloadData } 594 | ] 595 | //scope.mode = scope.modes[0] 596 | 597 | } 598 | }; 599 | }); 600 | -------------------------------------------------------------------------------- /lib/raw.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * RAW 1.0.0 3 | * http://raw.densitydesign.org 4 | * Copyright 2013-2014 DensityDesign Lab, Giorgio Caviglia, Michele Mauri, Giorgio Uboldi, Matteo Azzi 5 | * 6 | * Licensed under the LGPL License, Version 3.0 7 | * You should have received a copy of the GNU Lesser General Public License 8 | * along with this program. If not, see 9 | * 10 | * http://www.gnu.org/licenses/lgpl-3.0.html 11 | * 12 | * This program is free software: you can redistribute it and/or modify it 13 | * under the terms of the GNU Lesser General Public License as published 14 | * by the Free Software Foundation, either version 3 of the License, 15 | * or (at your option) any later version. 16 | * 17 | * This program is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty 19 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 20 | * See the GNU Lesser General Public License for more details. 21 | */ 22 | 23 | !function (exports){ 24 | 'use strict'; 25 | 26 | var raw = { 27 | version : "1.0.0", 28 | models : d3.map(), 29 | charts : d3.map() 30 | }; 31 | 32 | // Parsing 33 | 34 | raw.parser = function (delimiter) { 35 | 36 | // Insiperd by Ben Nadel's algorithm 37 | // http://www.bennadel.com/blog/1504-ask-ben-parsing-csv-strings-with-javascript-exec-regular-expression-command.htm 38 | function parser(string) { 39 | if (!string || string.length === 0) return []; 40 | 41 | var delimiter = parser.delimiter || detectDelimiter(string), 42 | rows = [[]], 43 | match, matches, 44 | data = [], 45 | re = new RegExp(( 46 | "(\\" + delimiter + "|\\r?\\n|\\r|^)" + 47 | "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" + 48 | "([^\"\\" + delimiter + "\\r\\n]*))" 49 | ),"gi" 50 | ); 51 | 52 | while (matches = re.exec(string)){ 53 | match = matches[2] ? matches[2].replace(new RegExp( "\"\"", "g" ), "\"" ) : matches[3]; 54 | console.log(match,matches[2]) 55 | if (matches[1].length && matches[1] != delimiter ) rows.push([]); 56 | rows[rows.length - 1].push( match ); 57 | } 58 | 59 | var header = rows[0]; 60 | 61 | for (var i=1; i max) { 85 | mode = el; 86 | max = counter[el]; 87 | } 88 | } 89 | return mode; 90 | } 91 | 92 | function sniff(objs) { 93 | var keys = {}; 94 | d3.keys(objs[0]).forEach(function (d){ keys[d] = []; }); 95 | objs.forEach(function(d){ 96 | for(var key in keys) { 97 | var type = raw.typeOf(d[key]); 98 | if (type) keys[key].push(type); 99 | } 100 | }) 101 | return keys; 102 | } 103 | 104 | function detectDelimiter(string){ 105 | 106 | if (!arguments.length) return; 107 | 108 | var delimiters = [",",";","\t",":","|"], 109 | delimitersCount = delimiters.map(function (d){ return 0; }), 110 | header = string.split("\n")[0], 111 | character, 112 | quoted = false, 113 | firstChar = true; 114 | 115 | for (var i in header) { 116 | character = header[i]; 117 | switch(character) { 118 | case '"': 119 | if (quoted) { 120 | if (header[i+1] != '"') quoted = false; 121 | else i++; 122 | } 123 | else if (firstChar) quoted = true; 124 | break; 125 | 126 | default: 127 | if (quoted) break; 128 | var index = delimiters.indexOf(character); 129 | if (index !== -1) { 130 | delimitersCount[index]++; 131 | firstChar = true; 132 | continue; 133 | } 134 | break; 135 | } 136 | if (firstChar) firstChar = false; 137 | } 138 | 139 | var maxCount = d3.max(delimitersCount); 140 | return maxCount == 0 ? '\0' : delimiters[delimitersCount.indexOf(maxCount)]; 141 | } 142 | 143 | function ParseError(message) { 144 | this.name = "ParseError"; 145 | this.message = message || "Sorry something went wrong while parsing your data."; 146 | } 147 | ParseError.prototype = new Error(); 148 | ParseError.prototype.constructor = ParseError; 149 | 150 | parser.metadata = function(string){ 151 | return d3.entries(sniff(parser(string))).map(function (d){ 152 | return { key : d.key, type : mode(d.value) } 153 | }) 154 | } 155 | 156 | parser.delimiter = delimiter; 157 | 158 | return parser; 159 | 160 | } 161 | 162 | // Models 163 | 164 | var model_dimension = function () { 165 | 166 | var title = "Untitled", 167 | description = null, 168 | types = [Number, String, Date], 169 | multiple = false, 170 | required = false; 171 | 172 | var dimension = function(object) { 173 | if (!dimension.value.length) return null; 174 | if (!arguments.length) return dimension.value.map(function (d){return d.key;}); 175 | return multiple 176 | ? dimension.value.map(function (d){ return accessor.call(dimension, object[d.key]); }) 177 | : accessor.call(dimension, object[dimension.value[0].key]); 178 | }; 179 | 180 | function accessor(d){ 181 | return d; 182 | } 183 | 184 | dimension.accessor = function(_) { 185 | if (!arguments.length) return accessor; 186 | accessor = _; 187 | return dimension; 188 | } 189 | 190 | dimension.multiple = function(_) { 191 | if (!arguments.length) return multiple; 192 | multiple = _; 193 | return dimension; 194 | } 195 | 196 | dimension.required = function(_) { 197 | if (!arguments.length) return required; 198 | required = +_; 199 | return dimension; 200 | } 201 | 202 | dimension.title = function(_) { 203 | if (!arguments.length) return title; 204 | title = _ + ""; 205 | return dimension; 206 | } 207 | 208 | dimension.description = function(_) { 209 | if (!arguments.length) return description; 210 | description = _ + ""; 211 | return dimension; 212 | } 213 | 214 | dimension.types = function() { 215 | if (!arguments.length) return types; 216 | var i = -1, n = arguments.length; 217 | types = []; 218 | while (++i < n) types.push(arguments[i]); 219 | return dimension; 220 | } 221 | 222 | dimension.type = function() { 223 | if (!dimension.value[0] || !dimension.value[0].type) return; 224 | return multiple 225 | ? dimension.value.map(function (d){ return d.type }) 226 | : dimension.value[0].type; 227 | } 228 | 229 | dimension.clear = function() { 230 | dimension.value = []; 231 | } 232 | 233 | dimension.value = []; 234 | 235 | return dimension; 236 | } 237 | 238 | 239 | raw.model = function () { 240 | 241 | var title = "Untitled", 242 | description = null, 243 | dimensions = d3.map(); 244 | 245 | var model = function (data) { 246 | return map.call(this, data); 247 | } 248 | 249 | function map(data) { 250 | return data; 251 | } 252 | 253 | model.title = function(_) { 254 | if (!arguments.length) return title; 255 | title = "" + _; 256 | return model; 257 | } 258 | 259 | model.description = function(_) { 260 | if (!arguments.length) return description; 261 | description = "" + _; 262 | return model; 263 | } 264 | 265 | model.map = function(_) { 266 | if (!arguments.length) return map; 267 | map = _; 268 | return model; 269 | } 270 | 271 | model.dimension = function(id) { 272 | var id = id || dimensions.values().length; 273 | var dimension = model_dimension(); 274 | dimensions.set(id, dimension); 275 | return dimension; 276 | } 277 | 278 | model.dimensions = function() { 279 | return dimensions; 280 | } 281 | 282 | model.isValid = function() { 283 | return dimensions.values() 284 | .filter(function(d){ return d.required() > d.value.length; }) 285 | .length == 0; 286 | } 287 | 288 | model.instruction = function() { 289 | return dimensions.values() 290 | .filter(function(d){ return d.required() > d.value.length; }) 291 | .map(function(d){ var v = d.required() - d.value.length > 1 ? 'dimensions' : 'dimension'; return ''+d.title() + " requires at least " + (d.required() - d.value.length) + " more " + v; }) 292 | .join(". ") 293 | } 294 | 295 | model.clear = function() { 296 | dimensions.values().forEach(function (d){ d.clear()}); 297 | } 298 | 299 | return model; 300 | 301 | } 302 | 303 | 304 | // Built-in models 305 | 306 | // Tree 307 | raw.models.set('tree', function(){ 308 | 309 | var tree = raw.model(); 310 | 311 | var hierarchy = tree.dimension('hierarchy') 312 | .title('Hierarchy') 313 | .description("This is a description of the hierarchy that illustrates what the dimension is for and other things.") 314 | .required(1) 315 | .multiple(true); 316 | 317 | var size = tree.dimension('size') 318 | .title('Size') 319 | .description("This is a description of the hierarchy that illustrates what the dimension is for and other things.") 320 | .accessor(function (d){ return +d; }) 321 | .types(Number) 322 | 323 | var color = tree.dimension('color') 324 | .title('Color') 325 | 326 | var label = tree.dimension('label') 327 | .title('Label') 328 | .multiple(true) 329 | 330 | tree.map(function (data){ 331 | var root = { children : [] }; 332 | data.forEach(function (d){ 333 | 334 | if (!hierarchy()) return root; 335 | 336 | var leaf = seek(root, hierarchy(d), hierarchy()); 337 | if(leaf === false || !leaf) return; 338 | 339 | if (!leaf.size) leaf.size = 0; 340 | leaf.size += size() ? +size(d) : 1; 341 | 342 | leaf.color = color(d); 343 | leaf.label = label(d); 344 | 345 | delete leaf.children; 346 | }); 347 | return root; 348 | }) 349 | 350 | function seek(root, path, classes) { 351 | if (path.length < 1) return false; 352 | if (!root.children) root.children = []; 353 | var p = root.children.filter(function (d){ return d.name == path[0]; })[0]; 354 | 355 | if (!p) { 356 | if( /\S/.test(path[0]) ) { 357 | p = { name: path[0], class:classes[0], children:[]}; 358 | root.children.push(p); 359 | } else p = root; 360 | } 361 | if (path.length == 1) return p; 362 | else return seek(p, path.slice(1), classes.slice(1)); 363 | } 364 | 365 | return tree; 366 | 367 | }) 368 | 369 | // Points 370 | raw.models.set('points', function(){ 371 | 372 | var points = raw.model(); 373 | 374 | var x = points.dimension('x') 375 | .title("X Axis") 376 | .types(Number, Date) 377 | .accessor(function (d){ return this.type() == "Date" ? new Date(d) : +d; }) 378 | .required(1) 379 | 380 | var y = points.dimension('y') 381 | .title("Y Axis") 382 | .types(Number, Date) 383 | .accessor(function (d){ return this.type() == "Date" ? new Date(d) : +d; }) 384 | .required(1) 385 | 386 | var size = points.dimension('size') 387 | .title("Size") 388 | .types(Number) 389 | 390 | var color = points.dimension('color') 391 | .title("Color") 392 | 393 | var label = points.dimension('label') 394 | .title("Label") 395 | .multiple(true) 396 | 397 | points.map(function (data){ 398 | return data.map(function (d){ 399 | return { 400 | x : x(d), 401 | y : y(d), 402 | size : size() ? +size(d) : 1, 403 | color : color(d), 404 | label : label(d) 405 | } 406 | }) 407 | }) 408 | 409 | return points; 410 | 411 | }) 412 | 413 | // Graph 414 | raw.models.set('graph', function(){ 415 | 416 | var graph = raw.model(); 417 | 418 | var steps = graph.dimension('steps') 419 | .title('Steps') 420 | .multiple(true) 421 | .required(2) 422 | 423 | var size = graph.dimension('size') 424 | .title('Size') 425 | .types(Number) 426 | .accessor(function (d){ return +d; }) 427 | 428 | graph.map(function (data){ 429 | 430 | var d = { nodes: [], links: [] } 431 | 432 | if (!steps() || steps().length < 2) return d; 433 | 434 | var n = [], l = [], si, ti; 435 | 436 | for (var i=0; i < steps().length-1; i++ ) { 437 | 438 | var sg = steps()[i] 439 | var tg = steps()[i+1] 440 | var relations = d3.nest() 441 | .key(function (d) { return d[sg] } ) 442 | .key(function (d) { return d[tg] } ) 443 | .entries(data) 444 | 445 | relations.forEach(function (s){ 446 | si = getNodeIndex(n, s.key, sg); 447 | 448 | if ( si == -1) { 449 | n.push({ name : s.key, group : sg }) 450 | si = n.length-1; 451 | } 452 | 453 | s.values.forEach(function (t){ 454 | ti = getNodeIndex(n, t.key, tg) 455 | if (ti == -1) { 456 | n.push({ name : t.key, group : tg }) 457 | ti = n.length-1; 458 | } 459 | var value = size() ? d3.sum(t.values, function (d){ return +size(d); }) : t.values.length; 460 | var link = { source : n[si], target : n[ti], value : value }; 461 | l.push(link); 462 | }) 463 | 464 | }) 465 | } 466 | d.nodes = n.sort(customSort); 467 | l.forEach(function (d){ d.source = n.indexOf(d.source); d.target = n.indexOf(d.target)}); 468 | d.links = l; 469 | return d; 470 | 471 | }) 472 | 473 | function customSort(a, b) { 474 | var Item1 = a.group; 475 | var Item2 = b.group; 476 | if(Item1 != Item2){ 477 | return (Item1.localeCompare(Item2)); 478 | } 479 | else{ 480 | return (a.name.localeCompare(b.name)); 481 | } 482 | } 483 | 484 | function sortByGroup(a,b){ 485 | if(a.group < b.group) return -1; 486 | if(a.group > b.group) return 1; 487 | return 0; 488 | } 489 | 490 | function getNodeIndex(array, name, group) { 491 | for (var i in array){ 492 | var a = array[i] 493 | if (a['name'] == name && a['group'] == group) { 494 | return i; 495 | } 496 | } 497 | return -1; 498 | } 499 | 500 | return graph; 501 | 502 | }) 503 | 504 | // Identity 505 | raw.models.set('identity', function(){ 506 | return raw.model(); 507 | }) 508 | 509 | raw.models.tree = raw.models.get('tree'); 510 | raw.models.points = raw.models.get('points'); 511 | raw.models.graph = raw.models.get('graph'); 512 | raw.models.identity = raw.models.get('identity'); 513 | 514 | 515 | // Charts 516 | 517 | // Generic abstarct option 518 | var chart_option = function () { 519 | 520 | var title = 'Untitled', 521 | description, defaultValue; 522 | 523 | var option = function(){ 524 | return option.value; 525 | } 526 | 527 | option.title = function(_) { 528 | if (!arguments.length) return title; 529 | title = _ + ""; 530 | return option; 531 | } 532 | 533 | option.defaultValue = function(_) { 534 | if (!arguments.length) return defaultValue; 535 | option.value = defaultValue = _; 536 | return option; 537 | } 538 | 539 | option.description = function(_) { 540 | if (!arguments.length) return description; 541 | description = _ + ""; 542 | return option; 543 | } 544 | 545 | option.reset = function() { 546 | option.value = defaultValue; 547 | } 548 | 549 | option.value = defaultValue; 550 | 551 | return option; 552 | } 553 | 554 | // Number option 555 | var chart_option_number = function() { 556 | 557 | var option = chart_option(), 558 | type = 'number', 559 | fitToWidth = false; 560 | 561 | option.fitToWidth = function(_){ 562 | if (!arguments.length) return fitToWidth; 563 | fitToWidth = +_; 564 | return option; 565 | } 566 | 567 | option.type = function() { 568 | return type; 569 | } 570 | 571 | 572 | return option; 573 | } 574 | 575 | // List option 576 | var chart_option_list = function() { 577 | 578 | var option = chart_option(), 579 | type ='list', 580 | values = []; 581 | 582 | option.values = function(_){ 583 | if (!arguments.length) return values; 584 | values = _; 585 | return option; 586 | } 587 | 588 | option.type = function() { 589 | return type; 590 | } 591 | 592 | return option; 593 | } 594 | 595 | // Checkbox option 596 | var chart_option_checkbox = function() { 597 | var option = chart_option(), 598 | type = 'checkbox'; 599 | 600 | option.type = function() { 601 | return type; 602 | } 603 | 604 | return option; 605 | } 606 | 607 | // Color option 608 | var chart_option_color = function() { 609 | var option = chart_option(), 610 | type = 'color', 611 | domain = [], 612 | dispatch = d3.dispatch('change'); 613 | 614 | option.domain = function(array, f){ 615 | if (!arguments.length) return domain; 616 | if (arguments.length === 1) { 617 | domain = array; 618 | } else { 619 | domain = array.map(f); 620 | } 621 | dispatch.change(domain); 622 | return option; 623 | } 624 | 625 | option.type = function() { 626 | return type; 627 | } 628 | 629 | d3.rebind(option, dispatch, "on"); 630 | 631 | return option; 632 | } 633 | 634 | raw.chart = function (id) { 635 | 636 | var id = id || raw.charts.values().length, 637 | title = "Untitled", 638 | description = null, 639 | category = null, 640 | thumbnail = "", 641 | options = d3.map(); 642 | 643 | var chart = function (selection) { 644 | selection.each(function (data){ 645 | draw.call(this, selection, model(data)); 646 | }) 647 | } 648 | 649 | function model(data){ 650 | return data; 651 | } 652 | 653 | function draw(selection, data) { 654 | return; 655 | } 656 | 657 | chart.title = function(_) { 658 | if (!arguments.length) return title; 659 | title = _.toString(); 660 | return chart; 661 | } 662 | 663 | chart.description = function(_) { 664 | if (!arguments.length) return description; 665 | description = _.toString(); 666 | return chart; 667 | } 668 | 669 | chart.category = function(_) { 670 | if (!arguments.length) return category; 671 | category = _.toString(); 672 | return chart; 673 | } 674 | 675 | chart.thumbnail = function(_) { 676 | if (!arguments.length) return thumbnail; 677 | thumbnail = _.toString(); 678 | return chart; 679 | } 680 | 681 | chart.model = function(_) { 682 | if (!arguments.length) return model; 683 | model = _; 684 | return chart; 685 | } 686 | 687 | chart.draw = function(_) { 688 | if (!arguments.length) return draw; 689 | draw = _; 690 | return chart; 691 | } 692 | 693 | // Options 694 | 695 | chart.number = function(id){ 696 | var id = id || options.size(); 697 | var option = chart_option_number(); 698 | options.set(id, option); 699 | return option; 700 | } 701 | 702 | chart.list = function(id){ 703 | var id = id || options.size(); 704 | var option = chart_option_list(); 705 | options.set(id, option); 706 | return option; 707 | } 708 | 709 | chart.checkbox = function(id){ 710 | var id = id || options.size(); 711 | var option = chart_option_checkbox(); 712 | options.set(id, option); 713 | return option; 714 | } 715 | 716 | chart.color = function(id){ 717 | var id = id || options.size(); 718 | var option = chart_option_color(); 719 | options.set(id, option); 720 | return option; 721 | } 722 | 723 | chart.options = function() { 724 | return options.values(); 725 | } 726 | 727 | chart.clear = function() { 728 | options.values().clear(); 729 | } 730 | 731 | raw.charts.set(id, chart); 732 | 733 | return chart; 734 | 735 | } 736 | 737 | // Utils 738 | 739 | raw.dateFormats = [ 740 | /^((0?[1-9]|[12][0-9]|3[01])[\-\_\.\/\s])?(0?[1-9]|1[012])[\-\_\.\/\s][0-9]{2,4}$/, 741 | /^((0?[1-9]|[12][0-9]|3[01])[\-\_\.\/\s])?[A-z]+[\-\_\.\/\s][0-9]{2,4}$/, 742 | /^[A-z]+[\-\_\.\/\s]((0?[1-9]|[12][0-9]|3[01])[,][\-\_\.\/\s])?[0-9]{2,4}$/, 743 | /^(0?[1-9]|1[012])[\-\_\.\/\s](0?[1-9]|[12][0-9]|3[01])[\-\_\.\/\s][0-9]{2,4}$/, 744 | /^[0-9]{2,4}[\-\_\.\/\s](0?[1-9]|1[012])[\-\_\.\/\s](0?[1-9]|[12][0-9]|3[01])$/ 745 | ] 746 | 747 | raw.isString = function(value){ 748 | return typeof value == 'string'; 749 | } 750 | 751 | raw.isBoolean = function(value){ 752 | if (value.toLowerCase() === 'true' || value.toLowerCase() === 'yes' || value === 1 ) return true; 753 | if (value.toLowerCase() === 'false' || value.toLowerCase() === 'no' || value === 0 ) return true; 754 | return false; 755 | } 756 | 757 | raw.isNumber = function(value) { 758 | return !isNaN(value); 759 | } 760 | 761 | raw.isDate = function(value){ 762 | var isDate = false; 763 | for (var format in raw.dateFormats){ 764 | if (value.match(raw.dateFormats[format])) { 765 | isDate = !isNaN(Date.parse(value)); 766 | } 767 | } 768 | return isDate; 769 | } 770 | 771 | raw.typeOf = function (value) { 772 | if (value === null || value.length === 0) return null; 773 | if (raw.isDate(value)) return Date.name; 774 | if (raw.isNumber(value)) return Number.name; 775 | if (raw.isString(value)) return String.name; 776 | return null; 777 | } 778 | 779 | raw.divergingRange = function(n){ 780 | return d3.range(n).map(function (d){ 781 | return d3.hsl( 360 / n * d, .4, .58 ).toString(); 782 | }) 783 | } 784 | 785 | raw.foreground = function(color){ 786 | return d3.hsl(color).l > .5 ? "#222222" : "#ffffff"; 787 | } 788 | 789 | exports.raw = raw; 790 | 791 | }(typeof exports !== 'undefined' && exports || this); -------------------------------------------------------------------------------- /css/raw.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | background-color: #F5F5F5; 5 | font-family: 'Karla', Arial, Helvetica, sans-serif; 6 | font-weight: 400; 7 | font-size: 14px; 8 | } 9 | 10 | h2 { 11 | font-size: 18px; 12 | font-family: 'Karla', sans-serif; 13 | font-weight: 300; 14 | line-height: 26px; 15 | margin-top: 0px; 16 | } 17 | 18 | h2 a { 19 | border-bottom: 1px dotted; 20 | } 21 | 22 | h3 { 23 | font-weight: 400; 24 | letter-spacing: -0.01em; 25 | line-height: 48px; 26 | margin: 0px; 27 | font-size: 21px; 28 | margin-bottom: 30px; 29 | font-family: 'Karla', sans-serif; 30 | } 31 | 32 | a { 33 | color: #888; 34 | cursor: pointer; 35 | } 36 | 37 | a:hover { 38 | color: #444; 39 | text-decoration: none; 40 | } 41 | 42 | .stronga a { 43 | font-weight: 600; 44 | } 45 | .stronga a:hover { 46 | text-decoration: underline; 47 | } 48 | 49 | h3 a { 50 | font-size: 15px; 51 | text-transform: none; 52 | letter-spacing: normal; 53 | } 54 | 55 | h4 { 56 | font-size: 15px; 57 | font-weight: 400; 58 | margin-top: 6px; 59 | padding-bottom: 6px; 60 | } 61 | 62 | .light { 63 | font-weight: 400; 64 | } 65 | 66 | .breath-right { 67 | margin-right: 8px; 68 | } 69 | 70 | .breath-left { 71 | margin-left: 8px; 72 | } 73 | 74 | .breath-both { 75 | margin-left: 8px; 76 | margin-right: 8px; 77 | } 78 | 79 | /* Header and footer */ 80 | 81 | .wrap { 82 | min-height: 100%; 83 | height: auto !important; 84 | height: 100%; 85 | /* Negative indent footer by it's height */ 86 | margin: 0 auto -215px; 87 | padding-bottom: 215px; 88 | 89 | } 90 | 91 | #push, 92 | #footer { 93 | height: 215px; 94 | } 95 | 96 | #footer { 97 | background-color: #565656; 98 | font-size: 14px; 99 | color: #bbb; 100 | font-weight: 400; 101 | padding: 0px 20px; 102 | } 103 | 104 | #footer a { 105 | color: #bbb; 106 | text-decoration: none; 107 | } 108 | 109 | #footer a:hover { 110 | color: #eee; 111 | } 112 | 113 | #footer p { 114 | margin: 0 0 2px; 115 | } 116 | 117 | #footer .container { 118 | padding: 30px; 119 | } 120 | 121 | @media (max-width: 767px) { 122 | #footer, #header { 123 | margin-left: -20px; 124 | margin-right: -20px; 125 | padding-left: 20px; 126 | padding-right: 20px; 127 | } 128 | } 129 | 130 | .wrapper { 131 | } 132 | 133 | section { 134 | padding: 40px 0px; 135 | } 136 | 137 | section.light { 138 | background-color: #fff; 139 | } 140 | 141 | section.dark { 142 | background-color: #ECECEC; 143 | } 144 | 145 | 146 | /* Navbar */ 147 | 148 | .navbar { 149 | color: #E5E5E5; 150 | text-align: center; 151 | opacity: .97; 152 | z-index: 10000; 153 | border-radius: 0px; 154 | padding: 20px 0px; 155 | margin-bottom: 30px; 156 | background-color: #fff; 157 | } 158 | 159 | .navbar-brand { 160 | color: #222; 161 | font-size: 32px; 162 | font-weight: 900; 163 | text-transform: uppercase; 164 | font-family: 'Lato', Arial, Helvetica, sans-serif; 165 | } 166 | 167 | 168 | .navbar-brand small { 169 | font-weight: 400; 170 | font-size: 14px; 171 | } 172 | 173 | .navbar .nav>li>a { 174 | font-size: 17px; 175 | font-weight: 400; 176 | color: #0dc4a3; 177 | 178 | -webkit-transition: color .15s ease-in-out; 179 | -moz-transition: color .15s ease-in-out; 180 | -ms-transition: color .15s ease-in-out; 181 | -o-transition: color .15s ease-in-out; 182 | transition: color .15s ease-in-out; 183 | } 184 | 185 | .navbar .nav>li>a, 186 | .navbar-brand, 187 | .option-title, 188 | .dimension-title { 189 | 190 | } 191 | 192 | .navbar .nav>li>a:focus, 193 | .navbar .nav>li>a:hover, 194 | .navbar .nav>.active>a, 195 | .navbar .nav>.active>a:hover, 196 | .navbar .nav>.active>a:focus { 197 | background-color: transparent; 198 | color: #000; 199 | } 200 | 201 | .navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form { 202 | border-color: transparent; 203 | } 204 | 205 | .navbar-toggle .icon-bar { 206 | background-color: #444; 207 | } 208 | 209 | /* Alerts */ 210 | 211 | .alert { 212 | border: none; 213 | font-weight: 400; 214 | padding: 10px 12px; 215 | background-color: transparent; 216 | color: #5A5E5A; 217 | 218 | -webkit-border-radius: 2px; 219 | -moz-border-radius: 2px; 220 | border-radius: 2px; 221 | 222 | } 223 | 224 | .alert-success { 225 | background-color: #0dc4a3; 226 | color:#fff; 227 | } 228 | 229 | .alert-warning { 230 | color: #444; 231 | background-color: #FFE666; 232 | } 233 | 234 | /* Inputs */ 235 | 236 | select, textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"], .uneditable-input { 237 | -webkit-border-radius: 2px; 238 | -moz-border-radius: 2px; 239 | border-radius: 2px; 240 | } 241 | 242 | textarea, input[type="text"], 243 | input[type="password"], 244 | input[type="datetime"], 245 | input[type="datetime-local"], 246 | input[type="date"], 247 | input[type="month"], 248 | input[type="time"], 249 | input[type="week"], 250 | input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"], .uneditable-input { 251 | -webkit-box-shadow: none; 252 | -moz-box-shadow: none; 253 | box-shadow: none; 254 | border: 1px solid transparent; 255 | padding: 6px; 256 | font-weight: 400; 257 | } 258 | 259 | 260 | .btn:focus, 261 | input[type="number"]:focus, 262 | input[type="text"]:focus, 263 | textarea:focus { 264 | -webkit-box-shadow: none; 265 | -moz-box-shadow: none; 266 | box-shadow: none; 267 | border: 1px solid #bbb; 268 | outline: 0px auto -webkit-focus-ring-color !important; 269 | outline: none; 270 | } 271 | 272 | .btn:focus, 273 | .btn:hover { 274 | border: none; 275 | background-color: #e5e5e5; 276 | } 277 | 278 | .form-control { 279 | font-size: 14px; 280 | } 281 | 282 | .btn.choose { 283 | font-weight: 300; 284 | letter-spacing: -0.01em; 285 | margin: 0px; 286 | font-size: 21px; 287 | font-family: 'Karla', sans-serif; 288 | background-color: transparent; 289 | border-bottom-right-radius: 0px; 290 | border-bottom-left-radius: 0px; 291 | line-height: 2px !important; 292 | padding: 10px 0px; 293 | color: #888; 294 | } 295 | 296 | .btn.choose:focus, 297 | .btn.choose:hover { 298 | border-radius: 0px; 299 | color: #444; 300 | } 301 | 302 | .btn.choose .caret { 303 | margin-left: 5px; 304 | } 305 | 306 | 307 | /* Tooltips */ 308 | 309 | .tooltip-inner { 310 | font-weight: 400; 311 | padding: 10px 15px; 312 | -webkit-border-radius: 2px; 313 | -moz-border-radius: 2px; 314 | border-radius: 2px; 315 | } 316 | 317 | .btn { 318 | border: none; 319 | -webkit-border-radius: 2px; 320 | -moz-border-radius: 2px; 321 | border-radius: 2px; 322 | font-weight: 400; 323 | font-size: 14px; 324 | } 325 | 326 | .btn-success.disabled, .btn-success[disabled], fieldset[disabled] .btn-success, .btn-success.disabled:hover, .btn-success[disabled]:hover, fieldset[disabled] .btn-success:hover, .btn-success.disabled:focus, .btn-success[disabled]:focus, fieldset[disabled] .btn-success:focus, .btn-success.disabled:active, .btn-success[disabled]:active, fieldset[disabled] .btn-success:active, .btn-success.disabled.active, .btn-success[disabled].active, fieldset[disabled] .btn-success.active, 327 | .btn-success { 328 | background-color: #0dc4a3; 329 | } 330 | 331 | .btn-success.disabled { 332 | opacity: .2; 333 | } 334 | 335 | .btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active, .open .dropdown-toggle.btn-success { 336 | background-color: #0dc4a3; 337 | } 338 | 339 | .btn .caret { 340 | margin-left: 20px; 341 | } 342 | 343 | .dropdown-menu { 344 | border: none; 345 | -webkit-border-radius: 2px; 346 | -moz-border-radius: 2px; 347 | border-radius: 2px; 348 | box-shadow: 0px 1px 2px rgba(0,0,0,.2); 349 | 350 | 351 | } 352 | 353 | .dropdown-menu>.active>a, .dropdown-menu>.active>a:hover, .dropdown-menu>.active>a:focus { 354 | background-color: #0dc4a3; 355 | } 356 | 357 | .dropdown-menu>li>a { 358 | font-size: 14px; 359 | font-weight: 400; 360 | } 361 | 362 | #export .btn { 363 | margin: 10px 0px; 364 | } 365 | 366 | #export .btn:first-child { 367 | margin-top: 0px; 368 | } 369 | 370 | /* Charts */ 371 | 372 | .chart-description { 373 | font-size: 14px; 374 | } 375 | 376 | .chart-description h4{ 377 | font-size: 16px; 378 | font-weight: 700; 379 | margin-bottom: 1px; 380 | font-family: 'Karla', sans-serif; 381 | } 382 | 383 | .chart-description p{ 384 | margin-top: 9px; 385 | font-size: 14px; 386 | font-family: 'Karla', sans-serif; 387 | font-weight: 300; 388 | } 389 | 390 | .chart-description hr{ 391 | background-color: #3F403F; 392 | height: 1px; 393 | width: 20px; 394 | margin-left: 0; 395 | margin-top: 10px; 396 | margin-bottom: 18px; 397 | } 398 | 399 | .chart-description a { 400 | font-weight: 500; 401 | } 402 | 403 | .chart-description a:hover { 404 | 405 | } 406 | 407 | 408 | /* Dimensions */ 409 | 410 | .dimensions-container { 411 | padding: 0px; 412 | min-height: 55px; 413 | margin-bottom: 0px; 414 | } 415 | 416 | 417 | .dimensions-wrapper { 418 | margin-bottom: 20px; 419 | } 420 | 421 | .dimensions-model { 422 | position: relative; 423 | -webkit-border-radius: 2px; 424 | -moz-border-radius: 2px; 425 | border-radius: 2px; 426 | background-color: white; 427 | padding: 10px; 428 | overflow: hidden; 429 | 430 | margin-bottom: 5px; 431 | 432 | -webkit-transition: border .15s ease-in-out; 433 | -moz-transition: border .15s ease-in-out; 434 | -ms-transition: border .15s ease-in-out; 435 | -o-transition: border .15s ease-in-out; 436 | transition: border .15s ease-in-out; 437 | 438 | } 439 | 440 | .dimensions-model.invalid { 441 | border-color: #f00; 442 | } 443 | 444 | .dimension-placeholder, 445 | .dimension { 446 | padding: 8px 10px; 447 | position: relative; 448 | margin-bottom: 3px; 449 | font-size: 14px; 450 | font-weight: 400; 451 | line-height: 18px; 452 | -webkit-border-radius: 2px; 453 | -moz-border-radius: 2px; 454 | border-radius: 2px; 455 | opacity: .85; 456 | 457 | -webkit-transition: background .1s ease-in-out; 458 | -moz-transition: background .1s ease-in-out; 459 | -ms-transition: background .1s ease-in-out; 460 | -o-transition: background .1s ease-in-out; 461 | transition: background .1s ease-in-out; 462 | 463 | } 464 | 465 | .dimension-key { 466 | margin-right: 3px; 467 | } 468 | 469 | .layout { 470 | position: relative; 471 | background-color: #fff; 472 | cursor: pointer; 473 | margin-bottom: 10px; 474 | display: table; 475 | width: 100%; 476 | height: 120px; 477 | 478 | -webkit-border-radius: 2px; 479 | -moz-border-radius: 2px; 480 | border-radius: 2px; 481 | 482 | -webkit-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 483 | -moz-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 484 | box-shadow: 0px 1px 1px rgba(0,0,0,.1); 485 | 486 | } 487 | 488 | .layout.selected { 489 | background-color: #14E2B9; 490 | } 491 | 492 | .layout-title { 493 | font-family: 'Karla', sans-serif; 494 | color: #000; 495 | font-size: 18px; 496 | font-weight: 400; 497 | } 498 | 499 | 500 | .layout-thumb { 501 | background-position: center; 502 | background-size: 180%; 503 | background-color: #fff; 504 | 505 | -webkit-border-radius: 2px; 506 | -moz-border-radius: 2px; 507 | border-radius: 2px; 508 | 509 | position: absolute; 510 | top: 0px; 511 | bottom: 0px; 512 | left: 0px; 513 | right: 0px; 514 | } 515 | 516 | .layout.selected .layout-thumb, 517 | .layout:hover .layout-thumb { 518 | opacity: .15; 519 | -webkit-transition: opacity .2s ease-in-out; 520 | -moz-transition: opacity .2s ease-in-out; 521 | -ms-transition: opacity .2s ease-in-out; 522 | -o-transition: opacity .2s ease-in-out; 523 | transition: opacity .2s ease-in-out; 524 | 525 | } 526 | 527 | .layout.selected .layout-title{ 528 | 529 | } 530 | 531 | .layout-inner { 532 | opacity: 0; 533 | position: absolute; 534 | top: 0px; 535 | bottom: 0px; 536 | left: 0px; 537 | right: 0px; 538 | 539 | -webkit-border-radius: 2px; 540 | -moz-border-radius: 2px; 541 | border-radius: 2px; 542 | 543 | text-align: center; 544 | margin: 0px; 545 | 546 | /* Internet Explorer 10 */ 547 | display:-ms-flexbox; 548 | -ms-flex-pack:center; 549 | -ms-flex-align:center; 550 | 551 | /* Firefox */ 552 | display:-moz-box; 553 | -moz-box-pack:center; 554 | -moz-box-align:center; 555 | 556 | /* Safari, Opera, and Chrome */ 557 | display:-webkit-box; 558 | -webkit-box-pack:center; 559 | -webkit-box-align:center; 560 | 561 | /* W3C */ 562 | display:box; 563 | box-pack:center; 564 | box-align:center; 565 | 566 | 567 | } 568 | 569 | .layout.selected .layout-inner, 570 | .layout:hover .layout-inner { 571 | opacity: 1; 572 | 573 | -webkit-transition: opacity .2s ease-in-out; 574 | -moz-transition: opacity .2s ease-in-out; 575 | -ms-transition: opacity .2s ease-in-out; 576 | -o-transition: opacity .2s ease-in-out; 577 | transition: opacity .2s ease-in-out; 578 | 579 | } 580 | 581 | .layout.yours { 582 | background-color: transparent; 583 | border: 2px dashed #ddd; 584 | 585 | -webkit-box-shadow: none; 586 | -moz-box-shadow: none; 587 | box-shadow: none; 588 | } 589 | 590 | .layout.yours .layout-thumb { 591 | background-color: transparent; 592 | text-align: center; 593 | font-size: 60px; 594 | line-height: 118px; 595 | opacity: .1; 596 | height: 76px; 597 | } 598 | 599 | .layout.yours:hover .layout-thumb { 600 | } 601 | 602 | .dimension-placeholder, 603 | .dimension { 604 | cursor: move; 605 | color: #ffffff; 606 | background-color: #0dc4a3; 607 | border-bottom: 1px solid rgba(0,0,0,.1); 608 | } 609 | 610 | .layout:hover, 611 | .ui-draggable-dragging, 612 | .dimension:hover { 613 | opacity: 1; 614 | } 615 | 616 | .dimension-multiple { 617 | position: absolute; 618 | top: 10px; 619 | left: 10px; 620 | color: #bbbbbb; 621 | } 622 | 623 | .dimension-required { 624 | position: absolute; 625 | top: 12px; 626 | right: 10px; 627 | color: #0dc4a3; 628 | } 629 | 630 | .dimension-type { 631 | color: rgba(255,255,255,.6); 632 | font-size: 14px; 633 | font-weight: 400; 634 | text-transform: lowercase; 635 | } 636 | 637 | .dimension-type-valid { 638 | font-size: 9px; 639 | color: #999; 640 | letter-spacing: 1px; 641 | line-height: 18px; 642 | text-transform: uppercase; 643 | } 644 | 645 | .dimension-title { 646 | text-align: center; 647 | padding-bottom: 5px; 648 | margin: 10px 0px 5px 0px; 649 | color: #000; 650 | font-size: 18px; 651 | font-weight: 400; 652 | 653 | } 654 | 655 | .remove { 656 | position: absolute; 657 | font-size: 16px; 658 | font-weight: 200; 659 | top: 8px; 660 | right: 10px; 661 | cursor: pointer; 662 | } 663 | 664 | .drop { 665 | padding: 8px 10px; 666 | -webkit-border-radius: 2px; 667 | -moz-border-radius: 2px; 668 | border-radius: 2px; 669 | background-color: #ddd; 670 | font-size: 14px; 671 | font-weight: 400; 672 | line-height: 18px; 673 | color: #fff; 674 | margin-bottom: 3px; 675 | 676 | display: block; 677 | width: 100%; 678 | border-top: 1px solid rgba(100,100,100,.1); 679 | 680 | } 681 | 682 | .dimension.invalid { 683 | background-color: #F8E937; 684 | color: #000; 685 | } 686 | 687 | .dimension.invalid .dimension-type { 688 | color: rgba(0,0,0,.6) 689 | } 690 | 691 | .dimension-placeholder { 692 | opacity: .5; 693 | } 694 | 695 | .dimension-info { 696 | position: absolute; 697 | cursor: pointer; 698 | top: 10px; 699 | right: 10px; 700 | color: #bbbbbb; 701 | } 702 | 703 | .dimension-icon { 704 | opacity: .5; 705 | } 706 | 707 | .dimension-description { 708 | position: absolute; 709 | left: 0; 710 | padding: 10px; 711 | background: #ffffff; 712 | height: 100%; 713 | width: 100%; 714 | top: 37px; 715 | bottom: 0; 716 | opacity: 0; 717 | font-size: 14px; 718 | font-weight: 400; 719 | 720 | -webkit-transform: translateY(100%); 721 | -moz-transform: translateY(100%); 722 | -ms-transform: translateY(100%); 723 | transform: translateY(100%); 724 | 725 | -webkit-transition: -webkit-transform 0.4s, opacity 0.1s 0.3s; 726 | -moz-transition: -moz-transform 0.4s, opacity 0.1s 0.3s; 727 | transition: transform 0.4s, opacity 0.1s 0.3s; 728 | 729 | } 730 | 731 | .dimension-description.open { 732 | opacity: .95; 733 | z-index: 1005; 734 | -webkit-transform: translateY(0px); 735 | -moz-transform: translateY(0px); 736 | -ms-transform: translateY(0px); 737 | transform: translateY(0px); 738 | -webkit-transition: -webkit-transform 0.4s, opacity 0.1s; 739 | -moz-transition: -moz-transform 0.4s, opacity 0.1s; 740 | transition: transform 0.4s, opacity 0.1s; 741 | } 742 | 743 | .msg { 744 | color: #888; 745 | font-size: 12px; 746 | font-weight: 400; 747 | margin-bottom: 10px; 748 | text-align: center; 749 | } 750 | 751 | .option-title { 752 | text-transform: uppercase; 753 | font-weight: 400; 754 | font-size: 11px; 755 | letter-spacing: 1px; 756 | margin: 8px 0px; 757 | padding: 10px 0px; 758 | padding-bottom: 0px; 759 | color: #444; 760 | } 761 | 762 | /*.sticky { 763 | -webkit-transition: top 0.3s; 764 | -moz-transition: top 0.3s; 765 | transition: top 0.3s; 766 | }*/ 767 | 768 | /* Colors */ 769 | 770 | div[colors] { 771 | } 772 | 773 | div[colors] .colors-table { 774 | max-height: 230px; 775 | -webkit-border-radius: 2px; 776 | -moz-border-radius: 2px; 777 | border-radius: 2px; 778 | overflow: scroll; 779 | margin-top: 10px; 780 | position: relative; 781 | } 782 | 783 | div[colors] .sample-color { 784 | font-size: 11px; 785 | margin: 0px; 786 | width: 60px; 787 | padding: 2px 4px; 788 | float: right; 789 | background: transparent; 790 | outline: 0px; 791 | height: auto; 792 | border: none; 793 | font-family: 'Menlo', 'Monaco', Courier, monospace; 794 | } 795 | 796 | div[colors] .sample-color:focus { 797 | -webkit-box-shadow: none; 798 | -moz-box-shadow: none; 799 | box-shadow: none; 800 | outline: 0px auto -webkit-focus-ring-color !important; 801 | } 802 | 803 | 804 | div[colors] table{ 805 | margin-bottom: 0px; 806 | } 807 | 808 | div[colors] table td { 809 | padding: 5px 8px; 810 | background: #FAFAFa; 811 | border: none; 812 | } 813 | 814 | div[colors] .table-striped>tbody>tr:nth-child(odd)>td, 815 | div[colors] .table-striped>tbody>tr:nth-child(odd)>th { 816 | background-color: #FFFFFF; 817 | } 818 | 819 | div[colors] table tr:first-child td { 820 | border-top: none; 821 | } 822 | 823 | .colorpicker { 824 | min-width: 128px; 825 | } 826 | 827 | .colorpicker .dropdown-menu { 828 | border: none; 829 | -webkit-box-shadow: none; 830 | -moz-box-shadow: none; 831 | box-shadow: none; 832 | } 833 | 834 | .colorpicker .close { 835 | display: none; 836 | } 837 | 838 | .colorpicker .dropdown-menu::before { 839 | display: none; 840 | } 841 | 842 | .colorpicker:before, 843 | .colorpicker:after { 844 | display: none; 845 | } 846 | 847 | .sample { 848 | max-width: 110px; 849 | } 850 | 851 | div[colors] input[type="text"] { 852 | font-weight: 400; 853 | border-bottom-left-radius: 0px; 854 | border-bottom-right-radius: 0px; 855 | border: none; 856 | } 857 | 858 | .search-clear { 859 | position: absolute; 860 | top: 8px; 861 | right: 10px; 862 | z-index: 10000; 863 | cursor: pointer; 864 | opacity: .5; 865 | color: #999; 866 | } 867 | 868 | .search-clear:hover { 869 | opacity: 1; 870 | } 871 | 872 | .sample-name { 873 | line-height: 15px; 874 | margin: 0px; 875 | } 876 | 877 | .sample-text { 878 | outline: none; 879 | } 880 | 881 | #chart { 882 | padding: 10px; 883 | background: #fff; 884 | 885 | } 886 | 887 | .chart-resize { 888 | padding: 0px; 889 | 890 | /* Internet Explorer 10 */ 891 | display:-ms-flexbox; 892 | -ms-flex-pack:center; 893 | -ms-flex-align:center; 894 | 895 | /* Firefox */ 896 | display:-moz-box; 897 | -moz-box-pack:center; 898 | -moz-box-align:center; 899 | 900 | /* Safari, Opera, and Chrome */ 901 | display:-webkit-box; 902 | -webkit-box-pack:center; 903 | -webkit-box-align:center; 904 | 905 | /* W3C */ 906 | display:box; 907 | box-pack:center; 908 | box-align:center; 909 | } 910 | 911 | textarea.source-area { 912 | width: 100%; 913 | font-family: Menlo, Monaco, Courier, monospace; 914 | font-size: 11px; 915 | color: #999999; 916 | padding: 6px 10px; 917 | resize: vertical; 918 | cursor: auto; 919 | margin-bottom: 10px; 920 | 921 | -webkit-transition: border .15s ease-in-out; 922 | -moz-transition: border .15s ease-in-out; 923 | -ms-transition: border .15s ease-in-out; 924 | -o-transition: border .15s ease-in-out; 925 | transition: border .15s ease-in-out; 926 | } 927 | 928 | .list-type { 929 | font-size: 14px; 930 | } 931 | 932 | .type { 933 | color: #999; 934 | cursor: pointer; 935 | } 936 | 937 | .type.selected { 938 | color: #3F403F; 939 | } 940 | 941 | #copy-button { 942 | } 943 | 944 | #copy-button.zeroclipboard-is-hover, 945 | #copy-button.zeroclipboard-is-active { 946 | color: #333; 947 | } 948 | 949 | .ui-resizable { position: relative;} 950 | .ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } 951 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } 952 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } 953 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } 954 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } 955 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } 956 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } 957 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } 958 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } 959 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} 960 | 961 | /* Table */ 962 | 963 | .data-table { 964 | font-size: 11px; 965 | font-weight: 400; 966 | height: 275px; 967 | overflow: scroll; 968 | margin-bottom: 10px; 969 | background-color: #fff; 970 | border-radius: 2px; 971 | font-family: Menlo, Monaco, Courier, monospace; 972 | 973 | /* Internet Explorer 10 */ 974 | display:-ms-flexbox; 975 | -ms-flex-pack:center; 976 | -ms-flex-align:center; 977 | 978 | /* Firefox */ 979 | display:-moz-box; 980 | -moz-box-pack:center; 981 | -moz-box-align:center; 982 | 983 | /* Safari, Opera, and Chrome */ 984 | display:-webkit-box; 985 | -webkit-box-pack:center; 986 | -webkit-box-align:center; 987 | 988 | /* W3C */ 989 | display:box; 990 | box-pack:center; 991 | box-align:center; 992 | 993 | -webkit-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 994 | -moz-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 995 | box-shadow: 0px 1px 1px rgba(0,0,0,.1); 996 | 997 | } 998 | 999 | .data-table thead th { 1000 | cursor: pointer; 1001 | } 1002 | 1003 | .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { 1004 | border-top: none; 1005 | } 1006 | 1007 | .data-table table { 1008 | margin-bottom: 0px; 1009 | } 1010 | 1011 | .table>thead>tr>th { 1012 | 1013 | } 1014 | 1015 | .table-striped>tbody>tr:nth-child(odd)>td, .table-striped>tbody>tr:nth-child(odd)>th { 1016 | background-color: #FAfAfA; 1017 | } 1018 | 1019 | 1020 | /* CodeMirror */ 1021 | 1022 | .CodeMirror { 1023 | font-family: Menlo, Monaco, Courier, monospace; 1024 | font-size: 11px; 1025 | background-color: #ffffff; 1026 | line-height: 18px; 1027 | border-radius: 2px; 1028 | margin: 10px 0; 1029 | height: 275px; 1030 | 1031 | -webkit-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 1032 | -moz-box-shadow: 0px 1px 1px rgba(0,0,0,.1); 1033 | box-shadow: 0px 1px 1px rgba(0,0,0,.1); 1034 | 1035 | } 1036 | 1037 | .CodeMirror-activeline { 1038 | color: #333; 1039 | } 1040 | 1041 | .CodeMirror-activeline-background { 1042 | background: rgba(68, 204, 164, 0.18) !important; 1043 | } 1044 | 1045 | pre.CodeMirror-placeholder { 1046 | color: #999; 1047 | } 1048 | 1049 | .CodeMirror.highlight { 1050 | opacity: .5; 1051 | } 1052 | 1053 | .CodeMirror-gutters { 1054 | height: 100%; 1055 | border: none; 1056 | background-color: #fff; 1057 | border-right: 1px solid #eee; 1058 | } 1059 | 1060 | .CodeMirror-linenumber { 1061 | color: #bbb; 1062 | } 1063 | 1064 | .CodeMirror-focused { 1065 | 1066 | } 1067 | 1068 | .CodeMirror-code div:first-child pre{ 1069 | font-weight: bold; 1070 | } 1071 | 1072 | .CodeMirror .line-error .CodeMirror-linenumber { 1073 | color: #f00; 1074 | } 1075 | 1076 | .CodeMirror .line-error { 1077 | background-color: #FFF3B8; 1078 | color: #3F403F; 1079 | } 1080 | 1081 | .cm-tab { 1082 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=); 1083 | background-position: right; 1084 | background-repeat: no-repeat; 1085 | opacity: .3; 1086 | } 1087 | --------------------------------------------------------------------------------