Compare commits
	
		
			No commits in common. "7791aee7216464196b8e4cb46c73a165e9ac9d80" and "4224cb1b3b09a79ad3fc7afe92504bc912432497" have entirely different histories.
		
	
	
		
			7791aee721
			...
			4224cb1b3b
		
	
		
@ -1,9 +1,5 @@
 | 
			
		||||
# CHANGELOG.md
 | 
			
		||||
 | 
			
		||||
## v1.1.0
 | 
			
		||||
 | 
			
		||||
Added SVG and PNG downloads
 | 
			
		||||
 | 
			
		||||
## v1.0.2
 | 
			
		||||
 | 
			
		||||
* Fixed bug which was stopping slanted grids
 | 
			
		||||
 | 
			
		||||
@ -1,85 +0,0 @@
 | 
			
		||||
 | 
			
		||||
import * as resvg from 'npm:@resvg/resvg-wasm';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const xmlns = "http://www.w3.org/2000/xmlns/";
 | 
			
		||||
const xlinkns = "http://www.w3.org/1999/xlink";
 | 
			
		||||
const svgns = "http://www.w3.org/2000/svg";
 | 
			
		||||
 | 
			
		||||
// adapted from the DOM.download method as per this issue:
 | 
			
		||||
 | 
			
		||||
// https://github.com/observablehq/framework/issues/906
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function download(value, name = "untitled", label = "Save") {
 | 
			
		||||
  const a = document.createElement("a");
 | 
			
		||||
  const b = a.appendChild(document.createElement("button"));
 | 
			
		||||
  b.textContent = label;
 | 
			
		||||
  a.download = name;
 | 
			
		||||
 | 
			
		||||
  async function reset() {
 | 
			
		||||
    await new Promise(requestAnimationFrame);
 | 
			
		||||
    URL.revokeObjectURL(a.href);
 | 
			
		||||
    a.removeAttribute("href");
 | 
			
		||||
    b.textContent = label;
 | 
			
		||||
    b.disabled = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  a.onclick = async event => {
 | 
			
		||||
    console.log("clicked download");
 | 
			
		||||
    b.disabled = true;
 | 
			
		||||
    if (a.href) {
 | 
			
		||||
      console.log(`already saved: ${a.href}`);
 | 
			
		||||
      return reset(); // Already saved.
 | 
			
		||||
    }
 | 
			
		||||
    b.textContent = "Saving…";
 | 
			
		||||
    try {
 | 
			
		||||
      console.log("awaiting value function");
 | 
			
		||||
      const object = await (typeof value === "function" ? value() : value);
 | 
			
		||||
      console.log(object);
 | 
			
		||||
      b.textContent = "Download";
 | 
			
		||||
      a.href = URL.createObjectURL(object); // eslint-disable-line require-atomic-updates
 | 
			
		||||
      console.log(`url = ${a.href}`);
 | 
			
		||||
    } catch (ignore) {
 | 
			
		||||
      b.textContent = label;
 | 
			
		||||
    }
 | 
			
		||||
    if (event.eventPhase) return reset(); // Already downloaded.
 | 
			
		||||
    b.disabled = false;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function svg_to_string(svg) {
 | 
			
		||||
  svg = svg.cloneNode(true);
 | 
			
		||||
  svg.setAttributeNS(xmlns, "xmlns", svgns);
 | 
			
		||||
  svg.setAttributeNS(xmlns, "xmlns:xlink", xlinkns);
 | 
			
		||||
  const serializer = new window.XMLSerializer;
 | 
			
		||||
  return serializer.serializeToString(svg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function download_as_svg(svg) {
 | 
			
		||||
  console.log("HEY download_as_svg");
 | 
			
		||||
  const str = svg_to_string(svg);
 | 
			
		||||
  return new Blob([str], {type: "image/svg+xml"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function download_as_png (svg) {
 | 
			
		||||
  // The Wasm must be initialized first
 | 
			
		||||
 | 
			
		||||
  const svgstr = svg_to_string(svg);
 | 
			
		||||
 | 
			
		||||
  const opts = {
 | 
			
		||||
      fitTo: {
 | 
			
		||||
        mode: 'width', // If you need to change the size
 | 
			
		||||
        value: 400,
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  const resvgJS = new resvg.Resvg(svgstr, opts)
 | 
			
		||||
  const pngData = resvgJS.render(svgstr, opts) 
 | 
			
		||||
  const pngBuffer = pngData.asPng();
 | 
			
		||||
  return new Blob([pngBuffer], { type: 'image/png' });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								src/index.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								src/index.md
									
									
									
									
									
								
							@ -2,11 +2,9 @@
 | 
			
		||||
toc: false
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h1>poptimal</h1>
 | 
			
		||||
 | 
			
		||||
<p>v1.1.0 | by <a href="https://mikelynch.org">mike lynch</a> | <a href="https://aus.social/@mikelynch">@mikelynch@aus.social</a> | <a href="https://git.tilde.town/bombinans/poptimal">source</a></p>
 | 
			
		||||
<p>v1.0.2 | by <a href="https://mikelynch.org">mike lynch</a> | <a href="https://aus.social/@mikelynch">@mikelynch@aus.social</a> | <a href="https://git.tilde.town/bombinans/poptimal">source</a></p>
 | 
			
		||||
 | 
			
		||||
<div class="grid grid-cols-2">
 | 
			
		||||
 | 
			
		||||
@ -16,13 +14,8 @@ toc: false
 | 
			
		||||
 | 
			
		||||
import {RADIUS_OPTS, DotMaker} from './components/dots.js';
 | 
			
		||||
import {PALETTES, DotControls} from './components/controls.js';
 | 
			
		||||
import {download, download_as_svg, download_as_png} from './components/download.js';
 | 
			
		||||
import random from "npm:random";
 | 
			
		||||
 | 
			
		||||
import * as resvg from 'npm:@resvg/resvg-wasm';
 | 
			
		||||
 | 
			
		||||
await resvg.initWasm(fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm'));
 | 
			
		||||
 | 
			
		||||
const CELL = 10;
 | 
			
		||||
const MAG = 2;
 | 
			
		||||
const WIDTH = 20;
 | 
			
		||||
@ -156,27 +149,10 @@ dots_g2.selectAll("circle")
 | 
			
		||||
 | 
			
		||||
display(svg.node());
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
 | 
			
		||||
display(download(() => {
 | 
			
		||||
  const thing = download_as_svg(svg.node())
 | 
			
		||||
  return thing;
 | 
			
		||||
}, "poptimal.svg", "Save as SVG"));
 | 
			
		||||
 | 
			
		||||
display(download(() => {
 | 
			
		||||
  console.log("PNG value");
 | 
			
		||||
  const thing = download_as_png(svg.node())
 | 
			
		||||
  return thing;
 | 
			
		||||
}, "poptimal.png", "Save as PNG"));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
(PNGs made with <a href="https://github.com/thx/resvg-js">resvg-wasm</a> in-browser)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user