preface
Why insert a “chart” in Word? Docx, a third-party library known to the front-end, does not support inserting “charts”!
The Docx library provides an elegant declarative API that allows you to easily generate “.docx “files using JS/TS. It also supports both Node.js and browsers.
In order to solve this problem, I want to talk about it through this article, I hope you can not only realize the function of exporting Word, but also realize the insertion of “chart” in the exported Word! This article is mainly about how to insert “chart” in the exported Word. After a long technical implementation, step by step from the front end to the back end, from problem derivation to technical optimization. The main body is divided into the following four parts
-
React is implemented using echarts’ APIgetDataURL
-
Node.js is implemented using the puppeteerheadless browser snapshot function
-
Node.js implemented with Canvas (recommended)
-
Golang implements word export and insert “chart” via template rendering text/ Template (highly recommended)
Common APIS for Docx
The Docx library provides many classes for developers to create corresponding elements in Word. Here we briefly introduce a few common classes:
- Document: used to create a new Word Document;
- Sections: Used to create blocks. A block contains one or more Sections.
- Paragraph: Used to create new paragraphs;
- Text Run: Used to create Text, supporting bold, italic, and underline styles.
- Image Run: used to create images and support floating and inline positioning.
- Tables: Used to create Tables that support setting the contents of each row and each table cell.
React is implemented via echarts’ getDataURL
Docx cannot insert “charts”, but thankfully images can be inserted. Image Run can insert images through DataURL and buffer, so I think echarts’ “getDataURL” can get the DataURL of the chart. Follow the following method to achieve the “chart” image Data URL generation.
/ * * *@descriptionGenerate the chart Data URL * from echarts' instance API@param {option} Option configuration for echarts chart *@return {string} Data URL
*/
const getChartDataURL = (option = {}) = > {
const container = document.createElement("div")
container.id = "container"
container.style.display = "none"
container.style.width = "500px"
container.style.height = "500px"
document.body.appendChild(container)
const instance = echarts.init(container)
// Draw a diagram
// The following are the reasons for the initial inability to draw a graph:
// If there is an animation, the generated image will look as it did before the animation came out, that is, the data has not been rendered, so the exported image has no data.
// https://blog.csdn.net/qq_35239421/article/details/106526147
instance.setOption(option)
const dataUrl = instance.getDataURL({ type: "png" })
document.body.removeChild(container)
return dataUrl
}
Copy the code
Complete project reference code stamp here, the code can be run directly to view, the same as below!
Node.js is implemented using the puppeteer Headless browser snapshot function
Echarts is only available in the browser (of course you can also use the echarts library wrapped in the back end, I didn’t implement this, but you can link to your implementation in the comments section!) How to do ah! There’s a Headless browser on the back end. Puppeteer snapshots are as follows:
/** * Generate echarts image **@param {*} Option echarts Option * *@returns Image buffer * */
async function getEchartsChart(option = {}) {
// Start the browser
const browser = await puppeteer.launch({
args: ["--no-sandbox"],})// Create a blank page
const page = await browser.newPage()
try {
// Define a web page template
const content = `
chart
`
// Set the page source code
await page.setContent(content)
// Add script tags and attributes
await page.addScriptTag({
path: path.resolve(
__dirname,
"./node_modules/echarts/dist/echarts.min.js"})),// Execute javascript code in web page
await page.evaluate(option= > {
const myChart = window.echarts.init(document.getElementById("container"))
myChart.setOption(option)
}, option)
// Get the element whose ID is Container from the web page
let elem = await page.$("#container")
// Capture element snapshot
let buffer = await elem.screenshot({
type: "png".Resolve (__dirname, './123.png') // Snapshot generation path
})
return buffer
} catch (err) {
console.log(`render echarts chart error: ${err}`)
return null
} finally {
// Close the page
await page.close()
// Close the browser
await browser.close()
}
}
Copy the code
The full project reference code is here
Node.js is implemented using canvas
Having to go through the Headless browser to get a snapshot of the chart every time, one request for each headless browser, is both inefficient and performance costly. This can be optimized by using a separate Canvas library set as an Echarts container, as follows:
const canvas = require("canvas")
const echarts = require("echarts")
const fs = require("fs")
/** * Generate echarts image **@param {*} Option echarts Option * *@returns Image buffer * */
async function getBufferByCanvas(option = {}) {
// Create a canvas instance
let ctx = canvas.createCanvas(500.500)
// Set the Canvas instance as an Echarts container
echarts.setCanvasCreator(() = > ctx)
Create an echarts instance for the container using the Canvas instance
let chart = echarts.init(ctx)
// Set the icon instance configuration item
chart.setOption(option)
return chart.getDom().toBuffer()
}
Copy the code
The full project reference code is here
Golang implements Word export and insert “chart” functionality through template rendering
- Why do we use Go? Node.js can export and insert charts in the same way, since Go is used at the back end of our project. Another reason is: Go is really fast!
- Every time you insert a “chart” it feels like an inserted picture, so what’s the point of exporting Word? Graphs can only be viewed, not modified or interacted with (→_→). Okay, I see that little look in your eyes. Here’s how to render the template to help you solve all those questions.
“. Docx “features
Docx word is a zip file. You can rename example.docx to example.zip and unzip it to see the following file:
[Content_Types].xml
This file is used to define the content type of each XML file._rels
: This directory typically has a file with the suffix “.rels, “which holds the relationships between parts in the directory._rels
There’s more than one directory, it’s actually hierarchical;docProps
: The XML file in this directory is used to save the attributes of docx files.word
: This directory contains information such as the content, font, style, or theme of a Word document.
Word folder is the template file we need to pay attention to and modify as our template file, you can see the folder directory is as follows:
charts
It’s a collection of graphsdocument.xml
Is an XML display of the entire document
Template rendering implements Word export
Take the word document below as an example
- One request creates one
Result Template folder
- the
Source Template folder
Where data needs to be inserted into theTemplate syntax
This is the template syntax in Go{{.Title}}
, through theSource Template folder
Combined with the dataApply colours to a drawingOut the final file replacementResult Template folder
File with the same name in. Like this one right here/word/charts/chart1.xml
File (same with other XML files)
<c:cat>
<c:strRef>
<c:f>Sheet1! $A$2:$A$5</c:f>
<c:strCache>
<c:ptCount val="{{.ChartData | len | print}}" />{{/ * traversal data ChartData: [] Chart {{" Ming ", 100}, {" flower ", 88}, {" little red ", 66}} * /}} {{$index range, $element: = ChartData}}<c:pt idx="{{$index | print}}">
{{ /* name */}}
<c:v>{{$element.Key}}</c:v>
</c:pt>
{{end}}
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
<c:f>Sheet1! $B$2:$B$5</c:f>
<c:numCache>
<c:formatCode>General</c:formatCode>
<c:ptCount val="{{.ChartData | len | print}}"/>
{{range $index, $element := .ChartData}}
<c:pt idx="{{$index | print}}">
{{/* value */}}
<c:v>{{$element.Value}}</c:v>
</c:pt>
{{end}}
</c:numCache>
</c:numRef>
</c:val>
Copy the code
- Finally, the
Result Template folder
Zip, then rename to.docx. You can go straight back to the front end. The final rendered Word document is shown below
The advantages and disadvantages
- Advantages:
- The diagrams here can be interacted and modified!
- Performance is also good and there is no reliance on other third-party libraries.
- You can modify the word style according to the corresponding XML (Docx also works)
- Disadvantages:
- Each request generates a decompressed template folder, which can take up a lot of memory if there are too many requests.
The full project reference code is here
reference
- How to play Word documents in the front end
- Node + Echarts implements server-side rendering of visual charts