diff --git a/package.json b/package.json index d0959dbeb45..7b782515036 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "optimize:png": "find source/images -type f -name '*.png' -print0 | xargs -0 -n 1 -P 6 optipng", "optimize": "run-p optimize:**", "server": "pipenv run python network-api/manage.py runserver", - "start": "npm i && npm run build-uncompressed && run-p server watch:**", + "start": "npm i && run-p build-uncompressed server watch:**", "snyk": "snyk test --file=package.json", "test:procfile": "node test/test-procfile.js", "test:eslint": "eslint --config ./.eslintrc.yaml \"source/js/**/*.js\" \"source/js/**/*.jsx\" webpack.config.js", diff --git a/source/js/buyers-guide/homepage-c-slider.js b/source/js/buyers-guide/homepage-c-slider.js index c4d60aaa388..d50de9ce329 100644 --- a/source/js/buyers-guide/homepage-c-slider.js +++ b/source/js/buyers-guide/homepage-c-slider.js @@ -1,13 +1,28 @@ import CREEPINESS_LABELS from "./components/creepiness-labels.js"; -// Height of a single frame, see the -// ".current-creepiness" rule in homagepage.sccs -const creepStep = 70; +// Height of a single frame in the emoji sprite sheet, +// see the ".current-creepiness" rule in homagepage.sccs +const EMOJI_FRAME_HEIGHT = 70; -// Total number of frames in our sprite sheet, -// see the "./source/images/buyers-guide/faces/sprite.png" file -const totalSteps = 40; +// Total number of frames in our sprite sheet, see the +// "./source/images/buyers-guide/faces/sprite.png" file. +const SPRITE_FRAME_COUNT = 40; +// Our threshold value for which average creepiness ratings +// still count as "happy face" for the purpose of showing +// the emoji while scrolling. +// +// Note: this is a cosmetic value for scroll only. +const MINIMUM_HAPPINESS_RATING = 25; + +// Our threshold value beyond which everything is super +// creepy by default. +// +// Note: this is a cosmetic value for scroll only. +const MAXIMUM_CREEPINESS_RATING = 80; + +// Helper function to determine whether products are +// in view, and so need to be considered for averaging. function isElementInViewport(element) { let rect = element.getBoundingClientRect(); @@ -19,6 +34,18 @@ function isElementInViewport(element) { ); } +// map a value from one range to another +function map(v, s1,e1, s2,e2) { + return s2 + (v-s1) * (e2-s2) / (e1-s1); +} + +// cap a value to a range +function cap(v, m, M) { + m = m || 0; + M = M || 100; + return v < m ? m : v > M ? M : v; +} + export default { init: () => { let face = document.querySelector(`.current-creepiness`); @@ -40,15 +67,18 @@ export default { let averageCreepiness = visible.reduce( (tally, v) => tally + parseFloat(v.dataset.creepiness)/n, 0); + // compress the value so that we show a smiley face even for products with a lowish creepiness score. + let mappedAverageCreepiness = cap(map(averageCreepiness, MINIMUM_HAPPINESS_RATING, MAXIMUM_CREEPINESS_RATING, 0, 100), 1, 100); + // The averageCreepiness will be in range [1,100] so we can dec1 the // valueto make sure we're in frame range [0,frames.length-1]: - let frame = Math.round((totalSteps-1) * (averageCreepiness-1)/100); + let frame = Math.round((SPRITE_FRAME_COUNT-1) * (mappedAverageCreepiness-1)/100); - face.style.backgroundPositionY = `${-frame * creepStep}px`; + face.style.backgroundPositionY = `${-frame * EMOJI_FRAME_HEIGHT}px`; // Figure out what the corresponding creepiness label should be: let len = CREEPINESS_LABELS.length; - let bin = Math.floor(len * (averageCreepiness-1)/100); + let bin = Math.floor(len * (mappedAverageCreepiness-1)/100); if (bin === -1) { bubbleText.textContent = ``;