docs: function (id, txt, cb, container) {
    if (typeof container !== 'undefined') {
      container.innerHTML = ''
  
      d3.select(container).append('div')
        .attr('id', 'd' + id)
        .append('svg')
        .attr('id', id)
        .attr('width', '100%')
        .attr('xmlns', 'http://www.w3.org/2000/svg')
        .append('g')
    } else {
      const element = document.querySelector('#' + 'd' + id)
      if (element) {
        element.innerHTML = ''
      }
  
      d3.select('body').append('div')
        .attr('id', 'd' + id)
        .append('svg')
        .attr('id', id)
        .attr('width', '100%')
        .attr('xmlns', 'http://www.w3.org/2000/svg')
        .append('g')
    }
  
    window.txt = txt
    txt = encodeEntities(txt)
  
    const element = d3.select('#d' + id).node()
    const graphType = utils.detectType(txt)
  
    // insert inline style into svg
    const svg = element.firstChild
    const firstChild = svg.firstChild
  
    // pre-defined theme
    let style = themes[config.theme]
    if (style === undefined) {
      style = ''
    }
  
    // user provided theme CSS
    if (config.themeCSS !== undefined) {
      style += `\n${config.themeCSS}`
    }
  
    // classDef
    if (graphType === 'flowchart') {
      const classes = flowRenderer.getClasses(txt)
      for (const className in classes) {
        style += `\n.${className} > * { ${classes[className].styles.join(' !important; ')} !important; }`
      }
    }
  
    const style1 = document.createElement('style')
    style1.innerHTML = scope(style, `#${id}`)
    svg.insertBefore(style1, firstChild)
  
    const style2 = document.createElement('style')
    const cs = window.getComputedStyle(svg)
    style2.innerHTML = `#${id} {
      color: ${cs.color};
      font: ${cs.font};
    }`
    svg.insertBefore(style2, firstChild)
  
    switch (graphType) {
      case 'git':
        config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute
        gitGraphRenderer.setConf(config.git)
        gitGraphRenderer.draw(txt, id, false)
        break
      case 'flowchart':
        config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute
        flowRenderer.setConf(config.flowchart)
        flowRenderer.draw(txt, id, false)
        break
      case 'sequence':
        config.sequence.arrowMarkerAbsolute = config.arrowMarkerAbsolute
        if (config.sequenceDiagram) { // backwards compatibility
          sequenceRenderer.setConf(Object.assign(config.sequence, config.sequenceDiagram))
          console.error('`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.')
        } else {
          sequenceRenderer.setConf(config.sequence)
        }
        sequenceRenderer.draw(txt, id)
        break
      case 'gantt':
        config.gantt.arrowMarkerAbsolute = config.arrowMarkerAbsolute
        ganttRenderer.setConf(config.gantt)
        ganttRenderer.draw(txt, id)
        break
      case 'class':
        config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute
        classRenderer.setConf(config.class)
        classRenderer.draw(txt, id)
        break
    }
  
    d3.select(`[id="${id}"]`).selectAll('foreignobject > *').attr('xmlns', 'http://www.w3.org/1999/xhtml')
  
    let url = ''
    if (config.arrowMarkerAbsolute) {
      url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search
      url = url.replace(/\(/g, '\\(')
      url = url.replace(/\)/g, '\\)')
    }
  
    // Fix for when the base tag is used
    let svgCode = d3.select('#d' + id).node().innerHTML.replace(/url\(#arrowhead/g, 'url(' + url + '#arrowhead', 'g')
  
    svgCode = decodeEntities(svgCode)
  
    if (typeof cb !== 'undefined') {
      cb(svgCode, flowDb.bindFunctions)
    } else {
      logger.warn('CB = undefined!')
    }
  
    const node = d3.select('#d' + id).node()
    if (node !== null && typeof node.remove === 'function') {
      d3.select('#d' + id).node().remove()
    }
  
    return svgCode
  }