SVG绘画折线图

代码如下:

1.html代码:

<svg viewBox="0 0 200 100" id="chart">
  <g transform="translate(0, 100) scale(1, -1)" id="path-container">
    <path fill="none" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" id="line" />
  </g>
  <text text-anchor="middle" alignment-baseline="middle" x="100" y="50" class="loading">
    Loading...
  </text>
</svg>

2,css代码:

body {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

#chart {
  background-color: #f6f6f6;
  width: 100%;
  max-width: 1000px;

  --stroke-length: 0;
}

#chart #line {
  stroke: #9F3AF0;
  stroke-dasharray: var(--stroke-length);
  stroke-dashoffset: var(--stroke-length);
}

.name, .caption {
  font-family: Helvetica;
  font-size: 4px;
  font-weight: bold;
  fill: #999;

  animation: .5s fade-in ease-in-out;
  animation-fill-mode: forwards;
}

.values {
  font-family: Helvetica;
  font-size: 3px;
}

@keyframes animate-line {
  from {
    stroke-dashoffset: var(--stroke-length);
  }
  to {
    stroke-dashoffset: 0;
  }
}

#chart.animate #line {
  animation: 3s animate-line linear;
  animation-fill-mode: forwards;
  animation-delay: .3s;
}

@keyframes zoom-in {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

#chart .point {
  opacity: 0;
}

#chart.animate .point {
  animation: .5s fade-in ease-in-out, .5s zoom-in ease-in-out;
  animation-fill-mode: forwards;
  animation-delay: var(--delay);
}

#chart .values {
  opacity: 0;
}

#chart.animate .values {
  animation: .5s fade-in ease-in-out;
  animation-fill-mode: forwards;
  animation-delay: var(--delay);
}

.loading {
  font-family: Helvetica;
  font-size: 5px;
  fill: #999;

  transition: .25s opacity ease-in-out;
}

#chart.animate .loading {
  opacity: 0;
}

3,js代码:

let padding = 15
let start_x = padding
let svg_width = document.querySelector('#chart').viewBox.baseVal.width

function loadData() {
  fetch(`https://codingstartup.com/assets/svg-chart/appl.php`)
    .then((response) => {
      return response.json()
    })
    .then((data) => {
      console.log(`api data`, data)
      drawChart(data)
    })
    .catch((err) => {
      console.log(err)
    })
}

setTimeout(() => {
  loadData()
}, 1000)

function drawChart(api_data) {
  let name = document.createElementNS('http://www.w3.org/2000/svg', 'text')
  name.setAttribute('text-anchor', 'middle')
  name.setAttribute('alignment-baseline', 'middle')
  name.setAttribute('x', svg_width / 2)
  name.setAttribute('y', 6)
  name.classList.add('name')
  name.appendChild(document.createTextNode(api_data['stock_name']))
  document.querySelector('#chart').appendChild(name)

  let stock_data = api_data['data']
  let path_data = []

  for (let i in stock_data) {
    path_data.push(`${start_x}, ${stock_data[i]['normalized']}`)

    let caption = document.createElementNS('http://www.w3.org/2000/svg', 'text')
    caption.setAttribute('text-anchor', 'middle')
    caption.setAttribute('alignment-baseline', 'middle')
    caption.setAttribute('x', start_x)
    caption.setAttribute('y', 96)
    caption.classList.add('caption')
    caption.appendChild(document.createTextNode(stock_data[i]['date']))
    document.querySelector('#chart').appendChild(caption)

    let circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle')
    circle.setAttribute('cx', start_x)
    circle.setAttribute('cy', stock_data[i]['normalized'])
    circle.setAttribute('r', 3)
    circle.setAttribute('stroke', '#9F3AF0')
    circle.setAttribute('stroke-width', 2)
    circle.setAttribute('fill', 'white')
    circle.setAttribute('transform-origin', `${start_x} ${stock_data[i]['normalized']}`)
    circle.style.setProperty('--delay', `${(3 * parseInt(i) / stock_data.length)}s`)
    circle.classList.add('point')
    document.querySelector('#path-container').appendChild(circle)

    let value = document.createElementNS('http://www.w3.org/2000/svg', 'text')
    value.setAttribute('text-anchor', 'middle')
    value.setAttribute('alignment-baseline', 'middle')
    value.setAttribute('x', start_x)
    value.setAttribute('y', stock_data[i]['normalized'])
    value.setAttribute('transform', `translate(0, ${stock_data[i]['normalized'] * 2 - 8}) scale(1, -1)`)
    value.style.setProperty('--delay', `${(3 * parseInt(i) / stock_data.length)}s`)
    value.classList.add('values')
    value.appendChild(document.createTextNode(stock_data[i]['index']))
    document.querySelector('#path-container').appendChild(value)

    start_x += (svg_width - padding * 2) / (stock_data.length - 1)
  }

  let line = document.querySelector('#line')
  line.setAttribute('d', `M${path_data.join(' ')}`)
  let strokeLength = Math.ceil(line.getTotalLength())
  document.querySelector('#chart').style.setProperty('--stroke-length', strokeLength)

  document.querySelector('#chart').classList.add('animate')
}