block by vijithassar 9e5348184bd183fd1597556ef44f5fc4

batch configuration methods

Full Screen

Since Mike originally intended the reusable chart pattern as a straw man proposal for further refinement, here’s a simple extension which I’ve found helpful on some recent projects. In addition to the configuration methods, a single multiple-input wrapper method can be defined (it’s called .set() in this example) which can then be used to run other individual configuration methods based on an input hashmap which specifies method names and arguments as keys and values. Here, it’s used to safely run methods which set size and position attributes for circles and squares which have slight semantic differences (r/cx/cy vs height/width/x/y, respectively) without needing to know which shape it’s operating on. This small addition allows for the flexibility and syntactic clarity of the individual methods while also retaining the option for fast one-shot configurations based on a single object.

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>batch configuration methods</title>
    <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="./wormhole.js"></script>
    </div>
  </body>
</html>

wormhole.js

(function() {
    'use strict'
    var height,
        width,
        duration,
        svg,
        wrapper,
        factory,
        circle,
        rect
    height = 500
    width = 960
    duration = 500
    svg = d3.select('div.target')
        .append('svg')
        .attr('height', height)
        .attr('width', width)
    wrapper = svg.append('g')
        .classed('wrapper', true)
    wrapper.append('rect')
        .attr('height', height)
        .attr('width', width)
        .style('fill', 'black')
    factory = function(type) {
        var f,
            color,
            r,
            cx,
            cy,
            height,
            width,
            x,
            y,
            increase,
            transform
        increase = 10
        transform = 'translate(0,0)scale(' + increase + ')'
        f = function(selection) {
            var start,
                item
            start = d3.mouse(wrapper.node())
            item = selection.append(type)
                .classed('marker', true)
                .attr('transform', 'translate(' + start[0] + ',' + start[1] + ')')
                .style('fill-opacity', 0.1)
                .style('fill', color)
                .style('stroke', 'white')
                .transition()
                .duration(duration)
                .attr('transform', transform)
                .remove()
            if (r) {item.attr('r', r)}
            if (cx) {item.attr('cx', cx)}
            if (cy) {item.attr('cy', cy)}
            if (height) {item.attr('height', height)}
            if (width) {item.attr('width', width)}
            if (x) {item.attr('x', x)}
            if (y) {item.attr('y', y)}
        }
        f.color = function(value) {
            if (! arguments.length) {
                return color
            } else {
                color = value
                return f
            }
        }
        if (type === 'circle') {
            f.r = function(value) {
                if (! arguments.length) {
                    return r
                } else {
                    r = value
                    return f
                }
            }
            f.cx = function(value) {
                if (! arguments.length) {
                    return cx
                } else {
                    cx = value
                    return cx
                }
            }
            f.cy = function(value) {
                if (! arguments.length) {
                    return cy
                } else {
                    cy = value
                    return f
                }
            }
        }
        if (type === 'rect') {
            f.x = function(value) {
                if (! arguments.length) {
                    return x
                } else {
                    x = value
                    return f
                }
            }
            f.y = function(value) {
                if (! arguments.length) {
                    return y
                } else {
                    y = value
                    return f
                }
            }
            f.height = function(value) {
                if (! arguments.length) {
                    return height
                } else {
                    height = value
                    return f
                }
            }
            f.width = function(value) {
                if (! arguments.length) {
                    return width
                } else {
                    width = value
                    return f
                }
            }
        }
        f.set = function(values) {
            Object.keys(values).forEach(function(key) {
                if (typeof f[key] === 'function') {f[key](values[key])}
            })
        }
        return f
    }
    circle = factory('circle')
    rect = factory('rect')
    wrapper.on('mousemove', function() {
        var position,
            now,
            hue,
            marker,
            size,
            size_modifier,
            parameters
        position = d3.mouse(this)
        now = Math.round(d3.now())
        hue = now / 10 % 360
        marker = now % 1000 > 500 ? circle : rect
        size = 50
        size_modifier = now / 1000 % 5
        parameters = {
            r: size * size_modifier,
            cx: position[0],
            cy: position[1],
            height: size * 2 * size_modifier,
            width: size * 2 * size_modifier,
            x: position[0],
            y: position[1],
            color: d3.hsl(hue, 0.5, 0.5)
        }
        marker.set(parameters)
        wrapper.call(marker)
    })
}).call(this)