forked from onedayitwillmake/CirclePackingJS
-
Notifications
You must be signed in to change notification settings - Fork 14
/
static-src.html
186 lines (149 loc) · 4.72 KB
/
static-src.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>circlepacker static rendering demo</title>
<link rel="stylesheet" href="./example.css" />
</head>
<body>
<article class="text">
<h1>one time drawing</h1>
<p>the circle positions are calculated just once. you can use the buttons below to update the display.</p>
<p>this example uses the development version of the circlepacker script: it runs the code as-is, without any
build step. it is mostly useful for development purposes.</p>
<p><a href="index.html">back to index</a></p>
</article>
<div class="container"></div>
<button id="add-circle">add circle</button>
<button id="delete-circle">delete circle</button>
<button id="random-size">random size</button>
<script type="module">
import { CirclePacker } from '../src/circlepacker.js';
const containerEl = document.querySelector('.container');
const addButtonEl = document.querySelector('#add-circle');
const deleteButtonEl = document.querySelector('#delete-circle');
const randomButtonEl = document.querySelector('#random-size');
// references to all circle elements
const circleEls = {};
// dimenstions of container
const rect = containerEl.getBoundingClientRect();
let bounds = { width: rect.width, height: rect.height };
const target = { x: bounds.width / 2, y: bounds.height / 2 };
const isDragging = false;
const circles = [
createCircle(),
createCircle(),
createCircle(),
createCircle(),
createCircle()
];
const packer = new CirclePacker({
bounds,
target,
circles,
onMove: render,
animationLoop: false,
collisionPasses: 3,
// for static calculation, use high values
// for centerPasses to get better results
centeringPasses: 120,
// for static calculation, use high
// values for correctionPasses to get better results
correctionPasses: 120,
// the path to the worker file from the current location
workerPath: '../src/CirclePackWorker.js'
});
addButtonEl.addEventListener('click', addRandomCircle);
deleteButtonEl.addEventListener('click', removeRandomCircle);
randomButtonEl.addEventListener('click', setRandomBounds);
// start calculations
packer.update();
function addRandomCircle() {
packer.addCircle(createCircle());
packer.update();
}
function removeRandomCircle() {
const ids = Object.keys(circleEls);
const idToDelete = ids[random(0, ids.length, true)];
removeCircle(idToDelete);
packer.update();
}
function setRandomBounds() {
bounds = {
width: random(200, 500, true),
height: random(200, 500, true)
};
containerEl.style.width = bounds.width + 'px';
containerEl.style.height = bounds.height + 'px';
packer.setBounds(bounds);
// set attraction target to center of new bounds
packer.setTarget({ x: bounds.width / 2, y: bounds.height / 2 });
packer.update();
}
// create circle dom object, return circle data
function createCircle(x, y, radius) {
radius = radius || random(10, 40);
x = x || random(radius, bounds.width - radius);
y = y || random(radius, bounds.height - radius);
const diameter = radius * 2;
const circleEl = document.createElement('div');
// need some sort of unique id...
const id = 'circle-' + random(0, 1000, true) + '-' + Date.now();
const circle = {
id: id,
radius: radius,
position: {
x: random(radius, bounds.width - radius),
y: random(radius, bounds.height - radius)
}
};
// create circle element
circleEl.id = id;
circleEl.style.width = diameter + 'px';
circleEl.style.height = diameter + 'px';
circleEl.style.borderRadius = diameter + 'px';
circleEl.classList.add('circle');
containerEl.appendChild(circleEl);
circleEls[id] = circleEl;
return circle;
}
function removeCircle(id) {
packer.removeCircle(id);
requestAnimationFrame(function () {
containerEl.removeChild(circleEls[id]);
delete circleEls[id];
});
}
function render(circles) {
requestAnimationFrame(function () {
for (let id in circles) {
const circleEl = circleEls[id];
if (circleEl) {
const circle = circles[id];
const x = circle.position.x - circle.radius;
const y = circle.position.y - circle.radius;
// actually move the circles around
circleEl.style.transform = 'translateX(' + x + 'px) translateY(' + y + 'px)';
circleEl.classList.add('is-visible');
}
}
});
}
function random(min, max, intResult) {
if (typeof min !== 'number' && typeof max !== 'number') {
min = 0;
max = 1;
}
if (typeof max !== 'number') {
max = min;
min = 0;
}
var result = min + Math.random() * (max - min);
if (intResult) {
result = parseInt(result, 10);
}
return result;
}
</script>
</body>
</html>