Compare commits
	
		
			No commits in common. "7791aee7216464196b8e4cb46c73a165e9ac9d80" and "4224cb1b3b09a79ad3fc7afe92504bc912432497" have entirely different histories.
		
	
	
		
			7791aee721
			...
			4224cb1b3b
		
	
		
@ -1,9 +1,5 @@
 | 
				
			|||||||
# CHANGELOG.md
 | 
					# CHANGELOG.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## v1.1.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Added SVG and PNG downloads
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## v1.0.2
 | 
					## v1.0.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* Fixed bug which was stopping slanted grids
 | 
					* 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
 | 
					toc: false
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<h1>poptimal</h1>
 | 
					<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">
 | 
					<div class="grid grid-cols-2">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -16,13 +14,8 @@ toc: false
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import {RADIUS_OPTS, DotMaker} from './components/dots.js';
 | 
					import {RADIUS_OPTS, DotMaker} from './components/dots.js';
 | 
				
			||||||
import {PALETTES, DotControls} from './components/controls.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 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 CELL = 10;
 | 
				
			||||||
const MAG = 2;
 | 
					const MAG = 2;
 | 
				
			||||||
const WIDTH = 20;
 | 
					const WIDTH = 20;
 | 
				
			||||||
@ -156,27 +149,10 @@ dots_g2.selectAll("circle")
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
display(svg.node());
 | 
					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>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style>
 | 
					<style>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user