- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 D3 v6 创建一个类似于 GitHub 热图的日历热图,这是我的起点 https://observablehq.com/@d3/calendar-view ,但相反,我只想要一个与 GitHub 热图完全一样的 1 年 map ,从今天开始。
这是我到目前为止能够实现的https://codesandbox.io/s/heatmap-d3-tzpnu?file=/src/App.js
如果您查看上面的沙盒热图,它首先显示 2021 年 1 月至 2021 年 8 月,然后开始显示 2020 年 8 月至 2020 年 12 月。
如何让它从 2020 年 8 月开始并在今天(2021 年 8 月)结束?像 github:
我正在使用 dayjs用于日期操作
这是 React 中的热图代码:
import React, { useEffect, useRef, useState } from "react";
import * as d3 from "d3";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
// import { legend } from '@d3/color-legend';
const Heatmap = ({ data }) => {
const [fullYearData, setFullYearData] = useState([]);
const [originalData, setOriginalData] = useState([]);
dayjs.extend(utc);
let chartRef = useRef(null);
const now = dayjs();
const today = now.format("YYYY/MM/DD");
useEffect(() => {
setOriginalData(data);
}, [data]);
useEffect(() => {
const yearBackFromNow = now.subtract(1, "year").format("YYYY/MM/DD");
const firstDate = yearBackFromNow;
const lastDate = today;
// fill the missing dates
if (data && originalData.length > 0) {
const dates = [
...Array(
Date.parse(lastDate) / 86400000 - Date.parse(firstDate) / 86400000 + 1
).keys()
].map(
(k) =>
new Date(86400000 * k + Date.parse(firstDate))
.toISOString()
.slice(0, 10)
// .replace(/-0(\d)$/, '-$1')
);
// console.log(dates);
let response = [];
for (let i = 0, j = 0; i < dates.length; i++) {
response[i] = {
date: dates[i],
contributions:
dates[i] === originalData[j]?.date
? originalData[j++].contributions
: 0
};
}
setFullYearData(response);
}
}, [originalData]);
useEffect(() => {
if (chartRef && fullYearData) {
let chart = chartRef?.current;
// remove existing svg before showing chart:
//Prevent showing multiple charts
d3.select(".heatmap").remove();
const years = d3.groups(fullYearData, (d) =>
new Date(d.date).getUTCFullYear()
);
// const years = data;
var margin = { top: 80, right: 25, bottom: 30, left: 40 };
// width = 650 - margin.left - margin.right,
// height = 400 - margin.top - margin.bottom;
const weekday = "sunday";
const cellSize = 13;
let width = 730;
const height = cellSize * 9;
// const height = cellSize * (weekday === 'weekday' ? 7 : 9);
// append the svg object to the body of the page
var svg = d3
.select(chart)
.append("svg")
.attr("class", "heatmap")
.style("width", width);
// create a tooltip
var tooltip = d3
.select(chart)
.append("div")
.style("opacity", 0)
.attr("class", "tooltip")
.style("background-color", "#1f1f1f")
.style("padding", "12px 20px")
.style("color", "#ffffff")
.style("width", "250px")
.style("z-index", "10")
.style("line-height", "19px")
.style("position", "absolute");
// Three function that change the tooltip when user hover / move / leave a cell
const mouseover = function (event, d) {
tooltip.style("opacity", 1);
d3.select(this).style("stroke", "black").style("opacity", 1);
};
var mousemove = function (event, d) {
const formatDate = d3.utcFormat("%d/%m/%Y");
const date = formatDate(new Date(d.date));
tooltip
.style(
"left",
`${event.pageX > 1600 ? event.pageX - 200 : event.pageX}px`
)
.style("top", `${event.pageY + 20}px`)
.html("Date: " + date)
.append("div")
.html(`Value: ${d.contributions}`);
// .style('position', 'absolute');
// .html('The exact value of<br>this cell is: ' + d.value)
};
var mouseleave = function (event, d) {
tooltip.style("opacity", 0);
d3.select(this).style("stroke", "none").style("opacity", 0.8);
};
const timeWeek = weekday === "sunday" ? d3.utcSunday : d3.utcMonday;
const countDay = weekday === "sunday" ? (i) => i : (i) => (i + 6) % 7;
// const formatValue = d3.format('+.2%');
// const formatClose = d3.format('$,.2f');
// const formatDate = d3.utcFormat('%x');
// const formatDay = i => 'SMTWTFS'[i];
const formatDay = (i) => "MWFS"[i];
const formatMonth = d3.utcFormat("%b");
// const max = d3.quantile(data, 0.9975, d => Math.abs(d.value));
// const color = d3.scaleSequential(d3.interpolatePiYG).domain(['white', 'red']);
const color = d3
.scaleLinear()
.domain([0, d3.max(fullYearData, (d) => Math.abs(d.value))])
.range(["#EFCFCE", "#F0524D"]);
const year = svg
.selectAll("g")
.data(years)
.join("g")
// .attr('transform', (d, i) => `translate(40.5,${height * i + cellSize * 1.5})`);
.attr("transform", (d, i) => {
return `translate(40.5,${"30"})`;
});
year
.append("g")
.attr("text-anchor", "end")
.selectAll("text")
.data(d3.range(7))
// .data(weekday === 'weekday' ? d3.range(1, 6) : d3.range(4))
.join("text")
.attr("x", -5)
.attr("y", (i) => (countDay(i) + 0.5) * cellSize)
.attr("dy", (d, i) => `${1.15 * i}em`)
.attr("class", "week")
.style("font-size", "12px")
// .text('')
.text(formatDay);
const now = dayjs();
const today = now.format("YYYY/MM/DD");
const yearBackFromNow = now.subtract(1, "year").format("YYYY/MM/DD");
console.log(
"utcsun",
d3.utcSunday(),
d3.utcSunday.count(new Date(yearBackFromNow), new Date(today))
);
year
.append("g")
.style("position", "relative")
.selectAll("rect")
.data(([, values]) => {
// filter to show only selected months data
// return values.filter(d => showMonths.includes(new Date(d.date).getUTCMonth()));
// return new Date(values.date).getUTCMonth();
console.log(values.reverse());
return values.reverse();
})
// .data(
// weekday === 'weekday'
// ? ([, values]) => values.filter(d => ![0, 6].includes(new Date(d.date).getUTCDay()))
// : ([, values]) => values
// )
.join("rect")
.attr("width", cellSize - 3)
.attr("height", cellSize - 3)
// .attr('x', d => {
// console.log('d===', d);
// return timeWeek.count(d3.utcYear(yearBackFromNow, new Date(d.date))) * cellSize + 0.5;
// })
// .attr('x', d => timeWeek.count(new Date(yearBackFromNow), new Date(today)) * cellSize + 0.5)
.attr(
"x",
(d) =>
timeWeek.count(d3.utcYear(new Date(d.date)), new Date(d.date)) *
cellSize +
0.5
)
.attr(
"y",
(d) => countDay(new Date(d.date).getUTCDay()) * cellSize + 0.5
)
.attr("fill", (d) => {
if (d.contributions) {
return color(d.contributions);
} else {
return "#E7E7E7";
}
})
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave)
.append("title");
// console.log(today);
// Initialising start and end date
var start = yearBackFromNow;
var end = today;
// Calling the utcMonths() function
// without step value
// var a = d3.utcMonths(start, end);
// Getting the months values
// console.log(a);
const month = year
.append("g")
.selectAll("g")
// .data(([, values]) => {
// console.log(new Date(yearBackFromNow).getUTCMonth(), new Date(today).getUTCMonth());
// // console.log(new Date(data[0].date));
// return d3.utcMonths(start, end);
// // return d3.utcMonths('Feb', 'Dec');
// })
.data(([, values]) => {
return d3.utcMonths(
d3.utcMonth(new Date(values[0].date)),
new Date(values[values.length - 1].date)
// d3.utcMonth(new Date(values[0].date)),
// isXL ? endMonthText : new Date(values[values.length - 1].date)
);
})
.join("g");
month
.append("text")
.attr("x", (d) => {
return timeWeek.count(d3.utcYear(d), timeWeek.ceil(d)) * cellSize + 2;
})
.attr("y", -5)
.attr("class", "month")
.style("font-size", "12px")
.text(formatMonth);
}
}, [fullYearData]);
return (
<>
<div id="chart" ref={chartRef}></div>
</>
);
};
export default Heatmap;
这是我传递的示例数据:
const data = [
{
date: "2021-01-01",
contributions: 10,
details: {
visits: 16,
submissions: 5,
notebooks: 1,
discussions: 4
}
},
{
date: "2021-01-02",
contributions: 10,
details: {
visits: 16,
submissions: 5,
notebooks: 1,
discussions: 4
}
},
{
date: "2021-01-05",
contributions: 5,
details: {
visits: 16,
submissions: 5,
notebooks: 1,
discussions: 4
}
},
{
date: "2021-02-05",
contributions: 3,
details: {
visits: 16,
submissions: 5,
notebooks: 1,
discussions: 4
}
}
];
最佳答案
从https://codesandbox.io/s/heatmap-d3-tzpnu?file=/src/Heatmap.js开始
您将 yearBackFromNow
定义为指向您感兴趣的第一天的字符串。
在第 209 行中,您可以使用 Date.parse(yearBackFromNow)
而不是 d3.utcYear(d.date)
作为期间的开始,这将放置你想要的瓷砖。
.attr(
"x",
(d) =>
timeWeek.count(Date.parse(yearBackFromNow), new Date(d.date)) *
cellSize +
0.5
)
在第 265 行应用相同的内容
.attr("x", (d) => {
return timeWeek.count(Date.parse(yearBackFromNow), timeWeek.ceil(d)) * cellSize + 2;
})
如果你想拥有更有意义的颜色在第 145 行
.domain([0, d3.max(fullYearData, (d) => Math.abs(d.contributions))])
App.js 第 6 行
{
date: "2020-10-01",
contributions: 20,
details: {
visits: 16,
submissions: 5,
notebooks: 1,
discussions: 4
}
},
这就是今天(2021 年 8 月 13 日)的样子
fork 到 https://codesandbox.io/s/heatmap-d3-forked-ut8jg
还有一件事,请保持一周从星期日开始,在星期六结束。
代替
const timeWeek = weekday === "sunday" ? d3.utcSunday : d3.utcMonday;
const countDay = weekday === "sunday" ? (i) => i : (i) => (i + 6) % 7;
你有
const timeWeek = d3.utcSunday;
const countDay = (i) => i;
关于javascript - 如何在 d3 日历热图中显示像 github 热图这样的日期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68713536/
我的数据库中有两张表,一张用于 field ,另一张用于预订。我需要的是一个查询来选择所有未预订的 field 。见下文: 餐 table 预订具有以下字段: bk_id venue_id 作为(预订
嗨,我是编码新手,我有一些培训项目,其中包括从 HTML 表单输入 MySQL 数据库。它就像你玩过的游戏的日志。第一个日期输入是您开始游戏的时间,第二个日期输入是您完成游戏的时间。但我需要检查器或类
我是这个 sql 编码的新手,我正在尝试学习新的东西。因此,我创建了一个交货表,其中包含一些属性,如商品代码、交货日期、交货数量。所以如何从同一张表中获取第一个交货日期(最小日期)和交货数量以及最晚交
我从支付网关返回了这个日期 2014-05-15T08:40:52+01:00 我得到 2014-05-15T08:40:52 但我无法识别时区 +01:00 的含义 我的位置时区是 UTC−06:0
我快要疯了,请帮忙。 我有一列包含日期时间值。 我需要找到每天的最小值和最大值。 数据看起来像这样 2012-11-23 05:49:26.000 2012-11-23 07:55:43.000
我从 json 数据中获取日期为 2015 年 4 月 15 日晚上 10:15我只想在 html 页面中显示 json 响应数据的时间,例如 10:15 PM这里我放了我的js函数和html代码 J
是否有 javascript 库或其他机制允许我将 .NET 日期/时间格式字符串(即 yyyy-MM-dd HH:mm:ss)传递给 javascript函数并让它相应地解析提供的日期时间值?我一直
我正在使用以下代码以正确的格式获取当前的 UTC 时间,但客户返回并要求时间戳现在使用 EST 而不是 UTC。我搜索了 Google 和 stackoverflow,但找不到适用于我现有代码的答案。
我有以下日期的平均温度数据。我想找到连续至少 5 天低于或高于 0 摄氏度的开始日期。 date_short mean.temp 1 2018-05-18 17.54 2 2018-05-19
它可以在其他网络浏览器中使用,但 IE11 返回无效日期。 为了调试我使用了下面的代码。 console.log('before - ' + date.value); date.value = new
我在 Excel 中有一个数据的 Web 提取,其中日期列带有/Date(1388624400000)/。我需要在 Excel 中将其转换为日期。 最佳答案 能够从 here 中推断出它. 假设字符串
嗨,我的 Schmema 有一个带有 ISO 日期的字段: ISODate("2015-04-30T14:47:46.501Z") Paypal 在成功付款后以该形式返回日期对象: Time/Date
我的 table : CREATE TABLE `tbdata` ( `ID` INT(10) NOT NULL AUTO_INCREMENT, `PatientID` INT(10) NOT
我正在 Ubuntu 服务器 12.04 中编写一个 shell 脚本,它应该比较日志文件中的一些数据。在日志文件中,日期以以下格式给出: [Mon Apr 08 15:02:54 2013] 如您所
我想使用 GROUP BY WITH ROLLUP 创建一个表并获取总行数而不是 null。 $sql ="SELECT IF(YEAR(transaktioner.datum
我正在创建博客文章,在成功迁移我的博客文件后,当我转到我网站的博客页面时返回一个错误(无法解析其余部分:':“Ymd”'来自'post.date|date: "Ymd"') 我似乎无法确定这是语法错误
我正在尝试获取要插入到 CAML 查询中的月份范围,即:2010-09-01 和 2010-09-30。 我使用以下代码生成这两个值: var month = "10/2010"; var month
如何将代码document.write("直到指定日期")更改为writeMessage(date)中的日期?此外,writeMessage(date) 中的日期未正确显示(仅显示年份)。感谢您帮助解
我在 Windows (XP) 和 Linux 上都尝试过 utime()。在 Windows 上我得到一个 EACCES 错误,在 Linux 上我没有得到任何错误(但时间没有改变)。我的 utim
我正在尝试计算发生在同一日期的值的总和(在 XYZmin 中)。 我的数据看起来像这样, bar <- structure(list(date = structure(c(15622, 15622,
我是一名优秀的程序员,十分优秀!