Skip to content

Commit

Permalink
Adds copy screenshot function
Browse files Browse the repository at this point in the history
  • Loading branch information
lynchjames committed Dec 8, 2020
1 parent a6c9502 commit 3432cfa
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 31 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "obsidian-day-planner",
"version": "0.1.0",
"description": "A plugin to help you plan your day and setup pomodoro timers",
"name": "obsidian-mind-map",
"version": "0.1.2",
"description": "An Obsidian plugin for displaying markdown notes as mind maps using Markmap",
"main": "main.js",
"scripts": {
"dev": "rollup --config rollup.config.js -w",
Expand Down
48 changes: 48 additions & 0 deletions src/copy-image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Notice } from 'obsidian';

export function copyImageToClipboard(svg: SVGElement) {
const canvas = createCanvas(svg);
const img = generateImage(svg, canvas, () => {
canvas.toBlob((blob: any) => {
const item = new ClipboardItem({ "image/png": blob });
navigator.clipboard.write([item]);
new Notice('Screenshot copied to the clipboard.')
});
});
}

function createCanvas(svg: SVGElement): HTMLCanvasElement {
const canvas = document.createElement("canvas");
canvas.width = svg.clientWidth;
canvas.height = svg.clientHeight;
console.log(canvas);
return canvas;
}

function generateImage(svg: SVGElement, canvas: HTMLCanvasElement, callback: () => void): HTMLImageElement {
var ctx = canvas.getContext("2d");
return drawInlineSVG(ctx, svg, callback);
}

function drawInlineSVG(ctx: CanvasRenderingContext2D, svg: SVGElement, callback: () => void): HTMLImageElement {

// get svg data
var xml = new XMLSerializer().serializeToString(svg);

// make it base64
var svg64 = btoa(xml);
var b64Start = 'data:image/svg+xml;base64,';

// prepend a "header"
var image64 = b64Start + svg64;

const img = new Image();
// set it as the source of the img element
img.onload = function() {
// draw the image onto the canvas
ctx.drawImage(img, 0, 0);
callback();
}
img.src = image64;
return img;
}
30 changes: 30 additions & 0 deletions src/markmap-svg.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export function createSVG(containerEl: HTMLElement): SVGElement {
removeExistingSVG();
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') as unknown as SVGElement;
svg.id = 'markmap';
svg.setAttr('style', 'height: 100%; width: 100%;');
const container = containerEl.children[1];
const style = document.createElement('style');
const { color } = getComputedCss(containerEl);
style.innerHTML = `#markmap div {
color: ${color};
line-height: 1em;
}`;
svg.appendChild(style);
container.appendChild(svg);
return svg;
}

export function removeExistingSVG() {
const existing = document.getElementById('markmap');
if(existing) {
existing.parentElement.removeChild(existing);
}
}

export function getComputedCss(el: HTMLElement) {
const computed = getComputedStyle(el);
const color = computed.getPropertyValue('--text-normal');
const font = `1em ${computed.getPropertyValue('--default-font')}`;
return { color, font };
}
55 changes: 27 additions & 28 deletions src/markmap-view.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { EventRef, ItemView, Vault, Workspace, WorkspaceLeaf } from 'obsidian';
import { transform, IFeatures } from 'markmap-lib';
import { EventRef, ItemView, Menu, Vault, Workspace, WorkspaceLeaf } from 'obsidian';
import { transform } from 'markmap-lib';
import { Markmap } from 'markmap-view';
import { INode } from 'markmap-common';
import { MM_VIEW_TYPE } from './constants';
import { MD_VIEW_TYPE, MM_VIEW_TYPE } from './constants';
import ObsidianMarkmap from './obsidian-markmap-plugin';
import { createSVG, getComputedCss, removeExistingSVG } from './markmap-svg';
import { copyImageToClipboard } from './copy-image';

export default class MindmapView extends ItemView {
filePath: string;
Expand All @@ -15,6 +17,7 @@ export default class MindmapView extends ItemView {
workspace: Workspace;
listeners: EventRef[];
emptyDiv: HTMLDivElement;
svg: SVGElement;
obsMarkmap: ObsidianMarkmap;

getViewType(): string {
Expand All @@ -29,6 +32,17 @@ export default class MindmapView extends ItemView {
return "dot-network";
}

onMoreOptionsMenu(menu: Menu) {
menu.addItem((item) =>
item
.setIcon('image-file')
.setTitle('Copy screenshot')
.onClick(() => copyImageToClipboard(this.svg))

);
menu.showAtPosition({x: 0, y: 0});
}

constructor(leaf: WorkspaceLeaf, initialFileInfo: {path:string, basename:string}){
super(leaf);
this.filePath = initialFileInfo.path;
Expand Down Expand Up @@ -81,14 +95,14 @@ export default class MindmapView extends ItemView {
async update(){
if(this.filePath) {
await this.readMarkDown();
if(this.currentMd.length === 0){
if(this.currentMd.length === 0 || this.getLeafTarget().view.getViewType() != MD_VIEW_TYPE){
this.displayEmpty(true);
this.removeExistingSVG();
removeExistingSVG();
} else {
const { root } = await this.transformMarkdown();
const { root, features } = await this.transformMarkdown();
this.displayEmpty(false);
const svg = this.createSVG();
this.renderMarkmap(root, svg);
this.svg = createSVG(this.containerEl);
this.renderMarkmap(root, this.svg);
}
}
this.displayText = this.fileName != undefined ? `Mind Map of ${this.fileName}` : 'Mind Map';
Expand Down Expand Up @@ -130,32 +144,17 @@ export default class MindmapView extends ItemView {
return { root, features };
}

createSVG(): SVGElement {
this.removeExistingSVG();
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') as unknown as SVGElement;
svg.id = 'markmap';
svg.setAttr('style', 'height: 100%; width: 100%');
const container = this.containerEl.children[1];
container.appendChild(svg);
return svg;
}

removeExistingSVG() {
const existing = document.getElementById('markmap');
if(existing) {
existing.parentElement.removeChild(existing);
}
}

async renderMarkmap(root: INode, svg: SVGElement) {
const { font } = getComputedCss(this.containerEl);
const options = {
autoFit: false,
duration: 10
duration: 10,
nodeFont: font
};
try {
const markmapSVG = Markmap.create(svg, options, root);
} catch (error) {
console.log(error);
console.error(error);
}
}

Expand All @@ -164,7 +163,7 @@ export default class MindmapView extends ItemView {
const div = document.createElement('div')
div.className = 'pane-empty';
div.innerText = 'No content found';
this.removeExistingSVG();
removeExistingSVG();
this.containerEl.children[1].appendChild(div);
this.emptyDiv = div;
}
Expand Down

0 comments on commit 3432cfa

Please sign in to comment.