g6/demos/case-american-migration.html
2020-02-14 11:30:12 +08:00

170 lines
5.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>American Migration Graph</title>
</head>
<style>
body {
background: rgb(0, 0, 0);
}
.g6-tooltip {
border: 1px solid #e2e2e2;
border-radius: 4px;
font-size: 12px;
color: #545454;
background-color: rgba(255, 255, 255, 0.9);
padding: 10px 8px;
box-shadow: rgb(174, 174, 174) 0px 0px 10px;
}
</style>
<body>
<div id="mountNode"></div>
<script src="../build/g6.js"></script>
<script src="./assets/d3-4.13.0.min.js"></script>
<script src="../build/bundling.js"></script>
<script>
const lightBlue = 'rgb(119, 243, 252)';
const llightBlue16 = '#C8FDFC';
const lightOrange = 'rgb(230, 100, 64)';
const llightOrange16 = '#FFAA86';
d3.json('./assets/data/american-migration.json', function(data) {
const nodes = data.nodes;
const edges = data.edges;
nodes.forEach(n => {
n.y = -n.y;
n.degree = 0;
n.inDegree = 0;
n.outDegree = 0;
});
// compute the degree of each node
const nodeIdMap = new Map();
nodes.forEach(node => {
nodeIdMap.set(node.id, node);
});
edges.forEach(e => {
const source = nodeIdMap.get(e.source);
const target = nodeIdMap.get(e.target);
source.outDegree++;
target.inDegree++;
source.degree++;
target.degree++;
if (e.sytle === undefined) e.style = {};
e.style.lineWidth = 0.7;
e.style.strokeOpacity = 0.1;
e.style.stroke = 'l(0) 0:' + llightOrange16 + ' 1:' + llightBlue16;
if (nodeIdMap.get(e.source).x < nodeIdMap.get(e.target).x) {
e.style.stroke = 'l(0) 0:' + llightBlue16 + ' 1:' + llightOrange16;
}
});
let maxDegree = -9999,
minDegree = 9999;
nodes.forEach(n => {
if (maxDegree < n.degree) maxDegree = n.degree;
if (minDegree > n.degree) minDegree = n.degree;
});
const sizeRange = [1, 20];
const sizeDataRange = [minDegree, maxDegree];
scaleNodeProp(nodes, 'size', 'degree', sizeDataRange, sizeRange);
// customize the node
G6.registerNode(
'pie-node',
{
drawShape: (cfg, group) => {
const radius = cfg.size / 2;
const inPercentage = cfg.inDegree / cfg.degree;
const inAngle = inPercentage * Math.PI * 2;
const outAngle = Math.PI * 2 - inAngle;
const inArcEnd = [radius * Math.cos(inAngle), radius * Math.sin(inAngle)];
let isInBigArc = 1,
isOutBigArc = 0;
if (inAngle > Math.PI) {
isInBigArc = 0;
isOutBigArc = 1;
}
const fanIn = group.addShape('path', {
attrs: {
path: [
['M', radius, 0],
['A', radius, radius, 0, isInBigArc, 0, inArcEnd[0], inArcEnd[1]],
['L', 0, 0],
['B'],
],
stroke: lightOrange,
lineWidth: 0,
fill: lightOrange,
},
});
const fanOut = group.addShape('path', {
attrs: {
path: [
['M', inArcEnd[0], inArcEnd[1]],
['A', radius, radius, 0, isOutBigArc, 0, radius, 0],
['L', 0, 0],
['B'],
],
stroke: lightBlue,
lineWidth: 0,
fill: lightBlue,
},
});
return fanIn;
},
},
'single-shape',
);
const edgeBundling = new Bundling({
bundleThreshold: 0.6,
K: 100,
});
const graph = new G6.Graph({
container: 'mountNode',
width: 1000,
height: 800,
plugins: [edgeBundling],
fitView: true,
defaultNode: {
shape: 'pie-node',
size: 3,
color: 'steelblue',
style: {
lineWidth: 0,
fill: 'steelblue',
},
},
modes: {
default: [
'drag-canvas',
'zoom-canvas',
{
type: 'tooltip',
formatText(model) {
const text = 'Longitude: ' + model.lon + '\n Latitude: ' + model.lat;
return text;
},
shouldUpdate: e => {
return true;
},
},
],
},
});
edgeBundling.bundling(data);
graph.data(data);
graph.render();
});
function scaleNodeProp(nodes, propName, refPropName, dataRange, outRange) {
const outLength = outRange[1] - outRange[0];
const dataLength = dataRange[1] - dataRange[0];
nodes.forEach(n => {
n[propName] = ((n[refPropName] - dataRange[0]) * outLength) / dataLength + outRange[0];
});
}
</script>
</body>
</html>