Skip to content

Instantly share code, notes, and snippets.

@vijithassar
Last active October 12, 2016 21:27
Show Gist options
  • Save vijithassar/f6e3601eeb0ecf6c91e9b8c45eea7435 to your computer and use it in GitHub Desktop.
Save vijithassar/f6e3601eeb0ecf6c91e9b8c45eea7435 to your computer and use it in GitHub Desktop.
one-line arrow function syntax for getter/setter methods

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.

<!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>
g.controls text.label {
text-anchor: middle;
fill: white;
stroke: black;
font-weight: bold;
stroke-width: 5;
paint-order: stroke;
font-size: xx-large;
}
(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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment