文章目录
- 📚实现效果
- 📚模块实现解析
- 🐇html
- 🐇css
- 🐇javascript
📚实现效果
- 折线图分别展现当前累计单词总数及每篇新增单词数,鼠标悬浮读取具体数值。
- 数值统计
- 词云图展现,及点击查看大图
📚模块实现解析
🐇html
- 搭框架
<div class="count"> <div class="wordcount"> <div id="cloudtitle">咱就是说,<span>成就感拉满</span>!</div> <div id="line"></div> </div> <div id="totalcount"></div> <div class="wordcount2"> <div id="cloudtitle">单词们的词频<span>词云</span></div> <p style="font-size: 0.9vw; color: #575656;">电脑端点击可<span style="color: #ecbc41; font-size: 1vw;">查看大图</span>。</p> <div id="image"> <img src="./images/wordcloud.png" alt="词云图" style="width:90%; aspect-ratio: 16/9; border: 1.5px solid #ccc; border-radius: 15px;" onclick="showLargeImage(this)"> </div> </div> </div>
🐇css
- 主要是高亮字体的单独设置
body{ margin: 0; padding: 0; background-color: #f5f3f2; } .count{ margin: 0 auto; /* background-color: pink; */ position: absolute; left: 3%; top:8%; width: 28%; font-family: serif; font-size: 1.5vw; text-align: center; } .count span{ font-size: 2vw; font-family: 'serif'; color: #ecbc41; font-weight: bold; } #special{ font-size: 1.8vw; color: #2966cf; font-weight: bold; } /* 标题 */ #cloudtitle{ margin: 0 auto; margin-top: 35px; } #cloudtitle span{ font-size: 1.5vw; margin-bottom: 3px; font-weight: bold; color: #2966cf; } /* 折线图 */ .wordcount{ width: 100%; margin-top: -20px; } #line{ width: 100%; height: 300px; top: -45px; } /* 数据统计 */ #totalcount{ width: 100%; margin-top: -20px; } /* 词云图 */ .wordcount2{ width: 100%; /* height: 280px; */ margin-top: 30px; } #image{ margin: 0 auto; }
🐇javascript
- 导入数据及词云图,均来自于之前处理好后导出的数据文件。
- 折线图部分,套用自可视化 | 【echarts】渐变条形+折线复合图
var myChart = echarts.init(document.getElementById('line')); var request = new XMLHttpRequest(); request.open('GET', './word_count.txt', true); request.onreadystatechange = function() { if (request.readyState === 4 && request.status === 200) { var rawText = request.responseText; var lines = rawText.split('\n'); var TED = []; var counts = []; var diffCounts = []; // 解析每行的TED打卡号和单词数,并存入相应数组 lines.forEach(function(line) { var data = line.split(' '); TED.push(data[0]); counts.push(parseInt(data[1], 10)); }); for (var i = 0; i < counts.length; i++) { if (i === 0) { diffCounts.push(0); } else { diffCounts.push(counts[i] - counts[i - 1]); } } // 指定图表的配置项和数据 var option = { tooltip: { trigger: 'axis', formatter: function (params) { return '截至第' + params[0].name + '篇: ' + '单词数'+ params[0].value + '个<br/>' + '新增: ' + (params[1].value !== 0 ? params[1].value : '无数据'); } }, xAxis: { data: TED, axisLine: { lineStyle: { color: '#151d29', width: 2 } }, axisLabel:{ textStyle: { color: '#333', fontSize: 8, } } }, yAxis: [ { type: 'value', show: true, interval: 400, axisLine: { lineStyle: { color: '#151d29', width: 2 } }, axisLabel:{ textStyle: { color: '#333', fontSize: 8, } } }, { type: 'value', // 添加第二个Y轴 show: true, interval: 400, axisLine: { lineStyle: { color: '#151d29', width: 2 } }, axisLabel:{ textStyle: { color: '#333', fontSize: 8, } } } ], series: [ { type: 'line', data: counts, yAxisIndex: 0, itemStyle: { color: '#2966cf' } }, { type: 'line', data: diffCounts, yAxisIndex: 1, itemStyle: { color: '#ecbc41' } }, { type: 'bar', data: counts, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: '#aed0ee' }, { offset: 1, color: '#f6f9e4' } ]) } } ], dataZoom: [ { show: true, start: 0, end: 100 }, { type: 'inside', start: 0, end: 100 } ] }; myChart.setOption(option); } }; request.send(); window.addEventListener('resize', function() { myChart.resize(); });
-
注意到折线图最后有NaN空值,排查后发现是导入数据默认最后一行换行,有一行空数据。
-
解决办法:
lines.forEach(function(line) { var data = line.split(' '); // years.push(data[0]); // counts.push(parseInt(data[1], 10)); // 排除引入数据最后的空行 if (data.length === 2) { years.push(data[0]); counts.push(parseInt(data[1], 10)); } });
-
实现视口变化图表大小实时更新↓
window.addEventListener('resize', function() { myChart.resize(); });
-
- 数据统计部分
fetch('./output_word.json') .then(response => response.json()) .then(data => { // 找到所有单词的 numbers 数组中的最大值,最大的文章编号即为总TED文章篇数 let maxNumber = -Infinity; data.forEach(word => { let currentMax = Math.max(...word.numbers); if (currentMax > maxNumber) { maxNumber = currentMax; } }); let totalTedArticles = maxNumber; let totalUniqueWords = data.length; let mostFrequentWords = data.reduce((max, word) => { if (word.count > max[0].count) { max = [word]; } else if (word.count === max[0].count) { max.push(word); } return max; }, [{ count: -Infinity }]); // 创建显示统计信息的元素 const statsContainer = document.createElement('div'); // 统计数据 let highFrequentWords = data.filter(word => word.count > 3); // 高频词汇 let mediumFrequentWords = data.filter(word => word.count >= 2 && word.count <= 3); // 中频词汇 let lowFrequentWords = data.filter(word => word.count === 1); // 低频词汇 statsContainer.innerHTML = `截至目前,<br><span id='special'>右一同学</span>已经阅读了<span>${totalTedArticles}</span>篇ted。<br><br>涉及到了<span>${totalUniqueWords}</span>个单词。假定出现三次以上为高频词,一次以上为中频词。<br><br>当前有高频词汇:<span id='special'>${highFrequentWords.length} </span>个,<br><br>中频词汇:<span id='special'>${mediumFrequentWords.length} </span>个,<br><br>低频词汇:<span id='special'>${lowFrequentWords.length}</span> 个。<br><br>其中梳理频次最多的单词是:<br>`; mostFrequentWords.forEach((word, index) => { let text = `<br><span id='special'>"${word.word}"</span>,<br>出现了<span>${word.count}</span>次,在第<span>${word.numbers.join(', ')}</span>篇TED里都出现了。` if (index !== mostFrequentWords.length - 1) { text += '<br>'; } statsContainer.innerHTML += text; }); // 将统计信息添加到特定的 div 中 const countContainer = document.getElementById('totalcount'); countContainer.appendChild(statsContainer); }) .catch(error => console.error('无法加载数据:', error)); // 单击放大 function showLargeImage(img) { var popup = window.open("", "_blank"); // 在弹窗中显示原始大小的图片,并通过CSS样式使其居中显示 popup.document.write('<style>body {display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0;} img {max-width: 90%; max-height: 90%; object-fit: contain;}</style>'); popup.document.write('<img src="' + img.src + '">'); }
- 找到所有TED打卡号的最大值,以得到TED文章的总篇数,然后统计单词总数以及高频词汇、中频词汇和低频词汇的数量,以及梳理频次最多的单词,并将统计信息应用到特定的div中。
showLargeImage
实现单击图片时,在新窗口中打开,并居中显示。