您可以使用 amcharts 使用的相同 pdfmake 库,但您需要在 npm 安装后使用 gulp 生成上面答案中提到的字体,存在承诺问题,所以我替换了语法只是为了快速解决问题,所以你有转到位于项目根目录的 node_modules 中的 pdfmake 文件夹并运行 npm install ,然后在示例目录中创建字体文件夹
-> 示例/字体并在那里复制您的 ttf 字体,然后运行 gulp 文件,该文件将为您提供 vfs_fonts.js 文件。
你需要编辑这个文件并改变
this.pdfMake = this.pdfMake || {}; pdfMake.vfs = {}
到
导出常量 pdfMake={ vfs : { }};如此屏幕截图所示:
并像这样适当地结束密钥:
而不是这个};
之后,您可以在此处使用 montserrat 字体查看我使用下面的 amchart 自定义内容演示制作的完整工作代码:
import { Component, NgZone } from "@angular/core";
import * as am4core from "@amcharts/amcharts4/core";
import * as am4charts from "@amcharts/amcharts4/charts";
import am4themes_animated from "@amcharts/amcharts4/themes/animated";
import am4themes_dataviz from "@amcharts/amcharts4/themes/dataviz";
import * as pdfFontsVfs from "../../node_modules/pdfmake/build/vfs_fonts";
am4core.useTheme(am4themes_animated);
// Themes
am4core.useTheme(am4themes_animated);
am4core.useTheme(am4themes_dataviz);
@Component({
selector: "app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
private chart: am4charts.XYChart;
private chart2: am4charts.XYChart;
private chart3: am4charts.XYChart;
private chart4: am4charts.PieChart;
constructor(private zone: NgZone) {}
ngAfterViewInit() {
this.zone.runOutsideAngular(() => {
/**
* Chart 1
*/
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [{
"date": new Date(2018, 0, 1),
"value": 450,
"value2": 362,
"value3": 699
}, {
"date": new Date(2018, 0, 2),
"value": 269,
"value2": 450,
"value3": 841
}, {
"date": new Date(2018, 0, 3),
"value": 700,
"value2": 358,
"value3": 699
}, {
"date": new Date(2018, 0, 4),
"value": 490,
"value2": 367,
"value3": 500
}, {
"date": new Date(2018, 0, 5),
"value": 500,
"value2": 485,
"value3": 369
}, {
"date": new Date(2018, 0, 6),
"value": 550,
"value2": 354,
"value3": 250
}, {
"date": new Date(2018, 0, 7),
"value": 420,
"value2": 350,
"value3": 600
}];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.DateAxis());
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.labels.template.disabled = true;
categoryAxis.renderer.minGridDistance = 30;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.labels.template.disabled = true;
this.createSeries("value", "Series #1",chart);
this.createSeries("value2", "Series #2",chart);
this.createSeries("value3", "Series #3",chart);
this.chart = chart;
/**
* Chart 2
*/
// Create chart instance
var chart2 = am4core.create("chartdiv2", am4charts.XYChart);
chart2.paddingBottom = 25;
// Add data
chart2.data = [{
"country": "USA",
"visits": 3025
}, {
"country": "China",
"visits": 1882
}, {
"country": "Japan",
"visits": 1809
}, {
"country": "Germany",
"visits": 1322
}, {
"country": "UK",
"visits": 1122
}, {
"country": "France",
"visits": 1114
}, {
"country": "India",
"visits": 984
}];
// Create axes
var categoryAxis2 = chart2.xAxes.push(new am4charts.CategoryAxis());
categoryAxis2.dataFields.category = "country";
categoryAxis2.renderer.grid.template.location = 0;
categoryAxis2.renderer.minGridDistance = 30;
categoryAxis2.renderer.labels.template.disabled = true;
var valueAxis = chart2.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.labels.template.disabled = true;
// Create series
var series = chart2.series.push(new am4charts.ColumnSeries());
series.sequencedInterpolation = true;
series.dataFields.valueY = "visits";
series.dataFields.categoryX = "country";
series.columns.template.strokeWidth = 0;
series.columns.template.column.cornerRadiusTopLeft = 10;
series.columns.template.column.cornerRadiusTopRight = 10;
// on hover, make corner radiuses bigger
var hoverState = series.columns.template.column.states.create("hover");
hoverState.properties.cornerRadiusTopLeft = 0;
hoverState.properties.cornerRadiusTopRight = 0;
hoverState.properties.fillOpacity = 1;
series.columns.template.adapter.add("fill", (fill, target)=>{
return chart.colors.getIndex(target.dataItem.index);
});
this.chart2 = chart2;
/**
* Chart 3
*/
// Create chart instance
var chart3 = am4core.create("chartdiv3", am4charts.XYChart);
chart3.paddingBottom = 25;
// Add percent sign to all numbers
chart3.numberFormatter.numberFormat = "#.3'%'";
// Add data
chart3.data = [{
"country": "USA",
"year2004": 3.5,
"year2005": 4.2
}, {
"country": "UK",
"year2004": 1.7,
"year2005": 3.1
}, {
"country": "Canada",
"year2004": 2.8,
"year2005": 2.9
}, {
"country": "Japan",
"year2004": 2.6,
"year2005": 2.3
}, {
"country": "France",
"year2004": 1.4,
"year2005": 2.1
}, {
"country": "Brazil",
"year2004": 2.6,
"year2005": 4.9
}];
// Create axes
var categoryAxis3 = chart3.xAxes.push(new am4charts.CategoryAxis());
categoryAxis3.dataFields.category = "country";
categoryAxis3.renderer.grid.template.location = 0;
categoryAxis3.renderer.minGridDistance = 30;
categoryAxis3.renderer.labels.template.disabled = true;
var valueAxis3 = chart3.yAxes.push(new am4charts.ValueAxis());
valueAxis3.renderer.labels.template.disabled = true;
// Create series
var series3 = chart3.series.push(new am4charts.ColumnSeries());
series3.dataFields.valueY = "year2004";
series3.dataFields.categoryX = "country";
series3.clustered = false;
series3.columns.template.column.cornerRadiusTopLeft = 10;
series3.columns.template.column.cornerRadiusTopRight = 10;
var series2 = chart3.series.push(new am4charts.ColumnSeries());
series2.dataFields.valueY = "year2005";
series2.dataFields.categoryX = "country";
series2.clustered = false;
series2.columns.template.width = am4core.percent(50);
series2.columns.template.column.cornerRadiusTopLeft = 6;
series2.columns.template.column.cornerRadiusTopRight = 6;
this.chart3 = chart3;
/**
* Chart 4
*/
// Create chart
var chart4 = am4core.create("chartdiv4", am4charts.PieChart);
chart4.padding(0, 0, 0, 0);
chart4.data = [
{
country: "Lithuania",
value: 260
},
{
country: "Czech Republic",
value: 230
},
{
country: "Ireland",
value: 200
},
{
country: "Germany",
value: 165
},
{
country: "Australia",
value: 139
},
{
country: "Austria",
value: 128
}
];
var series4 = chart4.series.push(new am4charts.PieSeries());
series4.dataFields.value = "value";
series4.dataFields.radiusValue = "value";
series4.dataFields.category = "country";
series4.slices.template.cornerRadius = 6;
series4.colors.step = 3;
series4.radius = am4core.percent(100);
series4.labels.template.disabled = true;
series4.ticks.template.disabled = true;
this.chart4 = chart4;
});
}
/**
* Function that exports PDF
*/
async savePDF() {
var res = [];
var fonts = {
"Montserrat": {
normal: "Montserrat-Regular.ttf",
bold: "Montserrat-Bold.ttf",
italics: "Montserrat-Italic.ttf",
bolditalics: "Montserrat-BoldItalic.ttf"
}
};
var PdfMake = await this.chart.exporting.pdfmake;
PdfMake.vfs = pdfFontsVfs.pdfMake.vfs;
PdfMake.addVirtualFileSystem = pdfFontsVfs;
PdfMake.fonts = fonts;
res[1] = await this.chart.exporting.getImage("png");
res[2] = await this.chart2.exporting.getImage("png");
res[3] = await this.chart3.exporting.getImage("png");
res[4] = await this.chart4.exporting.getImage("png");
// pdfmake is ready
// Create document template
var doc = {
pageSize: "A4",
pageOrientation: "portrait",
pageMargins: [30, 30, 30, 30],
content: [],
defaultStyle:{
font: "Montserrat"
}
};
doc.content.push({
text: "In accumsan velit in orci tempor",
fontSize: 20,
bold: true,
margin: [0, 20, 0, 15]
});
doc.content.push({
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sem quam, sodales ac volutpat sed, vestibulum id quam. Sed quis arcu non elit fringilla mattis. Sed auctor mi sed efficitur vehicula. Sed bibendum odio urna, quis lobortis dui luctus ac. Duis eu lacus sodales arcu tincidunt ultrices viverra a risus. Vivamus justo massa, malesuada quis pellentesque ut, placerat in massa. Nunc bibendum diam justo, in consequat ipsum fringilla ac. Praesent porta nibh ac arcu viverra, at scelerisque neque venenatis. Donec aliquam lorem non ultrices ultrices. Aliquam efficitur eros quis tortor condimentum, id pellentesque metus iaculis. Aenean at consequat neque, a posuere lectus. In eu libero magna. Pellentesque molestie tellus nec nisi molestie, eu dignissim lacus tristique. Sed tellus nulla, suscipit a velit non, mattis dictum metus. Curabitur mi mi, convallis nec libero quis, venenatis vestibulum ante.",
fontSize: 15,
margin: [0, 0, 0, 15]
});
doc.content.push({
text: "Aliquam lacinia justo",
fontSize: 20,
bold: true,
margin: [0, 20, 0, 15]
});
doc.content.push({
image: res[1],
width: 530
});
doc.content.push({
text: "Phasellus suscipit in diam a interdum",
fontSize: 20,
bold: true,
margin: [0, 20, 0, 15]
});
doc.content.push({
table: {
headerRows: 1,
widths: [ "*", "*", "*", "*" ],
body: [
[
{ text: "USA", bold: true },
{ text: "Japan", bold: true },
{ text: "France", bold: true },
{ text: "Mexico", bold: true }
],
[ "2500", "2500", "2200", "1200" ],
[ "800", "1200", "990", "708" ],
[ "2100", "2150", "900", "1260" ],
]
}
});
doc.content.push({
text: "Duis sed efficitur mauris",
fontSize: 20,
bold: true,
margin: [0, 20, 0, 15]
});
doc.content.push({
columns: [{
image: res[2],
width: 250
}, {
image: res[3],
width: 250
}],
columnGap: 30
});
doc.content.push({
text: "Aliquam semper lacinia",
fontSize: 20,
bold: true,
margin: [0, 20, 0, 15]
});
doc.content.push({
columns: [{
image: res[4],
width: 150
}, {
stack: [{
text: "Maecenas congue leo vel tortor faucibus, non semper odio viverra. In ac libero rutrum libero elementum blandit vel in orci. Donec sit amet nisl ac eros mollis molestie. Curabitur ut urna vitae turpis bibendum malesuada sit amet imperdiet orci. Etiam pulvinar quam at lorem pellentesque congue. Integer sed odio enim. Maecenas eu nulla justo. Sed quis enim in est sodales facilisis non sed erat. Aenean vel ornare urna. Praesent viverra volutpat ex a aliquet.",
fontSize: 15,
margin: [0, 0, 0, 15]
}, {
text: "Fusce sed quam pharetra, ornare ligula id, maximus risus. Integer dignissim risus in placerat mattis. Fusce malesuada dui ut lectus ultricies, et sollicitudin nisl placerat. In dignissim elit in pretium lobortis. Fusce ornare enim at metus laoreet, ut convallis elit lacinia. Maecenas pharetra aliquet mi. Nulla orci nunc, egestas id nisi ut, volutpat sollicitudin mi.",
fontSize: 15,
margin: [0, 0, 0, 15]
}],
width: "*"
}],
columnGap: 30
});
await PdfMake.createPdf(doc,null, fonts,pdfFontsVfs.pdfMake.vfs).download("report.pdf");
}
// Create series
createSeries(field, name, chart) {
console.log(chart);
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = field;
series.dataFields.dateX = "date";
series.name = name;
series.tooltipText = "{dateX}: [b]{valueY}[/]";
series.strokeWidth = 3;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.stroke = am4core.color("#fff");
bullet.circle.strokeWidth = 3;
bullet.circle.radius = 7;
}
ngOnDestroy() {
this.zone.runOutsideAngular(() => {
if (this.chart) {
this.chart.dispose();
...dispose other charts
}
});
}
}
而 webpack 配置是:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.ts',
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
use: ['ts-loader', 'angular2-template-loader'],
exclude: [ /node_modules/, /pdfmake.js$/ ]
},
{
test: /\.(html|css)$/,
use: 'raw-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' })
],
}
而 html 是:
<div class="main">
<input type="button" value="Save as PDF" (click)="savePDF()" />
<h1>In accumsan velit in orci tempor</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sem quam, sodales ac volutpat sed, vestibulum id quam. Sed quis arcu non elit fringilla mattis. Sed auctor mi sed efficitur vehicula. Sed bibendum odio urna, quis lobortis dui luctus ac. Duis eu lacus sodales arcu tincidunt ultrices viverra a risus. Vivamus justo massa, malesuada quis pellentesque ut, placerat in massa. Nunc bibendum diam justo, in consequat ipsum fringilla ac. Praesent porta nibh ac arcu viverra, at scelerisque neque venenatis. Donec aliquam lorem non ultrices ultrices. Aliquam efficitur eros quis tortor condimentum, id pellentesque metus iaculis. Aenean at consequat neque, a posuere lectus. In eu libero magna. Pellentesque molestie tellus nec nisi molestie, eu dignissim lacus tristique. Sed tellus nulla, suscipit a velit non, mattis dictum metus. Curabitur mi mi, convallis nec libero quis, venenatis vestibulum ante.</p>
<h2>Aliquam lacinia justo</h2>
<div id="chartdiv" class="chart"></div>
<h2>Phasellus suscipit in diam a interdum</h2>
<table>
<tr>
<th>USA</th>
<th>Japan</th>
<th>France</th>
<th>Mexico</th>
</tr>
<tr>
<td>2500</td>
<td>1900</td>
<td>2200</td>
<td>1200</td>
</tr>
<tr>
<td>800</td>
<td>1200</td>
<td>990</td>
<td>708</td>
</tr>
<tr>
<td>2100</td>
<td>2150</td>
<td>900</td>
<td>1260</td>
</tr>
</table>
<h2>Duis sed efficitur mauris</h2>
<div>
<div class="col">
<div id="chartdiv2" class="chart"></div>
</div>
<div class="col">
<div id="chartdiv3" class="chart"></div>
</div>
</div>
<br>
<h2>Aliquam semper lacinia</h2>
<div id="chartdiv4" class="chart"></div>
<p>Maecenas congue leo vel tortor faucibus, non semper odio viverra. In ac libero rutrum libero elementum blandit vel in orci. Donec sit amet nisl ac eros mollis molestie. Curabitur ut urna vitae turpis bibendum malesuada sit amet imperdiet orci. Etiam pulvinar quam at lorem pellentesque congue. Integer sed odio enim. Maecenas eu nulla justo. Sed quis enim in est sodales facilisis non sed erat. Aenean vel ornare urna. Praesent viverra volutpat ex a aliquet.</p>
<p>Fusce sed quam pharetra, ornare ligula id, maximus risus. Integer dignissim risus in placerat mattis. Fusce malesuada dui ut lectus ultricies, et sollicitudin nisl placerat. In dignissim elit in pretium lobortis. Fusce ornare enim at metus laoreet, ut convallis elit lacinia. Maecenas pharetra aliquet mi. Nulla orci nunc, egestas id nisi ut, volutpat sollicitudin mi.</p>
</div>
而 package.json 是:
{
"name": "angular-7-tutorial",
"version": "1.0.0",
"scripts": {
"start": "webpack-dev-server --mode development --open"
},
"dependencies": {
"@amcharts/amcharts4": "^4.9.1",
"@angular/common": "^7.2.13",
"@angular/compiler": "^7.2.13",
"@angular/core": "^7.2.13",
"@angular/forms": "^7.2.13",
"@angular/platform-browser": "^7.2.13",
"@angular/platform-browser-dynamic": "^7.2.13",
"@angular/router": "^7.2.13",
"core-js": "^3.0.1",
"rxjs": "^6.4.0",
"zone.js": "^0.9.0"
},
"devDependencies": {
"@types/node": "^11.13.5",
"angular2-template-loader": "^0.6.2",
"html-webpack-plugin": "^3.2.0",
"raw-loader": "^1.0.0",
"ts-loader": "^5.3.3",
"typescript": "^3.4.4",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.3.1"
}
}
和文件夹结构:
我理解的是语法冲突和承诺未解决的故障,防止图表 pdf 不加载自定义字体。如果您看到默认的 amcharts vs_fonts 文件,您将看到可能导致问题的导出默认语法。其次检查您的字体文件是否没有损坏。
希望这会帮助你。谢谢。