block by vijithassar f6e3601eeb0ecf6c91e9b8c45eea7435

one-line arrow function syntax for getter/setter methods

Full Screen

Terse Configurable Functions

The powerful function configuration methods from the reusable charts design pattern are verbose, but their syntax can be condensed down to a one-liner by combining ES6 arrow functions, ternary operators, expression grouping, and the underscore variable convention for variadic functions. Note that this example will not work in Internet Explorer 11 or below.

Original syntax:

some_function.x = function(value) {
  if (!arguments.length) {
    return x;
  } else {
    x = value;
    return some_function;
  }
};

Condensed:

some_function.x = _ => _ !== undefined ? (x = _, some_function) : x;

This is a dense line of code, but brevity is beneficial here since this is an attempt to replace traditional function arguments with a more powerful semantic alternative.

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>one-line arrow function syntax for getter/setter methods</title>
    <link rel="stylesheet" type="text/css" href="./style.css">
    <meta charset="utf-8">
  </head>
  <body>
    <div class="target"></div>
    <div class="scripts">
      <script type="text/javascript" src="https://d3js.org/d3.v4.js"></script>
      <script type="text/javascript" src="./tiles.js"></script>
    </div>
  </body>
</html>

style.css

g.controls text.label {
    text-anchor: middle;
    fill: white;
    stroke: black;
    font-weight: bold;
    stroke-width: 5;
    paint-order: stroke;
    font-size: xx-large;
}

tiles.js

(function(d3) {
    'use strict'
    var height,
        width,
        count,
        duration,
        array,
        columns,
        parameters,
        grid,
        scales,
        svg,
        control,
        slider,
        item,
        loop,
        factory,
        shape,
        collect
    height = 500
    width = 960
    count = 200
    duration = 1000
    array = Array.apply(this, {length: count})
    // store variable names in a single data structure
    // so we can work with them programmatically
    parameters = {
        'hue': [0, 360],
        'saturation': [0, 1],
        'lightness': [0, 1],
        'opacity': [0, 1],
        'rotation': [-360, 360],
        'skew': [-360, 360],
        'size': [0, 2]
    }
    columns = Object.keys(parameters).length
    grid = width / columns
    scales = {}
    Object.keys(parameters).forEach(function(parameter) {
        var scale
        scale = d3.scaleLinear()
            .domain([height, 0])
            .range(parameters[parameter])
        scales[parameter] = scale
    })
    factory = function() {
        var f,
            hue,
            saturation,
            lightness,
            opacity,
            rotation = 0,
            skew = 0,
            size = 0
        f = function(selection) {
            var color,
                transform
            color = d3.hsl(hue, saturation, lightness, opacity)
            transform = 'rotate(' + rotation + ')skewX(' + skew + ')scale(' + size + ')'
            selection
                .append('rect')
                .style('fill', color.toString())
                .style('stroke', 'black')
                .attr('height', 0)
                .attr('width', 0)
                .transition('rotate')
                .duration(duration)
                .attr('transform', transform)
        }
        // configuration methods
        f.hue = _ => _ !== undefined ? (hue = _, f) : hue
        f.saturation = _ => _ !== undefined ? (saturation = _, f) : saturation
        f.lightness = _ => _ !== undefined  ? (lightness = _, f) : lightness
        f.opacity = _ => _ !== undefined ? (opacity = _, f) : opacity
        f.rotation = _ => _ !== undefined ? (rotation = _, f) : rotation
        f.skew = _ => _ !== undefined ? (skew = _, f) : skew
        f.size = _ => _ !== undefined ? (size = _, f) : size
        return f
    }
    shape = factory()
    svg = d3.select('div.target')
        .append('svg')
        .attr('height', height)
        .attr('width', width)
    item = svg.append('g')
        .classed('items', true)
        .attr('transform', 'translate(' + grid * 0.5 + ',0)')
        .selectAll('g.item')
        .data(array)
        .enter()
        .append('g')
        .classed('item', true)
    item.attr('transform', function(d, i) {
        var x,
            y
        x = i % columns * grid
        y = Math.floor(i / columns) * grid
        return 'translate(' + x + ',' + y + ')'
    })
    slider = function(selection) {
        var slider_width,
            x_offset
        slider_width = grid
        x_offset = (grid - slider_width) * 0.5
        selection.append('rect')
            .attr('x', x_offset)
            .attr('height', 10)
            .attr('width', slider_width)
            .style('stroke', 'white')
            .style('stroke-width', 3)
    }
    control = svg.append('g')
        .classed('controls', true)
        .selectAll('g.control')
        .data(Object.keys(parameters))
        .enter()
        .append('g')
        .attr('class', 'control')
        .attr('data-control', function(d) {
            return d
        })
        .attr('transform', function(d, i) {
            var x
            x = grid * i
            return 'translate(' + x + ',0)'
        })
    control
        .append('g')
        .classed('slider', true)
        .each(function() {
            d3.select(this).call(slider)
        })
    control
        .append('rect')
        .attr('height', height)
        .attr('width', grid)
        .style('opacity', 0)
    control
        .append('text')
        .classed('label', true)
        .attr('transform', 'translate(' + (grid * 0.5) + ',' + (height * 0.5) + ') rotate(270)')
        .text(function(d) {
            return d.replace(/_/g, ' ')
        })
    control.on('mousemove', function() {
        var new_y
        new_y = d3.mouse(this)[1]
        d3.select(this).select('g.slider rect')
            .transition()
            .ease(d3.easeLinear)
            .attr('y', new_y)
    })
    collect = function() {
        control.each(function(d) {
            var y,
                value
            y = d3.select(this).select('g.slider rect')
                .node()
                .getBBox()
                .y
            value = scales[d](y)
            if (typeof shape[d] === 'function') {
                shape[d](value)
            }
        })
    }
    loop = function(selection) {
        collect()
        selection
            .call(shape)
            .select('rect')
            .transition('change')
            .duration(duration)
            .delay(function(d, i) {
                return duration / count * i
            })
            .attr('height', grid)
            .attr('width', grid)
            .transition('remove')
            .duration(duration)
            .attr('height', 0)
            .attr('width', 0)
            .remove()
    }
    item.call(loop)
    setInterval(function() {
        item.selectAll('rect').remove()
        item.call(loop)
    }, duration * 3)
}).call(this, d3)