Random Negative or Positive
Math.round(Math.random()) * 2 - 1;
Randomly generate either -1 or 1. There are many ways to do this.
Math.round(Math.random()) * 2 - 1;
Randomly generate either -1 or 1. There are many ways to do this.
// https://stackoverflow.com/questions/38781968/problems-downloading-big-filemax-15-mb-on-google-chrome
function dataUriToBlob(dataURI) {
const binStr = atob(dataURI.split(',')[1]);
const len = binStr.length;
const arr = new Uint8Array(len);
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
for (let i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
const blob = new Blob([arr], {
type: mimeString
});
return URL.createObjectURL(blob);
}
const save = document.createElement('a');
save.innerText = 'save this big image';
document.body.appendChild(save);
const canvas = document.createElement('canvas');
const c = canvas.getContext('2d');
canvas.width = window.innerWidth * 4;
canvas.height = window.innerHeight * 4;
canvas.style.transformOrigin = '0 0';
canvas.style.transform = `scale(0.14)`;
document.body.appendChild(canvas);
c.fillStyle = 'black';
c.fillRect(0, 0, canvas.width, canvas.height);
const size = Math.max(window.innerWidth, window.innerHeight);
// draw some rectangles
c.globalCompositeOperation = 'difference'
for (let i = 0; i < 100; i++) {
const angle = Math.random() * 180 + 180;
const color = `hsl(${angle}deg, 50%, 50%)`;
c.fillStyle = color;
const width = Math.random() * size + 100;
const height = Math.random() * size + 100;
const x = Math.random() * canvas.width - width / 2;
const y = Math.random() * canvas.height - height / 2;
c.fillRect(
x,
y,
width,
height);
}
save.download = 'big-image';
save.href = dataUriToBlob(canvas.toDataURL());
Weirdly if you try to save a massive data URI to a file (> 15mb) it will just fail. In order to do this properly, you need to convert to a blob first and then save. I encountered this at some point and learned of the solution from user doppelgreener over at stack overflow. Take a look at the post here.
const str = ['one','-','two'].join``;
console.log(str);
// outputs "one-two"
With tagged templates you can pass a template string to a function without parens.
Object.getOwnPropertyNames(Math).forEach(i => window[i] = Math[i]);
// or with map, just to be shorter
Object.getOwnPropertyNames(Math).map(i => window[i] = Math[i]);
// if this points to window
Object.getOwnPropertyNames(Math).map(i => this[i] = Math[i]);
// or using the deprecated "with" statement
with (Math) {
console.log(PI, E, SQRT2, cos(1));
}
While not very useful, I sometimes like to make the entire Math
object global on the window – just when speed coding and playing around.
const hasTouch =
navigator.maxTouchPoints != null && navigator.maxTouchPoints > 0;
const el = document.body.appendChild(document.createElement('div'));
el.innerHTML = `
<svg id="mainSvg" width="100%" height="100%" viewBox="0 0 800 800">
<g transform="translate(100, 100) scale(0.8, 0.8) rotate(25, 400, 400)">
<rect x="0" y="0" width="800" height="800" fill="#ccc" stroke="none"/>
<text x="10" y="30" font-size="30px">click/tap the box</text>
</g>
</svg>
<style>
svg, div, body, html {
height: 100%;
width: 100%;
margin: 0; padding: 0;
}
svg {
overflow: hidden;
}
</style>
`;
function createSvg(type) {
return document.createElementNS('http://www.w3.org/2000/svg', type);
}
// mouse or touch location is always relative to the svg
// any css transformations on the svg are only accounted for in
// Chrome unfortunately
function svgTouch(e, svgEl) {
const touches = e.touches;
let locX, locY;
if (touches != null && touches.length > 0) {
locX = touches[0].clientX;
locY = touches[0].clientY;
} else {
locX = e.clientX;
locY = e.clientY;
}
const pt = svgEl.createSVGPoint();
pt.x = locX;
pt.y = locY;
const newPnt = pt.matrixTransform(svgEl.getScreenCTM().inverse());
return { locX: newPnt.x, locY: newPnt.y };
}
document.addEventListener(hasTouch ? 'touchstart' : 'mousedown', e => {
// global id `mainSvg` :P
const { locX, locY } = svgTouch(e, mainSvg);
const circle = createSvg('circle');
circle.cx.baseVal.value = locX;
circle.cy.baseVal.value = locY;
circle.r.baseVal.value = 20;
circle.style.fill = 'blue';
mainSvg.appendChild(circle);
});
This snippet shows how to get relative mouse/touch coordinates within an SVG element. The main trick here is on line 50… pt.matrixTransform(svgEl.getScreenCTM().inverse());
– we get the inverse transformation matrix of the “mainSvg” node and transform the mouse/touch coordinates by it.
Beware, when this was posted, as noted in the comments – CSS transforms on the SVG element or any of its parents won’t be accounted for in the `getScreenCTM` call in any browsers other than Chrome. There is an open Firefox issue for this I believe…