Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eliminate the flickering when re-evaluating code in an iFrame. #188

Open
micahstubbs opened this issue Feb 6, 2017 · 4 comments
Open

eliminate the flickering when re-evaluating code in an iFrame. #188

micahstubbs opened this issue Feb 6, 2017 · 4 comments
Labels

Comments

@micahstubbs
Copy link
Collaborator

screen shot 2017-02-05 at 4 55 52 pm

curran/example-viewer#12

https://curran.github.io/d3-in-motion/#1/1/11

@curran
Copy link
Collaborator

curran commented Feb 6, 2017

It appears this could be implemented entirely within the updateIFrame() function in renderer.js:

https://github.com/enjalot/blockbuilder/blob/master/public/js/components/renderer.js#L89

@micahstubbs micahstubbs added the bug label May 5, 2017
@curran
Copy link
Collaborator

curran commented Mar 30, 2018

Here's the React implementation we're using in Datavis.tech:

import React, { Component } from 'react'
import magicSandbox from 'magic-sandbox'

// Z Indices for layering iframe buffers.
const BACK = 4
const FRONT = 5

const defaultUpdateInterval = 300

// This "dumb" component runs the code for a visualization in an iframe.
export default class RunnerRenderer extends Component {
  constructor (props) {
    super(props)
    const updateInterval = props.updateInterval || defaultUpdateInterval
    this.contentChanged = true
    this.swapped = true

    this.interval = setInterval(() => {
      if (this.iFrameRefA && this.iFrameRefB) {
        if (this.needsBufferSwap) {
          this.swapBuffers()
          this.needsBufferSwap = false
        }
        if (this.contentChanged) {
          this.updateBackBuffer()
          this.needsBufferSwap = true
          this.contentChanged = false
        }
      }
    }, updateInterval)
  }

  swapBuffers () {
    this.swapped = !this.swapped
    this.backBuffer().style.zIndex = BACK
    this.frontBuffer().style.zIndex = FRONT
  }

  updateBackBuffer () {
    const {template, files} = this.props
    const srcDoc = magicSandbox(template, files)
    this.backBuffer().setAttribute('srcDoc', srcDoc)
  }

  backBuffer () {
    return this.swapped ? this.iFrameRefA : this.iFrameRefB
  }

  frontBuffer () {
    return this.swapped ? this.iFrameRefB : this.iFrameRefA
  }

  componentWillUnmount () {
    clearInterval(this.interval)
  }

  shouldComponentUpdate (nextProps) {
    this.contentChanged = true
    return false
  }

  render () {
    const width = '100%'
    const height = '500'
    const style = { position: 'absolute', top: '0px', left: '0px' }

    return (
      <div style={{position: 'relative', height: height + 'px'}} >
        <iframe
          ref={el => { this.iFrameRefA = el }}
          style={style}
          width={width}
          height={height}
          scrolling='no'
        />
        <iframe
          ref={el => { this.iFrameRefB = el }}
          style={style}
          width={width}
          height={height}
          scrolling='no'
        />
      </div>
    )
  }
}

@micahstubbs
Copy link
Collaborator Author

thanks for sharing this @curran 😄

would be happy to review a PR to add this improvement if you'd like to contribute it in that form 😄

@curran
Copy link
Collaborator

curran commented Mar 31, 2018

I'm noticing Blockbuilder handles the rendering if the iFrame a bit differently, using a Blob source URL rather than setting srcDoc. It looks like a bit of refactoring will be required around https://github.com/enjalot/blockbuilder/blob/master/public/js/components/renderer.js#L89

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants