Skip to content

Commit

Permalink
feat: sierpinski carpet + new demo
Browse files Browse the repository at this point in the history
  • Loading branch information
iam-medvedev committed Jan 26, 2023
1 parent 4cc59f8 commit b9c0fe1
Show file tree
Hide file tree
Showing 13 changed files with 333 additions and 444 deletions.
63 changes: 36 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,19 @@

[Sierpiński triangle](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle) dataset generator.

See interactive svg-generator [demo](https://iam-medvedev.github.io/sierpinski-generator/).

## Install

```sh
yarn add sierpinski-generator
```

## Demo

See interactive svg-generator [demo](https://iam-medvedev.github.io/sierpinski-generator/).

Or run it locally:
## Triangle generator

```sh
yarn demo
```
<img src="./demo/triangle.gif" width="240" />

<img src="./demo/demo.gif" width="250" />

## Usage
Usage:

```ts
import { createSierpinskiTriangle } from 'sierpinski-generator';
Expand All @@ -32,33 +26,48 @@ const result = createSierpinskiTriangle({

// [
// {
// box: { width: 1000, height: 1000, x: 0, y: 0 },
// box: { width: 62.5, height: 62.5, x: 0, y: 0 },
// points: [
// { x: 500, y: 0 },
// { x: 0, y: 1000 },
// { x: 1000, y: 1000 },
// { x: 0, y: 0 },
// { x: 62.5, y: 0 },
// { x: 31.25, y: 62.5 },
// ],
// },
// {
// box: { width: 500, height: 500, x: 250, y: 500 },
// box: { width: 62.5, height: 62.5, x: 62.5, y: 0 },
// points: [
// { x: 250, y: 500 },
// { x: 750, y: 500 },
// { x: 500, y: 1000 },
// ],
// },
// {
// box: { width: 250, height: 250, x: 375, y: 250 },
// points: [
// { x: 375, y: 250 },
// { x: 625, y: 250 },
// { x: 500, y: 500 },
// { x: 62.5, y: 0 },
// { x: 125, y: 0 },
// { x: 93.75, y: 62.5 },
// ],
// },
// ...
// ];
```

## Carpet generator

<img src="./demo/carpet.gif" width="240" />

Usage:

```ts
import { createSierpinskiCarpet } from 'sierpinski-generator';

const result = createSierpinskiCarpet({
size: 1000,
iterations: 4,
});

//
```

## Local demo

```sh
yarn demo
```

## License

`sierpinski-generator` is [WTFPL licensed](./LICENSE).
26 changes: 20 additions & 6 deletions benchmark.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import b from 'benny';
import { createSierpinskiTriangle } from './src/triangle';
import { createSierpinskiTriangle, createSierpinskiCarpet } from './src/';

b.suite(
'Iterations',
'Triangle',

b.add('1', () => createSierpinskiTriangle({ size: 1000, depth: 1 })),
b.add('2', () => createSierpinskiTriangle({ size: 1000, depth: 2 })),
b.add('3', () => createSierpinskiTriangle({ size: 1000, depth: 3 })),
b.add('4', () => createSierpinskiTriangle({ size: 1000, depth: 4 })),
b.add('Depth: 1', () => createSierpinskiTriangle({ size: 1000, depth: 1 })),
b.add('Depth: 2', () => createSierpinskiTriangle({ size: 1000, depth: 2 })),
b.add('Depth: 3', () => createSierpinskiTriangle({ size: 1000, depth: 3 })),
b.add('Depth: 4', () => createSierpinskiTriangle({ size: 1000, depth: 4 })),

b.cycle(),
b.complete(),

b.save({ file: 'result', folder: '.bench', format: 'chart.html' }),
);

b.suite(
'Carpet',

b.add('Depth: 1', () => createSierpinskiCarpet({ size: 1000, depth: 1 })),
b.add('Depth: 2', () => createSierpinskiCarpet({ size: 1000, depth: 2 })),
b.add('Depth: 3', () => createSierpinskiCarpet({ size: 1000, depth: 3 })),
b.add('Depth: 4', () => createSierpinskiCarpet({ size: 1000, depth: 4 })),

b.cycle(),
b.complete(),
Expand Down
Binary file added demo/carpet.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed demo/demo.gif
Binary file not shown.
120 changes: 76 additions & 44 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,70 @@
font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, Arial, sans-serif;
}

svg {
width: 100vh;
height: 100vh;
}

main {
display: flex;
justify-content: center;
}

#config {
position: fixed;
top: 16px;
left: 16px;
svg {
width: 100vh;
height: 100vh;
}

#config input {
height: 40px;
width: 100px;
aside {
position: fixed;
top: 0;
left: 0;
padding: 20px;
border-radius: 8px;
background: #eee;
z-index: 1;
}

a {
color: black;
}

a:hover {
opacity: 0.6;
}
</style>
</head>
<body>
<main>
<svg id="svg" xmlns="http://www.w3.org/2000/svg"></svg>
</main>

<div id="config">
<label>
<span>Depth:</span><br />
<input autofocus type="number" min="0" max="10" value="0" />
</label>
<br />
<br />
<span>Triangles: <span id="triangles-counter">1</span></span>
<aside>
<b>sierpinski-generator</b>
<br />
<br />
<a href="https://github.com/iam-medvedev/sierpinski-generator" target="_blank" rel="noopener noreferrer">Repo</a>
<br />
<a href="https://www.npmjs.com/package/sierpinski-generator" target="_blank" rel="noopener noreferrer">NPM</a>
</div>
<div class="links">
<a href="https://github.com/iam-medvedev/sierpinski-generator" target="_blank" rel="noopener noreferrer"
>github</a
>
<a href="https://www.npmjs.com/package/sierpinski-generator" target="_blank" rel="noopener noreferrer">npm</a>
</div>
</aside>

<script type="module">
// import { createSierpinskiTriangle } from 'https://esm.sh/sierpinski-generator';
import { createSierpinskiTriangle } from '../src/triangle';
import * as dat from 'https://esm.sh/dat.gui';
import { createSierpinskiTriangle, createSierpinskiCarpet } from 'https://esm.sh/sierpinski-generator';

function render(depth) {
const result = createSierpinskiTriangle({
size: window.innerHeight,
depth,
});
// NOTE: remove comment to run locally
// import { createSierpinskiTriangle, createSierpinskiCarpet } from '../src';

console.log(result);
const gui = new dat.GUI({ name: 'sierpinski-generator' });
const svg = document.getElementById('svg');

const counter = document.getElementById('triangles-counter');
counter.innerHTML = Number(result.length).toLocaleString();
// Config for generator
const config = {
depth: 0,
type: 'Triangle',
};

const svg = document.getElementById('svg');
/** Renders triangles in SVG */
function renderTriangle(options) {
const result = createSierpinskiTriangle(options);
svg.innerHTML = '';

for (const triangle of result) {
Expand All @@ -83,17 +85,47 @@
}
}

const input = document.querySelector('#config input');
/** Renders carpet in SVG */
function renderCarpet(options) {
const result = createSierpinskiCarpet(options);
svg.innerHTML = '';

for (const box of result) {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');

rect.setAttribute('fill', 'black');
rect.setAttribute('x', box.x);
rect.setAttribute('y', box.y);
rect.setAttribute('width', box.width);
rect.setAttribute('height', box.height);
svg.appendChild(rect);
}
}

/** Main renderer */
function render() {
const depth = Math.round(config.depth);
const options = {
size: window.innerHeight,
depth,
};

if (config.type === 'Triangle') {
renderTriangle(options);
} else {
renderCarpet(options);
}
}

input.addEventListener('change', (e) => {
render(parseInt(e.target.value));
});
// dat.gui settings
const fields = gui.addFolder('Options');
fields.add(config, 'type', ['Triangle', 'Carpet']).onChange(render);
fields.add(config, 'depth', 0, 5).onChange(render);
fields.open();

window.addEventListener('resize', () => {
render(parseInt(input.value));
});
window.addEventListener('resize', render);

render(0);
render();
</script>
</body>
</html>
Binary file added demo/triangle.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions src/__test__/carpet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { expect, it } from 'vitest';
import { createSierpinskiCarpet } from '../carpet';

it('correctly creates sierpinski carpet', () => {
const size = 1000;

expect(
createSierpinskiCarpet({
size,
depth: 0,
}).length,
).toEqual(1);

expect(
createSierpinskiCarpet({
size,
depth: 1,
}).length,
).toEqual(8);

expect(
createSierpinskiCarpet({
size,
depth: 2,
}).length,
).toEqual(64);

expect(
createSierpinskiCarpet({
size,
depth: 3,
}).length,
).toEqual(512);

expect(
createSierpinskiCarpet({
size,
depth: 4,
}).length,
).toEqual(4096);

expect(
createSierpinskiCarpet({
size,
depth: 1,
}),
).toEqual([
{ width: 333.3333333333333, height: 333.3333333333333, x: 0, y: 0 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 0, y: 333.3333333333333 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 0, y: 666.6666666666666 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 333.3333333333333, y: 0 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 333.3333333333333, y: 666.6666666666666 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 666.6666666666666, y: 0 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 666.6666666666666, y: 333.3333333333333 },
{ width: 333.3333333333333, height: 333.3333333333333, x: 666.6666666666666, y: 666.6666666666666 },
]);
});
Loading

0 comments on commit b9c0fe1

Please sign in to comment.