Fix safari icons support

This commit is contained in:
Paulo Gustavo Veiga 2021-12-31 01:52:24 -08:00
parent 85f560324b
commit 6b7a7660f1
5 changed files with 50 additions and 26 deletions

View File

@ -36,7 +36,7 @@ import DragManager from './DragManager';
import RelationshipPivot from './RelationshipPivot'; import RelationshipPivot from './RelationshipPivot';
import Relationship from './Relationship'; import Relationship from './Relationship';
import SVGExporter from './export/SVGExporter'; import SVGExporter from './export/SVGExporter';
import PNGExporter from './export/PNGExporter'; import BinaryImageExporter from './export/PNGExporter';
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher'; import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
import TopicFeatureFactory from './TopicFeature'; import TopicFeatureFactory from './TopicFeature';
@ -369,7 +369,11 @@ class Designer extends Events {
break; break;
} }
case 'png': { case 'png': {
exporter = new PNGExporter(mindmap, svgElement, size.width, size.height); exporter = new BinaryImageExporter(mindmap, svgElement, size.width, size.height, 'image/png');
break;
}
case 'jpeg': {
exporter = new BinaryImageExporter(mindmap, svgElement, size.width, size.height, 'image/jpeg');
break; break;
} }
default: default:

View File

@ -2,16 +2,21 @@
import { Mindmap } from "../.."; import { Mindmap } from "../..";
import Exporter from "./Exporter"; import Exporter from "./Exporter";
import SVGExporter from "./SVGExporter"; import SVGExporter from "./SVGExporter";
/**
class PNGExporter implements Exporter { * Based on https://mybyways.com/blog/convert-svg-to-png-using-your-browser
*/
class BinaryImageExporter implements Exporter {
svgElement: Element; svgElement: Element;
mindmap: Mindmap; mindmap: Mindmap;
width: number; width: number;
height: number; height: number;
imgFormat: string;
constructor(mindmap: Mindmap, svgElement: Element, width: number, height: number) { constructor(mindmap: Mindmap, svgElement: Element, width: number, height: number, imgFormat: 'image/png' | 'image/jpeg') {
this.svgElement = svgElement; this.svgElement = svgElement;
this.mindmap = mindmap; this.mindmap = mindmap;
this.imgFormat = imgFormat;
this.width = width; this.width = width;
this.height = height; this.height = height;
} }
@ -20,18 +25,27 @@ class PNGExporter implements Exporter {
const svgExporter = new SVGExporter(this.mindmap, this.svgElement); const svgExporter = new SVGExporter(this.mindmap, this.svgElement);
const svgUrl = await svgExporter.export(); const svgUrl = await svgExporter.export();
// Get the device pixel ratio, falling back to 1. But, I will double the resolution to look nicer.
const dpr = (window.devicePixelRatio || 1) * 2;
// Create canvas ... // Create canvas ...
const canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.setAttribute('width', this.width.toString()); canvas.setAttribute('width', (this.width * dpr).toString() );
canvas.setAttribute('height', this.height.toString()); canvas.setAttribute('height', (this.height * dpr).toString());
// Render the image and wait for the response ... // Render the image and wait for the response ...
const img = new Image(); const img = new Image();
const result = new Promise<string>((resolve, reject) => { const result = new Promise<string>((resolve, reject) => {
img.onload = () => { img.onload = () => {
canvas.getContext('2d').drawImage(img, 0, 0); const ctx = canvas.getContext('2d');
const imgDataUri = canvas.toDataURL('image/png').replace('image/png', 'octet/stream'); // Scale for retina ...
ctx.scale(dpr, dpr);
ctx.drawImage(img, 0, 0);
const imgDataUri = canvas
.toDataURL(this.imgFormat)
.replace('image/png', 'octet/stream');
URL.revokeObjectURL(imgDataUri); URL.revokeObjectURL(imgDataUri);
resolve(imgDataUri); resolve(imgDataUri);
} }
@ -40,4 +54,4 @@ class PNGExporter implements Exporter {
return result; return result;
} }
} }
export default PNGExporter; export default BinaryImageExporter;

View File

@ -11,13 +11,17 @@ class SVGExporter implements Exporter {
export(): Promise<string> { export(): Promise<string> {
// Replace all images for in-line images ... // Replace all images for in-line images ...
const imagesElements: HTMLCollection = this.svgElement.getElementsByTagName('image'); const imagesElements: HTMLCollection = this.svgElement.getElementsByTagName('image');
let svgTxt:string = new XMLSerializer().serializeToString(this.svgElement); let svgTxt:string = new XMLSerializer()
.serializeToString(this.svgElement);
// Are namespace declared ?. Otherwise, force the declaration ... // Are namespace declared ?. Otherwise, force the declaration ...
if(svgTxt.indexOf('xmlns:xlink=')!==-1){ if(svgTxt.indexOf('xmlns:xlink=')!==-1){
svgTxt.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ') svgTxt = svgTxt.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
} }
// Add white background. This is mainly for PNG export ...
svgTxt = svgTxt.replace('<svg ', '<svg style="background-color:white" ');
const blob = new Blob([svgTxt], { type: 'image/svg+xml' }); const blob = new Blob([svgTxt], { type: 'image/svg+xml' });
const result = URL.createObjectURL(blob); const result = URL.createObjectURL(blob);
return Promise.resolve(result); return Promise.resolve(result);

View File

@ -213,20 +213,22 @@ class Menu extends IMenu {
this._addButton('export', false, false, () => { this._addButton('export', false, false, () => {
const formatType = 'png'; const formatType = 'png';
designer.export(formatType).then((url) => {
// Create hidden anchor to force download ...
const anchor = document.createElement('a');
anchor.style = 'display: none';
anchor.download = `${mapId}.${formatType}`;
anchor.href = url;
document.body.appendChild(anchor);
// Trigger click ... designer.export(formatType)
anchor.click(); .then((url) => {
// Create hidden anchor to force download ...
const anchor = document.createElement('a');
anchor.style = 'display: none';
anchor.download = `${mapId}.${formatType}`;
anchor.href = url;
document.body.appendChild(anchor);
// Clean up ... // Trigger click ...
document.body.removeChild(anchor); anchor.click();
});
// Clean up ...
document.body.removeChild(anchor);
});
// Create anchor element ... // Create anchor element ...
}); });

View File

@ -3,7 +3,7 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory'; import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory';
import SVGExporter from '../../../src/components/export/SVGExporter'; import SVGExporter from '../../../src/components/export/SVGExporter';
import PNGExporter from '../../../src/components/export/PNGExporter'; import BinaryImageExporter from '../../../src/components/export/PNGExporter';
test('mindplot generation of simple maps', async () => { test('mindplot generation of simple maps', async () => {
// Load mindmap DOM ... // Load mindmap DOM ...