0

I am working on an application for psychology researches. In some specific cases, the web application need to display an image for a very short amount of time (like 20-50ms).

Loading the image from the internet is not an issue as the program will cache all images when entering the site with following script.

  for stimulus in stimuli
    if stimulus
      extension = stimulus.split(".").pop()
      if extension.match(/png|jpg|jpeg|gif|bmp/i)
        # Pre-cache every image to the browser by creating dummy image DOMs
        image = $("<img src='#{stimulus}' style='display:none;'></img>")
        $(document.body).append(image)

However, the problem is as following: when I append the image DOM to the container, a timer function will be immediately created, after designated time (like 10ms) the function will remove the image DOM and display next image. This works perfectly when the timeout is long enough (> 100ms), but sometimes the image just won't display on the screen if the timeout is very short (like 10-50ms). My current work around is apply a opacity animation for few milliseconds before the image has been removed. Not only this is not a good method, sometimes (subjective observation) the image will display longer and sometime it displays shorter.

  # Call render function to get the image DOM
  $("#stimulus-container").append(stimulus.render(_i + 1, stimuli.length))
  if maxTimeout > 0
    nextTimer = setTimeout(->
      clearTimeout(nextTimer)
      # Current (bad) workaround defer the removal of the image DOM
      $("#stimulus-container *").animate({
        opacity: 0,
      }, 50, () ->
        # Remove current image and display next
        playStimulus(nextSequence)
      )
    # The designated time to display the image
    , maxTimeout
    )

I believe the problem may be related to the latency of DOM operations. Is there any good workarounds for my code, or should I use other approaches such as CSS animation / Canvas to reimplement? I am new to these (CSS animation / Canvas) so any detail suggested for implementation would be highly appreciated. The key point is to display an image on screen for a very short (and stable) period of time. Thank you very much for your attention.

Peter Chan
  • 63
  • 1
  • 4

1 Answers1

2

You are right, DOM latencies can sometimes be too high especially for manipulations in a short time frame like that. However, you could just use one DOM image element, preload all needed images and change the image's src attribute each 20ms.

I have compiled a short demo for you: http://codepen.io/cgav/pen/MaKbJg?editors=101

HTML:

<img id="image" />

JS:

allImages = []
urls = [
  # the images' URLs go in here
]

DURATION = 10

startTimer = ->
  domImage = document.getElementById("image")
  counter = 0
  setInterval ->
    domImage.src = allImages[counter].dataurl
    counter++
    counter = 0 if counter is allImages.length
  , DURATION

storeNextDataURLFromImage = () ->
  url = urls.pop()
  if not url?
    return startTimer()

  img = new Image()
  img.crossOrigin = "Anonymous"  # this is needed to avoid http://stackoverflow.com/questions/22710627/tainted-canvases-may-not-be-exported 
  img.onload = (e) ->
    canvas = document.createElement("canvas")
    canvas.width = img.width
    canvas.height = img.height

    ctx = canvas.getContext("2d")
    ctx.drawImage(img, 0, 0)
    allImages.push {
      dataurl: canvas.toDataURL()
      width: img.width
      height: img.height
    }
    storeNextDataURLFromImage()

  img.src = url

storeNextDataURLFromImage()  
ccg
  • 313
  • 2
  • 8