block by eesur 872bf0ccbc4dee64b27925f82aea0a0c

d3 | Redux action

Full Screen

Testing out a Redux action that makes a circle active on a click event, based on Philippe Rivière’s Redux + D3 in the browser block

script.js

// #1a1a1a : #a634a0
(function () {
  const d3 = window.d3
  const Redux = window.Redux
  // Create a Redux store holding the state of the app
  // Its API is { subscribe, dispatch, getState }.
  const store = Redux.createStore(active)

  const initialstate = {
    fill: '#1a1a1a',
    ref: null
  }

  const xScale = d3.scaleLinear()
    .domain([0, 10])
    .range([40, 960])

  const svg = d3.select('#vis')

  svg.selectAll('circle')
    .data(d3.range(10))
    .enter().append('circle')
    .attr('cx', d => xScale(d))
    .attr('cy', 100)
    .attr('r', 30)
    .attr('class', d => `circle-${d}`)
    .attr('fill', '#1a1a1a')
    .on('click', (d) => store.dispatch({ type: 'SELECTED', ref: d }))

  d3.select('.btn-primary')
    .on('click', () => store.dispatch({ type: 'RESET', ref: null }))

  function active (_state = initialstate, action = null) {
    let state = snapshot(_state) // snapshot == clone
    switch (action.type) {
      case 'SELECTED':
        console.log('action received for circle: ', action.ref)
        state.fill = '#e5f015'
        state.ref = action.ref
        return state
      case 'RESET':
        return initialstate
      default:
        return _state
    }
  }

  // You can use subscribe() to update the UI in response to state changes.
  // Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
  // However it can also be handy to persist the current state in the localStorage.

  store.subscribe(() => {
    const state = store.getState()
    svg.selectAll('circle')
      .attr('fill', initialstate.fill)
      .filter(`.circle-${state.ref}`)
      .attr('fill', state.fill)
  })

// deep cloning function excerpted from underscore.js
  function snapshot (obj) {
    if (obj == null || typeof (obj) !== 'object') {
      return obj
    }
    const temp = new obj.constructor()
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        temp[key] = snapshot(obj[key])
      }
    }
    return temp
  };
}())

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <!-- //www.basscss.com/ -->
  <link href="https://unpkg.com/basscss@8.0.2/css/basscss.min.css" rel="stylesheet">
  <style>
    body { 
      background: #a634a0;
      font-size: 16px;
      font-family: -apple-system, BlinkMacSystemFont, Consolas, monaco, monospace;
    }
    button.btn {
      font-family : inherit;
      font-size: 16px;
      letter-spacing: 2px;
      font-weight: 700;
      font-weight: 500;
      cursor: pointer;
      display: inline-block;
      padding: .5rem 1rem;
      height: auto;
      border: 1px solid transparent;
      vertical-align: middle;
      -webkit-appearance: none;
      color: inherit;
      background-color: transparent;
      text-decoration: none;
    }
    button.btn-primary {
      color: #fff;
      background-color: #6b2167;
      border-radius: 3px;
    }
    button.btn-primary:hover {
      box-shadow: inset 0 0 0 20rem #952e90;
    }
  </style>
</head>
<body>
  <header class="pl2">
    <p>Click on circle to set state via a Redux action</p>
  </header>

  <svg width="960" height="200">
    <g id="vis" transform="translate(10, 10)"></g>
  </svg>

  <nav class="pl2">
    <button class="btn btn-primary">RESET</button>
  </nav>

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.min.js"></script>
<!-- d3 code -->
<script src=".script-compiled.js" charset="utf-8"></script>

</body>
</html>