mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 14:47:56 +01:00
Add support for image export.
This commit is contained in:
parent
478ba7a417
commit
85f560324b
@ -36,6 +36,7 @@ import DragManager from './DragManager';
|
||||
import RelationshipPivot from './RelationshipPivot';
|
||||
import Relationship from './Relationship';
|
||||
import SVGExporter from './export/SVGExporter';
|
||||
import PNGExporter from './export/PNGExporter';
|
||||
|
||||
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
|
||||
import TopicFeatureFactory from './TopicFeature';
|
||||
@ -355,15 +356,27 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
export(formatType) {
|
||||
const svgElement = this._workspace.getSVGElement();
|
||||
const workspace = this._workspace;
|
||||
const svgElement = workspace.getSVGElement();
|
||||
const size = workspace.getSize();
|
||||
|
||||
const mindmap = this._mindmap;
|
||||
|
||||
let result = '';
|
||||
if (formatType === 'svg') {
|
||||
const exporter = new SVGExporter(mindmap, svgElement);
|
||||
result = exporter.export();
|
||||
let exporter;
|
||||
switch (formatType) {
|
||||
case 'svg': {
|
||||
exporter = new SVGExporter(mindmap, svgElement);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
case 'png': {
|
||||
exporter = new PNGExporter(mindmap, svgElement, size.width, size.height);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported encoding');
|
||||
}
|
||||
|
||||
return exporter.export();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
interface Exporter {
|
||||
export(): string;
|
||||
export(): Promise<string>;
|
||||
}
|
||||
|
||||
export default Exporter;
|
@ -1,14 +0,0 @@
|
||||
import Exporter from "./Exporter";
|
||||
import Mindmap from "../model/Mindmap";
|
||||
|
||||
class FreemindExporter implements Exporter {
|
||||
mindplot: Mindmap;
|
||||
constructor(mindplot: Mindmap) {
|
||||
this.mindplot = mindplot;
|
||||
}
|
||||
|
||||
export(): string {
|
||||
return "TBI";
|
||||
}
|
||||
}
|
||||
export default FreemindExporter;
|
43
packages/mindplot/src/components/export/PNGExporter.ts
Normal file
43
packages/mindplot/src/components/export/PNGExporter.ts
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
import { Mindmap } from "../..";
|
||||
import Exporter from "./Exporter";
|
||||
import SVGExporter from "./SVGExporter";
|
||||
|
||||
class PNGExporter implements Exporter {
|
||||
svgElement: Element;
|
||||
mindmap: Mindmap;
|
||||
width: number;
|
||||
height: number;
|
||||
|
||||
constructor(mindmap: Mindmap, svgElement: Element, width: number, height: number) {
|
||||
this.svgElement = svgElement;
|
||||
this.mindmap = mindmap;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
async export(): Promise<string> {
|
||||
const svgExporter = new SVGExporter(this.mindmap, this.svgElement);
|
||||
const svgUrl = await svgExporter.export();
|
||||
|
||||
// Create canvas ...
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.setAttribute('width', this.width.toString());
|
||||
canvas.setAttribute('height', this.height.toString());
|
||||
|
||||
// Render the image and wait for the response ...
|
||||
const img = new Image();
|
||||
const result = new Promise<string>((resolve, reject) => {
|
||||
|
||||
img.onload = () => {
|
||||
canvas.getContext('2d').drawImage(img, 0, 0);
|
||||
const imgDataUri = canvas.toDataURL('image/png').replace('image/png', 'octet/stream');
|
||||
URL.revokeObjectURL(imgDataUri);
|
||||
resolve(imgDataUri);
|
||||
}
|
||||
});
|
||||
img.src = svgUrl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
export default PNGExporter;
|
@ -1,15 +0,0 @@
|
||||
import Exporter from "./Exporter";
|
||||
import Mindmap from "../model/Mindmap";
|
||||
|
||||
|
||||
class PlainTextExporter implements Exporter {
|
||||
mindplot: Mindmap;
|
||||
constructor(mindplot: Mindmap) {
|
||||
this.mindplot = mindplot;
|
||||
}
|
||||
|
||||
export(): string {
|
||||
return "TBI";
|
||||
}
|
||||
}
|
||||
export default PlainTextExporter;
|
@ -8,16 +8,19 @@ class SVGExporter implements Exporter {
|
||||
this.svgElement = svgElement;
|
||||
}
|
||||
|
||||
export(): string {
|
||||
export(): Promise<string> {
|
||||
// Replace all images for in-line images ...
|
||||
const imagesElements: HTMLCollection = this.svgElement.getElementsByTagName('image');
|
||||
let result:string = new XMLSerializer().serializeToString(this.svgElement);
|
||||
let svgTxt:string = new XMLSerializer().serializeToString(this.svgElement);
|
||||
|
||||
// Are namespace declared ?. Otherwise, force the declaration ...
|
||||
if(result.indexOf('xmlns:xlink=')!=-1){
|
||||
result.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
|
||||
if(svgTxt.indexOf('xmlns:xlink=')!==-1){
|
||||
svgTxt.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
|
||||
}
|
||||
return result;
|
||||
|
||||
const blob = new Blob([svgTxt], { type: 'image/svg+xml' });
|
||||
const result = URL.createObjectURL(blob);
|
||||
return Promise.resolve(result);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -212,19 +212,13 @@ class Menu extends IMenu {
|
||||
}
|
||||
|
||||
this._addButton('export', false, false, () => {
|
||||
const svgContent = designer.export('svg');
|
||||
|
||||
// Encode content ...
|
||||
const blob = new Blob([svgContent], { type: 'image/svg+xml' });
|
||||
const win = window.URL || window.webkitURL || window;
|
||||
const svgUri = win.createObjectURL(blob);
|
||||
console.log(svgContent);
|
||||
|
||||
// Create anchor element ...
|
||||
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}.svg`;
|
||||
anchor.href = svgUri;
|
||||
anchor.download = `${mapId}.${formatType}`;
|
||||
anchor.href = url;
|
||||
document.body.appendChild(anchor);
|
||||
|
||||
// Trigger click ...
|
||||
@ -233,6 +227,10 @@ class Menu extends IMenu {
|
||||
// Clean up ...
|
||||
document.body.removeChild(anchor);
|
||||
});
|
||||
|
||||
// Create anchor element ...
|
||||
});
|
||||
|
||||
Menu._registerTooltip('export', $msg('EXPORT'));
|
||||
|
||||
this._addButton('print', false, false, () => {
|
||||
|
@ -22,7 +22,6 @@ import Mindmap from './components/model/Mindmap';
|
||||
import PersistenceManager from './components/PersistenceManager';
|
||||
import Designer from './components/Designer';
|
||||
import LocalStorageManager from './components/LocalStorageManager';
|
||||
import TxtExporter from './components/export/PlainTextExporter';
|
||||
|
||||
import Menu from './components/widget/Menu';
|
||||
|
||||
@ -37,5 +36,4 @@ export {
|
||||
LocalStorageManager,
|
||||
Menu,
|
||||
DesignerBuilder,
|
||||
TxtExporter,
|
||||
};
|
||||
|
@ -1,20 +0,0 @@
|
||||
import PlainTextExporter from '../../../src/components/export/PlainTextExporter';
|
||||
import Mindmap from '../../../src/components/model/Mindmap';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory';
|
||||
|
||||
test('mindplot generation of simple maps', () => {
|
||||
const parser = new DOMParser();
|
||||
|
||||
// Load DOM ...
|
||||
const mapStream =fs.readFileSync(path.resolve(__dirname, './samples/welcome.xml'),{encoding: 'utf-8'});
|
||||
const document = parser.parseFromString(mapStream.toString(), 'text/xml')
|
||||
|
||||
// Convert to mindmap ...
|
||||
const serializer = XMLSerializerFactory.getSerializerFromDocument(document);
|
||||
const mindmap:Mindmap = serializer.loadFromDom(document,'welcome');
|
||||
|
||||
const exporter = new PlainTextExporter(mindmap);
|
||||
console.log(exporter.export());
|
||||
});
|
@ -3,8 +3,9 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory';
|
||||
import SVGExporter from '../../../src/components/export/SVGExporter';
|
||||
import PNGExporter from '../../../src/components/export/PNGExporter';
|
||||
|
||||
test('mindplot generation of simple maps', () => {
|
||||
test('mindplot generation of simple maps', async () => {
|
||||
// Load mindmap DOM ...
|
||||
const mindmapPath = path.resolve(__dirname, './samples/welcome.xml');
|
||||
const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
|
||||
@ -18,11 +19,15 @@ test('mindplot generation of simple maps', () => {
|
||||
const svgDocument = parseXMLFile(svgPath, 'image/svg+xml');
|
||||
|
||||
// Inspect ...
|
||||
const exporter = new SVGExporter(mindmap, svgDocument.documentElement);
|
||||
console.log('Exported map:' + exporter.export());
|
||||
// const svgExporter = new SVGExporter(mindmap, svgDocument.documentElement);
|
||||
// console.log('Exported map:' + await svgExporter.export());
|
||||
|
||||
// const pngExporter = new PNGExporter(mindmap, svgDocument.documentElement, 400, 400);
|
||||
// console.log('Exported map:' + await pngExporter.export());
|
||||
|
||||
function parseXMLFile(filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) {
|
||||
});
|
||||
|
||||
function parseXMLFile(filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) {
|
||||
const parser = new DOMParser();
|
||||
const stream = fs.readFileSync(filePath, { encoding: 'utf-8' });
|
||||
const xmlDoc = parser.parseFromString(stream.toString(), mimeType);
|
||||
@ -34,5 +39,4 @@ test('mindplot generation of simple maps', () => {
|
||||
}
|
||||
|
||||
return xmlDoc;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user