Miscellaneous Findings IV: Web odds and ends

For this round of Miscellaneous Findings, we have a few web dev odds and ends.

This is a roundup of miscellaneous things that I’ve found out about (or have rediscovered). I take notes on findings regularly, and I put the findings that translate well to speech on my podcast, Small Findings. The rest (which are often technical findings), I put here. They’re not always written up for maximum comprehension as a blog post, but if anything is hard to understand, please email me if you need clarification.

DOM events

input

The input event fires when the value of an input, select, or textarea changes. This is an event introduced in HTML 5.

The change event only fires when a value is committed. So, a range input will fire change only when the user stops dragging the slider, but input will fire whenever the slider is moved.

There’s many cases in which you do not want an event listener to run every time the user moves the slider.

#html #js #event #control

Cropping shapes in SVG

You can crop in SVG in the browser by using clipPath. The thing to remember is that the clipPath defines the part that should be shown, not the part that should be hidden.

For example, here, anything in the .hills group that goes outside of the 100x100 viewBox is hidden, because it uses a clipPath defined as a 100x100 rect starting at 0, 0.

<svg class="board" width="1600" height="900" viewBox="0 0 100 100" preserveAspectRatio="none">
  <clipPath id="cut-off-bottom">
    <rect x="0" y="0" width="100" height="100" />
  </clipPath>
  <g class="hills" clip-path="url(#cut-off-bottom)">
    <rect id="bg-rect" x="0" y="0" width="100" height="100" />
  </g>
  <g id="debug-layer"></g>
</svg>

This svg markup will be respected by the browser but also, at the least, Inkscape and Ubuntu Image Viewer.

MDN on clipping and masking

#svg #cropping #browser

Transforming a hierarchy by key type

Here’s an example of walking an object hierarchy in JavaScript and producing a copy that’s gotten rid of values considered “default” values. e.g. '' for strings, 0 for numbers, etc.

You can copy this and do a different kind of transformation, if you’d like. It is recursive, so be careful where you apply it.

import curry from 'lodash.curry';

export function dropDefaults(depth, maxDepth, value) {
  var type = typeof value;

  if (value === null || value === undefined) {
    return;
  } else if (type === 'string') {
    if (value === '') {
      return;
    }
    return value;
  } else if (type === 'boolean') {
    if (value === false) {
      return;
    }
    return value;
  } else if (type === 'number') {
    if (value === 0) {
      return;
    }
    return value;
  } else if (Array.isArray(value)) {
    // We handle depth differently for arrays because
    // if we are one away from maxDepth and we recurse,
    // we'll end up just logging an array filled with
    // all truncated values.
    if (depth + 1 >= maxDepth) {
      return '<nested content not included>';
    } else {
      if (value.length === 0) {
        return;
      }
      return value.map(curry(dropDefaults)(depth + 1, maxDepth));
    }
  } else if (type === 'object') {
    if (depth >= maxDepth) {
      return '<nested content not included>';
    } else {
      let fields = {};
      for (let key in value) {
        let transformedVal = dropDefaults(depth + 1, maxDepth, value[key]);
        if (transformedVal !== undefined) {
          fields[key] = transformedVal;
        }
      }
      return fields;
    }
  } else if (type === 'function') {
    return `<<function>> ${value.name}`;
  }
}

#javascript #hierarchy