DEV Community

mstrVLT
mstrVLT

Posted on

Vue + any js library (like D3.js, Chart.js etc)

While the documentation suggests using ref, useTemplateRef, and onMounted, this approach becomes cumbersome when dealing with multiple libraries. Instead of creating multiple wrapper components or using composables, we can use a custom directive.

const scopeMap = new WeakMap()
// enables v-el in templates
const vEl = {
  mounted: (el, binding) => {
    const scope = effectScope();
    scopeMap.set(el, scope)
    scope.run(() => binding.value && (typeof binding.value === 'function') && binding.value(el));
  },
  unmounted: (el) => {
    const scope = scopeMap.get(el)
    scope && scope.stop();
  }
}
Enter fullscreen mode Exit fullscreen mode

This approach simplifies the process significantly. You only need to add the v-el attribute:

v-el="barChart"
Enter fullscreen mode Exit fullscreen mode

And write the function:

const barChart = (el) => {
  console.log('mount')
  const chart = new Chart(
    el,
    {
      type: 'bar',
      data: {
        labels: data.value.map(row => row.year),
        datasets: [
          {
            label: '',
            data: data.value.map(row => row.count)
          }
        ]
      }
    }
  );

  watch(data, (newData) => {
    console.log('update')
    chart.data.labels = newData.map(row => row.year)
    chart.data.datasets[0].data = newData.map(row => row.count)
    chart.update('none')
  }, {deep: true})
}
Enter fullscreen mode Exit fullscreen mode

Check out the ChartJS example here play.vuejs.org


If you want to use AirDatepicker:

const datepicker = (el) => {
  const dp = new AirDatepicker(el, {
    timepicker: true,
    selectedDates: [currentDate.value],
    onSelect: ({date, formattedDate, datepicker}) => {
      currentDate.value = Array.isArray(date) ? date[0] : date
    }
  })
  watch(currentDate, newCurrentDate => {
    dp.selectDate(newCurrentDate)
  })
}
Enter fullscreen mode Exit fullscreen mode

Check out the AirDatepicker example here play.vuejs.org

Top comments (0)