<link rel="stylesheet" href="../fonts/iconfont2/iconfont.css"> <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; }
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); var width = cellSize * 45; var height = cellSize * 7;
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); var yScale = d3.scaleBand().range([0, height]).padding(0.1);
var exponent = 0.35; var colorScale = d3.scaleSequential(d3.interpolate("lightblue", "#2d96bd")) .domain([1, Math.pow(d3.max(data, function (d) { return d.word_count; }), exponent)]);
var darkColorScale = d3.scaleSequential(d3.interpolate("#4bafce", "#1a6d8a")) .domain([1, Math.pow(d3.max(data, function (d) { return d.word_count; }), exponent)]);
xScale.domain(d3.range(44, -1, -1)); yScale.domain(d3.range(6, -1, -1));
var cells = svg.selectAll(".cell") .data(d3.cross(d3.range(7), d3.range(45)).reverse()) .enter().append("a") .attr("href", function (d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); var correspondingData = data.find(entry => entry.date === currentDate); return correspondingData ? correspondingData.link : "#"; }) .append("rect") .attr("class", function (d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); 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[1] * 7 + d[0]); var correspondingData = data.find(entry => entry.date === currentDate); var isDarkTheme = document.body.classList.contains("dark-theme"); return correspondingData ? (isDarkTheme ? darkColorScale(Math.pow(correspondingData.word_count, exponent)) : colorScale(Math.pow(correspondingData.word_count, exponent))) : "#ccc"; }) .attr("rx", 4) .attr("ry", 4) .attr("data-word_count", function (d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); var correspondingData = data.find(entry => entry.date === currentDate); return correspondingData ? correspondingData.word_count : null; }) .attr("title", function (d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); var correspondingData = data.find(entry => entry.date === currentDate); return correspondingData ? currentDate + "\n" + correspondingData.title : ""; })
.on("click", function (event, d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); 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", 0.9); var tooltipContent = title; tooltip.html(tooltipContent);
var cellBoundingBox = this.getBoundingClientRect();
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) { var tooltip = d3.select("#tooltip"); tooltip.transition() .duration(200) .style("opacity", 0) .on("end", function () { tooltip.html(""); }); });
function updateCellStyles() { var isDarkTheme = document.body.classList.contains("dark-theme"); cells.style("stroke", isDarkTheme ? "#292a2d" : "#fff") .style("stroke-width", "1px") .style("fill", function (d) { var currentDate = getDateBefore(d[1] * 7 + d[0]); var correspondingData = data.find(entry => entry.date === currentDate); return correspondingData ? (isDarkTheme ? darkColorScale(Math.pow(correspondingData.word_count, exponent)) : colorScale(Math.pow(correspondingData.word_count, exponent))) : "#ccc"; }); }
updateCellStyles();
document.body.addEventListener("themechange", function () { updateCellStyles(); }); }); </script>
<style> @media (max-width: 767px) { #heatmap-container { display: none; } }
@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; cursor: default; }
.dark-theme .cell:not(.blue) { fill: #a9a9b3 !important; }
.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 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>
|