Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

chiasm-charts

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

chiasm-charts - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

src/mixins/backgroundColor.js

2

package.json
{
"name": "chiasm-charts",
"version": "0.1.1",
"version": "0.1.2",
"description": "Reusable data visualization components.",

@@ -5,0 +5,0 @@ "repository": "git://github.com/chiasm-project/chiasm-charts.git",

# chiasm-charts
[![](http://bl.ocks.org/curran/raw/46050d18d5ec1ab401fa/thumbnail.png)](http://bl.ocks.org/curran/46050d18d5ec1ab401fa)
Reusable data visualization components for [Chiasm](https://github.com/chiasm-project/chiasm).
Reusable data visualization components.
The beginnings of this library are explained in this [video tutorial: Introduction to Chiasm](https://www.youtube.com/watch?v=MpweS7gNBt4). This video tutorial ends with this [code example: Reactive Mixins for Visualizations](http://bl.ocks.org/curran/5e3c1bed7c9cdd2b431c).
<a href="http://bl.ocks.org/curran/5e3c1bed7c9cdd2b431c">
<img align="right" src="http://bl.ocks.org/curran/raw/5e3c1bed7c9cdd2b431c/thumbnail.png">
</a>The beginnings of this library are explained in this [video tutorial: Introduction to Chiasm](https://www.youtube.com/watch?v=MpweS7gNBt4). This video tutorial ends with this [code example: Reactive Mixins for Visualizations](http://bl.ocks.org/curran/5e3c1bed7c9cdd2b431c).
## Examples
| thumbnail | description |
|---|---|
| [![](http://bl.ocks.org/curran/raw/9938078a93a4ba380a0e/thumbnail.png)](http://bl.ocks.org/curran/9938078a93a4ba380a0e) | Interactive Scatter Plot with selectable X, Y columns. |
| [![](http://bl.ocks.org/curran/raw/46050d18d5ec1ab401fa/thumbnail.png)](http://bl.ocks.org/curran/46050d18d5ec1ab401fa) | Chiasm-Charts v0.1.0 |
## Developing

@@ -21,8 +24,14 @@

After that, you can run the visual tests with the command:
After that, you can launch the visual test suite with the command:
```
npm run serve-tests
```
This will launch an instance of [live-server](https://github.com/tapio/live-server), which will automatically re-load the page every time you build the test application bundle. To build the bundle, run
```
npm run build
```
This will build the test application, which you can then inspect in a browser window open to the visual test page. This serves as the unit test suite for chiasm-charts.
This will build the test application, which you can then inspect in the browser window open to the visual test page. This serves as the unit test suite for chiasm-charts.

@@ -8,19 +8,35 @@ var d3 = require("d3");

var my = ChiasmComponent();
var my = ChiasmComponent({
fill: "black",
stroke: "none",
strokeWidth: "1px"
});
var svg = d3.select(my.initSVG());
mixins.backgroundColor(my, svg);
var g = mixins.marginConvention(my, svg);
mixins.marginEditor(my, svg);
mixins.column(my, "x");
mixins.column(my, "y");
mixins.scale(my, "x");
mixins.autoScaleType(my, "x");
mixins.rangeBands(my, "x");
mixins.scale(my, "y");
mixins.scaleRange(my, "x");
mixins.scaleRange(my, "y");
mixins.autoScaleType(my, "x", "Bands");
mixins.autoScaleType(my, "y", "Bands");
// The placement of this line ensures that the bars are drawn
// behind the axis.
var barsG = g.append("g");
var xAxisG = mixins.xAxis(my, g);
mixins.xAxisLabel(my, xAxisG);
mixins.scale(my, "y", "linear");
var yAxisG = mixins.yAxis(my, g);
mixins.yAxisLabel(my, yAxisG);
mixins.marginEditor(my, svg);
mixins.xAxisLabel(my, svg);
mixins.yAxisLabel(my, svg);

@@ -32,6 +48,6 @@ // Use a zero based Y scale.

my.when(["dataset", "xScaled", "yScaled", "height", "xRangeBand"],
function (dataset, xScaled, yScaled, height, xRangeBand) {
my.when(["dataset", "xScaled", "yScaled", "height", "xRangeBand", "fill", "stroke", "strokeWidth"],
function (dataset, xScaled, yScaled, height, xRangeBand, fill, stroke, strokeWidth){
var bars = g.selectAll("rect").data(dataset.data);
var bars = barsG.selectAll("rect").data(dataset.data);
bars.enter().append("rect");

@@ -42,3 +58,6 @@ bars

.attr("y", yScaled)
.attr("height", function (d){ return height - yScaled(d); });
.attr("height", function (d){ return height - yScaled(d); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth)
.style("fill", fill);
bars.exit().remove();

@@ -45,0 +64,0 @@

@@ -18,13 +18,24 @@ // A bot plot component.

var svg = d3.select(my.initSVG());
mixins.backgroundColor(my, svg);
var g = mixins.marginConvention(my, svg);
mixins.marginEditor(my, svg);
mixins.column(my, "x");
mixins.column(my, "y");
mixins.scale(my, "x");
mixins.scale(my, "y");
mixins.scaleRange(my, "x");
mixins.scaleRange(my, "y");
mixins.autoScaleType(my, "x", "Bands");
mixins.autoScaleType(my, "y", "Bands");
var xAxisG = mixins.xAxis(my, g);
mixins.scale(my, "x", "ordinal");
mixins.xAxisLabel(my, xAxisG);
var yAxisG = mixins.yAxis(my, g);
mixins.scale(my, "y", "linear");
mixins.yAxisLabel(my, yAxisG);
mixins.marginEditor(my, svg);
mixins.xAxisLabel(my, svg);
mixins.yAxisLabel(my, svg);

@@ -31,0 +42,0 @@ my.when(["dataset", "xAccessor"], function (dataset, xAccessor){

@@ -11,20 +11,27 @@ var d3 = require("d3");

var svg = d3.select(my.initSVG());
mixins.backgroundColor(my, svg);
var g = mixins.marginConvention(my, svg);
mixins.marginEditor(my, svg);
mixins.scale(my, "x");
mixins.autoScaleType(my, "x");
mixins.rangeBands(my, "x");
mixins.column(my, "x");
mixins.column(my, "y");
var xAxisG = mixins.xAxis(my, g);
mixins.xAxisLabel(my, xAxisG);
mixins.scaleRange(my, "x");
mixins.scaleRange(my, "y");
mixins.scale(my, "x");
mixins.scale(my, "y");
mixins.autoScaleType(my, "y");
mixins.rangeBands(my, "y");
mixins.autoScaleType(my, "x", "Bands");
mixins.autoScaleType(my, "y", "Bands");
var xAxisG = mixins.xAxis(my, g);
var yAxisG = mixins.yAxis(my, g);
mixins.yAxisLabel(my, yAxisG);
mixins.marginEditor(my, svg);
mixins.xAxisLabel(my, svg);
mixins.yAxisLabel(my, svg);
// TODO make this color scale into a mixin.
my.addPublicProperty("colorColumn", Model.None);

@@ -31,0 +38,0 @@ my.addPublicProperty("colorRangeMin", "#FFFFFF");

@@ -14,15 +14,25 @@ var d3 = require("d3");

var svg = d3.select(my.initSVG());
mixins.backgroundColor(my, svg);
var g = mixins.marginConvention(my, svg);
mixins.marginEditor(my, svg);
mixins.column(my, "x");
mixins.column(my, "y");
mixins.scale(my, "x");
mixins.scale(my, "y");
mixins.scaleRange(my, "x");
mixins.scaleRange(my, "y");
mixins.autoScaleType(my, "x");
mixins.autoScaleType(my, "y");
var xAxisG = mixins.xAxis(my, g);
mixins.scale(my, "x", "time");
mixins.xAxisLabel(my, xAxisG);
var yAxisG = mixins.yAxis(my, g);
mixins.scale(my, "y", "linear");
mixins.yAxisLabel(my, yAxisG);
mixins.marginEditor(my, svg);
mixins.xAxisLabel(my, svg);
mixins.yAxisLabel(my, svg);
var line = d3.svg.line()

@@ -29,0 +39,0 @@

@@ -14,17 +14,51 @@ var d3 = require("d3");

var svg = d3.select(my.initSVG());
mixins.backgroundColor(my, svg);
var g = mixins.marginConvention(my, svg);
mixins.marginEditor(my, svg);
mixins.scale(my, "x", "linear")
mixins.column(my, "x");
mixins.column(my, "y");
mixins.scale(my, "x");
mixins.scale(my, "y");
mixins.scaleRange(my, "x");
mixins.scaleRange(my, "y");
mixins.autoScaleType(my, "x", "Points");
mixins.autoScaleType(my, "y", "Points");
var xAxisG = mixins.xAxis(my, g);
mixins.xAxisLabel(my, xAxisG);
mixins.scale(my, "y", "linear");
var yAxisG = mixins.yAxis(my, g);
mixins.yAxisLabel(my, yAxisG);
mixins.marginEditor(my, svg);
mixins.xAxisLabel(my, svg);
mixins.yAxisLabel(my, svg);
my.when(["dataset", "xAccessor"], function (dataset, xAccessor){
my.xScaleDomain = d3.extent(dataset.data, xAccessor);
});
my.xScaleRangePadding = 0.5;
my.yScaleRangePadding = 0.5;
//// Allow the API client to optionally specify fixed min and max values.
//model.xDomainMin = None;
//model.xDomainMax = None;
//model.when(["data", "getX", "xDomainMin", "xDomainMax"],
// function (data, getX, xDomainMin, xDomainMax) {
// if(xDomainMin === None && xDomainMax === None){
// model.xDomain = d3.extent(data, getX);
// } else {
// if(xDomainMin === None){
// xDomainMin = d3.min(data, getX);
// }
// if(xDomainMax === None){
// xDomainMax = d3.max(data, getX);
// }
// model.xDomain = [xDomainMin, xDomainMax]
// }
//});
// TODO move this elsewhere
//my.when(["dataset", "xAccessor"], function (dataset, xAccessor){
// my.xScaleDomain = d3.extent(dataset.data, xAccessor);
//});

@@ -31,0 +65,0 @@ my.when(["dataset", "yAccessor"], function (dataset, yAccessor){

@@ -1,369 +0,15 @@

var d3 = require("d3");
var Model = require("model-js");
var ChiasmDataset = require("chiasm-dataset");
var getColumnMetadata = ChiasmDataset.getColumnMetadata;
module.exports = {
column: require("./scale/column"),
scale: require("./scale/scale"),
scaleRange: require("./scale/scaleRange"),
autoScaleType: require("./scale/autoScaleType"),
// TODO split up this file.
// TODO migrate to ES6 modules & Rollup.
marginConvention: require("./marginConvention"),
marginEditor: require("./marginEditor"),
xAxis: require("./xAxis"),
yAxis: require("./yAxis"),
xAxisLabel: require("./xAxisLabel"),
yAxisLabel: require("./yAxisLabel"),
function marginConvention(my, svg){
var g = svg.append("g");
// TODO maybe the margin would be better suited as 4 separate properties?
// margin-top
// margin-bottom
// margin-left
// margin-right
my.addPublicProperty("margin", {top: 20, right: 20, bottom: 50, left: 60});
my.when(["box", "margin"], function (box, margin){
my.width = box.width - margin.left - margin.right;
my.height = box.height - margin.top - margin.bottom;
g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
});
return g;
}
function marginEditor(my, svg){
// The width of the handles.
my.addPublicProperty("marginEditorWidth", 15);
// The color of the handles on hover.
my.addPublicProperty("marginEditorFill", "rgba(0, 0, 0, 0.2)");
var data = [ "left", "right", "top", "bottom" ];
var handles = svg.selectAll(".margin-handle").data(data);
handles.enter().append("rect")
.attr("class", "margin-handle")
.style("fill", "none")
.style("pointer-events", "all")
var drag = d3.behavior.drag().on("drag", function (d) {
// Mutate the margin object.
my.margin[d] = {
left: d3.event.x,
right: -d3.event.x,
top: d3.event.y,
bottom: -d3.event.y,
}[d];
// Notify model-js that the margin object has been mutated.
my.margin = my.margin;
// Hide the handles during drag.
handles.style("fill", "none");
});
handles.call(drag);
// Fill in the handles on hover.
my.when("marginEditorFill", function (marginEditorFill){
handles
.on("mouseenter", function (){
d3.select(this).style("fill", marginEditorFill);
})
.on("mouseout", function (){
d3.select(this).style("fill", "none");
});
});
// Update the drag origin function based on the margin.
my.when("margin", function (margin){
var origins = {
left: { x: margin.left, y: 0 },
right: { x: -margin.right, y: 0 },
top: { x: 0, y: margin.top },
bottom: { x: 0, y: -margin.bottom },
};
drag.origin(function(d) {
return origins[d];
});
});
// Render the handles
my.when(["margin", "marginEditorWidth", "width", "height"],
function (margin, marginEditorWidth, width, height){
var x = {
left: margin.left - marginEditorWidth / 2,
right: margin.left + width - marginEditorWidth / 2,
top: margin.left,
bottom: margin.left
};
var y = {
left: margin.top,
right: margin.top,
top: margin.top - marginEditorWidth / 2,
bottom: margin.top + height - marginEditorWidth / 2
};
var w = {
left: marginEditorWidth,
right: marginEditorWidth,
top: width,
bottom: width
};
var h = {
left: height,
right: height,
top: marginEditorWidth,
bottom: marginEditorWidth
};
var cursor = {
left: "ew-resize",
right: "ew-resize",
top: "ns-resize",
bottom: "ns-resize"
};
handles
.attr("x", function (d){ return x[d]; })
.attr("y", function (d){ return y[d]; })
.attr("width", function (d){ return w[d]; })
.attr("height", function (d){ return h[d]; })
.style("cursor", function (d){ return cursor[d]; })
// Rounded corners.
.attr("rx", function (d){ return marginEditorWidth / 2; })
.attr("ry", function (d){ return marginEditorWidth / 2; });
});
}
function scale(my, prefix, initialScaleType){
var scaleName = prefix + "Scale";
var scaleDomain = prefix + "ScaleDomain";
var scaleRange = prefix + "ScaleRange";
var scalePadding = prefix + "ScaleRangePadding"
var scaleType = prefix + "ScaleType";
var columnName = prefix + "Column";
var columnAccessor = prefix + "Accessor";
var scaled = prefix + "Scaled";
var columnMetadata = prefix + "Metadata";
my.addPublicProperty(columnName, Model.None);
// TODO this feels like it should be elsewhere.
if(prefix === "x"){
my.when("width", function (width){
my[scaleRange] = [0, width];
});
} else if(prefix === "y"){
my.when("height", function (height){
my[scaleRange] = [height, 0];
});
}
var scaleTypes = {
linear: function (my){
var myScale = d3.scale.linear();
return my.when([scaleDomain, scaleRange], function (domain, range){
if(domain !== Model.None && range !== Model.None){
my[scaleName] = myScale.domain(domain).range(range);
}
});
},
ordinal: function (my){
var myScale = d3.scale.ordinal();
return my.when([scaleDomain, scaleRange, scalePadding], function (domain, range, padding){
if(domain !== Model.None && range !== Model.None){
// TODO what about rangePoints?
my[scaleName] = myScale.domain(domain).rangeBands(range, padding);
}
});
},
time: function (my){
var myScale = d3.time.scale();
return my.when([scaleDomain, scaleRange], function (domain, range){
if(domain !== Model.None && range !== Model.None){
my[scaleName] = myScale.domain(domain).range(range);
}
});
}
};
my.addPublicProperty(scaleDomain, Model.None);
my.addPublicProperty(scaleType, initialScaleType ? initialScaleType : Model.None )
// This property is relevant only for ordinal scales.
my.addPublicProperty(scalePadding, 0.1);
var oldListener;
my.when(scaleType, function (type){
if(type !== Model.None){
// TODO add tests for this line.
if(oldListener){ my.cancel(oldListener); }
oldListener = scaleTypes[type](my);
}
});
my.when(columnName, function (column){
my[columnAccessor] = function (d){ return d[column]; };
});
my.when([scaleName, columnName], function (scale, column){
my[scaled] = function (d){ return scale(d[column]); };
});
my.when(["dataset", columnName], function (dataset, column){
if(column !== Model.None){
my[columnMetadata] = getColumnMetadata(dataset, column);
}
});
}
// TODO figure out what this really is about.
// The name autoScaleType does not really express what it does.
// It really is more the thing that isolates the difference between
// a bar chart and a histogram.
// This is used in the histogram and heatmap visualizations.
// It has to do with "rangeBands" vs. "rangePoints" too.
function autoScaleType(my, prefix){
// TODO move these into functions, eliminate duplicate code.
var columnName = prefix + "Column";
var columnAccessor = prefix + "Accessor";
var scaleDomain = prefix + "ScaleDomain";
var scaleType = prefix + "ScaleType";
var columnAccessor = prefix + "Accessor";
var columnMetadata = prefix + "Metadata";
my.when(["dataset", columnMetadata, columnAccessor], function (dataset, meta, accessor){
if(meta.interval){
// TODO use symbols, e.g. ChiasmDataset.NUMBER rather than strings.
// TODO use ES6 modules, where symbols make more sense.
var columnIsNumber = (meta.type === "number");
var columnIsDate = (meta.type === "date");
if(columnIsNumber){
// Histogram bins.
my[scaleType] = "linear";
my[scaleDomain] = d3.extent(dataset.data, accessor);
my[scaleDomain][1] += meta.interval;
} else if(columnIsDate){
// TODO support time intervals.
}
} else {
// Typical ordinal bars.
my[scaleType] = "ordinal";
my[scaleDomain] = dataset.data.map(accessor);
}
});
}
function rangeBands(my, prefix){
// TODO make these into functions, reduce duplicate code.
var scaleName = prefix + "Scale";
var columnMetadata = prefix + "Metadata";
var rangeBand = prefix + "RangeBand";
my.when([columnMetadata, scaleName], function (metadata, scale) {
if(metadata.interval){
// Histogram bins.
my[rangeBand] = Math.abs( scale(metadata.interval) - scale(0) );
} else {
// Typical ordinal bars.
my[rangeBand] = scale.rangeBand();
}
});
}
function xAxis(my, g){
var axisG = g.append("g").attr("class", "x axis");
var axis = d3.svg.axis();
my.addPublicProperty("xAxisTickDensity", 70);
my.when(["xScale", "xAxisTickDensity", "width"], function (xScale, xAxisTickDensity, width){
axis.scale(xScale).ticks(width / xAxisTickDensity)
axisG.call(axis);
});
my.when("height", function (height){
axisG.attr("transform", "translate(0," + height + ")");
});
return axisG;
}
function yAxis(my, g){
var axisG = g.append("g").attr("class", "y axis");
var axis = d3.svg.axis().orient("left");
my.addPublicProperty("yAxisTickDensity", 30);
my.when(["yScale", "yAxisTickDensity", "height"], function (yScale, yAxisTickDensity, height){
axis.scale(yScale).ticks(height / yAxisTickDensity)
axisG.call(axis);
});
return axisG;
}
function xAxisLabel(my, xAxisG){
var label = xAxisG.append("text").attr("class", "x axis-label");
my.addPublicProperty("xAxisLabelText", "X Axis Label");
my.addPublicProperty("xAxisLabelTextOffset", 43);
my.when("xAxisLabelText", function (xAxisLabelText){
label.text(xAxisLabelText);
});
my.when("xAxisLabelTextOffset", function (xAxisLabelTextOffset){
label.attr("y", xAxisLabelTextOffset);
});
my.when("width", function (width){
label.attr("x", width / 2);
});
}
function yAxisLabel(my, yAxisG){
var label = yAxisG.append("text").attr("class", "y axis-label");
my.addPublicProperty("yAxisLabelText", "Y Axis Label");
my.addPublicProperty("yAxisLabelTextOffset", 35);
my.when("yAxisLabelText", function (yAxisLabelText){
label.text(yAxisLabelText);
});
my.when(["yAxisLabelTextOffset", "height"], function (offset, height){
label.attr("transform", "translate(-" + offset + "," + (height / 2) + ") rotate(-90)")
});
}
module.exports = {
marginConvention: marginConvention,
marginEditor: marginEditor,
scale: scale,
autoScaleType: autoScaleType,
rangeBands: rangeBands,
xAxis: xAxis,
xAxisLabel: xAxisLabel,
yAxis: yAxis,
yAxisLabel: yAxisLabel
backgroundColor: require("./backgroundColor")
};

@@ -23,4 +23,4 @@ var Chiasm = require("chiasm");

// These are custom property values used across many components.
var xAxisLabelTextOffset = 30;
var yAxisLabelTextOffset = 30;
var xAxisLabelTextOffset = 6;
var yAxisLabelTextOffset = 15;
var margin = { top: 10, right: 10, bottom: 40, left: 42 };

@@ -41,2 +41,3 @@

"myScatterPlot",
"myScatterPlotOrdinalX",
"myBoxPlot"

@@ -93,2 +94,14 @@ ]

},
"myScatterPlotOrdinalX": {
"plugin": "scatterPlot",
"state": {
"xAxisLabelText": "Class",
"xColumn": "class",
"yAxisLabelText": "Petal Length",
"yColumn": "petal_length",
"xAxisLabelTextOffset": xAxisLabelTextOffset,
"yAxisLabelTextOffset": yAxisLabelTextOffset,
"margin": margin
}
},
"myBoxPlot": {

@@ -119,2 +132,4 @@ "plugin": "boxPlot",

"yColumn": "amount",
"fill": "#1EABE8",
"stroke": "#008CC8",
"xAxisLabelTextOffset": xAxisLabelTextOffset,

@@ -195,2 +210,3 @@ "yAxisLabelTextOffset": yAxisLabelTextOffset,

"scatterPlotDataLoader.dataset -> myScatterPlot.dataset",
"scatterPlotDataLoader.dataset -> myScatterPlotOrdinalX.dataset",
"scatterPlotDataLoader.dataset -> myBoxPlot.dataset",

@@ -197,0 +213,0 @@ "scatterPlotDataLoader.dataset -> histogramData.datasetIn",

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc