- const graphsNum = 50
- const graphWidth = 500
- const graphHeight = 200
- const graphPaddingBottom = 30
- const graphPaddingLeft = 40
- const totalLinesCount = 30
- const totalLabelsCount = 10
- const separatorsCount = 10
- const verticalSeparatorsCount = 5
- const lineStepX = (graphWidth - graphPaddingLeft) / totalLinesCount
- const labelStepX = (graphWidth - graphPaddingLeft) / totalLabelsCount
- const separatorStepX = (graphWidth - graphPaddingLeft) / separatorsCount
- const minBarHeight = 40
- const graphLegendPadding = 30
- const labels = ['400k', '300k', '200k', '100k']

h1 SVG Graphs Demo with <use>

//- SVG to be used to hold our reference graphic
//- ⚠️ Notice that is visually hidden with display: none, yet we can still use it's contents as a reference to be drawn
svg(
  xmlns="http://www.w3.org/2000/svg"
  version="1.1"
  width=graphWidth
  viewBox=`0 0 ${graphWidth} ${graphHeight}`
  style="display: none;"
)
  defs
    g#svg-repeated-element
      rect(
        x=graphPaddingLeft + 0
        y=graphHeight - graphLegendPadding / 2
        width=10
        height=10
        fill="url(#negative-value-gradient)"
      )
      text(
        x=graphPaddingLeft + 15
        y=graphHeight - graphLegendPadding / 6
        fill="url(#negative-value-gradient)"
        font-size="14"
        font-family="Helvetica, sans-serif"
      ) Bad

      g
        rect(
          x=graphPaddingLeft + 60
          y=graphHeight - graphLegendPadding / 2
          width=10
          height=10
          fill="url(#positive-value-gradient)"
        )
        text(
          x=graphPaddingLeft + 75
          y=graphHeight - graphLegendPadding / 6
          fill="url(#positive-value-gradient)"
          font-size="14"
          font-family="Helvetica, sans-serif"
        ) Good

      //- Horizontal lines
      each val, i in (new Array(verticalSeparatorsCount + 1).fill(null))
        - const yStep = (graphHeight - graphPaddingBottom - graphLegendPadding) / verticalSeparatorsCount
        - const y = i * yStep
        - const textx = 10
        - const texty = y + yStep + 4
        line(
          x1=graphPaddingLeft
          y1=(y)
          x2=graphWidth
          y2=(y)
          stroke="rgba(0, 0, 0, 0.08)"
        )
        text.graph-label(
          x=textx
          y=texty
          font-size="13"
          font-family="Helvetica, sans-serif"
          transform=`rotate(-30 ${textx} ${texty})`
        ) #{labels[i]}

      //- Left & Right Border lines
      line(
        x1=graphPaddingLeft + 1
        y1=0
        x2=graphPaddingLeft + 1
        y2=graphHeight - graphPaddingBottom - graphLegendPadding
        stroke="rgba(0, 0, 0, 0.08)"
      )
      line(
        x1=graphWidth - 1
        y1=0
        x2=graphWidth - 1
        y2=graphHeight - graphPaddingBottom - graphLegendPadding
        stroke="rgba(0, 0, 0, 0.08)"
      )

      //- Footer horizontal texts
      each val, i in (new Array(totalLabelsCount).fill(null).map((_, i) => i < 10 ? `0${i}` : i))
        text.graph-footer-text(
          x=graphPaddingLeft + i * labelStepX + 2
          y=graphHeight - 10 - graphLegendPadding
          fill="red"
          font-size="11"
          font-family="Helvetica, sans-serif"
        ) #{val}

      //- Footer vertical lines
      each val, i in (new Array(totalLinesCount).fill(null))
        line(
          x1=graphPaddingLeft + i * lineStepX
          y1=graphHeight - 5 - graphLegendPadding
          x2=graphPaddingLeft + i * lineStepX
          y2=graphHeight - graphLegendPadding
          stroke="black"
          strokeWidth=0.5
        )

      //- Dotted separator lines
      each val, i in (new Array(separatorsCount).fill(null))
        unless i === 0
          line(
            x1=i * separatorStepX - 6 + graphPaddingLeft
            y1=0
            x2=i * separatorStepX - 6 + graphPaddingLeft
            y2=graphHeight - graphLegendPadding
            stroke="rgba(0, 0, 0, 0.4)"
            stroke-dasharray=5
          )

div.wrapper
  each val, i in (new Array(graphsNum).fill(null))
    div.graph-wrapper
      header.graph-header
        .graph-title
          .icon-holder
          h5
            span Metric Name 
            | (Graph #{i + 1})
        .graph-metric
          - const metricVal = Math.round(Math.random() * 80 + 20)
          - const comparisonVal = Math.round(Math.random() * 80 + 20)
          - const growthVal = Math.round((metricVal / comparisonVal - 1) * 100)
          if growthVal
            h5.growth-value #{`${growthVal}%`}
          h4.metric-value(style={ color: metricVal > 50 ? 'green' : 'red' }) #{`$${metricVal}`}
          h4.comparison-value #{`vs. $${comparisonVal}`}
          
      svg(
        xmlns="http://www.w3.org/2000/svg"
        version="1.1"
        width=graphWidth
        viewBox=`0 0 ${graphWidth} ${graphHeight}`
      )
        defs
          linearGradient#positive-value-gradient(
            x1=0
            y1=0
            x2=0
            y2=1
          )
            stop(
              stop-color="#2ecc71"
              offset="0%"
            )
            stop(
              stop-color="#27ae60"
              offset="100%"
            )
          linearGradient#negative-value-gradient(
            x1=0
            y1=0
            x2=0
            y2=1
          )
            stop(
              stop-color="#e74c3c"
              offset="0%"
            )
            stop(
              stop-color="#c0392b"
              offset="100%"
            )

        //-
          ⚠️ We simply reference our original graphic here.
          No need to redeclare and repeat it
        use(
          xlink:href="#svg-repeated-element"
          x="0"
          y="0"
        )
        
        //-
          Render our graph bars as boxes to visualise our data.
          💡 This part is different for each graph, since each of them displays different sets of data
        g.graph-data
          each val, i in (new Array(totalLinesCount).fill(null))
            - const height = minBarHeight + Math.random() * (graphHeight - minBarHeight - graphPaddingBottom)
            - const fill = height > 100 ? `url(#positive-value-gradient)` : `url(#negative-value-gradient)`
            rect(
              x=graphPaddingLeft + i * lineStepX
              y=graphHeight - height - graphPaddingBottom
              width=lineStepX * 0.5
              height=height - graphPaddingBottom
              fill=fill
            )
View Compiled
body {
  padding: 0;
  margin: 0;
  font-family: Helvetica, sans-serif;
  line-height: 1.7;
}

h1 {
  text-align: center;
/*   padding-left: 1rem */
}

svg {
  width: 100%;
}

.graph-header {
  margin-top: 8px;
  padding: 0 12px;
  margin-bottom: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.graph-title {
  display: flex;
  align-items: center;
/*   justify-content: center; */
}

.graph-title span {
  font-weight: 400;
}

.growth-value {
  margin: 0;
  font-weight: 400;
  font-size: 12px;
  margin-bottom: -10px;
}

.metric-value {
  font-size: 24px;
  margin: 0;
}

.comparison-value {
  margin: -10px 0 0 0;
  font-size: 12px;
  font-weight: 400;
  color: #aaa
}

.icon-holder {
  position: relative;
  margin-right: 14px;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  background-color: rgba(0, 0, 0, 0.12);
}

.icon-holder:before,
.icon-holder:after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 1px;
  background: white;
}

.icon-holder:before {
  transform: translate(-50%, -50%) rotate(45deg);
}

.icon-holder:after {
  transform: translate(-50%, -50%) rotate(-45deg);
}

.wrapper {
  display: flex;
  flex-wrap: wrap;
  box-shadow: 0px -1px 1px #ccc;
}

.graph-wrapper {
  padding: 0 0.5rem;
  box-sizing: border-box;
  text-align: center;
  width: 50%;
  box-shadow: 1px 1px 1px #ccc;
}

@media (min-width: 1100px) {
  .graph-wrapper {
    width: 33.33%;
    padding: 0 2rem;
  }
}

@media (min-width: 1400px) {
  .graph-wrapper {
    width: 25%;
    padding: 0 0.75rem;
  }
}

/* @media (min-width: 1700px) {
  .graph-wrapper {
    width: 16.66667%;
    padding: 0 0.5rem;
  }
} */

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.