summaryrefslogtreecommitdiff
path: root/static/script.js
diff options
context:
space:
mode:
Diffstat (limited to 'static/script.js')
-rw-r--r--static/script.js272
1 files changed, 272 insertions, 0 deletions
diff --git a/static/script.js b/static/script.js
new file mode 100644
index 0000000..4dfd3c6
--- /dev/null
+++ b/static/script.js
@@ -0,0 +1,272 @@
+"use strict";
+
+var questionState = new Map();
+var globalLevel;
+var globalId;
+
+function randomId() {
+ return works[randomInt(0, works.length-1)];
+}
+
+var queryTypes = [
+ {
+ modes: new Set(["novice", "intermediate", "expert"]),
+ type: "hue",
+ inputType: "range",
+ generateInputAttrs: function(attrs) {
+ return new Map([["min", "0"], ["max", "359"], ["value", "180"]]);
+ },
+ changeEvents: ["input"],
+ calculateScore: function(attrs) {
+ var hue = attrs.get("hue");
+ return Math.min(360 - hue, hue);
+ },
+ imgAttrsModifier: function(evt) {
+ var imgAttrs = questionState.get(globalId);
+ var hueRandomness = imgAttrs.get("hueRandomness");
+ var newHue = Number(evt.target.value);
+ imgAttrs.set("hue", mod(newHue + (hueRandomness - 180), 360));
+ redraw();
+ },
+ filterStyleString: function(attrs) {
+ return 'hue-rotate(' + attrs.get("hue") + 'deg)'
+ },
+ generateDefaultAttrs: function() {
+ var r = randomInt(0, 359);
+ return new Map([["hueRandomness", r], ["hue", r]]);
+ },
+ generateInputId: function(id) {
+ return `hue-input-${id}`;
+ }
+ },
+ {
+ modes: new Set(["intermediate", "expert"]),
+ type: "contrast",
+ inputType: "range",
+ generateInputAttrs: function(attrs) {
+ return new Map([["min", attrs.get("contrastLowerBound")], ["max", attrs.get("contrastUpperBound")], ["value", attrs.get("contrast")]]);
+ },
+ changeEvents: ["input"],
+ calculateScore: function(attrs) {
+ var contrast = attrs.get("contrast");
+ return abs(100 - contrast);
+ },
+ imgAttrsModifier: function(evt) {
+ var imgAttrs = questionState.get(globalId);
+ imgAttrs.set("contrast", Number(evt.target.value));
+ redraw();
+ },
+ filterStyleString: function(attrs) {
+ return 'contrast(' + attrs.get("contrast") + '%)'
+ },
+ generateDefaultAttrs: function() {
+ var r = randomInt(50, 100);
+ var mid = r + 50;
+ var lowerBound = r;
+ var upperBound = r + 100;
+ return new Map([["contrast", mid], ["contrastLowerBound", lowerBound], ["contrastUpperBound", upperBound]]);
+ },
+ generateInputId: function(id) {
+ return `contrast-input-${id}`;
+ }
+ },
+ {
+ modes: new Set(["expert"]),
+ type: "saturation",
+ inputType: "range",
+ generateInputAttrs: function(attrs) {
+ return new Map([["min", attrs.get("saturationLowerBound")], ["max", attrs.get("saturationUpperBound")], ["value", attrs.get("saturation")]]);
+ },
+ changeEvents: ["input"],
+ calculateScore: function(attrs) {
+ var saturation = attrs.get("saturation");
+ return abs(100 - saturation);
+ },
+ imgAttrsModifier: function(evt) {
+ var imgAttrs = questionState.get(globalId);
+ imgAttrs.set("saturation", Number(evt.target.value));
+ redraw();
+ },
+ filterStyleString: function(attrs) {
+ return 'saturate(' + attrs.get("saturation") + '%)'
+ },
+ generateDefaultAttrs: function() {
+ var r = randomInt(50, 100);
+ var mid = r + 50;
+ var lowerBound = r;
+ var upperBound = r + 100;
+ return new Map([["saturation", mid], ["saturationLowerBound", lowerBound], ["saturationUpperBound", upperBound]]);
+ },
+ generateInputId: function(id) {
+ return `saturation-input-${id}`;
+ }
+ }
+];
+
+function load() {
+ var urlParams = new URLSearchParams(window.location.search);
+ var id = urlParams.get('id')
+ var level = urlParams.get('level')
+
+ if (!id) {
+ id = randomId();
+ level = "novice";
+ }
+
+ startGame(id, level);
+}
+
+function renderArtist(s) {
+ return s.split('-').map(capitalize).join(' ');
+}
+
+function getArtist(id) {
+ var info = artists[id]
+ var artist = manifest.features[1].type.names[info]
+ return renderArtist(artist);
+}
+
+function startGame(id, level) {
+ document.getElementById('answer').innerHTML = '';
+ document.getElementById('scoring').innerHTML = '';
+ document.getElementById('sliders').innerHTML = '';
+ document.getElementById('question').innerHTML = '';
+ globalId = id;
+ globalLevel = level;
+ addQuestion(id, level);
+ finalizeQuestion(id, level);
+ redraw();
+ document.getElementById('copy').addEventListener('click', function() {
+ navigator.clipboard.writeText(`${location.origin}/countervisual?id=${id}&level=${level}`)
+ });
+}
+
+function redraw() {
+ var el = document.getElementById('img');
+ var styleString = ''
+ for (var queryType of queryTypes) {
+ if (queryType.modes.has(globalLevel)) {
+ var attrs = questionState.get(globalId);
+ styleString += ` ${queryType.filterStyleString(attrs)} `
+ }
+ }
+ el.setAttribute("style", 'filter: ' + styleString);
+}
+
+function addQuestion(id, level) {
+ var attrs = new Map();
+ for (var queryType of queryTypes) {
+ if (queryType.modes.has(level)) {
+ attrs = new Map([...attrs, ...queryType.generateDefaultAttrs()]);
+ }
+ }
+
+ document.getElementById('question').innerHTML = `<figcaption>Countervisual #${id}</figcaption>` + generateImgDom(id, "img");
+ document.getElementById('sliders').innerHTML = generateAttrDOM(id, level, attrs)
+ questionState.set(id, attrs);
+}
+
+function getImgUrl(id) {
+ return `/countervisual/static/data/${id}.jpg`
+}
+
+function generateImgDom(id, htmlId) {
+ return `<img id="${htmlId}" src="${getImgUrl(id)}"></img>`
+}
+
+function finalizeQuestion(id, level) {
+ for (var queryType of queryTypes) {
+ var inputId = queryType.generateInputId(id);
+ var input = document.getElementById(inputId);
+ if (queryType.modes.has(level)) {
+ for (var changeEvent of queryType.changeEvents) {
+ input.addEventListener(changeEvent, queryType.imgAttrsModifier);
+ }
+ }
+ }
+}
+
+function generateAttrDOM(id, level, attrs) {
+ var dom = ``;
+ for (var queryType of queryTypes) {
+ if (queryType.modes.has(level)) {
+ var attrString = generateAttrString(queryType.generateInputAttrs(attrs));
+ dom += `<label>${queryType.type}</label><br>
+ <input id="${queryType.generateInputId(id)}" style="width: 45%" type="${queryType.inputType}" ${attrString}>
+ <br>`;
+ }
+ }
+ dom += `</div>`;
+ return dom;
+}
+
+document.onload = load();
+
+document.getElementById('score-game').addEventListener('click', function(evt) {
+ var s = score();
+ var imageUrl = location.protocol + '//' + location.host + location.pathname + getImgUrl(globalId)
+ var lensUrl = `https://www.google.com/searchbyimage?image_url=${imageUrl}&client=app`
+ document.getElementById('scoring').innerHTML = `<p>You were ${s} points away from zero.</p>
+ <p>This work is by <a target="_blank" href="${lensUrl}">${getArtist(globalId)}</a>.</p>`
+ document.getElementById('answer').innerHTML = `<figcaption>Solution</figcaption>` + generateImgDom(globalId, "ans");
+ evt.preventDefault();
+})
+
+document.getElementById('reset').addEventListener('click', function(evt) {
+ startGame(globalId, globalLevel);
+});
+
+document.getElementById('random-novice').addEventListener('click', function(evt) {
+ startGame(randomId(), "novice");
+});
+
+document.getElementById('random-intermediate').addEventListener('click', function(evt) {
+ startGame(randomId(), "intermediate");
+});
+
+document.getElementById('random-expert').addEventListener('click', function(evt) {
+ startGame(randomId(), "expert");
+});
+
+function generateAttrString(attrs) {
+ var attrString = "";
+ for (var [attr, val] of attrs) {
+ attrString += ` ${attr}=${val}`
+ }
+ return attrString;
+}
+
+// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
+function randomInt(min, max) {
+ var min = Math.ceil(min);
+ var max = Math.floor(max);
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function score() {
+ var total = 0;
+ for (var queryType of queryTypes) {
+ if (queryType.modes.has(globalLevel)) {
+ total += queryType.calculateScore(questionState.get(globalId));
+ }
+ }
+ return total;
+}
+
+function mod(p, n) {
+ var z = (p % n);
+ if (z >= 0) {
+ return z;
+ } else {
+ return z + n;
+ }
+}
+
+function abs(a) {
+ return Math.max(a, -a);
+}
+
+function capitalize(s) {
+ return s.substr(0,1).toUpperCase() + s.substr(1);
+}
+