Skip to content

Instantly share code, notes, and snippets.

@giorgi-ghviniashvili
Last active July 26, 2018 21:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save giorgi-ghviniashvili/8f131391f9d09812bf172bf2fa7528b7 to your computer and use it in GitHub Desktop.
Save giorgi-ghviniashvili/8f131391f9d09812bf172bf2fa7528b7 to your computer and use it in GitHub Desktop.
radial line v4
license: mit
function renderChart(params) {
// Exposed variables
var attrs = {
id: "ID" + Math.floor(Math.random() * 1000000), // Id for event handlings
svgWidth: 400,
svgHeight: 400,
marginTop: 0,
marginBottom: 0,
marginRight: 0,
marginLeft: 0,
container: 'body',
defaultTextFill: '#2C3E50',
defaultFont: 'Helvetica',
data: null
};
//InnerFunctions which will update visuals
var updateData;
//Main chart object
var main = function (selection) {
selection.each(function scope() {
//Calculated properties
var calc = {}
calc.id = "ID" + Math.floor(Math.random() * 1000000); // id for event handlings
calc.chartLeftMargin = attrs.marginLeft;
calc.chartTopMargin = attrs.marginTop;
calc.chartWidth = attrs.svgWidth - attrs.marginRight - calc.chartLeftMargin;
calc.chartHeight = attrs.svgHeight - attrs.marginBottom - calc.chartTopMargin;
//Drawing containers
var container = d3.select(this);
//Add svg
var svg = container.patternify({ tag: 'svg', selector: 'svg-chart-container' })
.attr('width', attrs.svgWidth)
.attr('height', attrs.svgHeight)
.attr('font-family', attrs.defaultFont);
//Add container g element
var chart = svg.patternify({ tag: 'g', selector: 'chart' })
.attr('transform', 'translate(' + (calc.chartLeftMargin) + ',' + calc.chartTopMargin + ')');
var line = d3.line()
.curve(d3.curveCatmullRom)
.x(function(d){ return d.x })
.y(function(d){ return d.y })
chart.patternify({tag: "path", selector: "outerCircle", data: [attrs.data.outerPoints.concat(attrs.data.outerPoints[0])] })
.attr("d",line)
.style("fill", "none")
.style("stroke-dasharray", "5, 5")
.style("stroke", "#000080")
chart.patternify({tag: "path", selector: "innerCircle", data: [attrs.data.innerPoints.concat(attrs.data.innerPoints[0])] })
.attr("d", line)
.style("fill", "none")
.style("stroke-dasharray", "5, 5")
.style("stroke", "#000080")
chart.patternify({ tag: "path", selector: "line", data: attrs.data.links })
.style("fill", "none")
.style("stroke", "#fff")
.attr("data-source", function(d){
return d.s;
})
.attr("d", function(d){
var source = attrs.data.outerPoints[d.s];
var target = attrs.data.innerPoints[d.t];
return link({source: source, target: target});
})
var pointsData = getPointsData();
chart.patternify({ tag: "circle", selector: 'nodes', data: pointsData })
.attr("r", 5)
.attr("cx",function(d) {return d.x;})
.attr("cy", function(d) {return d.y;})
.style("stroke-width", 2)
.style("fill", "white")
.style("stroke", "#000080")
.on("mouseenter", function(d){
var i = attrs.data.outerPoints.indexOf(d);
d3.select(this)
.transition()
.duration(100)
.style("fill", "#000080");
chart.selectAll('path[data-source="' + i + '"]')
.transition()
.duration(100)
.style("stroke", "#000080");
})
.on("mouseleave", function(d){
var i = pointsData.indexOf(d);
d3.select(this)
.transition()
.duration(100)
.style("fill", "#fff");
chart.selectAll('path[data-source="' + i + '"]')
.transition()
.duration(100)
.style("stroke", "#fff");
});
// Smoothly handle data updating
updateData = function () {
}
//######################################### UTIL FUNCS ##################################
function link(d) {
return "M" + d.source.x + "," + d.source.y
+ "C" + d.source.x + "," + (d.source.y + d.target.y) / 2
+ " " + d.target.x + "," + (d.source.y + d.target.y) / 2
+ " " + d.target.x + "," + d.target.y;
}
function getPointsData () {
return attrs.data.outerPoints.concat(attrs.data.innerPoints);
}
function handleWindowResize() {
d3.select(window).on('resize.' + attrs.id, function () {
setDimensions();
});
}
function setDimensions() {
setSvgWidthAndHeight();
container.call(main);
}
function setSvgWidthAndHeight() {
var containerRect = container.node().getBoundingClientRect();
if (containerRect.width > 0)
attrs.svgWidth = containerRect.width;
if (containerRect.height > 0)
attrs.svgHeight = containerRect.height;
}
function debug() {
if (attrs.isDebug) {
//Stringify func
var stringified = scope + "";
// Parse variable names
var groupVariables = stringified
//Match var x-xx= {};
.match(/var\s+([\w])+\s*=\s*{\s*}/gi)
//Match xxx
.map(function(d) { return d.match(/\s+\w*/gi).filter(s => s.trim()) })
//Get xxx
.map(function(v) { return v[0].trim() })
//Assign local variables to the scope
groupVariables.forEach(function(v) {
main['P_' + v] = eval(v)
})
}
}
debug();
});
};
//----------- PROTOTYEPE FUNCTIONS ----------------------
d3.selection.prototype.patternify = function (params) {
var container = this;
var selector = params.selector;
var elementTag = params.tag;
var data = params.data || [selector];
// Pattern in action
var selection = container.selectAll('.' + selector).data(data, function(d,i) {
if (typeof d === "object") {
if (d.id) {
return d.id;
}
}
return i;
})
selection.exit().remove();
selection = selection.enter().append(elementTag).merge(selection)
selection.attr('class', selector);
return selection;
}
//Dynamic keys functions
Object.keys(attrs).forEach(function(key) {
// Attach variables to main function
return main[key] = function (_) {
var string = `attrs['${key}'] = _`;
if (!arguments.length) { return eval(` attrs['${key}'];`); }
eval(string);
return main;
};
});
//Set attrs as property
main.attrs = attrs;
//Debugging visuals
main.debug = function (isDebug) {
attrs.isDebug = isDebug;
if (isDebug) {
if (!window.charts) window.charts = [];
window.charts.push(main);
}
return main;
}
//Exposed update functions
main.data = function (value) {
if (!arguments.length) return attrs.data;
attrs.data = value;
if (typeof updateData === 'function') {
updateData();
}
return main;
}
// Run visual
main.run = function () {
d3.selectAll(attrs.container).call(main);
return main;
}
return main;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Chart</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-color: #E1E5EC;
}
#myGraph {
width: 500px;
height: auto;
margin: auto;
}
</style>
</head>
<body translate="no">
<div class="container centered">
<div id="myGraph"></div>
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="d3script.js"></script>
<script>
var width = document.getElementById('myGraph').getBoundingClientRect().width;
var height = width;
var center = {
x: width / 2,
y: height / 2
};
var pointsOuter = getPoints(24, 220);
var pointsInner = getPoints(12, 100);
var links = [
{s: 0, t: 8},
{s: 0, t: 2},
{s: 1, t: 4},
{s: 18, t: 9},
{s: 12, t: 5},
{s: 22, t: 10},
{s: 21, t: 10},
{s: 9, t: 4},
{s: 19, t: 5},
{s: 4, t: 3},
{s: 16, t: 8},
{s: 16, t: 1},
{s: 14, t: 7},
{s: 14, t: 6},
];
var dataset = {
outerPoints: pointsOuter,
innerPoints: pointsInner,
links: links
};
var chart = renderChart()
.svgHeight(height)
.svgWidth(width)
.container('#myGraph')
.data(dataset)
.debug(true)
.run()
function getPoints(n, r){
var coords = [];
var radian = (2 * Math.PI) / n;
for(var i = 0; i < n; i++){
var angle = i * radian;
var x = center.x + r * Math.cos(angle);
var y = center.y + r * Math.sin(angle);
coords.push({
x: x,
y: y
});
}
return coords;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment