Skip to content

Commit

Permalink
Merge pull request #238 from palantir/add-category-renderer
Browse files Browse the repository at this point in the history
Add in OrdinalScale and CategoryBarRenderer
  • Loading branch information
jtlan committed Mar 28, 2014
2 parents 20df9b7 + df391f8 commit 0a963cd
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 5 deletions.
50 changes: 50 additions & 0 deletions examples/quicktests/quicktest-categoryRenderer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<html>
<head>
<title>CATegory Bar Renderer Quicktest</title>
<link rel="stylesheet" type="text/css" href="../../plottable.css">
<style>
.plottable .bounding-box {
stroke: none;
}
</style>
<script src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
<script src="../../build/plottable.js"></script>
<script src="../../build/exampleUtil.js"></script>

<script>
var dataseries = {
data: [
{ name: "Spot", age: 8 },
{ name: "Poptart", age: 1 },
{ name: "Budoka", age: 3 },
{ name: "Sugar", age: 14 }
],
metadata: { cssClass: "cats" }
}

function makeCatXAxisChart() {
var svg = d3.select("#meow");
svg.attr("width", 480).attr("height", 320);

var xScale = new Plottable.OrdinalScale();
var xAxis = new Plottable.XAxis(xScale, "bottom", function(d) { return d} );

var yScale = new Plottable.LinearScale();
var yAxis = new Plottable.YAxis(yScale, "left").showEndTickLabels(true);

var renderAreaD1 = new Plottable.CategoryBarRenderer(dataseries, xScale, yScale, "name", 50, "age");
yScale.widenDomain([0, yScale.domain()[1]+1]);
var basicTable = new Plottable.Table().addComponent(0, 0, yAxis)
.addComponent(0, 1, renderAreaD1)
.addComponent(1, 1, xAxis);
basicTable.renderTo(svg);
};

window.onload = function() { makeCatXAxisChart(); }
</script>
</head>
<body>
<svg id="meow"></svg>
</body>

</html>
81 changes: 81 additions & 0 deletions src/categoryBarRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
///<reference path="reference.ts" />

module Plottable {
export class CategoryBarRenderer extends CategoryRenderer {
private _widthAccessor: any;

/**
* Creates a CategoryBarRenderer.
*
* @constructor
* @param {IDataset} dataset The dataset to render.
* @param {OrdinalScale} xScale The x scale to use.
* @param {QuantitiveScale} yScale The y scale to use.
* @param {IAccessor} [xAccessor] A function for extracting the start position of each bar from the data.
* @param {IAccessor} [widthAccessor] A function for extracting the width position of each bar, in pixels, from the data.
* @param {IAccessor} [yAccessor] A function for extracting height of each bar from the data.
*/
constructor(dataset: IDataset,
xScale: OrdinalScale,
yScale: QuantitiveScale,
xAccessor?: IAccessor,
widthAccessor?: IAccessor,
yAccessor?: IAccessor) {
super(dataset, xScale, yScale, xAccessor, yAccessor);
this.classed("bar-renderer", true);
this._widthAccessor = (widthAccessor != null) ? widthAccessor : 10; // default width is 10px
}

/**
* Sets the width accessor.
*
* @param {any} accessor The new width accessor.
* @returns {CategoryBarRenderer} The calling CategoryBarRenderer.
*/
public widthAccessor(accessor: any) {
this._widthAccessor = accessor;
this._requireRerender = true;
this._rerenderUpdateSelection = true;
return this;
}

public _paint() {
super._paint();
var yRange = this.yScale.range();
var maxScaledY = Math.max(yRange[0], yRange[1]);

this.dataSelection = this.renderArea.selectAll("rect").data(this._data);
var xdr = this.xScale.domain()[1] - this.xScale.domain()[0];
var xrr = this.xScale.range()[1] - this.xScale.range()[0];
this.dataSelection.enter().append("rect");

var widthFunction = this._getAppliedAccessor(this._widthAccessor);

var xA = this._getAppliedAccessor(this._xAccessor);
var xFunction = (d: any, i: number) => {
var x = xA(d, i);
var scaledX = this.xScale.scale(x);
return scaledX - widthFunction(d, i)/2;
};

var yA = this._getAppliedAccessor(this._yAccessor);
var yFunction = (d: any, i: number) => {
var y = yA(d, i);
var scaledY = this.yScale.scale(y);
return scaledY;
};

var heightFunction = (d: any, i: number) => {
return maxScaledY - yFunction(d, i);
};

this.dataSelection
.attr("x", xFunction)
.attr("y", yFunction)
.attr("width", widthFunction)
.attr("height", heightFunction)
.attr("fill", this._getAppliedAccessor(this._colorAccessor));
this.dataSelection.exit().remove();
}
}
}
68 changes: 68 additions & 0 deletions src/categoryRenderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
///<reference path="reference.ts" />

