)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

Oera Linda Inspired Symbols

  1. var canvas = document.createElement("canvas"),
  2.   c = canvas.getContext("2d"),
  3.   title = document.createElement("h1");
  4.  
  5. canvas.style.transformOrigin = "top left";
  6. canvas.style.transform = "scale(0.5, 0.5)";
  7.  
  8. document.body.appendChild(canvas);
  9.  
  10. title.innerHTML = "Oera Linda Inspired Symbols";
  11. document.body.appendChild(title);
  12.  
  13. var erase = function () {
  14.   c.fillStyle = "#244250";
  15.   c.fillRect(0, 0, canvas.width, canvas.height);
  16. };
  17.  
  18. var shuffle = function () {
  19.   return 0.5 - Math.random();
  20. };
  21.  
  22. var Symbol = function (x, y, radius) {
  23.   this.x = x;
  24.   this.y = y;
  25.   this.radius = radius;
  26.   this.halfRadius = this.radius / 2;
  27.   this.draw();
  28. };
  29.  
  30. Symbol.ARC_NUM = 8;
  31. Symbol.TOTAL_SEGS = 23;
  32. Symbol.nodeMap = [
  33.   // [node index][list of possible node connections]
  34.   [7, 0, 9],
  35.   [10, 0, 2],
  36.   [11, 3, 1],
  37.   [4, 2, 12],
  38.   [3, 5, 13],
  39.   [4, 6, 14],
  40.   [5, 7, 15],
  41.   [6, 0, 16],
  42.   [0, 9],
  43.   [8, 10, 11, 12, 13, 14, 15, 16],
  44.   [1, 9],
  45.   [2, 9],
  46.   [3, 9],
  47.   [4, 9],
  48.   [5, 9],
  49.   [6, 9],
  50.   [7, 9]
  51. ];
  52.  
  53. Symbol.segMap = {
  54.   // [node-node][segment function index]
  55.   "0-1": 0,
  56.   "1-2": 1,
  57.   "2-3": 2,
  58.   "3-4": 3,
  59.   "4-5": 4,
  60.   "5-6": 5,
  61.   "6-7": 6,
  62.   "7-0": 7,
  63.  
  64.   "0-8": 9,
  65.   "8-9": 8,
  66.  
  67.   "9-10": 10,
  68.   "9-11": 12,
  69.   "9-12": 14,
  70.   "9-13": 16,
  71.   "9-14": 18,
  72.   "9-15": 20,
  73.   "9-16": 22,
  74.  
  75.   "1-10": 11,
  76.   "2-11": 13,
  77.   "3-12": 15,
  78.   "4-13": 17,
  79.   "5-14": 19,
  80.   "6-15": 21,
  81.   "7-16": 23
  82. };
  83.  
  84. // add reverse node connection keys
  85. for (var i in Symbol.segMap) {
  86.   var key = i.split("-").reverse().join("-");
  87.   Symbol.segMap[key] = Symbol.segMap[i];
  88. }
  89.  
  90. // store all keys
  91. Symbol.segMapKeys = [];
  92. for (var i in Symbol.segMap) {
  93.   Symbol.segMapKeys.push(i);
  94. }
  95.  
  96. Symbol.prototype = {
  97.   constructor: Symbol,
  98.   arcSegLength: (Math.PI * 2) / Symbol.ARC_NUM,
  99.   mirrors: [
  100.     [-1, -1],
  101.     [1, -1],
  102.     [-1, 1]
  103.   ],
  104.  
  105.   line: function (offset, isInner) {
  106.     var theta = this.arcSegLength * offset,
  107.       cos = Math.cos(theta),
  108.       sin = Math.sin(theta),
  109.       x1 = this.halfRadius * cos,
  110.       y1 = this.halfRadius * sin,
  111.       x2,
  112.       y2;
  113.  
  114.     if (isInner) {
  115.       x2 = 0;
  116.       y2 = 0;
  117.     } else {
  118.       x2 = this.radius * cos;
  119.       y2 = this.radius * sin;
  120.     }
  121.  
  122.     c.beginPath();
  123.     c.moveTo(x1, y1);
  124.     c.lineTo(x2, y2);
  125.     c.stroke();
  126.   },
  127.  
  128.   arc: function (offset) {
  129.     var step = this.arcSegLength * offset;
  130.     c.beginPath();
  131.     c.arc(0, 0, this.radius, step, step + this.arcSegLength, false);
  132.     c.stroke();
  133.   },
  134.  
  135.   drawAll: function () {
  136.     c.save();
  137.     c.translate(this.x, this.y);
  138.     for (var i = 0; i <= Symbol.TOTAL_SEGS; i++) {
  139.       this[i]();
  140.     }
  141.     c.restore();
  142.   },
  143.  
  144.   sequence: function (num) {
  145.     var keys = Symbol.segMapKeys,
  146.       index = Math.floor(keys.length * Math.random()),
  147.       curr = keys[index],
  148.       seq = [curr];
  149.  
  150.     for (var i = 0; i < num; i++) {
  151.       var comp = curr.split("-"),
  152.         end = comp[1],
  153.         begin = comp[0];
  154.  
  155.       for (var j = 0; j < keys.length; j++) {
  156.         var cc = keys[j].split("-");
  157.         if (cc[0] === end && cc[1] !== begin) {
  158.           curr = keys[j];
  159.           seq.push(curr);
  160.           break;
  161.         }
  162.       }
  163.     }
  164.     return seq;
  165.   },
  166.  
  167.   draw: function () {
  168.     var steps = 1 + Math.floor(Math.random() * 5);
  169.     (keys = this.sequence(steps)),
  170.       (indices = []),
  171.       (memory = {}),
  172.       (mirrorProb = 0.3),
  173.       (multiMirrorProb = 0.1),
  174.       (mirrorIter = 1),
  175.       (scales = []);
  176.  
  177.     c.lineWidth = 1;
  178.     c.strokeStyle = "rgba(255,255,255,0.15)";
  179.     this.drawAll();
  180.  
  181.     c.lineWidth = 2;
  182.     c.strokeStyle = "rgb(255,255,255)";
  183.  
  184.     c.save();
  185.     c.translate(this.x, this.y);
  186.     for (var i = 0; i < keys.length; i++) {
  187.       var index = Symbol.segMap[keys[i]];
  188.       this[index]();
  189.       indices.push(index);
  190.     }
  191.     c.restore();
  192.  
  193.     if (Math.random() < mirrorProb) {
  194.       mirrorIter = 1;
  195.  
  196.       if (Math.random() < multiMirrorProb) {
  197.         mirrorIter = 2 + Math.round(Math.random());
  198.       }
  199.  
  200.       scales = this.mirrors.sort(shuffle);
  201.  
  202.       for (var i = 0; i < mirrorIter; i++) {
  203.         c.save();
  204.         c.translate(this.x, this.y);
  205.         c.scale(scales[i][0], scales[i][1]);
  206.         for (var j = 0; j < indices.length; j++) {
  207.           this[indices[j]]();
  208.         }
  209.         c.restore();
  210.       }
  211.     }
  212.   }
  213. };
  214.  
  215. // arc partials:
  216. for (var i = 0; i < Symbol.ARC_NUM; i++) {
  217.   (function (i) {
  218.     Symbol.prototype[i] = function () {
  219.       this.arc(i);
  220.     };
  221.   })(i);
  222. }
  223.  
  224. // line partials:
  225. var j = 0;
  226. for (var i = Symbol.ARC_NUM; i <= Symbol.TOTAL_SEGS; i += 2) {
  227.   // inner
  228.   (function (i, j) {
  229.     Symbol.prototype[i] = function () {
  230.       this.line(j, true);
  231.     };
  232.   })(i, j);
  233.  
  234.   // outer
  235.   (function (i, j) {
  236.     Symbol.prototype[i] = function () {
  237.       this.line(j, false);
  238.     };
  239.   })(i + 1, j);
  240.   j++;
  241. }
  242.  
  243. var render = function () {
  244.   var radius = 70,
  245.     diameter = radius * 2,
  246.     padding = 10,
  247.     size = diameter + padding * 2,
  248.     winWidth = window.innerWidth * 2,
  249.     winHeight = window.innerHeight * 2,
  250.     cols = Math.floor(winWidth / size),
  251.     rows = Math.floor(winHeight / size),
  252.     num = cols * rows,
  253.     offX = Math.abs(winWidth - cols * size) / 2,
  254.     offY = Math.abs(winHeight - rows * size) / 2;
  255.  
  256.   for (var i = cols; i < num; i++) {
  257.     var x = offX + radius + (i % cols) * size;
  258.     var y = offY + radius + parseInt(i / cols) * size;
  259.     var s = new Symbol(x, y, radius);
  260.   }
  261. };
  262.  
  263. var renderTimeout;
  264. var rerender = function () {
  265.   clearInterval(renderTimeout);
  266.   renderTimeout = setTimeout(render, 500);
  267. };
  268.  
  269. var resize = function (e) {
  270.   canvas.width = window.innerWidth * 2;
  271.   canvas.height = window.innerHeight * 2;
  272.   erase();
  273.   if (e) {
  274.     rerender();
  275.   }
  276. };
  277.  
  278. window.addEventListener("resize", resize);
  279. resize();
  280. render();
  281.  
  282. document.addEventListener("click", function () {
  283.   erase();
  284.   render();
  285. });

Always fun to look through old codepen stuff…

See the Pen Better Oera Linda Inspired Symbols by Zevan Rosser (@ZevanRosser) on CodePen.

// canvas

Hamming Distance in JavaScript

  1. function hamming(a, b) {
  2.   const leng = a.length
  3.   let dist = 0
  4.  
  5.   // strings need to be same length
  6.   if (leng != b.length) return -1;
  7.  
  8.   a = a.toLowerCase()
  9.   b = b.toLowerCase()
  10.  
  11.   for (let i = 0; i < leng; i++)
  12.     if (a[i] !== b[i]) dist++
  13.  
  14.   return dist
  15. }
  16.  
  17. console.log(hamming('zevan', 'kevin'))
  18. console.log(hamming('joe', 'joe'))
  19. console.log(hamming('john', 'jake'))

The hamming distance between two strings…

Canvas Ring on Image

  1. const uploadInput = document.body.appendChild(
  2.   Object.assign(document.createElement('input'), {
  3.     type: 'file',
  4.     accept: 'image/png, image/jpeg'
  5.   })
  6. )
  7. uploadInput.style.display = 'block'
  8.  
  9. const canvas = document.body.appendChild(document.createElement('canvas'))
  10. const c = canvas.getContext('2d')
  11.  
  12. canvas.style.width = '70%'
  13.  
  14. let sampleSize
  15. const steps = 100
  16. const step = (Math.PI * 2) / steps
  17.  
  18. let interval
  19.  
  20. const ring = () => {
  21.   clearInterval(interval)
  22.   let x = imageEl.width / 2,
  23.     y = imageEl.height / 2,
  24.     rad = imageEl.width * 0.3,
  25.     theta = 0,
  26.     px,
  27.     py,
  28.     pxs = [],
  29.     spy = []
  30.   ;(pys = []), (im = []), (rects = [])
  31.  
  32.   for (let i = 0; i < steps; i++) {
  33.     px = x + rad * Math.cos(theta)
  34.     py = y + (rad / 2) * Math.sin(theta)
  35.     theta += step
  36.     pxs[i] = px
  37.     pys[i] = spy[i] = py
  38.     im[i] = c.getImageData(px, py, sampleSize, sampleSize)
  39.     rects[i] = [px, py, sampleSize, sampleSize]
  40.   }
  41.  
  42.   interval = setInterval(() => {
  43.     for (let i = 0; i < steps; i++) {
  44.       pys[i] -= 1
  45.       c.putImageData(im[i], pxs[i], pys[i])
  46.       v = (y - spy[i]) / rad
  47.       c.fillStyle = 'rgba(0,0,0,' + v + ')'
  48.       c.fillRect(pxs[i] - 1, pys[i], sampleSize + 2, sampleSize - 1)
  49.     }
  50.   }, 16)
  51. }
  52.  
  53. const imageEl = new Image()
  54. imageEl.src = 'https://snippet.zone/wp-content/uploads/2022/01/taho-scaled.jpg'
  55. imageEl.onload = () => {
  56.   canvas.width = imageEl.width
  57.   canvas.height = imageEl.height
  58.   c.drawImage(imageEl, 0, 0)
  59.   sampleSize = imageEl.width / 25
  60.  
  61.   ring()
  62. }
  63.  
  64. const reader = new FileReader()
  65.  
  66. reader.addEventListener('load', () => {
  67.   imageEl.src = reader.result
  68. })
  69.  
  70. uploadInput.addEventListener('change', e => {
  71.   const file = e.target.files[0]
  72.   if (file != null) {
  73.     reader.readAsDataURL(file)
  74.   }
  75. })

