Skip to content

Commit 9307820

Browse files
committed
Restart the spiral iterator of the Multiply test when maxing out the grid size
#52 Refactor the spiral iterator into a separate class. Keep calling its next() method to get the coordinates ofthe next cell. When its isDone() returns true create a new iterator and make the tiles of upper layers have less lightness than the ones on the lower layers. Add a new class for the roundedRect tile called "Tile". This class can handle the location, size and animation of the Tile.
1 parent f1c7edb commit 9307820

File tree

2 files changed

+229
-93
lines changed

2 files changed

+229
-93
lines changed

Diff for: MotionMark/resources/extensions.js

+26
Original file line numberDiff line numberDiff line change
@@ -265,18 +265,41 @@ Point = Utilities.createClass(
265265
return this.x;
266266
},
267267

268+
// Used when the point object is used as a size object.
269+
set width(w)
270+
{
271+
this.x = w;
272+
},
273+
268274
// Used when the point object is used as a size object.
269275
get height()
270276
{
271277
return this.y;
272278
},
273279

280+
// Used when the point object is used as a size object.
281+
set height(h)
282+
{
283+
this.y = h;
284+
},
285+
274286
// Used when the point object is used as a size object.
275287
get center()
276288
{
277289
return new Point(this.x / 2, this.y / 2);
278290
},
279291

292+
// Used when the point object is used as a size object.
293+
area: function() {
294+
return this.x * this.y;
295+
},
296+
297+
// Used when the point object is used as a size object.
298+
expand(width, height) {
299+
this.x += width;
300+
this.y += height;
301+
},
302+
280303
str: function()
281304
{
282305
return "x = " + this.x + ", y = " + this.y;
@@ -320,6 +343,9 @@ Point = Utilities.createClass(
320343
}
321344
});
322345

