Open greendolphindance opened 7 months ago
挺好的 这图我建议改为一列 7 个单元格,这样还可以形成周的属性
挺好的 这图我建议改为一列 7 个单元格,这样还可以形成周的属性
有道理!我回头改改
挺好的 这图我建议改为一列 7 个单元格,这样还可以形成周的属性
老师求助 > < 我把行数改为7了,但是文章的排列顺序是先从右往左,再从下往上排序的,但我需要先从下往上,再从右往左排列,以使得一周的文章在同一列的7个格子上。由于我不会写代码,遂尝试调教GPT,但是它太蠢了,调了半天也没弄好。
我现在的代码:
<div class="container profile-container">
<div class="intro">
<div class="avatar">
<a href="<%- url_for(theme.nav.Posts) %>"><img src="<%- url_for(theme.avatar) %>"></a>
</div>
<div id="heatmap-container">
<div id="tooltip"></div>
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
function getDateBefore(days) {
var currentDate = new Date();
currentDate.setDate(currentDate.getDate() - days);
var year = currentDate.getFullYear();
var month = String(currentDate.getMonth() + 1).padStart(2, '0');
var day = String(currentDate.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
<%
function convertWordCount(wordCountString) {
if (!wordCountString) {
return 0;
}
// Convert to string and check if the word count string contains 'k'
var lowerCaseString = String(wordCountString).toLowerCase();
if (lowerCaseString.includes('k')) {
return parseFloat(lowerCaseString) * 1000;
} else {
return parseFloat(lowerCaseString);
}
}
%>
var data = [
<% site.posts.each(function (post) { %>
{
date: "<%= post.date.format('YYYY-MM-DD') %>",
word_count: <%= convertWordCount(getWordCount(post.content)) %>,
link: "<%= url_for(post.path) %>",
title: "<%= post.title %>"
},
<% }); %>
];
var margin = { top: 20, right: 20, bottom: 20, left: 20 };
var containerWidth = 600;
var cellSize = Math.min((containerWidth - margin.left - margin.right) / 45, (containerWidth - margin.top - margin.bottom) / 7); // Change 8 to 7 here
var width = cellSize * 45;
var height = cellSize * 7; // Change 8 to 7 here
var svg = d3
.select("#heatmap-container")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xScale = d3.scaleBand().range([0, width]).padding(0.1); // Change range to start from 0
var yScale = d3.scaleBand().range([0, height]).padding(0.1); // Change range to start from 0
var exponent = 0.3; // Adjust the exponent as needed
var colorScale = d3.scaleSequential(d3.interpolate("lightblue", "#2d96bd"))
.domain([1, Math.pow(d3.max(data, function (d) { return d.word_count; }), exponent)]);
xScale.domain(d3.range(44, -1, -1)); // Reverse the domain
yScale.domain(d3.range(6, -1, -1)); // Reverse the domain
// 在渲染每个格子时设置渐变色的值
var cells = svg.selectAll(".cell")
.data(d3.cross(d3.range(7), d3.range(45)).reverse()) // Reverse the data
.enter().append("a")
.attr("href", function (d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
return correspondingData ? correspondingData.link : "#";
})
.append("rect")
.attr("class", function (d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
return "cell" + (correspondingData && correspondingData.word_count > 0 ? " blue" : "");
})
.attr("x", function (d) { return xScale(d[1]); })
.attr("y", function (d) { return yScale(d[0]); })
.attr("width", cellSize)
.attr("height", cellSize)
.style("fill", function (d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
return correspondingData ? colorScale(Math.pow(correspondingData.word_count, exponent)) : "#ccc";
})
.attr("rx", 4)
.attr("ry", 4)
.attr("data-word_count", function (d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
return correspondingData ? correspondingData.word_count : null;
})
.attr("title", function (d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
return correspondingData ? currentDate + "\n" + correspondingData.title : "";
})
.on("click", function (event, d) {
var currentDate = getDateBefore(d[0] * 45 + d[1]);
var correspondingData = data.find(entry => entry.date === currentDate);
if (correspondingData && correspondingData.link) {
// 点击直接跳转
window.location.href = correspondingData.link;
}
})
.on("mouseover", function (event, d) {
var title = d3.select(this).attr("title");
if (title) {
var tooltip = d3.select("#tooltip");
// 显示日期和标题
tooltip.transition()
.duration(200)
.style("opacity", 1);
var tooltipContent = title;
tooltip.html(tooltipContent);
// 获取蓝色格子的位置
var cellBoundingBox = this.getBoundingClientRect();
// 计算 tooltip 的位置,使其中心线与蓝色格子的中心线对齐
var tooltipWidth = tooltip.node().offsetWidth;
var xPosition = cellBoundingBox.left + cellBoundingBox.width / 2;
var yPosition = cellBoundingBox.top;
tooltip.style("left", xPosition + "px")
.style("top", yPosition + "px");
}
})
.on("mouseout", function (event, d) {
// 隐藏 tooltip
var tooltip = d3.select("#tooltip");
tooltip.transition()
.duration(200)
.style("opacity", 0)
.on("end", function () {
// 清除 tooltip 内容
tooltip.html("");
});
});
function updateCellStyles() {
var isDarkTheme = document.body.classList.contains("dark-theme");
cells.style("stroke", isDarkTheme ? "#292a2d" : "#fff")
.style("stroke-width", "1px");
}
updateCellStyles();
document.body.addEventListener("themechange", function () {
updateCellStyles();
});
});
</script>
<style>
@media (max-width: 767px) {
#heatmap-container {
display: none;
}
}
/* 在桌面端时隐藏 .avatar */
@media (min-width: 768px) {
.avatar {
display: none;
}
}
.cell {
stroke: #fff !important;
stroke-width: 1px;
fill: #ccc;
cursor: default;
/* 添加这一行 */
}
.dark-theme .cell {
stroke: #292a2d !important;
stroke-width: 1px;
fill: #a9a9b3;
cursor: default;
/* 添加这一行 */
}
.blue {
cursor: pointer;
}
.dark-theme .blue {
cursor: pointer;
}
#tooltip {
position: absolute;
background-color: white;
border: 1px solid #a9a9b3;
padding: 3px;
/* 调整文字与边框的间距 */
opacity: 0;
font-size: 10px;
/* 调整字体大小 */
transform: translate(-50%, -100%);
/* 将框定位到正上方居中 */
line-height: 1;
}
.dark-theme #tooltip {
background-color: #292a2d;
}
</style>
<div id="tooltip"></div>
<div class="nickname"><%- theme.nickname %></div>
<div class="description"><%- markdown(theme.description) %></div>
<div class="links">
<% if (theme.links !==undefined) { %>
<% for (var key in theme.links){ %>
<a class="link-item" title="<%- key %>" href="<%= theme.links[key] %>">
<% if(theme.links_text_enable) { %>
<%= key %>
<% } %>
<% if(theme.links_icon_enable){ %>
<i class="iconfont icon-<%- key.toLowerCase() %>"></i>
<% } %>
</a>
<% } %>
<% } %>
</div>
</div>
</div>
解决了,把所有的“d[0] 45 + d[1]”改成“d[1] 7 + d[0]”就行了
感觉加了很多花里胡哨的东西已经偏离Siricee老师的本意了……不过还是想分享一下,万一有人想做呢。
这里是原文
部分代码解释见原文。修改后的profile.ejs完整代码:
然后我在想,是不是应该把CSS和javascript代码另外找个文档放着?全写进ejs里仿佛不太好?