- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是我拥有的数据:
[
{'TotalTime': 10, 'Hour': 0, 'Name': 'Sam'},
{'TotalTime': 15, 'Hour': 1, 'Name': 'Bob'},
{'TotalTime': 300, 'Hour': 2, 'Name': 'Tom'},
... and so on till,
{'TotalTime': 124, 'Hour': 23, 'Name': 'Jon'}
]
一天中每个小时的数据。我希望从中创建一个甘特图,其中条形的大小基于 TotalTime。
y 轴上的名称和 x 轴上的小时。
是否可以在d3.js上制作没有开始时间和结束时间的甘特图?
最佳答案
这是可能的,但如果您使用 D3.js,则需要自己绘制它。因此,如果您以前制作过条形图,沿着这些思路,设置一些轴,将它们添加到 SVG 并使用它们将数据转换为您将放在图表上的矩形,然后使用数据中的名称标记矩形。 D3.js 不包含此布局。如果您还没有这样做,请浏览 tutorials : Let’s Make a Bar Chart, Parts I , II & III ,然后继续查看 custom time axis example ,以及 related A P I s。
还有许多其他基于 D3.js 构建的库,例如 C3提供预制图表(如 D3 的布局),但我不知道有哪个提供甘特样式图表。有one example Gantt chart那里(随机将任务添加到从 1 小时到 1 周的各种缩放时间 View 中),但我发现它比下面我自己的时间 block 更令人困惑。 YMMV。
我用 d3js 制作了一个更像日历的图表,您可以在这里阅读:https://github.com/dlamblin/timeblocks 。您有不同的输入数据格式,但您可以在紧要关头进行调整并交换旋转轴。假设您愿意尽快紧急执行此操作。
为了使上述内容更易于阅读和查看,我将其拆解为 JSfiddle example .
这里只是内嵌到答案中的 JavaScript(这不是甘特图,它是一周 7 天的预定时间 block 的垂直布局):
var timeFmt = d3.time.format.utc('%H.%M'),
weekdaydef = 'Mon Tue Wed Thu Fri Sat Sun'.split(' '),
weekdayseq = 'Mon Tue Wed Thu Fri Sat Sun'.split(' '),
axes = [null, null, null, null];
function hm(i) {
var s = i.toFixed(2);
return timeFmt.parse((s.length < 4) ? '0' + s : s);
}
var timeData = [
{key: "m1","wday": 0,"begin": hm(6.00),"end": hm(7.00),
label: "Rising, dress etc\n\retc"},
{key: "m2","wday": 0,"begin": hm(7.00),"end": hm(7.30),
label: "Prep Sophie"},
{key: "m3","wday": 0,"begin": hm(7.30),"end": hm(8.00),
label: "Transit to School"
}, {
key: "t1",
"wday": 1,
"begin": hm(6.00),
"end": hm(7.00),
label: "Rising, dress etc"
}, {
key: "t2",
"wday": 1,
"begin": hm(17.00),
"end": hm(18.00),
label: "call"
},
{
key: "w1",
"wday": 2,
"begin": hm(6.00),
"end": hm(7.00),
'color': 0,
label: "Rising, dress etc"
}, {
key: "w2",
"wday": 2,
"begin": hm(7.00),
"end": hm(7.30),
'color': 0,
label: "Prep Sophie"
}, {
key: "w3",
"wday": 2,
"begin": hm(7.30),
"end": hm(8.00),
'color': 1,
label: "Transit to School"
}, {
key: "w4",
"wday": 2,
"begin": hm(8.00),
"end": hm(9.00),
'color': 2,
label: "Read Emails"
}, {
key: "w5",
"wday": 2,
"begin": hm(9.00),
"end": hm(10.00),
'color': 2,
label: "Write Emails"
}, {
key: "w6",
"wday": 2,
"begin": hm(10.00),
"end": hm(13.00),
'color': 3,
label: "Job"
}, {
key: "w7",
"wday": 2,
"begin": hm(13.00),
"end": hm(14.00),
'color': 4,
label: "Lunch & Meditation"
}, {
key: "w8",
"wday": 2,
"begin": hm(14.00),
"end": hm(15.00),
'color': 5,
label: "Pick Sophie & Home"
}, {
key: "w9",
"wday": 2,
"begin": hm(15.00),
"end": hm(18.00),
'color': 0,
label: "Clean"
}, {
key: "wa",
"wday": 2,
"begin": hm(18.00),
"end": hm(19.00),
'color': 0,
label: "Plan"
}, {
key: "wb",
"wday": 2,
"begin": hm(19.00),
"end": hm(20.00),
'color': 0,
label: "Wrap: Read Email & Clean"
},
{
key: "r1",
"wday": 3,
"begin": hm(6.00),
"end": hm(7.00),
label: "Rising, dress etc"
},
{
key: "f1",
"wday": 4,
"begin": hm(6.00),
"end": hm(7.00),
label: "Rising, dress etc"
}
];
timeData = timeData.sort(function(a, b) {
var o = d3.ascending(a.wday, b.wday);
return o === 0 ? d3.ascending(a.begin, b.begin) : o;
});
// Spacing out times by 5 minutes... see display
// var timeDataMap = d3.map(timeData, function(d) {return d.key;});
// timeDataMap.forEach(function(k,v) {v.end.setMinutes(v.end.getMinutes()-5);});
// timeData = timeDataMap.values();
var scale, colors = d3.scale.category10();
colors.range(d3.range(10).map(
function(i) {
return d3.rgb(colors(i)).brighter(1.25).toString();
}));
function d3UpdateScales() {
var svg = d3.select('#timeblock')[0][0],
margin = {
top: 25,
right: 80,
bottom: 25,
left: 80
},
width = svg.clientWidth - margin.left - margin.right,
height = svg.clientHeight - margin.top - margin.bottom;
return scale = {
margin: margin,
width: width,
height: height,
time: d3.time.scale.utc() // not d3.scale.linear()
.domain([d3.min(timeData, function(d) {
return d.begin
}),
d3.max(timeData, function(d) {
return d.end
})
])
.rangeRound([0, height]),
days: d3.scale.ordinal()
.domain(weekdayseq)
.rangePoints([0, width]),
week: d3.scale.ordinal()
.domain(weekdayseq)
.rangeRoundBands([0, width], 0.05),
}
}
function d3Update() {
var scale = d3UpdateScales();
// Update…
var svg = d3.select('#timeblock');
if (svg.select('g.view')[0][0] == null) {
svg.append('g').attr('class', 'view').attr('transform', 'translate(' + scale.margin.left + ',' + scale.margin.top + ')');
}
var g = svg.select('g.view').selectAll('g.data')
.data(timeData);
// Enter…
var ge = g.enter()
.append("g")
.attr('class', 'data');
ge.append("rect")
.attr("x", function(d) {
return scale.week(weekdaydef[d.wday]) + (scale.week.rangeBand() / 2)
})
.attr("y", function(d) {
var e = new Date(d.end);
e.setMinutes(e.getMinutes() - 5);
return scale.time(d.begin) + ((scale.time(e) - scale.time(d.begin)) / 2)
})
.attr("width", 0)
.attr("height", 0)
.attr("style", function(d) {
return ("color" in d) ? "fill:" + colors(d.color) : null
})
ge.append("text")
.attr("dy", "1.1em")
.text(function(d) {
return d.label;
});
// Exit…
g.exit().remove();
// Update…
g.select("rect")
.transition()
.attr("x", function(d) {
return scale.week(weekdaydef[d.wday])
})
.attr("y", function(d) {
return scale.time(d.begin)
})
.attr("width", function(d) {
return scale.week.rangeBand()
})
.attr("height", function(d) {
var e = new Date(d.end);
e.setMinutes(e.getMinutes() - 5);
return (scale.time(e) - scale.time(d.begin))
})
g.select("text")
.transition()
.attr("x", function(d) {
return scale.week(weekdaydef[d.wday]) + 5
})
.attr("y", function(d) {
return scale.time(d.begin)
});
axesAddOrUpdate(svg);
}
function axesAddOrUpdate(svg) {
var xaxis_t = d3.svg.axis().scale(scale.week).tickSize(13).orient('top'),
yaxis_r = d3.svg.axis().scale(scale.time).tickSize(7).orient('right'),
xaxis_b = d3.svg.axis().scale(scale.week).tickSize(13),
yaxis_l = d3.svg.axis().scale(scale.time).tickSize(7).orient('left');
// global axes array contains top, right, bottom, left axis.
if (null == axes[0]) {
axes[0] = svg.append("g").attr('class', 'axis')
.attr('transform', 'translate(' + String(scale.margin.left) + ',' + String(scale.margin.top) + ')')
.call(xaxis_t);
} else {
axes[0].transition().call(xaxis_t);
}
if (null == axes[2]) {
axes[2] = svg.append("g").attr('class', 'axis')
.attr('transform', 'translate(' + String(scale.margin.left) + ',' + String(scale.height + scale.margin.top) + ')')
.call(xaxis_b);
} else {
axes[2].transition().call(xaxis_b);
}
if (null == axes[3]) {
axes[3] = svg.append("g").attr('class', 'axis')
.attr('transform', 'translate(' + String(scale.margin.left - 5) + ',' + String(scale.margin.top) + ')')
.call(yaxis_l);
} else {
axes[3].transition().call(yaxis_l);
}
if (null == axes[1]) {
axes[1] = svg.append("g").attr('class', 'axis')
.attr('transform', 'translate(' + String(scale.margin.left + scale.width + 5) + ',' + String(scale.margin.top) + ')')
.call(yaxis_r);
} else {
axes[1].transition().call(yaxis_r);
}
}
window.onload = d3Update;
d3.select('#b_rotate').on("click", function(d, i, t) {
weekdayseq.push(weekdayseq.shift());
d3Update();
});
关于javascript - 使用 d3.js 创建甘特图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37499500/
我正在学习构建单页应用程序 (SPA) 所需的所有技术。总而言之,我想将我的应用程序实现为单独的层,其中前端仅使用 API Web 服务(json 通过 socket.io)与后端通信。前端基本上是
当我看到存储在我的数据库中的日期时。 这是 正常 。日期和时间就是这样。 但是当我运行 get 请求来获取数据时。 此格式与存储在数据库 中的格式不同。为什么会发生这种情况? 最佳答案 我认为您可以将
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在尝试使用backbone.js 实现一些代码 和 hogan.js (http://twitter.github.com/hogan.js/) Hogan.js was developed ag
我正在使用 Backbone.js、Node.js 和 Express.js 制作一个 Web 应用程序,并且想要添加用户功能(登录、注销、配置文件、显示内容与该用户相关)。我打算使用 Passpor
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我尝试在 NodeJS 中加载数据,然后将其传递给 ExpressJS 以在浏览器中呈现 d3 图表。 我知道我可以通过这种方式加载数据 - https://github.com/mbostock/q
在 node.js 中,我似乎遇到了相同的 3 个文件名来描述应用程序的主要入口点: 使用 express-generator 包时,会创建一个 app.js 文件作为生成应用的主要入口点。 通过 n
最近,我有机会观看了 john papa 关于构建单页应用程序的精彩类(class)。我会喜欢的。它涉及服务器端和客户端应用程序的方方面面。 我更喜欢客户端。在他的实现过程中,papa先生在客户端有类
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一个图形新手,需要帮助了解各种 javascript 2D 库的功能。 . . 我从 Pixi.js 中得到了什么,而我没有从 Konva 等基于 Canvas 的库中得到什么? 我从 Konva
我正在尝试将一些 LESS 代码(通过 ember-cli-less)构建到 CSS 文件中。 1) https://almsaeedstudio.com/ AdminLTE LESS 文件2) Bo
尝试查看 Express Passport 中所有登录用户的所有 session ,并希望能够查看当前登录的用户。最好和最快的方法是什么? 我在想也许我可以在登录时执行此操作并将用户模型数据库“在线”
我有一个 React 应用程序,但我需要在组件加载完成后运行一些客户端 js。一旦渲染函数完成并加载,运行与 DOM 交互的 js 的最佳方式是什么,例如 $('div').mixItUp() 。对
请告诉我如何使用bodyparser.raw()将文件上传到express.js服务器 客户端 // ... onFilePicked(file) { const url = 'upload/a
我正在尝试从 Grunt 迁移到 Gulp。这个项目在 Grunt 下运行得很好,所以我一定是在 Gulp 中做错了什么。 除脚本外,所有其他任务均有效。我现在厌倦了添加和注释部分。 我不断收到与意外
我正在尝试更改我的网站名称。找不到可以设置标题或应用程序名称的位置。 最佳答案 您可以在 config/ 目录中创建任何文件,例如 config/app.js 包含如下内容: module.expor
经过多年的服务器端 PHP/MySQL 开发,我正在尝试探索用于构建现代 Web 应用程序的新技术。 我正在尝试对所有 JavaScript 内容进行排序,如果我理解得很好,一个有效的解决方案可以是服
我是 Nodejs 的新手。我在 route 目录中有一个 app.js 和一个 index.js。我有一个 app.use(multer....)。我还定义了 app.post('filter-re
我正在使用 angular-seed用于构建我的应用程序的模板。最初,我将所有 JavaScript 代码放入一个文件 main.js。该文件包含我的模块声明、 Controller 、指令、过滤器和
我是一名优秀的程序员,十分优秀!