<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Aspect Relationships</title>
<!-- Google Fonts -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<link
href="https://fonts.googleapis.com/css?family=Lato:400,900"
rel="stylesheet"
type="text/css"
/>
<style>
.tippy-content {
font-family: "Lato", sans-serif;
}
#chart-b1335770 {
font-size: 10px;
font-family: "Lato", sans-serif;
text-align: center;
fill: #454545;
}
#chart-b1335770 svg {
max-width: 700px;
}
@media (min-width: 600px) {
#chart-b1335770{
font-size: 15px;
}
}
</style>
</head>
<body>
<div id="chart-b1335770" class="chord">
</div>
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>
<script>
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://d3js.org/d3.v5.min.js";
script.onload = function () {
var script2 = document.createElement("script");
script2.type = "text/javascript";
script2.src = "https://shahinrostami.com/assets/chord/script.js";
script2.onload = function () {
margin = {
left: 0,
top: 0,
right: 0,
bottom: 0
};
width = Math.min(window.innerWidth, 700) - margin.left - margin.right;
height = Math.min(window.innerWidth, 700) - margin.top - margin.bottom;
innerRadius = Math.min(width, height) * 0.39;
outerRadius = innerRadius * 1.1;
tag_id = "chart-b1335770";
padding = 0.01;
Names = ['Built Form', 'Public Spaces', 'Zoning, Land Use, Bldg. Use', 'Context, Spatial Evolution', 'Accessibility, Circulation', 'Environment', 'Safety and Security', 'Scalability', 'Sense of Place, Imageability', 'Intangible Qualities'];
colors = d3.schemeSet1;
opacityDefault = 0.8;
matrix = [[0.0, 17.5, 16.67, 7.08, 18.33, 7.08, 10.42, 9.58, 7.08, 6.25], [8.33, 0.0, 13.75, 4.58, 17.92, 14.17, 13.75, 2.5, 15.83, 9.17], [21.67, 17.5, 0.0, 7.92, 17.92, 8.12, 6.88, 9.58, 6.46, 3.96], [17.08, 9.17, 20.83, 0.0, 20.42, 7.92, 4.17, 9.17, 6.25, 5.0], [13.75, 20.42, 25.83, 5.42, 0.0, 5.0, 7.92, 4.58, 12.5, 4.58], [9.79, 13.96, 19.58, 10.83, 17.92, 0.0, 10.21, 6.88, 6.04, 4.79], [17.33, 15.83, 9.75, 2.5, 18.75, 6.25, 0.0, 2.5, 14.58, 12.5], [18.33, 11.67, 20.42, 5.83, 11.67, 15.42, 7.5, 0.0, 4.58, 4.58], [15.42, 20.42, 4.79, 3.96, 15.42, 7.5, 14.17, 3.33, 0.0, 15.0], [18.75, 21.25, 3.75, 7.92, 10.0, 9.17, 9.58, 0.83, 18.75, 0.0]];
wrap_labels = true;
credit = false
////////////////////////////////////////////////////////////
/////////// Create scale and layout functions //////////////
////////////////////////////////////////////////////////////
var colors = d3
.scaleOrdinal()
.domain(d3.range(Names.length))
.range(colors);
//A "custom" d3 chord function that automatically sorts the order of the chords in such a manner to reduce overlap
var chord = customChordLayout()
.padding(padding)
.sortChords(d3.descending) //which chord should be shown on top when chords cross. Now the biggest chord is at the bottom
.matrix(matrix);
var arc = d3
.arc()
.innerRadius(innerRadius * 1.01)
.outerRadius(outerRadius);
var path = d3.ribbon().radius(innerRadius);
////////////////////////////////////////////////////////////
////////////////////// Create SVG //////////////////////////
///////////////////////////////////////////////////////////
var svg = d3
.select("#" + tag_id)
.append("svg")
.attr(
"viewBox",
"0 0 " +
(width + margin.left + margin.right) +
" " +
(height + margin.top + margin.bottom)
)
.attr("preserveAspectRatio", "xMinYMin meet")
.append("g")
.attr(
"transform",
"translate(" +
(width / 2 + margin.left) +
"," +
(height / 2 + margin.top) +
")"
);
d3
.select("#" + tag_id)
.append("span")
.style("display", "block")
.style("font-size", "12px")
.style("text-align", "right")
.style("font-family", '"Arial", sans-serif')
.html('Abhiroop Sarkar');
////////////////////////////////////////////////////////////
/////////////// Create the gradient fills //////////////////
////////////////////////////////////////////////////////////
//Function to create the id for each chord gradient
function getGradID(d) {
return (
"linkGrad-" + tag_id + "-" + d.source.index + "-" + d.target.index
);
}
//Create the gradients definitions for each chord
var grads = svg
.append("defs")
.selectAll("linearGradient")
.data(chord.chords())
.enter()
.append("linearGradient")
.attr("id", getGradID)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", function (d, i) {
return (
innerRadius *
Math.cos(
(d.source.endAngle - d.source.startAngle) / 2 +
d.source.startAngle -
Math.PI / 2
)
);
})
.attr("y1", function (d, i) {
return (
innerRadius *
Math.sin(
(d.source.endAngle - d.source.startAngle) / 2 +
d.source.startAngle -
Math.PI / 2
)
);
})
.attr("x2", function (d, i) {
return (
innerRadius *
Math.cos(
(d.target.endAngle - d.target.startAngle) / 2 +
d.target.startAngle -
Math.PI / 2
)
);
})
.attr("y2", function (d, i) {
return (
innerRadius *
Math.sin(
(d.target.endAngle - d.target.startAngle) / 2 +
d.target.startAngle -
Math.PI / 2
)
);
});
//Set the starting color (at 0%)
grads
.append("stop")
.attr("offset", "0%")
.attr("stop-color", function (d) {
return colors(d.source.index);
});
//Set the ending color (at 100%)
grads
.append("stop")
.attr("offset", "100%")
.attr("stop-color", function (d) {
return colors(d.target.index);
});
////////////////////////////////////////////////////////////
////////////////// Draw outer Arcs /////////////////////////
////////////////////////////////////////////////////////////
var outerArcs = svg
.selectAll("g.group")
.data(chord.groups)
.enter()
.append("g")
.attr("class", "group")
.on("mouseover", fade(0.1, 1))
.on("mouseout", fade(opacityDefault, opacityDefault));
outerArcs
.append("path")
.style("fill", function (d) {
return colors(d.index);
})
.attr("d", arc)
.each(function (d, i) {
//Search pattern for everything between the start and the first capital L
var firstArcSection = /(^.+?)L/;
//Grab everything up to the first Line statement
var newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
//Replace all the comma's so that IE can handle it
newArc = newArc.replace(/,/g, " ");
//If the end angle lies beyond a quarter of a circle (90 degrees or pi/2)
//flip the end and start position
if (
(d.endAngle > (90 * Math.PI) / 180) &
(d.startAngle < (270 * Math.PI) / 180)
) {
var startLoc = /M(.*?)A/, //Everything between the first capital M and first capital A
middleLoc = /A(.*?)0 0 1/, //Everything between the first capital A and 0 0 1
endLoc = /0 0 1 (.*?)$/; //Everything between the first 0 0 1 and the end of the string (denoted by $)
//Flip the direction of the arc by switching the start en end point (and sweep flag)
//of those elements that are below the horizontal line
var newStart = endLoc.exec(newArc)[1];
var newEnd = startLoc.exec(newArc)[1];
var middleSec = middleLoc.exec(newArc)[1];
//Build up the new arc notation, set the sweep-flag to 0
newArc = "M" + newStart + "A" + middleSec + "0 0 0 " + newEnd;
} //if
//Create a new invisible arc that the text can flow along
svg
.append("path")
.attr("class", "hiddenArcs")
.attr("id", "arc-" + tag_id + "-" + i)
.attr("d", newArc)
.style("fill", "none");
});
////////////////////////////////////////////////////////////
////////////////// Append Names ////////////////////////////
////////////////////////////////////////////////////////////
//Append the label names on the outside
if (wrap_labels) {
outerArcs
.append("text")
.attr("class", "titles")
.attr("dy", function (d, i) {
return (d.endAngle > (90 * Math.PI) / 180) &
(d.startAngle < (270 * Math.PI) / 180)
? 25
: -16;
})
.append("textPath")
.attr("startOffset", "50%")
.style("text-anchor", "middle")
.attr("xlink:href", function (d, i) {
return "#arc-" + tag_id + "-" + i;
})
.text(function (d, i) {
return Names[i];
});
} else {
//Append the label names on the outside
outerArcs
.append("text")
.each(function (d) {
d.angle = (d.startAngle + d.endAngle) / 2;
})
.attr("dy", ".35em")
.attr("class", "titles")
.attr("text-anchor", function (d) {
return d.angle > Math.PI ? "end" : null;
})
.attr("transform", function (d) {
return (
"rotate(" +
((d.angle * 180) / Math.PI - 90) +
")" +
"translate(" +
(outerRadius + 10) +
")" +
(d.angle > Math.PI ? "rotate(180)" : "")
);
})
.text(function (d, i) {
return Names[i];
});
}
////////////////////////////////////////////////////////////
////////////////// Draw inner chords ///////////////////////
////////////////////////////////////////////////////////////
svg
.selectAll("path.chord")
.data(chord.chords)
.enter()
.append("path")
.attr("class", "chord")
.style("fill", function (d) {
return "url(#" + getGradID(d) + ")";
})
.style("opacity", opacityDefault)
.attr("d", path)
.on("mouseover", mouseoverChord())
.on("mouseout", mouseoutChord(opacityDefault, opacityDefault));
////////////////////////////////////////////////////////////
////////////////// Extra Functions /////////////////////////
////////////////////////////////////////////////////////////
//Returns an event handler for fading a given chord group.
function fade(opacityIn, opacityOut) {
return function (d, i) {
d3.select(this.ownerSVGElement)
.selectAll("path.chord")
.filter(function (d) {
return d.source.index !== i && d.target.index !== i;
})
.transition()
.style("opacity", opacityIn);
d3.select(this.ownerSVGElement)
.selectAll("path.chord")
.filter(function (d) {
return d.source.index == i || d.target.index == i;
})
.transition()
.style("opacity", opacityOut);
};
} //fade
//Highlight hovered over chord
function mouseoverChord() {
return function (d, i) {
d3.select(this.ownerSVGElement)
.selectAll("path.chord")
.transition()
.style("opacity", 0.1);
//Show hovered over chord with full opacity
d3.select(this).transition().style("opacity", 1);
tippy_content = "<span style='font-weight:900'>" +
Names[d.source.index] +
"</span> and <span style='font-weight:900'>" +
Names[d.target.index] +
"</span><br>occur together in <span style='font-weight:900'>" +
d.source.value +
"</span> instances";
tippy_content2 = Names[d.source.index] + " → " + Names[d.target.index] +
" = " + d.source.value + "%" + "<br>" +
Names[d.target.index] + " → " + Names[d.source.index] +
" = " + d.target.value + "%";
if(this._tippy == null)
{
tippy(this, {
allowHTML: true,
followCursor: true,
content: tippy_content2,
size: "small",
arrow: true,
});
}
};
} //fade
//Bring all chords back to default opacity
function mouseoutChord(opacityIn, opacityOut) {
return function (d, i) {
d3.select(this.ownerSVGElement)
.selectAll("path.chord")
.transition()
.style("opacity", opacityOut);
};
//Set opacity back to default for all
} //function mouseoutChord
};
document.body.appendChild(script2);
};
document.body.appendChild(script);
</script>
<script></script>
</body>
</html>