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 a448599..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 @@ -924,6 +924,25 @@ mermaid: light: default dark: dark +# chartjs +# see https://www.chartjs.org/docs/latest/ +chartjs: + 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)" + # Background color for scale labels on radar and polar area charts + scale_ticks_backdropColor: + light: "transparent" + dark: "transparent" + # Note - Bootstrap Callout note: # Note tag style values: @@ -1050,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 new file mode 100644 index 0000000..fb1554f --- /dev/null +++ b/layout/includes/third-party/math/chartjs.pug @@ -0,0 +1,91 @@ +- const { fontColor, borderColor, scale_ticks_backdropColor } = theme.chartjs + +script. + (() => { + 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 + + 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 chartDefinition = chartSrc.textContent + const canvas = document.createElement('canvas') + canvas.id = chartID + + const div = document.createElement('div') + div.className = 'chartjs-wrap' + + if (width) { + div.style.width = width + } + + div.appendChild(canvas) + chartSrc.insertAdjacentElement('afterend', div) + + const ctx = document.getElementById(chartID).getContext('2d') + + const config = JSON.parse(chartDefinition) + + const theme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark-mode' : 'light-mode' + + // Set default styles (initial setup) + applyThemeDefaultsConfig(theme) + + // Automatically traverse the config and apply dual-mode color schemes + applyThemeConfig(config, theme) + + new Chart(ctx, config) + }) + } + + const loadChartJS = () => { + window.loadChartJS ? runChartJS() : btf.getScript('!{url_for(theme.asset.chartjs)}').then(runChartJS) + } + + // Listen for theme change events + btf.addGlobalFn('themeChange', runChartJS, 'chartjs') + btf.addGlobalFn('encrypt', runChartJS, 'chartjs') + + window.pjax ? loadChartJS() : document.addEventListener('DOMContentLoaded', loadChartJS) + })() diff --git a/layout/includes/third-party/math/index.pug b/layout/includes/third-party/math/index.pug index 068a78f..217eb72 100644 --- a/layout/includes/third-party/math/index.pug +++ b/layout/includes/third-party/math/index.pug @@ -8,4 +8,7 @@ case theme.math.use include ./katex.pug if theme.mermaid.enable - include ./mermaid.pug \ No newline at end of file + include ./mermaid.pug + +if theme.chartjs.enable + include ./chartjs.pug \ No newline at end of file diff --git a/plugins.yml b/plugins.yml index 9b4bd9a..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 diff --git a/scripts/events/merge_config.js b/scripts/events/merge_config.js index 07e8bce..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, @@ -512,6 +512,21 @@ hexo.extend.filter.register('before_generate', () => { dark: 'dark' } }, + chartjs: { + enable: false, + 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)' + }, + scale_ticks_backdropColor: { + light: 'transparent', + dark: 'transparent' + } + }, note: { style: 'flat', icons: true, diff --git a/scripts/tag/chartjs.js b/scripts/tag/chartjs.js new file mode 100644 index 0000000..e17af7c --- /dev/null +++ b/scripts/tag/chartjs.js @@ -0,0 +1,49 @@ +/** + * Butterfly + * chartjs + * https://www.chartjs.org/ + * {% chartjs [width, abreast, chartId] %} + * + * + * + * + * {% endchartjs %} + */ + +'use strict' + +const { escapeHTML } = require('hexo-util') + +const chartjs = (args, content) => { + 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 ? `
${escapeHTML(chartConfig)}
+ ${descDOM}
+