Skip to content

Commit a720636

Browse files
committed
Performance improvements on DOM rendering
1 parent 08779a1 commit a720636

File tree

6 files changed

+101
-14
lines changed

6 files changed

+101
-14
lines changed

config/grunt/browsersync.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ module.exports = {
66
},
77
options: {
88
watchTask: true,
9+
ghostMode: {
10+
clicks: false,
11+
forms: false,
12+
scroll: false
13+
},
914
server: {
1015
baseDir: '<%= config.target.dev %>',
1116
index: 'index.html'

src/assets/css/patternEditor.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828

2929
float: left;
3030

31+
&.fixed {
32+
position: fixed;
33+
top: @menu-height;
34+
}
35+
3136
li {
3237

3338
width: 40px;

src/js/controller/PatternEditorController.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const DOM = require( "zjslib" ).DOM;
2929
/* private properties */
3030

3131
let container, efflux, indiceContainer, controlContainer;
32-
let stepAmount = 0, patternIndices, rafPending = false;
32+
let stepAmount = 0, patternIndices, rafPending = false, controlOffsetY = 0;
3333

3434
module.exports =
3535
{
@@ -56,6 +56,7 @@ module.exports =
5656
// setup messaging system
5757
[
5858
Messages.WINDOW_SCROLLED,
59+
Messages.WINDOW_RESIZED,
5960
Messages.PATTERN_STEPS_UPDATED,
6061
Messages.STEP_POSITION_REACHED,
6162
Messages.SONG_LOADED
@@ -76,9 +77,16 @@ function handleBroadcast( type, payload )
7677
// ensure the controlContainer is always visible regardless of scroll offset
7778
// threshold defines when to offset the containers top, the last number defines the fixed header height
7879
const scrollY = window.scrollY;
79-
const threshold = DOM.getElementCoordinates( container, true ).y - 45;
80+
const threshold = ( controlOffsetY = controlOffsetY || DOM.getElementCoordinates( container, true ).y - 46 );
8081

81-
controlContainer.style.marginTop = (( scrollY > threshold ) ? scrollY - threshold : 0 ) + "px";
82+
if ( scrollY > threshold )
83+
controlContainer.classList.add( "fixed" );
84+
else
85+
controlContainer.classList.remove( "fixed" );
86+
break;
87+
88+
case Messages.WINDOW_RESIZED:
89+
controlOffsetY = 0; // flush cache
8290
break;
8391

8492
case Messages.PATTERN_STEPS_UPDATED:

src/js/controller/PatternTrackListController.js

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const PatternUtil = require( "../utils/PatternUtil" );
3636

3737
let wrapper, container, efflux, editorModel, keyboardController, stepHighlight;
3838
let interactionData = {},
39-
selectionModel, patternCopy, stepSelect;
39+
selectionModel, patternCopy, stepSelect, pContainers, pContainerSteps;
4040

4141
const PatternTrackListController = module.exports =
4242
{
@@ -110,12 +110,21 @@ const PatternTrackListController = module.exports =
110110
const coordinates = { x: container.scrollLeft, y: container.scrollTop };
111111

112112
const pattern = efflux.activeSong.patterns[ activePattern ];
113+
114+
// render the currently active pattern on screen
115+
113116
efflux.TemplateService.render( "patternTrackList", wrapper, {
114117

115-
steps : pattern.steps,
116-
pattern : pattern
118+
steps : pattern.steps,
119+
pattern : pattern,
120+
activeChannel : editorModel.activeInstrument,
121+
activeStep : editorModel.activeStep
117122

118-
}).then( highlightActiveStep );
123+
}).then(() => {
124+
// clear cached containers after render
125+
pContainers = null;
126+
pContainerSteps = [];
127+
});
119128

120129
Form.setSelectedOption( stepSelect, pattern.steps );
121130
container.scrollLeft = coordinates.x;
@@ -188,8 +197,8 @@ function handleBroadcast( type, payload )
188197

189198
function highlightActiveStep()
190199
{
191-
const pContainers = wrapper.querySelectorAll( ".pattern" ),
192-
activeStyle = "active", selectedStyle = "selected",
200+
grabPatternContainersFromTemplate();
201+
const activeStyle = "active", selectedStyle = "selected",
193202
activeStep = editorModel.activeStep;
194203

195204
let selection, pContainer, items, item;
@@ -198,7 +207,8 @@ function highlightActiveStep()
198207
{
199208
pContainer = pContainers[ i ];
200209
selection = selectionModel.selectedChannels[ i ];
201-
items = pContainer.querySelectorAll( "li" );
210+
items = grabPatternContainerStepFromTemplate( i );
211+
pContainer.querySelectorAll( "li" );
202212

203213
let j = items.length;
204214
while ( j-- )
@@ -243,7 +253,7 @@ function handleInteraction( aEvent )
243253

244254
if ( aEvent.target.nodeName === "LI" )
245255
{
246-
const pContainers = wrapper.querySelectorAll( ".pattern" );
256+
grabPatternContainersFromTemplate();
247257
let selectionChannelStart = editorModel.activeInstrument, selectionStepStart = editorModel.activeStep;
248258
let found = false, pContainer, items;
249259

@@ -257,7 +267,7 @@ function handleInteraction( aEvent )
257267
if ( found ) break;
258268

259269
pContainer = pContainers[ i ];
260-
items = pContainer.querySelectorAll( "li" );
270+
items = grabPatternContainerStepFromTemplate( i );
261271

262272
let j = items.length;
263273
while ( j-- )
@@ -461,3 +471,17 @@ function addEventAtPosition( event, optData )
461471
PatternTrackListController.update();
462472
Pubsub.publish( Messages.SAVE_STATE );
463473
}
474+
475+
/**
476+
* function to retrieve and cache the currently available DOM containers
477+
* inside the pattern template
478+
*
479+
* @private
480+
*/
481+
function grabPatternContainersFromTemplate() {
482+
pContainers = pContainers || wrapper.querySelectorAll( ".pattern" );
483+
}
484+
485+
function grabPatternContainerStepFromTemplate( i ) {
486+
return ( pContainerSteps[ i ] = pContainerSteps[ i ] || pContainers[ i ].querySelectorAll( "li" ));
487+
}

src/js/workers/TemplateWorker.js

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,45 @@ function registerHelpers() {
6767
return out;
6868
});
6969

70+
/**
71+
* comparison functions for templates, use like:
72+
* {{#if (eq variable "value")}} ... {{/if}}
73+
*
74+
* multiple conditionals:
75+
*
76+
* {{#if (and
77+
* (eq variable "value")
78+
* (eq variable2 "value"))}}
79+
*/
80+
Handlebars.registerHelper({
81+
82+
eq: function (v1, v2) {
83+
return v1 === v2;
84+
},/*
85+
ne: function (v1, v2) {
86+
return v1 !== v2;
87+
},
88+
lt: function (v1, v2) {
89+
return v1 < v2;
90+
},
91+
gt: function (v1, v2) {
92+
return v1 > v2;
93+
},
94+
lte: function (v1, v2) {
95+
return v1 <= v2;
96+
},
97+
gte: function (v1, v2) {
98+
return v1 >= v2;
99+
},
100+
*/
101+
and: function (v1, v2) {
102+
return v1 && v2;
103+
},
104+
or: function (v1, v2) {
105+
return v1 || v2;
106+
}
107+
});
108+
70109
/**
71110
* formats module parameter automations (patternTrackList)
72111
*
@@ -91,4 +130,4 @@ function registerHelpers() {
91130
}
92131
return out;
93132
});
94-
}
133+
}

src/templates/patternTrackList.hbs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
{{#each pattern.channels}}
22
<ul class="pattern">
33
{{#each this}}
4-
<li class="{{toLowerCase this.instrument}}">
4+
{{#if (and
5+
(eq @index ../../activeStep)
6+
(eq @../index ../../activeChannel))}}
7+
<li class="active">
8+
{{else}}
9+
<li>
10+
{{/if}}
511
{{#if this.action}}
612
{{# if this.note}}
713
<span class="note">

0 commit comments

Comments
 (0)