module Plottable {
export class CategoryRenderer extends Renderer {
public dataSelection: D3.UpdateSelection;
public xScale: OrdinalScale;
public yScale: QuantitiveScale;
public _xAccessor: any;
public _yAccessor: any;
public autorangeDataOnLayout = true;

/**
* Creates a CategoryRenderer with an Ordinal x scale and Quantitive y scale.
*
* @constructor
* @param {IDataset} dataset The dataset to render.
* @param {OrdinalScale} xScale The x scale to use.
* @param {QuantitiveScale} yScale The y scale to use.
* @param {IAccessor} [xAccessor] A function for extracting x values from the data.
* @param {IAccessor} [yAccessor] A function for extracting y values from the data.
*/
constructor(dataset: IDataset,
xScale: OrdinalScale,
yScale: QuantitiveScale,
xAccessor?: IAccessor,
yAccessor?: IAccessor) {
super(dataset);
this.classed("category-renderer", true);

this.xScale = xScale;
this.yScale = yScale;

this._xAccessor = (xAccessor != null) ? xAccessor : "x"; // default
this._yAccessor = (yAccessor != null) ? yAccessor : "y"; // default

this.xScale.registerListener(() => this.rescale());
this.yScale.registerListener(() => this.rescale());
}

public _computeLayout(xOffset?: number, yOffset?: number, availableWidth?: number, availableHeight? :number) {
super._computeLayout(xOffset, yOffset, availableWidth, availableHeight);
this.xScale.range([0, this.availableWidth]);
this.yScale.range([this.availableHeight, 0]);
if (this.autorangeDataOnLayout) {
this.autorange();
}
return this;
}

public autorange() {
super.autorange();
var data = this._data;
var xA = (d: any) => this._getAppliedAccessor(this._xAccessor)(d, null);
this.xScale.domain(data.map(xA));

var yA = (d: any) => this._getAppliedAccessor(this._yAccessor)(d, null);
var yDomain: number[] = d3.extent(data, yA);
this.yScale.widenDomain(yDomain);
return this;
}

private rescale() {
if (this.element != null) {
this._render();
}
}
}
}
2 changes: 2 additions & 0 deletions src/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/// <reference path="interaction.ts" />
/// <reference path="label.ts" />
/// <reference path="renderer.ts" />
/// <reference path="categoryRenderer.ts" />
/// <reference path="xyRenderer.ts" />
/// <reference path="circleRenderer.ts" />
/// <reference path="lineRenderer.ts" />
Expand All @@ -16,4 +17,5 @@
/// <reference path="coordinator.ts" />
/// <reference path="legend.ts" />
/// <reference path="chart.ts" />
/// <reference path="categoryBarRenderer.ts" />
//grunt-end
5 changes: 5 additions & 0 deletions src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ module Plottable {
// no-op
}

public autorange() {
// no-op
return this;
}

public _anchor(element: D3.Selection) {
super._anchor(element);
this.renderArea = this.content.append("g").classed("render-area", true);
Expand Down
Loading

0 comments on commit 0a963cd

Please sign in to comment.