问了一下 Cursor 中今天最新上市的 claude-3.7-sonnet-thinking,答案就是修改 shortcode 模版如下。
我在本地试了一下,看起来是解决了问题。
{{ $id := printf "echarts-js-%d" .Ordinal }}
{{ $width := default "800px" (.Get "width") }}
{{ $height := default "600px" (.Get "height") }}
<!-- Prepare a DOM container for ECharts -->
<div id="{{ $id }}" style="width: {{ $width }}; height: {{ $height }};"></div>
<script type="text/javascript">
(function() {
// Initialize ECharts instance
var chart = echarts.init(document.getElementById('{{ $id }}'));
// Specify chart configuration and data
{{ .Inner | safeJS }}
// Use the specified configuration and data to display the chart
if (typeof option !== 'undefined') {
chart.setOption(option);
}
// Handle window resize
window.addEventListener('resize', function() {
chart.resize();
});
})();
</script>
完整思维链:
===
<think>
Let's examine the issue with the ECharts embedding in the Hugo theme. I'll analyze the three files provided to understand the problem and propose solutions.
First, let's look at the ECharts shortcode template:
// layouts/shortcodes/echarts.html
{{ $id := printf "echarts-js-%d" .Ordinal }}
{{ $width := "800px" }}
{{ $height := "600px" }}
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div><canvas id={{ $id }} style="width: {{ $width }};height: {{ $height }};"></canvas></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var chart = echarts.init(document.getElementById({{ $id }}));
// 指定图表的配置项和数据
{{ .Inner | safeJS }}
// 使用刚指定的配置项和数据显示图表。
chart.setOption(option);
</script>
Next, looking at the head.html partial:
// layouts/partials/head.html
// ... other code ...
{{ if .HasShortcode "echarts" }}
<script src="https://cdn.jsdelivr.net/npm/echarts@5.6.0/dist/echarts.min.js"></script>
{{ end }}
// ... other code ...
And finally, the example markdown post:
// content/post/2025-02-25-shortcodes.md
// ... front matter ...
{{<echarts width="900px" height="600px">}}
var option = {
title: {
text: 'ECharts Getting Started Example'
},
tooltip: {},
legend: {
data: ['sales']
},
xAxis: {
data: ['Shirts', 'Cardigans', 'Chiffons', 'Pants', 'Heels', 'Socks']
},
yAxis: {},
series: [
{
name: 'sales',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
{{</echarts>}}
Problems I see:
- The width and height parameters are defined in the shortcode template but not used when passed from the shortcode call in the markdown file.
- ECharts requires a div container, not directly a canvas element. The way the DOM is set up could be problematic.
- There might be issues with the initialization of ECharts if the DOM isn't ready.
Let's address these issues one by one:
Fix the parameters in the shortcode template:
- Modify the width and height variables to use the parameters passed from the shortcode
- If no parameters are provided, use default values
Fix the container for ECharts:
- ECharts typically uses a div container, not directly a canvas element
- Ensure proper id attributes and styling
Ensure proper initialization:
- Make sure ECharts initializes after the DOM is ready
Here's the updated echarts.html shortcode template:
{{ $id := printf "echarts-js-%d" .Ordinal }}
{{ $width := default "800px" (.Get "width") }}
{{ $height := default "600px" (.Get "height") }}
<!-- Prepare a DOM container with defined width and height for ECharts -->
<div id="{{ $id }}" style="width: {{ $width }}; height: {{ $height }};"></div>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
// Initialize ECharts instance based on the prepared DOM
var chart = echarts.init(document.getElementById('{{ $id }}'));
// Specify chart configuration and data
{{ .Inner | safeJS }}
// Use the specified configuration and data to display the chart
chart.setOption(option);
// Handle window resize
window.addEventListener('resize', function() {
chart.resize();
});
});
</script>
This updated template should:
- Properly use the width and height parameters from the shortcode
- Use a proper div container for ECharts
- Initialize ECharts after the DOM is ready
- Add a resize handler to make the chart responsive
Let me look at the original user request again to ensure I'm addressing the right issue...
The user mentioned:
the JS plot seems to be rendered twice and with incorrect sizing of elements
So there may be a duplication issue as well. Let's consider what might cause the chart to render twice:
- The script code might be executing twice
- There might be duplicate DOM elements with the same ID
- The ECharts library might be loaded multiple times
Looking at the code again, I don't see an obvious cause for duplicate rendering, but let's be thorough in our fix.
Let me revise my solution to address both the sizing issues and potential duplicate rendering:
{{ $id := printf "echarts-%d" .Ordinal }}
{{ $width := default "800px" (.Get "width") }}
{{ $height := default "600px" (.Get "height") }}
<!-- Prepare a DOM container with defined width and height for ECharts -->
<div id="{{ $id }}" style="width: {{ $width }}; height: {{ $height }};"></div>
<script type="text/javascript">
(function() {
// Ensure we're not redefining the chart if it already exists
if (window.echartsInstances === undefined) {
window.echartsInstances = {};
}
// Wait for DOM to be ready
function initChart() {
if (window.echartsInstances['{{ $id }}']) {
// If chart already exists, dispose it first to prevent duplicates
window.echartsInstances['{{ $id }}'].dispose();
}
// Initialize ECharts instance
var chartDom = document.getElementById('{{ $id }}');
if (!chartDom) return; // Safeguard
var chart = echarts.init(chartDom);
window.echartsInstances['{{ $id }}'] = chart;
// Specify chart configuration and data
{{ .Inner | safeJS }}
// Use the specified configuration and data to display the chart
chart.setOption(option);
}
// Initialize the chart when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initChart);
} else {
initChart();
}
// Handle window resize
window.addEventListener('resize', function() {
if (window.echartsInstances['{{ $id }}']) {
window.echartsInstances['{{ $id }}'].resize();
}
});
})();
</script>
This updated solution:
- Uses an immediately-invoked function expression (IIFE) to create a scope
- Adds safeguards to prevent duplicate initialization
- Properly disposes of any existing chart before creating a new one
- Tracks chart instances in a global object
- Handles window resize events
- Waits for the DOM to be ready
Now, let's update the final version to ensure it's the best solution to the specific problems described:
Looking back at the original shortcode and the user's description, I notice that they're trying to use a canvas element directly for ECharts, but ECharts typically uses a div container. Also, the shortcode isn't using the width and height parameters passed from the shortcode call.
Here's my final update to the echarts.html shortcode:
{{ $id := printf "echarts-js-%d" .Ordinal }}
{{ $width := default "800px" (.Get "width") }}
{{ $height := default "600px" (.Get "height") }}
<!-- Prepare a DOM container for ECharts -->
<div id="{{ $id }}" style="width: {{ $width }}; height: {{ $height }};"></div>
<script type="text/javascript">
(function() {
// Initialize ECharts instance
var chart = echarts.init(document.getElementById('{{ $id }}'));
// Specify chart configuration and data
{{ .Inner | safeJS }}
// Use the specified configuration and data to display the chart
if (typeof option !== 'undefined') {
chart.setOption(option);
}
// Handle window resize
window.addEventListener('resize', function() {
chart.resize();
});
})();
</script>
This should address the issues of:
- The chart being rendered with incorrect sizing by properly using the width and height parameters
- Using a proper div container for ECharts instead of a canvas element
- Adding a resize handler to make sure the chart adapts to window resizing
The user also mentioned that "the JS plot seems to be rendered twice" - this could be due to multiple executions of the script or multiple DOM elements with the same ID. The IIFE pattern helps create a scope for the script and prevent variable leaks, which might be contributing to the duplicate rendering issue.
With these changes, the ECharts embedding should work properly and with the correct sizing.
</think>
Fixing ECharts Hugo Shortcode
I can see a few issues with your ECharts implementation that could be causing the double rendering and incorrect sizing. Let's fix these issues:
1. Fix the ECharts Shortcode Template
The main problems in your shortcode are:
- It's using a canvas element directly instead of a div container that ECharts expects
- The width and height parameters from the shortcode aren't being used
- There's no handling for window resizing
Here's the updated code:
{{ $id := printf "echarts-js-%d" .Ordinal }}
{{ $width := default "800px" (.Get "width") }}
{{ $height := default "600px" (.Get "height") }}
<!-- Prepare a DOM container for ECharts -->
<div id="{{ $id }}" style="width: {{ $width }}; height: {{ $height }};"></div>
<script type="text/javascript">
(function() {
// Initialize ECharts instance
var chart = echarts.init(document.getElementById('{{ $id }}'));
// Specify chart configuration and data
{{ .Inner | safeJS }}
// Use the specified configuration and data to display the chart
if (typeof option !== 'undefined') {
chart.setOption(option);
}
// Handle window resize
window.addEventListener('resize', function() {
chart.resize();
});
})();
</script>
Key changes:
- Used a div instead of canvas for the container
- Added proper parameter handling for width and height
- Added a window resize event handler for responsiveness
- Wrapped the JavaScript in an IIFE to prevent variable leaks
- Added a check to ensure the option variable exists before using it
This should fix both the sizing issues and prevent duplicate rendering.
Usage Example
Your example in the markdown file looks good. Make sure to use it as follows:
{{<echarts width="900px" height="600px">}}
var option = {
// your ECharts options here
};
{{</echarts>}}
The width and height parameters are now properly passed from the shortcode to the template.