chasemapper/static/js/micropolar-v0.2.2.js

1531 wiersze
62 KiB
JavaScript

var micropolar = {
version: "0.2.2"
};
var µ = micropolar;
µ.Axis = function module() {
var config = {
data: [],
layout: {}
}, inputConfig = {}, liveConfig = {};
var svg, container, dispatch = d3.dispatch("hover"), radialScale, angularScale;
var angularTooltip, radialTooltip, geometryTooltip;
var exports = {};
function render(_container) {
container = _container || container;
var data = config.data;
var axisConfig = config.layout;
if (typeof container === "string" || container.nodeName) {
container = d3.select(container);
}
container.datum(data).each(function(_data, _index) {
var dataOriginal = _data.slice();
liveConfig = {
data: µ.util.cloneJson(dataOriginal),
layout: µ.util.cloneJson(axisConfig)
};
var colorIndex = 0;
dataOriginal.forEach(function(d, i) {
if (!d.color) {
d.color = axisConfig.defaultColorRange[colorIndex];
colorIndex = (colorIndex + 1) % axisConfig.defaultColorRange.length;
}
if (!d.strokeColor) {
d.strokeColor = d.geometry === "LinePlot" ? d.color : d3.rgb(d.color).darker().toString();
}
liveConfig.data[i].color = d.color;
liveConfig.data[i].strokeColor = d.strokeColor;
liveConfig.data[i].strokeDash = d.strokeDash;
liveConfig.data[i].strokeSize = d.strokeSize;
});
var data = dataOriginal.filter(function(d, i) {
var visible = d.visible;
return typeof visible === "undefined" || visible === true;
});
var isStacked = false;
var dataWithGroupId = data.map(function(d, i) {
isStacked = isStacked || typeof d.groupId !== "undefined";
return d;
});
var dataYStack = [];
if (isStacked) {
var grouped = d3.nest().key(function(d, i) {
return typeof d.groupId !== "undefined" ? d.groupId : "unstacked";
}).entries(dataWithGroupId);
var stacked = grouped.map(function(d, i) {
if (d.key === "unstacked") {
return d.values;
} else {
var prevArray = d.values[0].r.map(function(d, i) {
return 0;
});
d.values.forEach(function(d, i, a) {
d.yStack = [ prevArray ];
dataYStack.push(prevArray);
prevArray = µ.util.sumArrays(d.r, prevArray);
});
return d.values;
}
});
data = d3.merge(stacked);
}
data.forEach(function(d, i) {
d.t = Array.isArray(d.t[0]) ? d.t : [ d.t ];
d.r = Array.isArray(d.r[0]) ? d.r : [ d.r ];
});
var radius = Math.min(axisConfig.width - axisConfig.margin.left - axisConfig.margin.right, axisConfig.height - axisConfig.margin.top - axisConfig.margin.bottom) / 2;
radius = Math.max(10, radius);
var chartCenter = [ axisConfig.margin.left + radius, axisConfig.margin.top + radius ];
var extent;
if (isStacked) {
var highestStackedValue = d3.max(µ.util.sumArrays(µ.util.arrayLast(data).r[0], µ.util.arrayLast(dataYStack)));
extent = [ 0, highestStackedValue ];
} else {
extent = d3.extent(µ.util.flattenArray(data.map(function(d, i) {
return d.r;
})));
}
if (axisConfig.radialAxis.domain !== µ.DATAEXTENT) {
extent[0] = 0;
}
radialScale = d3.scale.linear().domain(axisConfig.radialAxis.domain !== µ.DATAEXTENT && axisConfig.radialAxis.domain ? axisConfig.radialAxis.domain : extent).range([ 0, radius ]);
liveConfig.layout.radialAxis.domain = radialScale.domain();
var angularDataMerged = µ.util.flattenArray(data.map(function(d, i) {
return d.t;
}));
var isOrdinal = typeof angularDataMerged[0] === "string";
var ticks;
if (isOrdinal) {
if (isStacked) {
angularDataMerged = µ.util.deduplicate(angularDataMerged);
}
ticks = angularDataMerged.slice();
angularDataMerged = d3.range(angularDataMerged.length);
data = data.map(function(d, i) {
var result = d;
d.t = [ angularDataMerged ];
if (isStacked) {
result.yStack = d.yStack;
}
return result;
});
}
var hasOnlyLineOrDotPlot = data.filter(function(d, i) {
return d.geometry === "LinePlot" || d.geometry === "DotPlot";
}).length === data.length;
var needsEndSpacing = axisConfig.needsEndSpacing === null ? isOrdinal || !hasOnlyLineOrDotPlot : axisConfig.needsEndSpacing;
var useProvidedDomain = axisConfig.angularAxis.domain && axisConfig.angularAxis.domain !== µ.DATAEXTENT && !isOrdinal && axisConfig.angularAxis.domain[0] >= 0;
var angularDomain = useProvidedDomain ? axisConfig.angularAxis.domain : d3.extent(angularDataMerged);
var angularDomainStep = Math.abs(angularDataMerged[1] - angularDataMerged[0]);
if (hasOnlyLineOrDotPlot && !isOrdinal) {
angularDomainStep = 0;
}
var angularDomainWithPadding = angularDomain.slice();
if (needsEndSpacing && isOrdinal) {
angularDomainWithPadding[1] += angularDomainStep;
}
var tickCount = axisConfig.angularAxis.ticksCount || 4;
if (tickCount > 8) {
tickCount = tickCount / (tickCount / 8) + tickCount % 8;
}
if (axisConfig.angularAxis.ticksStep) {
tickCount = (angularDomainWithPadding[1] - angularDomainWithPadding[0]) / tickCount;
}
var angularTicksStep = axisConfig.angularAxis.ticksStep || (angularDomainWithPadding[1] - angularDomainWithPadding[0]) / (tickCount * (axisConfig.minorTicks + 1));
if (ticks) {
angularTicksStep = Math.max(Math.round(angularTicksStep), 1);
}
if (!angularDomainWithPadding[2]) {
angularDomainWithPadding[2] = angularTicksStep;
}
var angularAxisRange = d3.range.apply(this, angularDomainWithPadding);
angularAxisRange = angularAxisRange.map(function(d, i) {
return parseFloat(d.toPrecision(12));
});
angularScale = d3.scale.linear().domain(angularDomainWithPadding.slice(0, 2)).range(axisConfig.direction === "clockwise" ? [ 0, 360 ] : [ 360, 0 ]);
liveConfig.layout.angularAxis.domain = angularScale.domain();
liveConfig.layout.angularAxis.endPadding = needsEndSpacing ? angularDomainStep : 0;
svg = d3.select(this).select("svg.chart-root");
if (typeof svg === "undefined" || svg.empty()) {
var skeleton = '<svg xmlns="http://www.w3.org/2000/svg" class="chart-root">' + '<g class="outer-group">' + '<g class="chart-group">' + '<circle class="background-circle"></circle>' + '<g class="geometry-group"></g>' + '<g class="radial axis-group">' + '<circle class="outside-circle"></circle>' + "</g>" + '<g class="angular axis-group"></g>' + '<g class="guides-group"><line></line><circle r="0"></circle></g>' + "</g>" + '<g class="legend-group"></g>' + '<g class="tooltips-group"></g>' + '<g class="title-group"><text></text></g>' + "</g>" + "</svg>";
var doc = new DOMParser().parseFromString(skeleton, "application/xml");
var newSvg = this.appendChild(this.ownerDocument.importNode(doc.documentElement, true));
svg = d3.select(newSvg);
}
svg.select(".guides-group").style({
"pointer-events": "none"
});
svg.select(".angular.axis-group").style({
"pointer-events": "none"
});
svg.select(".radial.axis-group").style({
"pointer-events": "none"
});
var chartGroup = svg.select(".chart-group");
var lineStyle = {
fill: "none",
stroke: axisConfig.tickColor
};
var fontStyle = {
"font-size": axisConfig.font.size,
"font-family": axisConfig.font.family,
fill: axisConfig.font.color,
"text-shadow": [ "-1px 0px", "1px -1px", "-1px 1px", "1px 1px" ].map(function(d, i) {
return " " + d + " 0 " + axisConfig.font.outlineColor;
}).join(",")
};
var legendContainer, legendBBox;
if (axisConfig.showLegend) {
legendContainer = svg.select(".legend-group").attr({
transform: "translate(" + [ radius, axisConfig.margin.top ] + ")"
}).style({
display: "block"
});
var elements = data.map(function(d, i) {
var datumClone = µ.util.cloneJson(d);
datumClone.symbol = d.geometry === "DotPlot" ? d.dotType || "circle" : d.geometry !== "LinePlot" ? "square" : "line";
datumClone.visibleInLegend = typeof d.visibleInLegend === "undefined" || d.visibleInLegend;
datumClone.color = d.geometry === "LinePlot" ? d.strokeColor : d.color;
return datumClone;
});
var legendConfigMixin1 = µ.util.deepExtend({}, µ.Legend.defaultConfig().legendConfig);
var legendConfigMixin2 = µ.util.deepExtend(legendConfigMixin1, {
container: legendContainer,
elements: elements,
reverseOrder: axisConfig.legend.reverseOrder
});
var legendConfigMixin3 = {
data: data.map(function(d, i) {
return d.name || "Element" + i;
}),
legendConfig: legendConfigMixin2
};
µ.Legend().config(legendConfigMixin3)();
legendBBox = legendContainer.node().getBBox();
radius = Math.min(axisConfig.width - legendBBox.width - axisConfig.margin.left - axisConfig.margin.right, axisConfig.height - axisConfig.margin.top - axisConfig.margin.bottom) / 2;
radius = Math.max(10, radius);
chartCenter = [ axisConfig.margin.left + radius, axisConfig.margin.top + radius ];
radialScale.range([ 0, radius ]);
liveConfig.layout.radialAxis.domain = radialScale.domain();
legendContainer.attr("transform", "translate(" + [ chartCenter[0] + radius, chartCenter[1] - radius ] + ")");
} else {
legendContainer = svg.select(".legend-group").style({
display: "none"
});
}
svg.attr({
width: axisConfig.width,
height: axisConfig.height
}).style({
opacity: axisConfig.opacity
});
chartGroup.attr("transform", "translate(" + chartCenter + ")").style({
cursor: "crosshair"
});
var centeringOffset = [ (axisConfig.width - (axisConfig.margin.left + axisConfig.margin.right + radius * 2 + (legendBBox ? legendBBox.width : 0))) / 2, (axisConfig.height - (axisConfig.margin.top + axisConfig.margin.bottom + radius * 2)) / 2 ];
centeringOffset[0] = Math.max(0, centeringOffset[0]);
centeringOffset[1] = Math.max(0, centeringOffset[1]);
svg.select(".outer-group").attr("transform", "translate(" + centeringOffset + ")");
if (axisConfig.title) {
var title = svg.select("g.title-group text").style(fontStyle).text(axisConfig.title);
var titleBBox = title.node().getBBox();
title.attr({
x: chartCenter[0] - titleBBox.width / 2,
y: chartCenter[1] - radius - 20
});
}
var radialAxis = svg.select(".radial.axis-group");
if (axisConfig.radialAxis.gridLinesVisible) {
var gridCircles = radialAxis.selectAll("circle.grid-circle").data(radialScale.ticks(5));
gridCircles.enter().append("circle").attr({
"class": "grid-circle"
}).style(lineStyle);
gridCircles.attr("r", radialScale);
gridCircles.exit().remove();
}
radialAxis.select("circle.outside-circle").attr({
r: radius
}).style(lineStyle);
var backgroundCircle = svg.select("circle.background-circle").attr({
r: radius
}).style({
fill: axisConfig.backgroundColor,
stroke: axisConfig.stroke
});
function currentAngle(d, i) {
return angularScale(d) % 360 + axisConfig.orientation;
}
if (axisConfig.radialAxis.visible) {
var axis = d3.svg.axis().scale(radialScale).ticks(5).tickSize(5);
radialAxis.call(axis).attr({
transform: "rotate(" + axisConfig.radialAxis.orientation + ")"
});
radialAxis.selectAll(".domain").style(lineStyle);
radialAxis.selectAll("g>text").text(function(d, i) {
return this.textContent + axisConfig.radialAxis.ticksSuffix;
}).style(fontStyle).style({
"text-anchor": "start"
}).attr({
x: 0,
y: 0,
dx: 0,
dy: 0,
transform: function(d, i) {
if (axisConfig.radialAxis.tickOrientation === "horizontal") {
return "rotate(" + -axisConfig.radialAxis.orientation + ") translate(" + [ 0, fontStyle["font-size"] ] + ")";
} else {
return "translate(" + [ 0, fontStyle["font-size"] ] + ")";
}
}
});
radialAxis.selectAll("g>line").style({
stroke: "black"
});
}
var angularAxis = svg.select(".angular.axis-group").selectAll("g.angular-tick").data(angularAxisRange);
var angularAxisEnter = angularAxis.enter().append("g").classed("angular-tick", true);
angularAxis.attr({
transform: function(d, i) {
return "rotate(" + currentAngle(d, i) + ")";
}
}).style({
display: axisConfig.angularAxis.visible ? "block" : "none"
});
angularAxis.exit().remove();
angularAxisEnter.append("line").classed("grid-line", true).classed("major", function(d, i) {
return i % (axisConfig.minorTicks + 1) === 0;
}).classed("minor", function(d, i) {
return i % (axisConfig.minorTicks + 1) !== 0;
}).style(lineStyle);
angularAxisEnter.selectAll(".minor").style({
stroke: axisConfig.minorTickColor
});
angularAxis.select("line.grid-line").attr({
x1: axisConfig.tickLength ? radius - axisConfig.tickLength : 0,
x2: radius
}).style({
display: axisConfig.angularAxis.gridLinesVisible ? "block" : "none"
});
angularAxisEnter.append("text").classed("axis-text", true).style(fontStyle);
var ticksText = angularAxis.select("text.axis-text").attr({
x: radius + axisConfig.labelOffset,
dy: ".35em",
transform: function(d, i) {
var angle = currentAngle(d, i);
var rad = radius + axisConfig.labelOffset;
var orient = axisConfig.angularAxis.tickOrientation;
if (orient === "horizontal") {
return "rotate(" + -angle + " " + rad + " 0)";
} else if (orient === "radial") {
return angle < 270 && angle > 90 ? "rotate(180 " + rad + " 0)" : null;
} else {
return "rotate(" + (angle <= 180 && angle > 0 ? -90 : 90) + " " + rad + " 0)";
}
}
}).style({
"text-anchor": "middle",
display: axisConfig.angularAxis.labelsVisible ? "block" : "none"
}).text(function(d, i) {
if (i % (axisConfig.minorTicks + 1) !== 0) {
return "";
}
if (ticks) {
return ticks[d] + axisConfig.angularAxis.ticksSuffix;
} else {
return d + axisConfig.angularAxis.ticksSuffix;
}
}).style(fontStyle);
if (axisConfig.angularAxis.rewriteTicks) {
ticksText.text(function(d, i) {
if (i % (axisConfig.minorTicks + 1) !== 0) {
return "";
}
return axisConfig.angularAxis.rewriteTicks(this.textContent, i);
});
}
var rightmostTickEndX = d3.max(chartGroup.selectAll(".angular-tick text")[0].map(function(d, i) {
return d.getCTM().e + d.getBBox().width;
}));
legendContainer.attr({
transform: "translate(" + [ radius + rightmostTickEndX, axisConfig.margin.top ] + ")"
});
var hasGeometry = svg.select("g.geometry-group").selectAll("g").size() > 0;
var geometryContainer = svg.select("g.geometry-group").selectAll("g.geometry").data(data);
geometryContainer.enter().append("g").attr({
"class": function(d, i) {
return "geometry geometry" + i;
}
});
geometryContainer.exit().remove();
if (data[0] || hasGeometry) {
var geometryConfigs = [];
data.forEach(function(d, i) {
var geometryConfig = {};
geometryConfig.radialScale = radialScale;
geometryConfig.angularScale = angularScale;
geometryConfig.container = geometryContainer.filter(function(dB, iB) {
return iB === i;
});
geometryConfig.geometry = d.geometry;
geometryConfig.orientation = axisConfig.orientation;
geometryConfig.direction = axisConfig.direction;
geometryConfig.index = i;
geometryConfigs.push({
data: d,
geometryConfig: geometryConfig
});
});
var geometryConfigsGrouped = d3.nest().key(function(d, i) {
return typeof d.data.groupId !== "undefined" || "unstacked";
}).entries(geometryConfigs);
var geometryConfigsGrouped2 = [];
geometryConfigsGrouped.forEach(function(d, i) {
if (d.key === "unstacked") {
geometryConfigsGrouped2 = geometryConfigsGrouped2.concat(d.values.map(function(d, i) {
return [ d ];
}));
} else {
geometryConfigsGrouped2.push(d.values);
}
});
geometryConfigsGrouped2.forEach(function(d, i) {
var geometry;
if (Array.isArray(d)) {
geometry = d[0].geometryConfig.geometry;
} else {
geometry = d.geometryConfig.geometry;
}
var finalGeometryConfig = d.map(function(dB, iB) {
return µ.util.deepExtend(µ[geometry].defaultConfig(), dB);
});
µ[geometry]().config(finalGeometryConfig)();
});
}
var guides = svg.select(".guides-group");
var tooltipContainer = svg.select(".tooltips-group");
angularTooltip = angularTooltip || µ.tooltipPanel().config({
container: tooltipContainer,
fontSize: 8
})();
radialTooltip = radialTooltip || µ.tooltipPanel().config({
container: tooltipContainer,
fontSize: 8
})();
geometryTooltip = geometryTooltip || µ.tooltipPanel().config({
container: tooltipContainer,
fontSize: 8
})();
var angularValue, radialValue;
if (!isOrdinal) {
var angularGuideLine = guides.select("line").attr({
x1: 0,
y1: 0,
y2: 0
}).style({
stroke: "grey",
"pointer-events": "none"
});
// chartGroup.on("mousemove.angular-guide", function(d, i) {
// var mouseAngle = µ.util.getMousePos(backgroundCircle).angle;
// angularGuideLine.attr({
// x2: -radius,
// transform: "rotate(" + mouseAngle + ")"
// }).style({
// opacity: .5
// });
// var angleWithOriginOffset = (mouseAngle + 180 + 360 - axisConfig.orientation) % 360;
// angularValue = angularScale.invert(angleWithOriginOffset);
// var pos = µ.util.convertToCartesian(radius + 12, mouseAngle + 180);
// angularTooltip.text(µ.util.round(angularValue)).move([ pos[0] + chartCenter[0], pos[1] + chartCenter[1] ]);
// }).on("mouseout.angular-guide", function(d, i) {
// guides.select("line").style({
// opacity: 0
// });
// });
}
if (axisConfig.radialAxis.visible !== false) {
var angularGuideCircle = guides.select("circle").style({
stroke: "grey",
fill: "none"
});
// chartGroup.on("mousemove.radial-guide", function(d, i) {
// var r = µ.util.getMousePos(backgroundCircle).radius;
// angularGuideCircle.attr({
// r: r
// }).style({
// opacity: .5
// });
// radialValue = radialScale.invert(µ.util.getMousePos(backgroundCircle).radius);
// var pos = µ.util.convertToCartesian(r, axisConfig.radialAxis.orientation);
// radialTooltip.text(µ.util.round(radialValue)).move([ pos[0] + chartCenter[0], pos[1] + chartCenter[1] ]);
// }).on("mouseout.radial-guide", function(d, i) {
// angularGuideCircle.style({
// opacity: 0
// });
// geometryTooltip.hide();
// angularTooltip.hide();
// radialTooltip.hide();
// });
}
// svg.selectAll(".geometry-group .mark").on("mouseover.tooltip", function(d, i) {
// var el = d3.select(this);
// var color = el.style("fill");
// var newColor = "black";
// var opacity = el.style("opacity") || 1;
// el.attr({
// "data-opacity": opacity
// });
// if (color !== "none") {
// el.attr({
// "data-fill": color
// });
// newColor = d3.hsl(color).darker().toString();
// el.style({
// fill: newColor,
// opacity: 1
// });
// var textData = {
// t: µ.util.round(d[0]),
// r: µ.util.round(d[1])
// };
// if (isOrdinal) {
// textData.t = ticks[d[0]];
// }
// var text = "t: " + textData.t + ", r: " + textData.r;
// var bbox = this.getBoundingClientRect();
// var svgBBox = svg.node().getBoundingClientRect();
// var pos = [ bbox.left + bbox.width / 2 - centeringOffset[0] - svgBBox.left, bbox.top + bbox.height / 2 - centeringOffset[1] - svgBBox.top ];
// geometryTooltip.config({
// color: newColor
// }).text(text);
// geometryTooltip.move(pos);
// } else {
// color = el.style("stroke");
// el.attr({
// "data-stroke": color
// });
// newColor = d3.hsl(color).darker().toString();
// el.style({
// stroke: newColor,
// opacity: 1
// });
// }
// }).on("mousemove.tooltip", function(d, i) {
// if (d3.event.which !== 0) {
// return false;
// }
// if (d3.select(this).attr("data-fill")) {
// geometryTooltip.show();
// }
// }).on("mouseout.tooltip", function(d, i) {
// geometryTooltip.hide();
// var el = d3.select(this);
// var fillColor = el.attr("data-fill");
// if (fillColor) {
// el.style({
// fill: fillColor,
// opacity: el.attr("data-opacity")
// });
// } else {
// el.style({
// stroke: el.attr("data-stroke"),
// opacity: el.attr("data-opacity")
// });
// }
// });
});
return exports;
}
exports.render = function(_container) {
render(_container);
return this;
};
exports.config = function(_x) {
if (!arguments.length) {
return config;
}
var xClone = µ.util.cloneJson(_x);
xClone.data.forEach(function(d, i) {
if (!config.data[i]) {
config.data[i] = {};
}
µ.util.deepExtend(config.data[i], µ.Axis.defaultConfig().data[0]);
µ.util.deepExtend(config.data[i], d);
});
µ.util.deepExtend(config.layout, µ.Axis.defaultConfig().layout);
µ.util.deepExtend(config.layout, xClone.layout);
return this;
};
exports.getLiveConfig = function() {
return liveConfig;
};
exports.getinputConfig = function() {
return inputConfig;
};
exports.radialScale = function(_x) {
return radialScale;
};
exports.angularScale = function(_x) {
return angularScale;
};
exports.svg = function() {
return svg;
};
d3.rebind(exports, dispatch, "on");
return exports;
};
µ.Axis.defaultConfig = function(d, i) {
var config = {
data: [ {
t: [ 1, 2, 3, 4 ],
r: [ 10, 11, 12, 13 ],
name: "Line1",
geometry: "LinePlot",
color: null,
strokeDash: "solid",
strokeColor: null,
strokeSize: "1",
visibleInLegend: true,
opacity: 1
} ],
layout: {
defaultColorRange: d3.scale.category10().range(),
title: null,
height: 450,
width: 500,
margin: {
top: 40,
right: 40,
bottom: 40,
left: 40
},
font: {
size: 12,
color: "gray",
outlineColor: "white",
family: "Tahoma, sans-serif"
},
direction: "clockwise",
orientation: 0,
labelOffset: 10,
radialAxis: {
domain: null,
orientation: -45,
ticksSuffix: "",
visible: true,
gridLinesVisible: true,
tickOrientation: "horizontal",
rewriteTicks: null
},
angularAxis: {
domain: [ 0, 360 ],
ticksSuffix: "",
visible: true,
gridLinesVisible: true,
labelsVisible: true,
tickOrientation: "horizontal",
rewriteTicks: null,
ticksCount: null,
ticksStep: null
},
minorTicks: 0,
tickLength: null,
tickColor: "silver",
minorTickColor: "#eee",
backgroundColor: "none",
needsEndSpacing: null,
showLegend: true,
legend: {
reverseOrder: false
},
opacity: 1
}
};
return config;
};
µ.util = {};
µ.DATAEXTENT = "dataExtent";
µ.AREA = "AreaChart";
µ.LINE = "LinePlot";
µ.DOT = "DotPlot";
µ.BAR = "BarChart";
µ.PIE = "PieChart";
µ.util._override = function(_objA, _objB) {
for (var x in _objA) {
if (x in _objB) {
_objB[x] = _objA[x];
}
}
};
µ.util._extend = function(_objA, _objB) {
for (var x in _objA) {
_objB[x] = _objA[x];
}
};
µ.util._rndSnd = function() {
return Math.random() * 2 - 1 + (Math.random() * 2 - 1) + (Math.random() * 2 - 1);
};
µ.util.dataFromEquation2 = function(_equation, _step) {
var step = _step || 6;
var data = d3.range(0, 360 + step, step).map(function(deg, index) {
var theta = deg * Math.PI / 180;
var radius = _equation(theta);
return [ deg, radius ];
});
return data;
};
µ.util.dataFromEquation = function(_equation, _step, _name) {
var step = _step || 6;
var t = [], r = [];
d3.range(0, 360 + step, step).forEach(function(deg, index) {
var theta = deg * Math.PI / 180;
var radius = _equation(theta);
t.push(deg);
r.push(radius);
});
var result = {
t: t,
r: r
};
if (_name) {
result.name = _name;
}
return result;
};
µ.util.ensureArray = function(_val, _count) {
if (typeof _val === "undefined") {
return null;
}
var arr = [].concat(_val);
return d3.range(_count).map(function(d, i) {
return arr[i] || arr[0];
});
};
µ.util.fillArrays = function(_obj, _valueNames, _count) {
_valueNames.forEach(function(d, i) {
_obj[d] = µ.util.ensureArray(_obj[d], _count);
});
return _obj;
};
µ.util.cloneJson = function(json) {
return JSON.parse(JSON.stringify(json));
};
µ.util.deepExtend = function(destination, source) {
for (var property in source) {
if (source[property] && source[property].constructor && source[property].constructor === Object) {
destination[property] = destination[property] || {};
arguments.callee(destination[property], source[property]);
} else {
destination[property] = source[property];
}
}
return destination;
};
µ.util.validateKeys = function(obj, keys) {
if (typeof keys === "string") {
keys = keys.split(".");
}
var next = keys.shift();
return obj[next] && (!keys.length || objHasKeys(obj[next], keys));
};
µ.util.sumArrays = function(a, b) {
return d3.zip(a, b).map(function(d, i) {
return d3.sum(d);
});
};
µ.util.arrayLast = function(a) {
return a[a.length - 1];
};
µ.util.arrayEqual = function(a, b) {
var i = Math.max(a.length, b.length, 1);
while (i-- >= 0 && a[i] === b[i]) ;
return i === -2;
};
µ.util.flattenArray = function(arr) {
var r = [];
while (!µ.util.arrayEqual(r, arr)) {
r = arr;
arr = [].concat.apply([], arr);
}
return arr;
};
µ.util.deduplicate = function(arr) {
return arr.filter(function(v, i, a) {
return a.indexOf(v) === i;
});
};
µ.util.convertToCartesian = function(radius, theta) {
var thetaRadians = theta * Math.PI / 180;
var x = radius * Math.cos(thetaRadians);
var y = radius * Math.sin(thetaRadians);
return [ x, y ];
};
µ.util.round = function(_value, _digits) {
var digits = _digits || 2;
var mult = Math.pow(10, digits);
return Math.round(_value * mult) / mult;
};
µ.util.getMousePos = function(_referenceElement) {
var mousePos = d3.mouse(_referenceElement.node());
var mouseX = mousePos[0];
var mouseY = mousePos[1];
var mouse = {};
mouse.x = mouseX;
mouse.y = mouseY;
mouse.pos = mousePos;
mouse.angle = (Math.atan2(mouseY, mouseX) + Math.PI) * 180 / Math.PI;
mouse.radius = Math.sqrt(mouseX * mouseX + mouseY * mouseY);
return mouse;
};
µ.util.duplicatesCount = function(arr) {
var uniques = {}, val;
var dups = {};
for (var i = 0, len = arr.length; i < len; i++) {
val = arr[i];
if (val in uniques) {
uniques[val]++;
dups[val] = uniques[val];
} else {
uniques[val] = 1;
}
}
return dups;
};
µ.util.duplicates = function(arr) {
return Object.keys(µ.util.duplicatesCount(arr));
};
µ.util.translator = function(obj, sourceBranch, targetBranch, reverse) {
if (reverse) {
var targetBranchCopy = targetBranch.slice();
targetBranch = sourceBranch;
sourceBranch = targetBranchCopy;
}
var value = sourceBranch.reduce(function(previousValue, currentValue) {
if (typeof previousValue !== "undefined") {
return previousValue[currentValue];
}
}, obj);
if (typeof value === "undefined") {
return;
}
sourceBranch.reduce(function(previousValue, currentValue, index) {
if (typeof previousValue === "undefined") {
return;
}
if (index === sourceBranch.length - 1) {
delete previousValue[currentValue];
}
return previousValue[currentValue];
}, obj);
targetBranch.reduce(function(previousValue, currentValue, index) {
if (typeof previousValue[currentValue] === "undefined") {
previousValue[currentValue] = {};
}
if (index === targetBranch.length - 1) {
previousValue[currentValue] = value;
}
return previousValue[currentValue];
}, obj);
};
µ.PolyChart = function module() {
var config = [ µ.PolyChart.defaultConfig() ];
var dispatch = d3.dispatch("hover");
var dashArray = {
solid: "none",
dash: [ 5, 2 ],
dot: [ 2, 5 ]
};
var colorScale;
function exports() {
var geometryConfig = config[0].geometryConfig;
var container = geometryConfig.container;
if (typeof container === "string") {
container = d3.select(container);
}
container.datum(config).each(function(_config, _index) {
var isStack = !!_config[0].data.yStack;
var data = _config.map(function(d, i) {
if (isStack) {
return d3.zip(d.data.t[0], d.data.r[0], d.data.yStack[0]);
} else {
return d3.zip(d.data.t[0], d.data.r[0]);
}
});
var angularScale = geometryConfig.angularScale;
var domainMin = geometryConfig.radialScale.domain()[0];
var generator = {};
generator.bar = function(d, i, pI) {
var dataConfig = _config[pI].data;
var h = geometryConfig.radialScale(d[1]) - geometryConfig.radialScale(0);
var stackTop = geometryConfig.radialScale(d[2] || 0);
var w = dataConfig.barWidth;
d3.select(this).attr({
"class": "mark bar",
d: "M" + [ [ h + stackTop, -w / 2 ], [ h + stackTop, w / 2 ], [ stackTop, w / 2 ], [ stackTop, -w / 2 ] ].join("L") + "Z",
transform: function(d, i) {
return "rotate(" + (geometryConfig.orientation + angularScale(d[0])) + ")";
}
});
};
generator.dot = function(d, i, pI) {
var stackedData = d[2] ? [ d[0], d[1] + d[2] ] : d;
var symbol = d3.svg.symbol().size(_config[pI].data.dotSize).type(_config[pI].data.dotType)(d, i);
d3.select(this).attr({
"class": "mark dot",
d: symbol,
transform: function(d, i) {
var coord = convertToCartesian(getPolarCoordinates(stackedData));
return "translate(" + [ coord.x, coord.y ] + ")";
}
});
};
var line = d3.svg.line.radial().interpolate(_config[0].data.lineInterpolation).radius(function(d) {
return geometryConfig.radialScale(d[1]);
}).angle(function(d) {
return geometryConfig.angularScale(d[0]) * Math.PI / 180;
});
generator.line = function(d, i, pI) {
var lineData = d[2] ? data[pI].map(function(d, i) {
return [ d[0], d[1] + d[2] ];
}) : data[pI];
d3.select(this).each(generator.dot).style({
opacity: function(dB, iB) {
return +_config[pI].data.dotVisible;
},
fill: markStyle.stroke(d, i, pI)
}).attr({
"class": "mark dot"
});
if (i > 0) {
return;
}
var lineSelection = d3.select(this.parentNode).selectAll("path.line").data([ 0 ]);
lineSelection.enter().insert("path");
lineSelection.attr({
"class": "line",
d: line(lineData),
transform: function(dB, iB) {
return "rotate(" + (geometryConfig.orientation + 90) + ")";
},
"pointer-events": "none"
}).style({
fill: function(dB, iB) {
return markStyle.fill(d, i, pI);
},
"fill-opacity": 0,
stroke: function(dB, iB) {
return markStyle.stroke(d, i, pI);
},
"stroke-width": function(dB, iB) {
return markStyle["stroke-width"](d, i, pI);
},
"stroke-dasharray": function(dB, iB) {
return markStyle["stroke-dasharray"](d, i, pI);
},
opacity: function(dB, iB) {
return markStyle.opacity(d, i, pI);
},
display: function(dB, iB) {
return markStyle.display(d, i, pI);
}
});
};
var angularRange = geometryConfig.angularScale.range();
var triangleAngle = Math.abs(angularRange[1] - angularRange[0]) / data[0].length * Math.PI / 180;
var arc = d3.svg.arc().startAngle(function(d) {
return -triangleAngle / 2;
}).endAngle(function(d) {
return triangleAngle / 2;
}).innerRadius(function(d) {
return geometryConfig.radialScale(domainMin + (d[2] || 0));
}).outerRadius(function(d) {
return geometryConfig.radialScale(domainMin + (d[2] || 0)) + geometryConfig.radialScale(d[1]);
});
generator.arc = function(d, i, pI) {
d3.select(this).attr({
"class": "mark arc",
d: arc,
transform: function(d, i) {
return "rotate(" + (geometryConfig.orientation + angularScale(d[0]) + 90) + ")";
}
});
};
var pieArc = d3.svg.arc().outerRadius(geometryConfig.radialScale.range()[1]);
var pie = d3.layout.pie().value(function(d) {
return d[1];
});
var pieData = pie(data[0]);
generator.pie = function(d, i, pI) {
d3.select(this).attr({
"class": "mark arc",
d: pieArc(pieData[i], i)
});
};
var markStyle = {
fill: function(d, i, pI) {
return _config[pI].data.color;
},
stroke: function(d, i, pI) {
return _config[pI].data.strokeColor;
},
"stroke-width": function(d, i, pI) {
return _config[pI].data.strokeSize + "px";
},
"stroke-dasharray": function(d, i, pI) {
return dashArray[_config[pI].data.strokeDash];
},
opacity: function(d, i, pI) {
return _config[pI].data.opacity;
},
display: function(d, i, pI) {
return typeof _config[pI].data.visible === "undefined" || _config[pI].data.visible ? "block" : "none";
}
};
var geometryLayer = d3.select(this).selectAll("g.layer").data(data);
geometryLayer.enter().append("g").attr({
"class": "layer"
});
var geometry = geometryLayer.selectAll("path.mark").data(function(d, i) {
return d;
});
geometry.enter().append("path").attr({
"class": "mark"
});
geometry.style(markStyle).each(generator[geometryConfig.geometryType]);
geometry.exit().remove();
geometryLayer.exit().remove();
function getPolarCoordinates(d, i) {
var r = geometryConfig.radialScale(d[1]);
var t = (geometryConfig.angularScale(d[0]) + geometryConfig.orientation) * Math.PI / 180;
return {
r: r,
t: t
};
}
function convertToCartesian(polarCoordinates) {
var x = polarCoordinates.r * Math.cos(polarCoordinates.t);
var y = polarCoordinates.r * Math.sin(polarCoordinates.t);
return {
x: x,
y: y
};
}
});
}
exports.config = function(_x) {
if (!arguments.length) {
return config;
}
_x.forEach(function(d, i) {
if (!config[i]) {
config[i] = {};
}
µ.util.deepExtend(config[i], µ.PolyChart.defaultConfig());
µ.util.deepExtend(config[i], d);
});
return this;
};
exports.getColorScale = function() {
return colorScale;
};
d3.rebind(exports, dispatch, "on");
return exports;
};
µ.PolyChart.defaultConfig = function() {
var config = {
data: {
name: "geom1",
t: [ [ 1, 2, 3, 4 ] ],
r: [ [ 1, 2, 3, 4 ] ],
dotType: "circle",
dotSize: 64,
dotVisible: false,
barWidth: 20,
color: "#ffa500",
strokeSize: 1,
strokeColor: "silver",
strokeDash: "solid",
opacity: 1,
index: 0,
visible: true,
visibleInLegend: true
},
geometryConfig: {
geometry: "LinePlot",
geometryType: "arc",
direction: "clockwise",
orientation: 0,
container: "body",
radialScale: null,
angularScale: null,
colorScale: d3.scale.category20()
}
};
return config;
};
µ.BarChart = function module() {
return µ.PolyChart();
};
µ.BarChart.defaultConfig = function() {
var config = {
geometryConfig: {
geometryType: "bar"
}
};
return config;
};
µ.AreaChart = function module() {
return µ.PolyChart();
};
µ.AreaChart.defaultConfig = function() {
var config = {
geometryConfig: {
geometryType: "arc"
}
};
return config;
};
µ.DotPlot = function module() {
return µ.PolyChart();
};
µ.DotPlot.defaultConfig = function() {
var config = {
geometryConfig: {
geometryType: "dot",
dotType: "circle"
}
};
return config;
};
µ.LinePlot = function module() {
return µ.PolyChart();
};
µ.LinePlot.defaultConfig = function() {
var config = {
geometryConfig: {
geometryType: "line"
}
};
return config;
};
µ.Legend = function module() {
var config = µ.Legend.defaultConfig();
var dispatch = d3.dispatch("hover");
function exports() {
var legendConfig = config.legendConfig;
var flattenData = config.data.map(function(d, i) {
return [].concat(d).map(function(dB, iB) {
var element = µ.util.deepExtend({}, legendConfig.elements[i]);
element.name = dB;
element.color = [].concat(legendConfig.elements[i].color)[iB];
return element;
});
});
var data = d3.merge(flattenData);
data = data.filter(function(d, i) {
return legendConfig.elements[i] && (legendConfig.elements[i].visibleInLegend || typeof legendConfig.elements[i].visibleInLegend === "undefined");
});
if (legendConfig.reverseOrder) {
data = data.reverse();
}
var container = legendConfig.container;
if (typeof container === "string" || container.nodeName) {
container = d3.select(container);
}
var colors = data.map(function(d, i) {
return d.color;
});
var lineHeight = legendConfig.fontSize;
var isContinuous = legendConfig.isContinuous === null ? typeof data[0] === "number" : legendConfig.isContinuous;
var height = isContinuous ? legendConfig.height : lineHeight * data.length;
var legendContainerGroup = container.classed("legend-group", true);
var svg = legendContainerGroup.selectAll("svg").data([ 0 ]);
var svgEnter = svg.enter().append("svg").attr({
width: 300,
height: height + lineHeight,
xmlns: "http://www.w3.org/2000/svg",
"xmlns:xlink": "http://www.w3.org/1999/xlink",
version: "1.1"
});
svgEnter.append("g").classed("legend-axis", true);
svgEnter.append("g").classed("legend-marks", true);
var dataNumbered = d3.range(data.length);
var colorScale = d3.scale[isContinuous ? "linear" : "ordinal"]().domain(dataNumbered).range(colors);
var dataScale = d3.scale[isContinuous ? "linear" : "ordinal"]().domain(dataNumbered)[isContinuous ? "range" : "rangePoints"]([ 0, height ]);
var shapeGenerator = function(_type, _size) {
var squareSize = _size * 3;
if (_type === "line") {
return "M" + [ [ -_size / 2, -_size / 12 ], [ _size / 2, -_size / 12 ], [ _size / 2, _size / 12 ], [ -_size / 2, _size / 12 ] ] + "Z";
} else if (d3.svg.symbolTypes.indexOf(_type) !== -1) {
return d3.svg.symbol().type(_type).size(squareSize)();
} else {
return d3.svg.symbol().type("square").size(squareSize)();
}
};
if (isContinuous) {
var gradient = svg.select(".legend-marks").append("defs").append("linearGradient").attr({
id: "grad1",
x1: "0%",
y1: "0%",
x2: "0%",
y2: "100%"
}).selectAll("stop").data(colors);
gradient.enter().append("stop");
gradient.attr({
offset: function(d, i) {
return i / (colors.length - 1) * 100 + "%";
}
}).style({
"stop-color": function(d, i) {
return d;
}
});
svg.append("rect").classed("legend-mark", true).attr({
height: legendConfig.height,
width: legendConfig.colorBandWidth,
fill: "url(#grad1)"
});
} else {
var legendElement = svg.select(".legend-marks").selectAll("path.legend-mark").data(data);
legendElement.enter().append("path").classed("legend-mark", true);
legendElement.attr({
transform: function(d, i) {
return "translate(" + [ lineHeight / 2, dataScale(i) + lineHeight / 2 ] + ")";
},
d: function(d, i) {
var symbolType = d.symbol;
return shapeGenerator(symbolType, lineHeight);
},
fill: function(d, i) {
return colorScale(i);
}
});
legendElement.exit().remove();
}
var legendAxis = d3.svg.axis().scale(dataScale).orient("right");
var axis = svg.select("g.legend-axis").attr({
transform: "translate(" + [ isContinuous ? legendConfig.colorBandWidth : lineHeight, lineHeight / 2 ] + ")"
}).call(legendAxis);
axis.selectAll(".domain").style({
fill: "none",
stroke: "none"
});
axis.selectAll("line").style({
fill: "none",
stroke: isContinuous ? legendConfig.textColor : "none"
});
axis.selectAll("text").style({
fill: legendConfig.textColor,
"font-size": legendConfig.fontSize
}).text(function(d, i) {
return data[i].name;
});
return exports;
}
exports.config = function(_x) {
if (!arguments.length) {
return config;
}
µ.util.deepExtend(config, _x);
return this;
};
d3.rebind(exports, dispatch, "on");
return exports;
};
µ.Legend.defaultConfig = function(d, i) {
var config = {
data: [ "a", "b", "c" ],
legendConfig: {
elements: [ {
symbol: "line",
color: "red"
}, {
symbol: "square",
color: "yellow"
}, {
symbol: "diamond",
color: "limegreen"
} ],
height: 150,
colorBandWidth: 30,
fontSize: 12,
container: "body",
isContinuous: null,
textColor: "grey",
reverseOrder: false
}
};
return config;
};
µ.tooltipPanel = function() {
var tooltipEl, tooltipTextEl, backgroundEl;
var config = {
container: null,
hasTick: false,
fontSize: 12,
color: "white",
padding: 5
};
var id = "tooltip-" + µ.tooltipPanel.uid++;
var tickSize = 10;
var exports = function() {
tooltipEl = config.container.selectAll("g." + id).data([ 0 ]);
var tooltipEnter = tooltipEl.enter().append("g").classed(id, true).style({
"pointer-events": "none",
display: "none"
});
backgroundEl = tooltipEnter.append("path").style({
fill: "white",
"fill-opacity": .9
}).attr({
d: "M0 0"
});
tooltipTextEl = tooltipEnter.append("text").attr({
dx: config.padding + tickSize,
dy: +config.fontSize * .3
});
return exports;
};
exports.text = function(_text) {
var l = d3.hsl(config.color).l;
var strokeColor = l >= .5 ? "#aaa" : "white";
var fillColor = l >= .5 ? "black" : "white";
var text = _text || "";
tooltipTextEl.style({
fill: fillColor,
"font-size": config.fontSize + "px"
}).text(text);
var padding = config.padding;
var bbox = tooltipTextEl.node().getBBox();
var boxStyle = {
fill: config.color,
stroke: strokeColor,
"stroke-width": "2px"
};
var backGroundW = bbox.width + padding * 2 + tickSize;
var backGroundH = bbox.height + padding * 2;
backgroundEl.attr({
d: "M" + [ [ tickSize, -backGroundH / 2 ], [ tickSize, -backGroundH / 4 ], [ config.hasTick ? 0 : tickSize, 0 ], [ tickSize, backGroundH / 4 ], [ tickSize, backGroundH / 2 ], [ backGroundW, backGroundH / 2 ], [ backGroundW, -backGroundH / 2 ] ].join("L") + "Z"
}).style(boxStyle);
tooltipEl.attr({
transform: "translate(" + [ tickSize, -backGroundH / 2 + padding * 2 ] + ")"
});
tooltipEl.style({
display: "block"
});
return exports;
};
exports.move = function(_pos) {
if (!tooltipEl) {
return;
}
tooltipEl.attr({
transform: "translate(" + [ _pos[0], _pos[1] ] + ")"
}).style({
display: "block"
});
return exports;
};
exports.hide = function() {
if (!tooltipEl) {
return;
}
tooltipEl.style({
display: "none"
});
return exports;
};
exports.show = function() {
if (!tooltipEl) {
return;
}
tooltipEl.style({
display: "block"
});
return exports;
};
exports.config = function(_x) {
µ.util.deepExtend(config, _x);
return exports;
};
return exports;
};
µ.tooltipPanel.uid = 1;
µ.adapter = {};
µ.adapter.plotly = function module() {
var exports = {};
exports.convert = function(_inputConfig, reverse) {
var outputConfig = {};
if (_inputConfig.data) {
outputConfig.data = _inputConfig.data.map(function(d, i) {
var r = µ.util.deepExtend({}, d);
var toTranslate = [ [ r, [ "marker", "color" ], [ "color" ] ], [ r, [ "marker", "opacity" ], [ "opacity" ] ], [ r, [ "marker", "line", "color" ], [ "strokeColor" ] ], [ r, [ "marker", "line", "dash" ], [ "strokeDash" ] ], [ r, [ "marker", "line", "width" ], [ "strokeSize" ] ], [ r, [ "marker", "symbol" ], [ "dotType" ] ], [ r, [ "marker", "size" ], [ "dotSize" ] ], [ r, [ "marker", "barWidth" ], [ "barWidth" ] ], [ r, [ "line", "interpolation" ], [ "lineInterpolation" ] ], [ r, [ "showlegend" ], [ "visibleInLegend" ] ] ];
toTranslate.forEach(function(d, i) {
µ.util.translator.apply(null, d.concat(reverse));
});
if (!reverse) {
delete r.marker;
}
if (reverse) {
delete r.groupId;
}
if (!reverse) {
if (r.type === "scatter") {
if (r.mode === "lines") {
r.geometry = "LinePlot";
} else if (r.mode === "markers") {
r.geometry = "DotPlot";
} else if (r.mode === "lines+markers") {
r.geometry = "LinePlot";
r.dotVisible = true;
}
} else if (r.type === "area") {
r.geometry = "AreaChart";
} else if (r.type === "bar") {
r.geometry = "BarChart";
}
delete r.mode;
delete r.type;
} else {
if (r.geometry === "LinePlot") {
r.type = "scatter";
if (r.dotVisible === true) {
delete r.dotVisible;
r.mode = "lines+markers";
} else {
r.mode = "lines";
}
} else if (r.geometry === "DotPlot") {
r.type = "scatter";
r.mode = "markers";
} else if (r.geometry === "AreaChart") {
r.type = "area";
} else if (r.geometry === "BarChart") {
r.type = "bar";
}
delete r.geometry;
}
return r;
});
if (!reverse && _inputConfig.layout && _inputConfig.layout.barmode === "stack") {
var duplicates = µ.util.duplicates(outputConfig.data.map(function(d, i) {
return d.geometry;
}));
outputConfig.data.forEach(function(d, i) {
var idx = duplicates.indexOf(d.geometry);
if (idx !== -1) {
outputConfig.data[i].groupId = idx;
}
});
}
}
if (_inputConfig.layout) {
var r = µ.util.deepExtend({}, _inputConfig.layout);
var toTranslate = [ [ r, [ "plot_bgcolor" ], [ "backgroundColor" ] ], [ r, [ "showlegend" ], [ "showLegend" ] ], [ r, [ "radialaxis" ], [ "radialAxis" ] ], [ r, [ "angularaxis" ], [ "angularAxis" ] ], [ r.angularaxis, [ "showline" ], [ "gridLinesVisible" ] ], [ r.angularaxis, [ "showticklabels" ], [ "labelsVisible" ] ], [ r.angularaxis, [ "nticks" ], [ "ticksCount" ] ], [ r.angularaxis, [ "tickorientation" ], [ "tickOrientation" ] ], [ r.angularaxis, [ "ticksuffix" ], [ "ticksSuffix" ] ], [ r.angularaxis, [ "range" ], [ "domain" ] ], [ r.angularaxis, [ "endpadding" ], [ "endPadding" ] ], [ r.radialaxis, [ "showline" ], [ "gridLinesVisible" ] ], [ r.radialaxis, [ "tickorientation" ], [ "tickOrientation" ] ], [ r.radialaxis, [ "ticksuffix" ], [ "ticksSuffix" ] ], [ r.radialaxis, [ "range" ], [ "domain" ] ], [ r.angularAxis, [ "showline" ], [ "gridLinesVisible" ] ], [ r.angularAxis, [ "showticklabels" ], [ "labelsVisible" ] ], [ r.angularAxis, [ "nticks" ], [ "ticksCount" ] ], [ r.angularAxis, [ "tickorientation" ], [ "tickOrientation" ] ], [ r.angularAxis, [ "ticksuffix" ], [ "ticksSuffix" ] ], [ r.angularAxis, [ "range" ], [ "domain" ] ], [ r.angularAxis, [ "endpadding" ], [ "endPadding" ] ], [ r.radialAxis, [ "showline" ], [ "gridLinesVisible" ] ], [ r.radialAxis, [ "tickorientation" ], [ "tickOrientation" ] ], [ r.radialAxis, [ "ticksuffix" ], [ "ticksSuffix" ] ], [ r.radialAxis, [ "range" ], [ "domain" ] ], [ r.font, [ "outlinecolor" ], [ "outlineColor" ] ], [ r.legend, [ "traceorder" ], [ "reverseOrder" ] ], [ r, [ "labeloffset" ], [ "labelOffset" ] ], [ r, [ "defaultcolorrange" ], [ "defaultColorRange" ] ] ];
toTranslate.forEach(function(d, i) {
µ.util.translator.apply(null, d.concat(reverse));
});
if (!reverse) {
if (r.angularAxis && typeof r.angularAxis.ticklen !== "undefined") {
r.tickLength = r.angularAxis.ticklen;
}
if (r.angularAxis && typeof r.angularAxis.tickcolor !== "undefined") {
r.tickColor = r.angularAxis.tickcolor;
}
} else {
if (typeof r.tickLength !== "undefined") {
r.angularaxis.ticklen = r.tickLength;
delete r.tickLength;
}
if (r.tickColor) {
r.angularaxis.tickcolor = r.tickColor;
delete r.tickColor;
}
}
if (r.legend && typeof r.legend.reverseOrder !== "boolean") {
r.legend.reverseOrder = r.legend.reverseOrder !== "normal";
}
if (r.legend && typeof r.legend.traceorder === "boolean") {
r.legend.traceorder = r.legend.traceorder ? "reversed" : "normal";
delete r.legend.reverseOrder;
}
if (r.margin && typeof r.margin.t !== "undefined") {
var source = [ "t", "r", "b", "l", "pad" ];
var target = [ "top", "right", "bottom", "left", "pad" ];
var margin = {};
d3.entries(r.margin).forEach(function(dB, iB) {
margin[target[source.indexOf(dB.key)]] = dB.value;
});
r.margin = margin;
}
if (reverse) {
delete r.needsEndSpacing;
delete r.minorTickColor;
delete r.minorTicks;
if (r.angularaxis) {
delete r.angularaxis.ticksCount;
delete r.angularaxis.ticksCount;
delete r.angularaxis.ticksStep;
delete r.angularaxis.rewriteTicks;
delete r.angularaxis.nticks;
}
if (r.radialaxis) {
delete r.radialaxis.ticksCount;
delete r.radialaxis.ticksCount;
delete r.radialaxis.ticksStep;
delete r.radialaxis.rewriteTicks;
delete r.radialaxis.nticks;
}
}
outputConfig.layout = r;
}
return outputConfig;
};
return exports;
};