# How to display visual cues on the timeline to mark mid-rolls on Web

You may ask this question if you want to let the user know when and how many mid-rolls there are during the video.

Similar questions may be:

* Can I show where my ad is during the video?
* How can I let the user know when the ads will be during the video like in YouTube?
* Can ad markers be added to the timeline?

Showing visual cues indicating the moment in which the ads will start is certainly useful. **This is not (yet) a THEOplayer standard feature, but what follows is a first step in that direction**. Please keep in mind that this solution is still in development and has to date several limitations.

## Prerequisites and limitations

* It only works for THEOplayer ad integration

* A timeOffset for each roll must be included in the AdDescription

* timeOffset values must be one of the following:

* a keyword (“start” and “end” allowed);

* a number (seconds from video beginning);

* undefined (which indicates a pre-roll).

* it has only been tested on Chrome, Firefox and Edge for Win 10 and with the standard THEOplayer UI.

## The code

Add this line to your CSS

```css
.adCue {
  width: 0.3em;
  height: 100%;
  background-color: white;
  position: absolute;
  top: 0;
}
```

Your AdDescription should look something like this

```js
player.source.ads: [
    {
        "sources": "path/to/your-pre/midroll1.xml",
            "timeOffset": value //valid values: ["start", "end", numbers]
    },
    {
        "sources": "path/to/your-pre/midroll2.xml",
            "timeOffset": value //valid values: ["start", "end", numbers]
    },
    {...}
]
```

Include (or call) this JavaScript snippet on your page:

THEOdisplayCues.js

```js
var adsPresent = !!player.source.ads;
var contentDuration = 0;
var to = [];
var checker = true;
var playedAds = [];

player.addEventListener('pause', () => {
  checker = false;
});
player.addEventListener('playing', () => {
  var adIsPlaying = player.ads.playing;
  detectTimeOffset();
  detectDuration(adIsPlaying);
  if (!checker) {
    checker = adIsPlaying;
  }
  if (checker) {
    !adIsPlaying ? drawCues() : destroyCues();
  }
});

player.addEventListener('sourcechange', function () {
  playedAds.length = 0;
});

player.ads.addEventListener('adend', (adEvent) => {
  playedAds.push(adEvent.ad.adBreak.timeOffset);
});

function drawCues() {
  var progressBar = element.querySelector('.vjs-progress-control.vjs-control');

  for (var i = 0; i < to.length; i++) {
    var timeOffset = to[i];

    if (playedAds.indexOf(timeOffset) === -1) {
      var left = (to[i] * progressBar.offsetWidth) / contentDuration;
      var div = document.createElement('div');
      div.setAttribute('to', to[i]);
      div.classList.add('adCue');
      div.style.left = left + 'px';
      progressBar.children[0].appendChild(div);
    }
  }
}

function destroyCues() {
  var cues = element.querySelectorAll('.vjs-progress-control.vjs-control .adCue');
  for (cue of cues) {
    cue.parentNode.removeChild(cue);
  }
}

function detectDuration(adIsPlaying) {
  if (!adIsPlaying) {
    contentDuration = player.duration;
    //console.log("Duration ",contentDuration)
  }
  var t = 0;
  for (var ad of player.source.ads) {
    to[t] = to[t] == 'end' ? contentDuration : to[t];
    t++;
  }
}

function detectTimeOffset() {
  if (adsPresent) {
    var t = 0;
    for (var ad of player.source.ads) {
      to[t] = ad.timeOffset == undefined ? 0 : ad.timeOffset == 'start' ? 0 : ad.timeOffset;
      t++;
    }
  }
  //console.log("TimeOffsets ",to);
}
```