Upload an image and it will have a distortion ring drawn on it

Big Radio Button

  1. document.body.innerHTML = `
  2.   <p>Click/tap the radio button:</p>
  3.   <input type="radio" style="transform:translate(20px, 30px) scale(4);background:red">
  4. `;

I feel like at some point this didn’t work… nice to know it does now.

It will look different from browser to browser – as radio buttons do.

// tricks // ui

Airbrush-esque

  1. const canvas = document.createElement('canvas');
  2. const c = canvas.getContext('2d');
  3.  
  4. const brush = document.createElement('canvas');
  5. const brushC = brush.getContext('2d');
  6.  
  7. canvas.width = innerWidth;
  8. canvas.height = innerHeight;
  9. brush.width = innerWidth;
  10. brush.height = innerHeight;
  11.  
  12. document.body.appendChild(canvas);
  13.  
  14. c.fillStyle = 'black'
  15. c.fillRect(0, 0, canvas.width, canvas.height);
  16.  
  17. let brushSize = 50;
  18. let featherSize = .1;
  19. let featherSteps = Math.floor(brushSize * featherSize) + 1;
  20. let st = brushSize - featherSteps;
  21.  
  22. let a = 0;
  23. if (st < 1) st = 1;
  24. for (let i = 0; i < st; i++) {
  25.   a = 1 / (st - i)
  26.   c.strokeStyle = `rgba(255, 255, 255, ${a})`;
  27.   console.log(c.strokeStyle)
  28.   c.lineWidth = brushSize - i;
  29.   c.lineJoin = 'round'
  30.   c.lineCap = 'round'
  31.   c.beginPath();
  32.   c.moveTo(50, 50);
  33.   c.lineTo(200, 200);
  34.   c.bezierCurveTo(300, 200, 400, 200, 300, 400);
  35.   c.stroke();
  36. }
snippet.zone ~ 2021-22 /// {s/z}