One way to store accessible, redundant javascript data is using json. So the full parameterization of your game could be represented by the following string:
{ "bounciness": 0.5, "gravity": -0.25, "friction": 1.2, "windVector": { "ang": 2.7314, "mag": 4.23 } }
If that string was stored in a variable called dataString
, you could do the following:
let { bounciness, gravity, friction, windVector } = JSON.parse(dataString);
Now the trick is to get the value in dataString
into the URL. Json is good for arbitrary values, but it does not embed properly into a url. We need to make the additional step of encoding the json into a form that does fit in a url. One such encoding is base64, and base64 encoding already exists via the global btoa
function (mdn) So the process will look like:
original raw data -> json data -> base64 encoded json data
The value to be inserted into the url, if the raw data is held in a variable called params
, would be:
let params = { bounciness: 0.5, gravity: -0.25, friction: 1.2, windVector: { ang: 2.7314, mag: 4.23 } }
let valueForUrl = btoa(JSON.stringify(params));
console.log(valueForUrl);
Here's an example where, as the raw data is updated, the url value automatically updates:
let rawData = { "bounciness": 0.5, "gravity": -0.25, "friction": 1.2, "windVector": { "ang": 2.7314, "mag": 4.23 } }
let resultJson = document.querySelector('.result.json');
let resultBase64 = document.querySelector('.result.base64');
let elems = [ 'bounciness', 'gravity', 'friction', 'windVector-ang', 'windVector-mag' ]
.map(v => document.querySelector(`[name="${v}"]`));
let [ bElem, gElem, fElem, waElem, wmElem ] = elems;
let fullUpdate = () => {
if (document.querySelector(':invalid')) {
resultJson.innerHTML = 'Invalid input';
resultBase64.innerHTML = 'Invalid input';
return;
}
let json = JSON.stringify(rawData);
resultJson.innerHTML = json;
resultBase64.innerHTML = btoa(json);
};
let updateElem = (elem, obj, prop) => {
elem.value = obj[prop].toString();
elem.addEventListener('input', evt => {
if (elem.matches(':valid')) obj[prop] = parseFloat(elem.value, 10);
fullUpdate();
});
};
updateElem(bElem, rawData, 'bounciness');
updateElem(gElem, rawData, 'gravity');
updateElem(fElem, rawData, 'friction');
updateElem(waElem, rawData.windVector, 'ang');
updateElem(wmElem, rawData.windVector, 'mag');
fullUpdate();
input { display: block; }
input:valid { background-color: rgba(0, 150, 0, 0.2); }
input:invalid { background-color: rgba(150, 0, 0, 0.2); }
p { margin: 0; margin-top: 5px; }
.result {
font-family: monospace;
border: 2px solid #a0a0a0;
margin-top: 0;
overflow: hidden;
text-overflow: ellipsis;
}
<p>Bounciness</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="bounciness" />
<p>Gravity</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="gravity" />
<p>Friction</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="friction" />
<p>Wind Angle</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="windVector-ang" />
<p>Wind Magnitude</p>
<input type="text" pattern="[-+]?[0-9]+([.][0-9]+)?" name="windVector-mag" />
<p>JSON</p>
<p class="result json"></p>
<p>Base64</p>
<p class="result base64"></p>
Now when a new page loads with a supplied url, you can convert back from base64 (using atob
) to json, and then back from json to raw data. Assume the value in the url is in a variable urlData
:
let urlData = 'eyJib3VuY2luZXNzIjowLjUsImdyYXZpdHkiOi0wLjI1LCJmcmljdGlvbiI6MS4yLCJ3aW5kVmVjdG9yIjp7ImFuZyI6Mi43MzE0LCJtYWciOjQuMjN9fQ';
console.log(JSON.parse(atob(urlData)));
Note that base64 is not the only possible encoding (and it may be more inefficient than other encodings!)