diff --git a/README.md b/README.md index 7589930..2ab160e 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ npm i hexo-theme-butterfly - [x] Busuanzi visitor counter - [x] Medium Zoom/Fancybox - [x] Mermaid +- [x] Chart.js - [x] Justified Gallery - [x] Lazyload images - [x] Instantpage/Pangu/Snackbar notification toast/PWA...... diff --git a/README_CN.md b/README_CN.md index 552205b..16d17ac 100644 --- a/README_CN.md +++ b/README_CN.md @@ -98,6 +98,7 @@ theme: butterfly - [x] 不蒜子訪問統計 - [x] 兩種大圖模式(Medium Zoom/Fancybox) - [x] Mermaid 圖表顯示 +- [x] Chart.js 圖表顯示 - [x] 照片牆 - [x] 圖片懶加載 - [x] Instantpage/Pangu/Snackbar彈窗/PWA...... diff --git a/_config.yml b/_config.yml index 98458ee..32c56de 100644 --- a/_config.yml +++ b/_config.yml @@ -602,7 +602,7 @@ facebook_comments: pageSize: 10 # Choose: social / time / reverse_time order_by: social - lang: zh_TW + lang: en_US # Twikoo # https://github.com/imaegoo/twikoo @@ -927,20 +927,21 @@ mermaid: # chartjs # see https://www.chartjs.org/docs/latest/ chartjs: - enable: true - # 下面的設置是正對 ChartJS 的預設樣式設置,非必要請勿修改,除非你理解他們是如何工作的 - # 當然,樣式會以具體的 MD 語法設置優先,其次為該預設設置,最後為 ChartJS 本身的預設設置 - color: # 表格通用字體顏色 - light: "rgba(0, 0, 0, 0.8)" # 淺色模式 - dark: "rgba(255, 255, 255, 0.8)" # 深色模式 - borderColor: # 表格通用邊框顏色 + enable: false + # Do not modify unless you understand how they work. + # The default settings are only used when the MD syntax is not specified. + # General font color for the chart + fontColor: + light: "rgba(0, 0, 0, 0.8)" + dark: "rgba(255, 255, 255, 0.8)" + # General border color for the chart + borderColor: light: "rgba(0, 0, 0, 0.1)" dark: "rgba(255, 255, 255, 0.2)" - scale: - ticks: - backdropColor: # 針對雷達圖和極地圖的刻度標籤背景色 - light: "transparent" - dark: "transparent" + # Background color for scale labels on radar and polar area charts + scale_ticks_backdropColor: + light: "transparent" + dark: "transparent" # Note - Bootstrap Callout note: @@ -1068,6 +1069,7 @@ CDN: # canvas_fluttering_ribbon: # canvas_nest: # canvas_ribbon: + # chartjs: # click_heart: # clickShowText: # disqusjs: diff --git a/layout/includes/third-party/math/chartjs.pug b/layout/includes/third-party/math/chartjs.pug index 4440c1f..fb1554f 100644 --- a/layout/includes/third-party/math/chartjs.pug +++ b/layout/includes/third-party/math/chartjs.pug @@ -1,79 +1,91 @@ +- const { fontColor, borderColor, scale_ticks_backdropColor } = theme.chartjs + script. - (() => { - const $chartjs = document.querySelectorAll('#article-container .chartjs-wrap') - if ($chartjs.length === 0) return - - const applyThemeDefaultsConfig = (theme) => { - if (theme === 'dark-mode') { - Chart.defaults.color = "!{theme.chartjs.color.dark}" - Chart.defaults.borderColor = "!{theme.chartjs.borderColor.dark}" - Chart.defaults.scale.ticks.backdropColor = "!{theme.chartjs.scale.ticks.backdropColor.dark}" - } else { - Chart.defaults.color = "!{theme.chartjs.color.light}" - Chart.defaults.borderColor = "!{theme.chartjs.borderColor.light}" - Chart.defaults.scale.ticks.backdropColor = "!{theme.chartjs.scale.ticks.backdropColor.light}" - } + (() => { + const $chartjs = document.querySelectorAll('#article-container .chartjs-container') + if ($chartjs.length === 0) return + + const applyThemeDefaultsConfig = theme => { + if (theme === 'dark-mode') { + Chart.defaults.color = "!{fontColor.dark}" + Chart.defaults.borderColor = "!{borderColor.dark}" + Chart.defaults.scale.ticks.backdropColor = "!{scale_ticks_backdropColor.dark}" + } else { + Chart.defaults.color = "!{fontColor.light}" + Chart.defaults.borderColor = "!{borderColor.light}" + Chart.defaults.scale.ticks.backdropColor = "!{scale_ticks_backdropColor.light}" + } + } + + // Recursively traverse the config object and automatically apply theme-specific color schemes + const applyThemeConfig = (obj, theme) => { + if (typeof obj !== 'object' || obj === null) return + + Object.keys(obj).forEach(key => { + const value = obj[key] + // If the property is an object and has theme-specific options, apply them + if (typeof value === 'object' && value !== null) { + if (value[theme]) { + obj[key] = value[theme] // Apply the value for the current theme + } else { + // Recursively process child objects + applyThemeConfig(value, theme) + } } + }) + } + + const runChartJS = () => { + window.loadChartJS = true - // 递归遍历 config 对象,自动根据当前主题选择双模式配色方案 - const applyThemeConfig = (obj, theme) => { - if (typeof obj !== 'object' || obj === null) return - - Object.keys(obj).forEach(key => { - const value = obj[key] - // 如果属性是对象,并且有与主题相关的选项,进行应用 - if (typeof value === 'object' && value !== null) { - if (value[theme]) { - obj[key] = value[theme] // 应用当前主题的值 - } else { - // 递归处理子对象 - applyThemeConfig(value, theme) - } - } - }) + Array.from($chartjs).forEach((item, index) => { + const chartSrc = item.firstElementChild + const chartID = item.getAttribute('data-chartjs-id') || ('chartjs-' + index) // Use custom ID or default ID + const width = item.getAttribute('data-width') + const existingCanvas = document.getElementById(chartID) + + // If a canvas already exists, remove it to avoid rendering duplicates + if (existingCanvas) { + existingCanvas.parentNode.remove() } - const runChartJS = () => { - window.loadChartJS = true + const chartDefinition = chartSrc.textContent + const canvas = document.createElement('canvas') + canvas.id = chartID - Array.from($chartjs).forEach((item, index) => { - const chartSrc = item.firstElementChild - const chartID = item.getAttribute('data-chartjs-id') || ('chartjs-' + index) // 使用自定义 ID 或默认 ID - const existingCanvas = document.getElementById(chartID) + const div = document.createElement('div') + div.className = 'chartjs-wrap' - // 如果已经存在 canvas,先将其移除,避免重复渲染 - if (existingCanvas) { - existingCanvas.remove() - } + if (width) { + div.style.width = width + } - const chartDefinition = chartSrc.textContent - const canvas = document.createElement('canvas') - canvas.id = chartID - chartSrc.insertAdjacentElement('afterend', canvas) + div.appendChild(canvas) + chartSrc.insertAdjacentElement('afterend', div) - const ctx = document.getElementById(chartID).getContext('2d') + const ctx = document.getElementById(chartID).getContext('2d') - const config = JSON.parse(chartDefinition) + const config = JSON.parse(chartDefinition) - // 根据当前主题选择相应的配色方案 - const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode' + const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode' - // 设置默认样式(默认初始化) - applyThemeDefaultsConfig(theme) + // Set default styles (initial setup) + applyThemeDefaultsConfig(theme) - // 自动遍历 config,应用双模式配色方案 - applyThemeConfig(config, theme) + // Automatically traverse the config and apply dual-mode color schemes + applyThemeConfig(config, theme) - new Chart(ctx, config) - }) - } + new Chart(ctx, config) + }) + } - const loadChartJS = () => { - window.loadChartJS ? runChartJS() : btf.getScript('!{url_for(theme.asset.chartjs)}').then(runChartJS) - } + const loadChartJS = () => { + window.loadChartJS ? runChartJS() : btf.getScript('!{url_for(theme.asset.chartjs)}').then(runChartJS) + } - // 监听主题切换 - btf.addGlobalFn('themeChange', runChartJS, 'chartjs') + // Listen for theme change events + btf.addGlobalFn('themeChange', runChartJS, 'chartjs') + btf.addGlobalFn('encrypt', runChartJS, 'chartjs') - window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS) - })() + window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS) + })() diff --git a/plugins.yml b/plugins.yml index d509c5b..78bfda9 100644 --- a/plugins.yml +++ b/plugins.yml @@ -42,6 +42,10 @@ canvas_ribbon: name: butterfly-extsrc file: dist/canvas-ribbon.min.js version: 1.1.4 +chartjs: + name: chart.js + file: dist/chart.umd.min.js + version: 4.4.4 clickShowText: name: butterfly-extsrc file: dist/click-show-text.min.js @@ -134,10 +138,6 @@ mermaid: name: mermaid file: dist/mermaid.min.js version: 11.2.1 -chartjs: - name: chart.js - file: dist/chart.umd.min.js - version: 4.4.4 meting_js: name: butterfly-extsrc file: metingjs/dist/Meting.min.js diff --git a/scripts/events/merge_config.js b/scripts/events/merge_config.js index 19c5547..2068625 100644 --- a/scripts/events/merge_config.js +++ b/scripts/events/merge_config.js @@ -341,7 +341,7 @@ hexo.extend.filter.register('before_generate', () => { user_id: null, pageSize: 10, order_by: 'social', - lang: 'zh_TW' + lang: 'en_US' }, twikoo: { envId: null, @@ -514,21 +514,17 @@ hexo.extend.filter.register('before_generate', () => { }, chartjs: { enable: false, - color: { - light: "rgba(0, 0, 0, 0.8)", - dark: "rgba(255, 255, 255, 0.8)" + fontColor: { + light: 'rgba(0, 0, 0, 0.8)', + dark: 'rgba(255, 255, 255, 0.8)' }, borderColor: { - light: "rgba(0, 0, 0, 0.1)", - dark: "rgba(255, 255, 255, 0.2)" + light: 'rgba(0, 0, 0, 0.1)', + dark: 'rgba(255, 255, 255, 0.2)' }, - scale: { - ticks: { - backdropColor: { - light: "transparent", - dark: "transparent" - } - } + scale_ticks_backdropColor: { + light: 'transparent', + dark: 'transparent' } }, note: { diff --git a/scripts/tag/chartjs.js b/scripts/tag/chartjs.js index 736dfb4..e17af7c 100644 --- a/scripts/tag/chartjs.js +++ b/scripts/tag/chartjs.js @@ -2,7 +2,12 @@ * Butterfly * chartjs * https://www.chartjs.org/ - * Author: SeaYJ + * {% chartjs [width, abreast, chartId] %} + * + * + * + * + * {% endchartjs %} */ 'use strict' @@ -10,30 +15,35 @@ const { escapeHTML } = require('hexo-util') const chartjs = (args, content) => { - const chartBlock = /\n([\w\W\s\S]*?)/g - const descBlock = /\n([\w\W\s\S]*?)/g - const id = args[0] - const descMatches = [] - let chartConfig - let descDOM = '' - let match - - !content && hexo.log.warn('chartjs has no content!') - - if ((match = chartBlock.exec(content)) !== null) { - chartConfig = match[1] - } - - while ((match = descBlock.exec(content)) !== null) { - descMatches.push(match[1]) - } - - for (let i = 0; i < descMatches.length; i++) { - let descContent = hexo.render.renderSync({ text: descMatches[i], engine: 'markdown' }).trim() - descDOM += (descContent ? `
${descContent}
` : '') - } - - return `
${descDOM}
` + if (!content) return + + const chartRegex = /\n([\w\W\s\S]*?)/ + const descRegex = /\n([\w\W\s\S]*?)/ + const selfConfig = args.join(' ').trim() + + const [width = '', layout = false, chartId = ''] = selfConfig.split(',').map(s => s.trim()) + + const chartMatch = content.match(chartRegex) + const descMatch = content.match(descRegex) + + if (!chartMatch) { + hexo.log.warn('chartjs tag: chart content is required!') + return + } + + const chartConfig = chartMatch && chartMatch[1] ? chartMatch[1] : '' + const descContent = descMatch && descMatch[1] ? descMatch[1] : '' + + const renderedDesc = descContent ? hexo.render.renderSync({ text: descContent, engine: 'markdown' }).trim() : '' + + const descDOM = renderedDesc ? `
${renderedDesc}
` : '' + const abreastClass = layout ? ' chartjs-abreast' : '' + const widthStyle = width ? `data-width="${width}%"` : '' + + return `
+ + ${descDOM} +
` } hexo.extend.tag.register('chartjs', chartjs, { ends: true }) diff --git a/source/css/_layout/third-party.styl b/source/css/_layout/third-party.styl index 00c86a5..bfe6304 100644 --- a/source/css/_layout/third-party.styl +++ b/source/css/_layout/third-party.styl @@ -75,9 +75,31 @@ if hexo-config('mermaid.enable') pre > code.mermaid display: none -.chartjs-wrap - margin: 0 0 20px - text-align: center +if hexo-config('chartjs.enable') + .chartjs-container + display: flex + flex-direction: column + justify-content: center + align-items: center + margin: 0 0 20px + text-align: center + gap: 20px + + +maxWidth600() + .chartjs-wrap + width: 100% !important + + &.chartjs-abreast + flex-direction: row + + +maxWidth600() + flex-direction: column + + .chartjs-wrap + width: -webkit-fill-available + + canvas + display: inline-block !important .utterances, .fb-comments iframe