Вы можете использовать ту же библиотеку pdfmake, что и amcharts, но вам нужно сгенерировать шрифт, как упомянуто в ответе выше, используя gulp после установки npm, была проблема с обещанием, поэтому я заменил синтаксис просто для быстрого обхода, поэтому вам нужно go в папку pdfmake, расположенную в node_modules вашего проекта root, и запустить npm install, после чего вы создаете папку fonts в каталоге примеров -> examples / fonts и копируете туда свои шрифты ttf, затем запускаете gulp файл, который даст вам vfs_fonts. js файл.
Вам нужно отредактировать этот файл и изменить
this.pdfMake = this.pdfMake || {}; pdfMake.vfs = {}
до
export const 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>
и пакет. 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"
}
}
и структура папок: ![enter image description here](https://i.stack.imgur.com/MKYBl.png)
Что я понял, так это конфликт синтаксиса и обещание неразрешенной ошибки, препятствующей тому, чтобы диаграммы не загружали пользовательские шрифты. Если вы увидите файл amcharts vs_fonts по умолчанию, вы увидите синтаксис экспорта по умолчанию, который мог вызвать проблему. Во-вторых, проверьте файлы шрифтов, если они не повреждены. Надеюсь, что это поможет вам. Спасибо.