问题描述
我正在尝试复制在此github个人资料上看到的可视化效果
I am trying to replicate the visualization I see on this github profile
https://github.com/mojoaxel/d3-sunburst/tree/master/examples
我复制了以下代码,并将路径更改为各个文件.
I copied the following code and changed the path to the respective files.
suburst.html
suburst.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sequences sunburst</title>
<link rel="stylesheet" type="text/css" href="sunburst.css"/>
<link rel="stylesheet" type="text/css" href="examples.css"/>
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="sunburst.js" type="text/javascript"></script>
</head>
<body>
<div id="main">
<div id="sunburst-breadcrumbs"></div>
<div id="sunburst-chart">
<div id="sunburst-description"></div>
</div>
</div>
<div id="sidebar">
<input type="checkbox" id="togglelegend"> Legend<br/>
<div id="sunburst-legend" style="visibility: hidden;"></div>
</div>
<script type="text/javascript">
(function() {
var sunburst = new Sunburst({
colors: {
"home": "#5687d1",
"product": "#7b615c",
"search": "#de783b",
"account": "#6ab975",
"other": "#a173d1",
"end": "#bbbbbb"
}
});
sunburst.loadCsv("/Users/Documents/data/visit-sequences.csv");
d3.select("#togglelegend").on("click", function() {
var legend = d3.select('#sunburst-legend');
if (legend.style("visibility") == "hidden") {
legend.style("visibility", "");
} else {
legend.style("visibility", "hidden");
}
});
})();
</script>
</body>
</html>
sunburst.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['d3'], factory);
} else {
root.Sunburst = factory(root.d3);
}
}(this, function (d3) {
var defaultOptions = {
// DOM Selectors
selectors: {
breadcrumbs: '#sunburst-breadcrumbs',
chart: '#sunburst-chart',
description: '#sunburst-description',
legend: '#sunburst-legend'
},
// Dimensions of sunburst.
width: 750,
height: 600,
// Mapping of step names to colors.
colors: {},
// If a color-name is missing this color-scale is used
colorScale: d3.scale.category20(),
colorScaleLength: 20,
// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
breadcrumbs: {
w: 75,
h: 30,
s: 3,
t: 10
},
// parser settings
separator: '-'
};
/**
* This hashing function returns a number between 0 and 4294967295 (inclusive) from the given string.
* @see https://github.com/darkskyapp/string-hash
* @param {String} str
*/
function hash(str) {
var hash = 5381;
var i = str.length;
while(i) {
hash = (hash * 33) ^ str.charCodeAt(--i);
}
return hash >>> 0;
}
var Sunburst = function(options, data) {
this.opt = Object.assign({}, defaultOptions, options);
// Total size of all segments; we set this later, after loading the data.
this.totalSize = 0;
if (data) {
this.setData(data);
}
}
Sunburst.prototype.getColorByName = function(name) {
return this.opt.colors[name] || this.opt.colorScale(hash(name) % this.opt.colorScaleLength);
}
Sunburst.prototype.setData = function(data) {
var json = this.buildHierarchy(data);
this.createVisualization(json);
}
Sunburst.prototype.loadCsv = function(csvFile) {
// Use d3.text and d3.csv.parseRows so that we do not need to have a header
// row, and can receive the csv as an array of arrays.
d3.text(csvFile, function(text) {
var array = d3.csv.parseRows(text);
var json = this.buildHierarchy(array);
this.createVisualization(json);
}.bind(this));
}
// Main function to draw and set up the visualization, once we have the data.
Sunburst.prototype.createVisualization = function(json) {
var that = this;
var radius = Math.min(this.opt.width, this.opt.height) / 2
this.vis = d3.select(this.opt.selectors.chart).append("svg:svg")
.attr("width", this.opt.width)
.attr("height", this.opt.height)
.append("svg:g")
.attr("id", "sunburst-container")
.attr("transform", "translate(" + this.opt.width / 2 + "," + this.opt.height / 2 + ")");
var arc = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });
var partition = d3.layout.partition()
.size([2 * Math.PI, radius * radius])
.value(function(d) { return d.size; });
// Basic setup of page elements.
this.initializeBreadcrumbTrail();
this.drawLegend();
// For efficiency, filter nodes to keep only those large enough to see.
var nodes = partition.nodes(json)
.filter(function(d) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
});
var all = this.vis.data([json])
.selectAll("path")
.data(nodes)
.enter();
all.append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("fill", function(d) { return that.getColorByName(d.name); })
.style("opacity", 1)
.on("mouseover", that.mouseover.bind(this));
// some tests with text
/*
var arcText = d3.svg.arc()
.startAngle(function(d) { return d.x; })
.endAngle(function(d) { return d.x + d.dx; })
.innerRadius(function(d) { return Math.sqrt(d.y * 0.4); })
.outerRadius(function(d) { return Math.sqrt(d.y + d.dy * 0.4); })
var arcsText = arcs.append("svg:path")
.attr("d", arcText)
.style("fill", "none")
.attr("id", function(d, i){
return "s" + i;
});
var texts = all.append("svg:text")
.attr("dx", "0")
.attr("dy", "0")
.style("text-anchor","middle")
.append("textPath")
.attr("xlink:href", function(d, i){
return "#s" + i;
})
.attr("startOffset",function(d,i){return "25%";})
.text(function (d) {
return d.depth === 1 ? d.name : '';
});
*/
// Add the mouseleave handler to the bounding circle.
d3.select(this.opt.selectors.chart).on("mouseleave", that.mouseleave.bind(this));
// Get total size of the tree = value of root node from partition.
var node = all.node();
this.totalSize = node ? node.__data__.value : 0;
}
// Fade all but the current sequence, and show it in the breadcrumb trail.
Sunburst.prototype.mouseover = function(d) {
var percentage = (100 * d.value / this.totalSize).toPrecision(3);
var sequenceArray = this.getAncestors(d);
this.updateDescription(sequenceArray, d.value, percentage)
this.updateBreadcrumbs(sequenceArray, d.value, percentage);
// Fade all the segments.
this.vis.selectAll("path")
.style("opacity", 0.3);
// Then highlight only those that are an ancestor of the current segment.
this.vis.selectAll("path")
.filter(function(node) {
return (sequenceArray.indexOf(node) >= 0);
})
.style("opacity", 1);
}
// Restore everything to full opacity when moving off the visualization.
Sunburst.prototype.mouseleave = function(d) {
var that = this;
// Hide the breadcrumb trail
d3.select("#trail")
.style("visibility", "hidden");
// Deactivate all segments during transition.
d3.selectAll("path").on("mouseover", null);
// Transition each segment to full opacity and then reactivate it.
//TODO cancel this transition on mouseover
d3.selectAll("path")
.transition()
.duration(1000)
.style("opacity", 1)
.each("end", function() {
d3.select(this).on("mouseover", that.mouseover.bind(that));
});
d3.select(this.opt.selectors.description)
.style("visibility", "hidden");
}
// Given a node in a partition layout, return an array of all of its ancestor
// nodes, highest first, but excluding the root.
Sunburst.prototype.getAncestors = function(node) {
var path = [];
var current = node;
while (current.parent) {
path.unshift(current);
current = current.parent;
}
return path;
}
Sunburst.prototype.initializeBreadcrumbTrail = function() {
// Add the svg area.
var trail = d3.select(this.opt.selectors.breadcrumbs).append("svg:svg")
.attr("width", this.opt.width)
.attr("height", 50)
.attr("id", "trail");
// Add the label at the end, for the percentage.
trail.append("svg:text")
.attr("id", "endlabel")
.style("fill", "#000");
}
// Generate a string that describes the points of a breadcrumb polygon.
Sunburst.prototype.breadcrumbPoints = function(d, i) {
var points = [];
var b = this.opt.breadcrumbs;
points.push("0,0");
points.push(b.w + ",0");
points.push(b.w + b.t + "," + (b.h / 2));
points.push(b.w + "," + b.h);
points.push("0," + b.h);
if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
points.push(b.t + "," + (b.h / 2));
}
return points.join(" ");
}
// format the description string in the middle of the chart
Sunburst.prototype.formatDescription = function(sequence, value, percentage) {
return percentage < 0.1 ? "< 0.1%" : percentage + '%';
}
Sunburst.prototype.updateDescription = function(sequence, value, percentage) {
d3.select(this.opt.selectors.description)
.html(this.formatDescription(sequence, value, percentage))
.style("visibility", "");
}
// format the text at the end of the breadcrumbs
Sunburst.prototype.formatBreadcrumbText = function(sequence, value, percentage) {
return value + " (" + (percentage < 0.1 ? "< 0.1%" : percentage + "%") + ")";
}
// Update the breadcrumb trail to show the current sequence and percentage.
Sunburst.prototype.updateBreadcrumbs = function(sequence, value, percentage) {
var that = this;
var b = this.opt.breadcrumbs;
// Data join; key function combines name and depth (= position in sequence).
var g = d3.select("#trail")
.selectAll("g")
.data(sequence, function(d) { return d.name + d.depth; });
// Add breadcrumb and label for entering nodes.
var entering = g.enter().append("svg:g");
entering.append("svg:polygon")
.attr("points", this.breadcrumbPoints.bind(that))
.style("fill", function(d) { return that.getColorByName(d.name); });
entering.append("svg:text")
.attr("x", (b.w + b.t) / 2)
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name; });
// Set position for entering and updating nodes.
g.attr("transform", function(d, i) {
return "translate(" + i * (b.w + b.s) + ", 0)";
});
// Remove exiting nodes.
g.exit().remove();
// Now move and update the percentage at the end.
d3.select("#trail").select("#endlabel")
.attr("x", (sequence.length + 1) * (b.w + b.s))
.attr("y", b.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.html(this.formatBreadcrumbText(sequence, value, percentage));
// Make the breadcrumb trail visible, if it's hidden.
d3.select("#trail")
.style("visibility", "");
}
Sunburst.prototype.drawLegend = function() {
// Dimensions of legend item: width, height, spacing, radius of rounded rect.
var li = {
w: 75, h: 30, s: 3, r: 3
};
var legend = d3.select(this.opt.selectors.legend).append("svg:svg")
.attr("width", li.w)
.attr("height", d3.keys(this.opt.colors).length * (li.h + li.s));
var g = legend.selectAll("g")
.data(d3.entries(this.opt.colors))
.enter().append("svg:g")
.attr("transform", function(d, i) {
return "translate(0," + i * (li.h + li.s) + ")";
});
g.append("svg:rect")
.attr("rx", li.r)
.attr("ry", li.r)
.attr("width", li.w)
.attr("height", li.h)
.style("fill", function(d) { return d.value; });
g.append("svg:text")
.attr("x", li.w / 2)
.attr("y", li.h / 2)
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.key; });
}
// Take a 2-column CSV and transform it into a hierarchical structure suitable
// for a partition layout. The first column is a sequence of step names, from
// root to leaf, separated by hyphens. The second column is a count of how
// often that sequence occurred.
Sunburst.prototype.buildHierarchy = function(array) {
var root = {"name": "root", "children": []};
for (var i = 0; i < array.length; i++) {
var sequence = array[i][0];
var size = +array[i][1];
if (isNaN(size)) { // e.g. if this is a header row
continue;
}
var parts = sequence.split(this.opt.separator);
var currentNode = root;
for (var j = 0; j < parts.length; j++) {
var children = currentNode["children"] || [];
var nodeName = parts[j];
var childNode;
if (j + 1 < parts.length) {
// Not yet at the end of the sequence; move down the tree.
var foundChild = false;
for (var k = 0; k < children.length; k++) {
if (children[k]["name"] == nodeName) {
childNode = children[k];
foundChild = true;
break;
}
}
// If we don't already have a child node for this branch, create it.
if (!foundChild) {
childNode = {"name": nodeName, "children": []};
children.push(childNode);
}
currentNode = childNode;
} else {
// Reached the end of the sequence; create a leaf node.
childNode = {"name": nodeName, "size": size};
children.push(childNode);
}
}
}
return root;
}
return Sunburst;
}));
所有html,js和css文件都存储在同一文件夹中.
All the html, js and css files are stored in same folder.
但是,当我运行它时,我得到了这样的浏览器窗口,没有可视化,只是右侧的图例框.
But when I run it, I get the browser window like this with no visualization but just a legend box on the right.
我想念什么?数据集是从同一github页面下载的.
What am I missing? The dataset is downloaded from the same github page.
推荐答案
提供了visit-sequences.csv
的路径正确,浏览器将阻止其本地加载(请参阅CORS ).
Provided the path to visit-sequences.csv
is correct, its local loading will be blocked by the browser (see CORS).
您可以:
- 通过(甚至是本地)网络服务器运行它
- 使用
--allow-file-access-from-files
标志启动Chrome(如果您使用的是Chrome)
- run it via a (even local) webserver
- start Chrome with the
--allow-file-access-from-files
flag (if you're using Chrome)
这篇关于Javascript D3未显示可视化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!