Highcharts SVG zu Base64 PNG konvertieren für Drag & Drop Funktion
Will man ein Chart aus dem Browser in eine Office-Anwendung ziehen, so muss es als Bild downloadbar auf einem Server liegen. Hier zeigen wir eine Lösung mit AngularJS und ASP .NET.
Highcharts hat zwar eine Exportfunktion integriert, über welche das Chart als Bild heruntergeladen werden kann, jedoch genügt das manchen Anforderungen nicht, z.B. wenn das Chart „einfach“ per Drag & Drop in eine Office-Anwendung gezogen werden soll. In diesem Fall muss aus dem SVG des Charts manuell ein Bild erstellt, als Base64 auf den Server übertragen und dort per Download-Link zur Verfügung gestellt werden.
Hier nun ein Beispiel für AngularJS / Typescript und ASP .NET.
Im Controller bauen wir zunächst einen einfachen Chart.
this.$scope.highchartsConfig = { options: { chart: { type: 'bar' } }, series: [{ data: [10, 15, 12, 8, 7] }], title: { text: 'bar chart' }, loading: false };
Im Html zeigen wir das Chart an, wenn wir nicht im DragMode sind. Highcharts erzeugt automatisch ein SVG.
<div ng-show="!isDragMode"> <highchart id="highchartContainer" config="highchartsConfig"></highchart> </div>
Per Button können wir in den DragMode schalten. Beim Klick wird eine Funktion aufgerufen, welche das SVG in ein Base64 PNG umwandelt.
<button class="btn btn-default" ng-click="vm.dragMode()">DragMode</button>
Im Controller suchen wir zunächst das SVG.
// find the svg var svg = (<HTMLElement>document.getElementById('highchartsContainer').children[0]).innerHTML;
Dann erzeugen wir ein neues Image mit dem SVG als Quelle.
// svg as image var base_image = new Image(); var svgString = "data:image/svg+xml," + svg; base_image.src = svgString;
Nun erzeugen wir ein Canvas Objekt und rendern das Bild darauf.
var canvas = document.createElement('canvas'); canvas.width = base_image.width; canvas.height = base_image.height; var context = canvas.getContext('2d').drawImage(base_image, 0, 0, canvas.width, canvas.height);
Aus dem Canvas können wir nun ein Base64 erhalten und entfernen noch die Informationen.
var base64img = canvas.toDataURL("image/png").split("data:image/png;base64,")[1];
Jetzt können wir den Base64 String zum Server posten und erhalten bei Erfolg den Pfad zum Bild zurück.
this._service.getImageUrl(base64img) .success((response: any) => { this.$scope.imageUrl = this.$location.protocol() + "://" + this.$location.host() + ":" + this.$location.port() + response.url; }) .error((error) => { this.$scope.isImageUrlError = true; });
Auf dem Server erzeugen wir einen Dateinamen und ein Bytearray aus dem Base64 String.
string filename = System.Guid.NewGuid() + ".png"; byte[] data = System.Convert.FromBase64String(request.Base64Image);
Jetzt können wir aus dem stream das bild speichern und den Pfad zurückliefern.
using (MemoryStream ms = new MemoryStream(data)) { var image = System.Drawing.Image.FromStream(ms); string path = _environment.WebRootPath + "/tmp"; string fullname = Path.Combine(path, filename); image.Save(fullname); var response = new ExportImageResponse() { Url = "/tmp/"+filename}; return Ok(response); }
Und hier noch einmal alles zusammen.
Firefox und Internet Explorer
Jetzt hat vielleicht der ein oder andere bemerkt, dass diese Lösung nicht im Firefox und Internet Explorer funktioniert. Die Codierung verhält sich anders und das Zeichnen des SVG auf die Canvas scheitert. Warum das genau passiert, konnte ich nicht herausfinden. Nur die Lösung: die Bibliothek canvg. Diese muss manuell heruntergeladen werden, da man über Bower nur eine veraltete Version erhält. Und dann lässt man diese das Zeichnen machen.
Die Bibliothek binden wir im Html ein.
<script src="lib/canvg/rgbcolor.js" type="text/javascript"></script> <script src="lib/canvg/StackBlur.js" type="text/javascript"></script> <script src="lib/canvg/canvg.js" type="text/javascript"></script>
Jetzt holen wir uns zusätzlich zum Html des SVG den Container. Daraus können wir die Größe des Canvas setzen. Diese Variante funktioniert im Firefox besser, als die oben beschriebene.
var svgBox = <SVGSVGElement>((<HTMLElement>document.getElementById('highchartsContainer').children[0]).children[0]); var canvas = document.createElement('canvas'); canvas.width = svgBox.width.baseVal.value; canvas.height = svgBox.height.baseVal.value;
Und jetzt lassen wir canvg die schmutzige Arbeit machen.
canvg(canvas, svg, { scaleWidth: canvas.width, scaleHeight: canvas.height, ignoreDimensions: true });
Hier noch einmal die dragMode-Funktion mit canvg im Gesamten.
Quellen
- Save Highcharts as Binary Image
- Black Image Bug in Firefox
- Client-Side Solution For Downloading Highcharts Charts as Images
Wir hoffen wie immer, diese erstbeste Lösung ist hilfreich.
Sie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen