block by monfera f9f2662a5666a6482225efe5f7c3bb65

Device access on bl.ocks.org

Full Screen

Shows that bl.ocks.org is capable of running with https. Just change the URL to start with https:// or click here. The utility of https is that devices are accessible if the user permits. For example, this block from Curran Kelleher works similarly.

It’s just a copy of a piece of code I used for an overly early talk about D3 4.0 (slides of historical interest are here). Don’t look at the code as it uses v0.1 etc. deep pre-alpha versions of D3 4.0 code.

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3-path.v0.1.min.js"></script>
  <script src="https://d3js.org/d3-timer.v0.2.min.js"></script>
</head>

<body>
  <canvas></canvas>
  <script>

// Grid 2
// Web Audio works w/ Chrome & FF
// Put https:// before the codepen URL
//     as WebAudio needs SSL

/* 
 * D3 lookalike functionality
 */

// We don't have a d3 object as we selectively import plugins
const d3 = Object.assign(
  {}, 
  d3_path, 
  d3_timer
)

// We have no d3.select or d3.selectAll, so... no data binding
function select(s) {
  return document.querySelector(s)
}

function attr(element, attribute, value) {
  element.setAttribute(attribute, value)
}

function style(element, property, value) {
  element.style[property] = value
}

/*
 * Setup the canvas
 */

const width = document.documentElement.clientWidth
const height = document.documentElement.clientHeight
const aaMultiple = window.devicePixelRatio

const canvas = select('canvas')

attr(canvas, 'width', width * aaMultiple)
attr(canvas, 'height', height * aaMultiple)

style(canvas, 'width', 100 + '%')
style(canvas, 'height', 100 + '%')

const canvasContext = canvas.getContext('2d')

/*
 * Render a circle
 */

const lineWidth = 0.5
const radius = 31

function render(context, x, y, radius, s) {
  const r = radius * s
  context.moveTo(x * s + r, y * s)
  context.arc(x * s , y * s, r, 0, 2 * Math.PI)
}

/* 
 * Render the audio visualisation
 */

canvasContext.strokeStyle = 'rgba(0,0,0,1)'
canvasContext.fillStyle = 'rgba(255,255,255,.1)'

function renderOnCanvas(context, frequencyData) {
  context.lineWidth = aaMultiple * lineWidth
  context.fillRect(
    0, 0, 
    width * aaMultiple, height * aaMultiple
  )
  context.beginPath()
  for(let j = 0; j < 10; j++) {
    for(let i = 0; i < 10; i++) {
      render(
        context, 
        (i + 1 ) * 2 * radius //,
            + (j % 2) * radius, // hex 
        -radius / 2 + (9 - j + 1) * 2 // * radius,
            * (radius ** 2 - (radius / 2) ** 2) ** 0.5, 
        frequencyData[(i + 10 * j) * 2] * radius / 255,
        aaMultiple
      )      
    }
  }
  context.stroke()
}

/*
 * Audio input and analyser
 */

navigator.getUserMedia  = MediaDevices.getUserMedia 
                       || navigator.webkitGetUserMedia 
                       || navigator.mozGetUserMedia
const audioApi = new AudioContext()

function makeAnalyser(source) {
  const analyser = audioApi.createAnalyser()
  analyser.fftSize = 2048
  analyser.smoothingTimeConstant = 0.5
  source.connect(analyser)
  return analyser
}

function onStream(stream) {
    const source = audioApi.createMediaStreamSource(stream)
    const analyser = makeAnalyser(source)
    const frequencyData = new Uint8Array(1024)
    d3.timer(t => {
      // side effect: refresh frequencyData
      analyser.getByteFrequencyData(frequencyData)
      // side effect: rerender on canvas
      renderOnCanvas(canvasContext, frequencyData)
    })
}

navigator.getUserMedia(
  {audio:true},
  onStream,
  function(error) {
    console.log("Error: " + error)
  } 
)


  </script>
</body>