diff --git a/bower.json b/bower.json index 7ed0f4f3..ac5d6f15 100755 --- a/bower.json +++ b/bower.json @@ -35,6 +35,7 @@ "codemirror": "4.0.1", "zeroclipboard": "1.3.2", "canvas-toBlob.js": "https://github.com/eligrey/canvas-toBlob.js.git", - "jqueryui-touch-punch": "*" + "jqueryui-touch-punch": "*", + "momentjs": "~2.6.0" } } diff --git a/charts/hexagonalBinning.js b/charts/hexagonalBinning.js index 1e51475a..a664a358 100755 --- a/charts/hexagonalBinning.js +++ b/charts/hexagonalBinning.js @@ -38,6 +38,10 @@ .defaultValue(true) chart.draw(function (selection, data){ + + // Retrieving dimensions from model + var x = points.dimensions().get('x'), + y = points.dimensions().get('y'); var g = selection .attr("width", +width() ) @@ -52,8 +56,12 @@ var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })], yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })]; - var xScale = d3.scale.linear().range([marginLeft,width()]).domain(xExtent), - yScale = d3.scale.linear().range([h, 0]).domain(yExtent), + var xScale = x.type() == "Date" + ? d3.time.scale().range([marginLeft,width()]).domain(xExtent) + : d3.scale.linear().range([marginLeft,width()]).domain(xExtent), + yScale = y.type() == "Date" + ? d3.time.scale().range([h, 0]).domain(yExtent) + : d3.scale.linear().range([h, 0]).domain(yExtent), xAxis = d3.svg.axis().scale(xScale).tickSize(-h).orient("bottom"), yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w).orient("left"); diff --git a/charts/scatterPlot.js b/charts/scatterPlot.js index afbef34a..8c67ff9a 100755 --- a/charts/scatterPlot.js +++ b/charts/scatterPlot.js @@ -34,6 +34,10 @@ .defaultValue(true) chart.draw(function (selection, data){ + + // Retrieving dimensions from model + var x = points.dimensions().get('x'), + y = points.dimensions().get('y'); var g = selection .attr("width", +width() ) @@ -48,10 +52,14 @@ var xExtent = !useZero()? d3.extent(data, function (d){ return d.x; }) : [0, d3.max(data, function (d){ return d.x; })], yExtent = !useZero()? d3.extent(data, function (d){ return d.y; }) : [0, d3.max(data, function (d){ return d.y; })]; - var xScale = d3.scale.linear().range([marginLeft,width()-maxRadius()]).domain(xExtent), - yScale = d3.scale.linear().range([h-maxRadius(), maxRadius()]).domain(yExtent), - sizeScale = d3.scale.linear().range([1, Math.pow(+maxRadius(),2)*Math.PI]).domain([0, d3.max(data, function (d){ return d.size; })]), - xAxis = d3.svg.axis().scale(xScale).tickSize(-h+maxRadius()*2).orient("bottom")//.tickSubdivide(true), + var xScale = x.type() == "Date" + ? d3.time.scale().range([marginLeft,width()-maxRadius()]).domain(xExtent) + : d3.scale.linear().range([marginLeft,width()-maxRadius()]).domain(xExtent), + yScale = y.type() == "Date" + ? d3.time.scale().range([h-maxRadius(), maxRadius()]).domain(yExtent) + : d3.scale.linear().range([h-maxRadius(), maxRadius()]).domain(yExtent), + sizeScale = d3.scale.linear().range([1, Math.pow(+maxRadius(),2)*Math.PI]).domain([0, d3.max(data, function (d){ return d.size; })]), + xAxis = d3.svg.axis().scale(xScale).tickSize(-h+maxRadius()*2).orient("bottom")//.tickSubdivide(true), yAxis = d3.svg.axis().scale(yScale).ticks(10).tickSize(-w+maxRadius()).orient("left"); diff --git a/charts/smallMultiplesArea.js b/charts/smallMultiplesArea.js new file mode 100644 index 00000000..65b5b873 --- /dev/null +++ b/charts/smallMultiplesArea.js @@ -0,0 +1,142 @@ +(function(){ + + var stream = raw.model(); + + var group = stream.dimension() + .title('Group') + + var date = stream.dimension() + .title('Date') + .types(Date) + .accessor(function (d){ return this.type() == "Date" ? moment(d).toDate() : +d; }) + + var size = stream.dimension() + .title('Size') + .types(Number) + + stream.map(function (data){ + if (!group()) return []; + + var dates = d3.set(data.map(function (d){ return +date(d); })).values(); + + var groups = d3.nest() + .key(group) + .rollup(function (g){ + + var singles = d3.nest() + .key(function(d){ return +date(d); }) + .rollup(function (d){ + return { + group : group(d[0]), + date : date(d[0]), + size : size() ? d3.sum(d,size) : d.length + } + }) + .map(g); + + return d3.values(singles); + }) + .map(data) + + return d3.values(groups).map(function(d){ return d.sort(function(a,b){ return a.date - b.date; }) }); + + }) + + var chart = raw.chart() + .title('Small Multiples (Area)') + .thumbnail("imgs/smallMultiples.png") + .description("Based on http://bl.ocks.org/mbostock/9490313") + .model(stream) + + var width = chart.number() + .title("Width") + .defaultValue(1000) + .fitToWidth(true) + + var height = chart.number() + .title("Height") + .defaultValue(500) + + var padding = chart.number() + .title("Padding") + .defaultValue(10) + + var scale = chart.checkbox() + .title("Same scale") + .defaultValue(false) + + var colors = chart.color() + .title("Color scale") + + chart.draw(function (selection, data){ + + var w = +width(), + h = (+height() - (+padding()*(data.length-1))) / (data.length); + + var svg = selection + .attr("width", +width()) + .attr("height", +height()) + + var x = d3.time.scale() + .range([0, w]); + + var y = d3.scale.linear() + .range([h, 0]); + + var area = d3.svg.area() + .x(function(d) { return x(d.date); }) + .y0(h) + .y1(function(d) { return y(d.size); }); + + var line = d3.svg.line() + .x(function(d) { return x(d.date); }) + .y(function(d) { return y(d.size); }); + + x.domain([ + d3.min(data, function(layer) { return d3.min(layer, function(d) { return d.date; }); }), + d3.max(data, function(layer) { return d3.max(layer, function(d) { return d.date; }); }) + ]) + + colors.domain(data, function (d){ return d[0].group; }) + + svg.selectAll("g") + .data(data) + .enter().append("g") + .attr("title", function(d) { return d[0].group; }) + .attr("transform", function(d,i) { return "translate(0," + ((h+padding())*i) + ")"}) + .each(multiple); + + svg.selectAll("g") + .append("text") + .attr("x", w - 6) + .attr("y", h - 6) + .style("font-size","10px") + .style("fill", function(d){ return raw.foreground(colors()(d[0].group)) }) + .style("font-family","Arial, Helvetica") + .style("text-anchor", "end") + .text(function(d) { return d[0].group; }); + + function multiple(single) { + + var g = d3.select(this); + + if (scale()) y.domain([0, d3.max(data, function(layer) { return d3.max(layer, function(d) { return d.size; }); })]) + else y.domain([0, d3.max(single, function(d) { return d.size; })]); + + g.append("path") + .attr("class", "area") + .style("fill", function(d){ return colors()(d[0].group); }) + .attr("d", area(single)); + + /*g.append("path") + .attr("class", "line") + .style("fill","none") + .style("stroke","#666") + .style("stroke-width","1.5px") + .attr("d", line(single));*/ + + } + + }) + +})(); \ No newline at end of file diff --git a/charts/streamgraph.js b/charts/streamgraph.js index 027b1d3a..40d7606a 100755 --- a/charts/streamgraph.js +++ b/charts/streamgraph.js @@ -8,6 +8,7 @@ var date = stream.dimension() .title('Date') .types(Number,Date) + .accessor(function (d){ return this.type() == "Date" ? moment(d).toDate() : +d; }) var size = stream.dimension() .title('Size') @@ -16,18 +17,18 @@ stream.map(function (data){ if (!group()) return []; - var dates = d3.set(data.map(function (d){ return date(d); })).values(); + var dates = d3.set(data.map(function (d){ return +date(d); })).values(); var groups = d3.nest() .key(group) .rollup(function (g){ var singles = d3.nest() - .key(date) + .key(function(d){ return +date(d); }) .rollup(function (d){ return { group : group(d[0]), - x : +date(d[0]), + x : date(d[0]), y : size() ? d3.sum(d,size) : d.length } }) @@ -35,14 +36,18 @@ // let's create the empty ones dates.forEach(function(d){ - if (!singles[d]) singles[d] = { group : group(g[0]), x : +d, y : 0 } + if (!singles.hasOwnProperty(d)) { + //console.log(singles, d); + singles[d] = { group : group(g[0]), x : d, y : 0 } + } }) return d3.values(singles); }) .map(data) - return d3.values(groups); + return d3.values(groups).map(function(d){ return d.sort(function(a,b){ return a.x - b.x; }) }); + }) var chart = raw.chart() @@ -85,15 +90,22 @@ var layers = stack(data); - var x = d3.scale.linear() + /*var x = d3.scale.linear() .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; }); }) ]) - .range([0, +width()]); + .range([0, +width()]);*/ + var x = date.type() == "Date" + ? d3.time.scale() + .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; }); }) ]) + .range([0, +width()]) + : d3.scale.linear() + .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; }); }) ]) + .range([0, +width()]); var y = d3.scale.linear() .domain([0, d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); })]) .range([+height()-20, 0]); - var xAxis = d3.svg.axis().scale(x).tickSize(-height()+20).orient("bottom").tickFormat(d3.format("d")) + var xAxis = d3.svg.axis().scale(x).tickSize(-height()+20).orient("bottom")//.tickFormat(d3.format("d")) g.append("g") .attr("class", "x axis") diff --git a/css/raw.css b/css/raw.css index acd8c8cf..7bbae1c3 100755 --- a/css/raw.css +++ b/css/raw.css @@ -171,11 +171,9 @@ section.dark { } .navbar .nav>li>a { - font-size: 14px; + font-size: 17px; font-weight: 400; - letter-spacing: 1px; color: #0dc4a3; - text-transform: uppercase; -webkit-transition: color .15s ease-in-out; -moz-transition: color .15s ease-in-out; @@ -383,7 +381,7 @@ textarea:focus { .chart-description hr{ background-color: #3F403F; - height: 2px; + height: 1px; width: 20px; margin-left: 0; margin-top: 10px; @@ -484,7 +482,7 @@ textarea:focus { margin-bottom: 5px; bottom: 0px; background-position: center; - background-size: 250%; + background-size: 150%; background-color: #fff; /*filter: url("data:image/svg+xml;utf8,#grayscale"); diff --git a/imgs/alluvial.png b/imgs/alluvial.png index d8ff4ec6..08fd621a 100644 Binary files a/imgs/alluvial.png and b/imgs/alluvial.png differ diff --git a/imgs/circlePacking.png b/imgs/circlePacking.png index a1f03e5a..c37164e4 100644 Binary files a/imgs/circlePacking.png and b/imgs/circlePacking.png differ diff --git a/imgs/smallMultiples.png b/imgs/smallMultiples.png new file mode 100644 index 00000000..31d5102e Binary files /dev/null and b/imgs/smallMultiples.png differ diff --git a/imgs/streamgraph.png b/imgs/streamgraph.png index 54e45ded..c1245b01 100644 Binary files a/imgs/streamgraph.png and b/imgs/streamgraph.png differ diff --git a/index.html b/index.html index 96471786..ad1281d1 100644 --- a/index.html +++ b/index.html @@ -40,11 +40,11 @@
@@ -98,6 +98,9 @@ + + + @@ -117,6 +120,7 @@ + diff --git a/lib/raw.js b/lib/raw.js index 8f006df1..185b91a1 100644 --- a/lib/raw.js +++ b/lib/raw.js @@ -172,8 +172,8 @@ if (!dimension.value.length) return null; if (!arguments.length) return dimension.value.map(function (d){return d.key;}); return multiple - ? dimension.value.map(function (d){ return accessor.call(this, object[d.key]); }) - : accessor.call(this, object[dimension.value[0].key]); + ? dimension.value.map(function (d){ return accessor.call(dimension, object[d.key]); }) + : accessor.call(dimension, object[dimension.value[0].key]); }; function accessor(d){ @@ -218,6 +218,12 @@ return dimension; } + dimension.type = function() { + return multiple + ? dimension.value.map(function (d){ return d.type }) + : dimension.value[0].type; + } + dimension.clear = function() { dimension.value = []; } @@ -352,12 +358,12 @@ var x = points.dimension('x') .title("X Axis") .types(Number, Date) - .accessor(function (d){ return +d; }) + .accessor(function (d){ return this.type() == "Date" ? moment(d).toDate() : +d; }) var y = points.dimension('y') .title("Y Axis") .types(Number, Date) - .accessor(function (d){ return +d; }) + .accessor(function (d){ return this.type() == "Date" ? moment(d).toDate() : +d; }) var size = points.dimension('size') .title("Size") @@ -373,8 +379,8 @@ points.map(function (data){ return data.map(function (d){ return { - x : +x(d), - y : +y(d), + x : x(d), + y : y(d), size : size() ? +size(d) : 1, color : color(d), label : label(d) @@ -704,6 +710,35 @@ // Utils + raw.dateFormats = [ + 'MM DD YYYY', // 02 16 2014 + 'DD MM YYYY', // 16 02 2014 + 'YYYY MM DD', // 2014 02 16 + 'MM-DD-YYYY', // 02-16-2014 + 'DD-MM-YYYY', // 16-02-2014 + 'YYYY-MM-DD', // 2014-02-16 + 'MM/DD/YYYY', // 02/16/2014 + 'DD/MM/YYYY', // 16/02/2014 + 'YYYY/MM/DD', // 2014/02/16 + 'MM.DD.YYYY', // 02.16.2014 + 'DD.MM.YYYY', // 16.02.2014 + 'YYYY.MM.DD', // 2014.02.16 + 'DD MMM YYYY', // 16 Feb 2014 + 'D MMM YYYY', // 16 Feb 2014 + 'DD MMMM YYYY', // 16 February 2014 + 'D MMMM YYYY', // 16 February 2014 + 'MMM YYYY', // Feb 2014 + 'MMMM YYYY', // Febraury 2014 + 'Q YYYY', // 1 2014 + 'YYYY', // 2014 + 'MMM-YYYY', // Feb-2014 + 'MMMM-YYYY', // Febraury-2014 + 'Q-YYYY', // 1-2014 + 'MMM/YYYY', // Feb/2014 + 'MMMM/YYYY', // Febraury/2014 + 'Q/YYYY', // 1/2014 + ] + raw.isString = function(value){ return typeof value == 'string'; } @@ -719,11 +754,12 @@ } raw.isDate = function(value){ - value = value.replace(/[\-|\.\_]/g, '/'); + return moment(value,raw.dateFormats,true).isValid(); + /*value = value.replace(/[\-|\.\_]/g, '/'); value = value.replace(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})/g , '$3/$1/$2'); if (value.search(/^\d{2,4}\/\d{1,2}\/\d{1,2}\b$/) != 0) return false; if (!raw.isNumber(value) && Date.parse(value)) return true; - return false; + return false;*/ } raw.typeOf = function (value) {