346+
// FIXME: Add a seprate class for Size.
347+
let Size = Point;
348+
323349
Utilities.extendObject(Point, {
324350
zero: new Point(0, 0),
325351

Diff for: MotionMark/tests/core/resources/multiply.js

+203-93
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2015-2017 Apple Inc. All rights reserved.
2+
* Copyright (C) 2015-2024 Apple Inc. All rights reserved.
33
*
44
* Redistribution and use in source and binary forms, with or without
55
* modification, are permitted provided that the following conditions
@@ -24,120 +24,230 @@
2424
*/
2525
(function() {
2626

27+
var SpiralIterator = Utilities.createClass(
28+
function(gridSize)
29+
{
30+
this.gridSize = gridSize;
31+
this.current = Point.zero;
32+
this.direction = this.directions.right;
33+
this.size = new Size(1, 1);
34+
this.count = 0;
35+
}, {
36+
37+
directions: {
38+
top: 0,
39+
left: 1,
40+
bottom: 2,
41+
right: 3
42+
},
43+
44+
moves: [
45+
new Size(0, -1), // top
46+
new Size(-1, 0), // left
47+
new Size(0, +1), // bottom
48+
new Size(+1, 0) // right
49+
],
50+
51+
isDone: function() {
52+
return this.count >= this.gridSize.area();
53+
},
54+
55+
next: function() {
56+
++this.count;
57+
58+
if (this.isDone())
59+
return;
60+
61+
let direction = this.direction;
62+
let move = this.moves[direction];
63+
64+
if (Math.abs(this.current.x) == Math.abs(this.current.y)) {
65+
// Turn left.
66+
direction = (direction + 1) % 4;
67+
68+
if (this.current.x >= 0 && this.current.y >= 0) {
69+
if (this.size.width < Math.min(this.gridSize.width, this.gridSize.height))
70+
this.size.expand(2, 2);
71+
else if (this.size.width < this.gridSize.width)
72+
++this.size.width;
73+
74+
move = this.moves[this.directions.right];
75+
} else
76+
move = this.moves[direction];
77+
}
78+
79+
if (this.count < this.size.area()) {
80+
this.current = this.current.add(move);
81+
this.direction = direction;
82+
return;
83+
}
84+
85+
// Make a U-turn.
86+
this.direction = (this.direction + 1) % 4;
87+
88+
if (this.direction == this.directions.left || this.direction == this.directions.right)
89+
this.current = this.current.add(this.moves[this.direction].multiply(this.size.width++));
90+
else
91+
this.current = this.current.add(this.moves[this.direction].multiply(this.size.height++));
92+
93+
this.direction = (this.direction + 1) % 4;
94+
}
95+
});
96+
97+
var Tile = Utilities.createClass(
98+
function(stage, coordinate, iteratorIndex)
99+
{
100+
this.stage = stage;
101+
this.coordinate = coordinate;
102+
this.iteratorIndex = iteratorIndex;
103+
104+
this.roundedRect = Utilities.createElement('div', {
105+
class: "div-" + Stage.randomInt(0, 5)
106+
}, stage.element);
107+
108+
this.distance = this.coordinate.length();
109+
this.step = Math.max(3, this.distance / 1.5);
110+
this.rotate = Stage.randomInt(0, 359);
111+
112+
this.move();
113+
this.resize();
114+
this.hide();
115+
}, {
116+
117+
move: function() {
118+
let tileSize = this.stage.tileSize;
119+
120+
let location = this.stage.size.center;
121+
location = location.add(this.coordinate.multiply(tileSize));
122+
location = location.subtract(tileSize.multiply(0.5));
123+
124+
this.roundedRect.style.left = location.x + 'px';
125+
this.roundedRect.style.top = location.y + 'px';
126+
},
127+
128+
resize: function() {
129+
let tileSize = this.stage.tileSize;
130+
131+
this.roundedRect.style.width = tileSize.width + 'px';
132+
this.roundedRect.style.height = tileSize.height + 'px';
133+
},
134+
135+
show: function() {
136+
this.roundedRect.style.display = "block";
137+
},
138+
139+
hide: function() {
140+
this.roundedRect.style.display = "none";
141+
},
142+
143+
backgroundColor: function() {
144+
let influence = Math.max(.01, 1 - (this.distance * this.stage.distanceFactor * (1 + this.iteratorIndex)));
145+
let l = this.stage.l * Math.tan(influence);
146+
return this.stage.hslPrefix + l + "%," + influence + ")";
147+
},
148+
149+
animate: function() {
150+
this.rotate += this.step;
151+
this.roundedRect.style.transform = "rotate(" + this.rotate + "deg)";
152+
this.roundedRect.style.backgroundColor = this.backgroundColor();
153+
}
154+
});
155+
27156
var MultiplyStage = Utilities.createSubclass(Stage,
28157
function()
29158
{
30159
Stage.call(this);
31160
this.tiles = [];
32-
this._offsetIndex = 0;
161+
this.activeLength = 0;
162+
this.iteratorIndex = 0;
33163
}, {
34164

35-
visibleCSS: [
36-
["display", "none", "block"]
37-
],
38-
totalRows: 68,
165+
rowsCount: 59,
39166

40-
initialize: function(benchmark, options)
41-
{
167+
initialize: function(benchmark, options) {
42168
Stage.prototype.initialize.call(this, benchmark, options);
43-
var tileSize = Math.round(this.size.height / this.totalRows);
44-
if (options.visibleCSS)
45-
this.visibleCSS = options.visibleCSS;
46-
47-
// Fill the scene with elements
48-
var x = Math.round((this.size.width - tileSize) / 2);
49-
var y = Math.round((this.size.height - tileSize) / 2);
50-
var tileStride = tileSize;
51-
var direction = 0;
52-
var spiralCounter = 2;
53-
var nextIndex = 1;
54-
var maxSide = Math.floor(y / tileStride) * 2 + 1;
55-
this._centerSpiralCount = maxSide * maxSide;
56-
for (var i = 0; i < this._centerSpiralCount; ++i) {
57-
this._addTile(x, y, tileSize, Stage.randomInt(0, 359));
58-
59-
if (i == nextIndex) {
60-
direction = (direction + 1) % 4;
61-
spiralCounter++;
62-
nextIndex += spiralCounter >> 1;
63-
}
64-
if (direction == 0)
65-
x += tileStride;
66-
else if (direction == 1)
67-
y -= tileStride;
68-
else if (direction == 2)
69-
x -= tileStride;
70-
else
71-
y += tileStride;
72-
}
73169

74-
this._sidePanelCount = maxSide * Math.floor((this.size.width - x) / tileStride) * 2;
75-
for (var i = 0; i < this._sidePanelCount; ++i) {
76-
var sideX = x + Math.floor(Math.floor(i / maxSide) / 2) * tileStride;
77-
var sideY = y - tileStride * (i % maxSide);
170+
this.rowsCount = this.rowsCount;
171+
172+
let tileSide = Math.round(this.size.height / this.rowsCount);
173+
let columnsCount = Math.floor(this.size.width / tileSide);
174+
if (columnsCount % 2 == 0)
175+
--columnsCount;
176+
177+
this.tileSize = new Size(tileSide, tileSide);
178+
this.tileGrid = new Size(columnsCount, this.rowsCount);
179+
this.iterator = new SpiralIterator(this.tileGrid);
180+
181+
while (!this.iterator.isDone())
182+
this.tiles.push(this.createTile());
183+
},
78184

79-
if (Math.floor(i / maxSide) % 2 == 1)
80-
sideX = this.size.width - sideX - tileSize + 1;
81-
this._addTile(sideX, sideY, tileSize, Stage.randomInt(0, 359));
185+
createTile: function() {
186+
if (this.iterator.isDone()) {
187+
this.iterator = new SpiralIterator(this.tileGrid);
188+
this.iteratorIndex++;
82189
}
190+
let tile = new Tile(this, this.iterator.current, this.iteratorIndex);
191+
this.iterator.next();
192+
return tile;
83193
},
84194

85-
_addTile: function(x, y, tileSize, rotateDeg)
86-
{
87-
var tile = Utilities.createElement("div", { class: "div-" + Stage.randomInt(0,6) }, this.element);
88-
var halfTileSize = tileSize / 2;
89-
tile.style.left = x + 'px';
90-
tile.style.top = y + 'px';
91-
tile.style.width = tileSize + 'px';
92-
tile.style.height = tileSize + 'px';
93-
var visibleCSS = this.visibleCSS[this.tiles.length % this.visibleCSS.length];
94-
tile.style[visibleCSS[0]] = visibleCSS[1];
95-
96-
var distance = 1 / tileSize * this.size.multiply(0.5).subtract(new Point(x + halfTileSize, y + halfTileSize)).length();
97-
this.tiles.push({
98-
element: tile,
99-
rotate: rotateDeg,
100-
step: Math.max(3, distance / 1.5),
101-
distance: distance,
102-
active: false,
103-
visibleCSS: visibleCSS,
104-
});
195+
complexity: function() {
196+
return this.activeLength;
105197
},
106198

107-
complexity: function()
108-
{
109-
return this._offsetIndex;
199+
activeTiles: function() {
200+
return this.tiles.slice(0, this.activeLength);
110201
},
111202

112-
tune: function(count)
113-
{
114-
this._offsetIndex = Math.max(0, Math.min(this._offsetIndex + count, this.tiles.length));
115-
this._distanceFactor = 1.5 * (1 - 0.5 * Math.max(this._offsetIndex - this._centerSpiralCount, 0) / this._sidePanelCount) / Math.sqrt(this._offsetIndex);
203+
inactiveTiles: function(end) {
204+
return this.tiles.slice(this.activeLength, end);
116205
},
117206

118-
animate: function()
119-
{
120-
var progress = this._benchmark.timestamp % 10000 / 10000;
121-
var bounceProgress = Math.sin(2 * Math.abs( 0.5 - progress));
122-
var l = Utilities.lerp(bounceProgress, 20, 50);
123-
var hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,";
124-
125-
for (var i = 0; i < this._offsetIndex; ++i) {
126-
var tile = this.tiles[i];
127-
tile.active = true;
128-
tile.element.style[tile.visibleCSS[0]] = tile.visibleCSS[2];
129-
tile.rotate += tile.step;
130-
tile.element.style.transform = "rotate(" + tile.rotate + "deg)";
131-
132-
var influence = Math.max(.01, 1 - (tile.distance * this._distanceFactor));
133-
tile.element.style.backgroundColor = hslPrefix + l * Math.tan(influence / 1.25) + "%," + influence + ")";
134-
}
207+
reusableTune: function(count) {
208+
if (count == 0)
209+
return;
135210

136-
for (var i = this._offsetIndex; i < this.tiles.length && this.tiles[i].active; ++i) {
137-
var tile = this.tiles[i];
138-
tile.active = false;
139-
tile.element.style[tile.visibleCSS[0]] = tile.visibleCSS[1];
211+
if (count < 0) {
212+
this.activeLength = Math.max(this.activeLength + count, 0);
213+
for (var i = this.activeLength; i < this.tiles.length; ++i)
214+
this.tiles[i].hide();
215+
return;
140216
}
217+
218+
let inactiveTiles = this.inactiveTiles(this.activeLength + count);
219+
for (let tile of inactiveTiles)
220+
tile.show();
221+
222+
for (let i = inactiveTiles.length; i < count; ++i)
223+
this.tiles.push(this.createTile());
224+
225+
this.activeLength += count;
226+
},
227+
228+
reusableAnimate: function() {
229+
for (let tile of this.activeTiles())
230+
tile.animate();
231+
},
232+
233+
tune: function(count) {
234+
this.reusableTune(count);
235+
236+
let totalSpiralCount = this.tileGrid.area();
237+
let centerSpiralCount = this.tileGrid.height * this.tileGrid.height;
238+
let sideSpiralCount = totalSpiralCount - centerSpiralCount;
239+
let activeSideSpiralCount = Math.min(Math.max(this.activeLength - centerSpiralCount, 0), sideSpiralCount);
240+
let activeTotalSpiralCount = Math.min(this.activeLength, totalSpiralCount);
241+
this.distanceFactor = 1.5 * (1 - 0.5 * activeSideSpiralCount / sideSpiralCount) / Math.sqrt(activeTotalSpiralCount);
242+
},
243+
244+
animate: function() {
245+
let progress = this._benchmark.timestamp % 10000 / 10000;
246+
let bounceProgress = Math.sin(2 * Math.abs(0.5 - progress));
247+
this.l = Utilities.lerp(bounceProgress, 20, 50);
248+
this.hslPrefix = "hsla(" + Utilities.lerp(progress, 0, 360) + ",100%,";
249+
250+
this.reusableAnimate();
141251
}
142252
});
143253

0 commit comments

Comments
 (0)