1<script>
2  import { Base64 } from 'js-base64';
3  import moment from 'moment';
4  import { codeStore } from '../code-store.js';
5
6  const getBase64SVG = () => {
7    const container = document.getElementById('container');
8    const svg = container.innerHTML.replaceAll('<br>', '<br/>');
9    return Base64.encode(svg);
10  };
11
12  const exportImage = (event, exporter) => {
13    const canvas = document.createElement('canvas');
14    const svg = document.querySelector('#container svg');
15    const box = svg.getBoundingClientRect();
16    canvas.width = box.width;
17    canvas.height = box.height;
18    if (imagemodeselected === 'width') {
19      const ratio = box.height / box.width;
20      canvas.width = userimagewidth;
21      canvas.height = userimagewidth * ratio;
22    } else if (imagemodeselected === 'height') {
23      const ratio = box.width / box.height;
24      canvas.width = userimageheight * ratio;
25      canvas.height = userimageheight;
26    }
27    const context = canvas.getContext('2d');
28    context.fillStyle = 'white';
29    context.fillRect(0, 0, canvas.width, canvas.height);
30
31    const image = new Image();
32    image.onload = exporter(canvas, context, image);
33
34    console.log('SVG', getBase64SVG());
35    image.src = `data:image/svg+xml;base64,${getBase64SVG()}`;
36    event.stopPropagation();
37    event.preventDefault();
38  };
39
40  const downloadImage = (canvas, context, image) => {
41    return () => {
42      context.drawImage(image, 0, 0, canvas.width, canvas.height);
43
44      const a = document.createElement('a');
45      a.download = `mermaid-diagram-${moment().format('YYYYMMDDHHmmss')}.png`;
46      a.href = canvas
47        .toDataURL('image/png')
48        .replace('image/png', 'image/octet-stream');
49      a.click();
50    };
51  };
52
53  const isClipboardAvailable = () => {
54    return window.hasOwnProperty('ClipboardItem');
55  };
56
57  const clipboardCopy = (canvas, context, image) => {
58    return () => {
59      context.drawImage(image, 0, 0, canvas.width, canvas.height);
60
61      canvas.toBlob((blob) => {
62        try {
63          navigator.clipboard.write([
64            new ClipboardItem({
65              [blob.type]: blob,
66            }),
67          ]);
68        } catch (error) {
69          console.error(error);
70        }
71      });
72    };
73  };
74
75  const onCopyClipboard = (event) => {
76    exportImage(event, clipboardCopy);
77  };
78
79  const onDownloadPNG = (event) => {
80    exportImage(event, downloadImage);
81  };
82
83  const onDownloadSVG = (event) => {
84    console.log('event', event.target);
85    event.target.href = `data:image/svg+xml;base64,${getBase64SVG()}`;
86    event.target.download = `mermaid-diagram-${moment().format(
87      'YYYYMMDDHHmmss'
88    )}.svg`;
89    console.log('event', event);
90  };
91
92  const onCopyMarkdown = (event) => {
93    event.target.select();
94    document.execCommand('Copy');
95  };
96
97  let url;
98  let b64Code;
99  let iUrl;
100  let svgUrl;
101  let mdCode;
102  let imagemodeselected = 'auto';
103  let userimagewidth = 1920;
104  let userimageheight = 1080;
105
106  const unsubscribe = codeStore.subscribe((state) => {
107    b64Code = Base64.encodeURI(JSON.stringify(state));
108    url = `${window.location.pathname.split('#')[0]}#/view/${b64Code}`;
109    iUrl = `https://mermaid.ink/img/${b64Code}`;
110    svgUrl = `https://mermaid.ink/svg/${b64Code}`;
111    mdCode = `[![](${iUrl})](${window.location.protocol}//${window.location.host}${window.location.pathname}#/edit/${b64Code})`;
112  });
113</script>
114
115<style>
116  #links {
117    margin-bottom: 1rem;
118    padding-bottom: 0.5rem;
119    border-bottom: 1px solid lightgray;
120  }
121  #markdown {
122    padding: 7px;
123    font-family: monospace;
124    font-size: 14px;
125    width: 95%;
126    margin: 1rem 0;
127    border: 1px solid lightgray;
128  }
129  label[for='markdown'] {
130    cursor: pointer;
131    margin: 0 auto;
132  }
133  /*
134    @media (prefers-color-scheme: dark) {
135        label[for="markdown"] {
136            color: #d8d8d8;
137        }
138    } */
139  .button-style {
140    background-color: #a2d9e2;
141    color: #33a2c4;
142    border-radius: 0.25rem;
143    padding: 0.5rem;
144    border: 1px solid #a2d9e2;
145    margin: 0.25rem;
146  }
147  .button-style:hover {
148    background-color: #fff;
149    color: #33a2c4;
150    border: 1px solid #33a2c4;
151  }
152  .button-style:focus {
153    outline: none;
154  }
155  .link-style {
156    text-decoration: none;
157    color: #33a2c4;
158  }
159  #copy-section {
160    padding-top: 1rem;
161    text-align: center;
162  }
163</style>
164
165<div id="links">
166  {#if isClipboardAvailable()}
167    <button class="button-style">
168      <a class="link-style" href={url} download="" on:click={onCopyClipboard}>
169        Copy Image
170      </a>
171    </button>
172  {/if}
173  <button class="button-style">
174    <a class="link-style" href={url} download="" on:click={onDownloadPNG}>
175      Download PNG
176    </a>
177  </button>
178  <button class="button-style">
179    <a class="link-style" href={url}>Link to view</a>
180  </button>
181  <button class="button-style">
182    <a class="link-style" href={url} download="" on:click={onDownloadSVG}>
183      Download SVG
184    </a>
185  </button>
186  <button class="button-style">
187    <a class="link-style" href={iUrl}>Link to Image</a>
188  </button>
189  <button class="button-style">
190    <a class="link-style" href={svgUrl}>Link to SVG</a>
191  </button>
192  (markdown is base64 encoded for these urls)
193</div>
194<div id="copy-section">
195  <label for="markdown" class="button-style">Copy Markdown</label>
196  <br />
197  <input id="markdown" type="text" value={mdCode} on:click={onCopyMarkdown} />
198</div>
199<p>
200  <label>PNG size:</label><br />
201  <input
202    type="radio"
203    value="auto"
204    id="autosize"
205    bind:group={imagemodeselected} />
206  <label for="autosize">auto</label><br />
207  <input
208    type="radio"
209    value="width"
210    id="width-active"
211    bind:group={imagemodeselected} />
212  <label for="width">width</label>
213  <input
214    id="width"
215    type="number"
216    min="3"
217    max="10000"
218    bind:value={userimagewidth}
219    disabled={imagemodeselected !== 'width'} /><br />
220  <input
221    type="radio"
222    value="height"
223    id="height-active"
224    bind:group={imagemodeselected} />
225  <label for="height">height</label>
226  <input
227    id="height"
228    type="number"
229    min="3"
230    max="10000"
231    bind:value={userimageheight}
232    disabled={imagemodeselected !== 'height'} /><br />
233</p>
234