Accounts with linked plex accounts can view their watch history per day by duration on number of plays. Have two graphs and adding more requires a new canvas element and new list element in this.charts.
This commit is contained in:
		@@ -1,112 +1,303 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <div class="wrapper">
 | 
					  <div class="wrapper" v-if="hasPlexUser">
 | 
				
			||||||
    <h1>Your activity</h1>
 | 
					    <h1>Your watch activity</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Number of days: <input v-model="days" placeholder="number of days" type="number" />
 | 
					    <div class="filter">
 | 
				
			||||||
 | 
					      <h2>Filter</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <div class="filter-item">
 | 
				
			||||||
 | 
					        <label class="desktop-only">Days:</label>
 | 
				
			||||||
 | 
					        <input class="dayinput"
 | 
				
			||||||
 | 
					               v-model="days"
 | 
				
			||||||
 | 
					               placeholder="number of days"
 | 
				
			||||||
 | 
					               type="number"
 | 
				
			||||||
 | 
					               pattern="[0-9]*"
 | 
				
			||||||
 | 
					               :style="{maxWidth: `${3 + (0.5 * days.length)}rem`}"/>
 | 
				
			||||||
 | 
					<!--         <datalist id="days">
 | 
				
			||||||
 | 
					          <option v-for="index in 1500" :value="index" :key="index"></option>
 | 
				
			||||||
 | 
					        </datalist> -->
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <toggle-button class="filter-item" :options="chartTypes" :selected.sync="selectedChartDataType" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="chart-section">
 | 
					    <div class="chart-section">
 | 
				
			||||||
 | 
					      <h3 class="chart-header">Activity per day:</h3>
 | 
				
			||||||
      <div class="chart">
 | 
					      <div class="chart">
 | 
				
			||||||
        <canvas ref="activityCanvas"></canvas>
 | 
					        <canvas ref="activityCanvas"></canvas>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <h3 class="chart-header">Activity per day of week:</h3>
 | 
				
			||||||
 | 
					      <div class="chart">
 | 
				
			||||||
 | 
					        <canvas ref="playsByDayOfWeekCanvas"></canvas>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					  <div v-else>
 | 
				
			||||||
 | 
					    <h1>Must be authenticated</h1>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					import store from '@/store'
 | 
				
			||||||
 | 
					import ToggleButton from '@/components/ui/ToggleButton.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var Chart = require('chart.js');
 | 
					var Chart = require('chart.js');
 | 
				
			||||||
 | 
					Chart.defaults.global.elements.point.radius = 0
 | 
				
			||||||
 | 
					Chart.defaults.global.elements.point.hitRadius = 10
 | 
				
			||||||
 | 
					Chart.defaults.global.elements.point.pointHoverRadius = 10
 | 
				
			||||||
 | 
					Chart.defaults.global.elements.point.hoverBorderWidth = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
 | 
					  components: { ToggleButton },
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      days: 30,
 | 
					      days: 30,
 | 
				
			||||||
      series: undefined,
 | 
					      selectedChartDataType: 'plays',
 | 
				
			||||||
      categories: undefined,
 | 
					      charts: [{
 | 
				
			||||||
      activityChart: undefined
 | 
					        name: 'Watch activity',
 | 
				
			||||||
 | 
					        ref: 'activityCanvas',
 | 
				
			||||||
 | 
					        data: null,
 | 
				
			||||||
 | 
					        urlPath: 'api/v1/user/plays_by_day',
 | 
				
			||||||
 | 
					        graphType: 'line'
 | 
				
			||||||
 | 
					      }, {
 | 
				
			||||||
 | 
					        name: 'Plays by day of week',
 | 
				
			||||||
 | 
					        ref: 'playsByDayOfWeekCanvas',
 | 
				
			||||||
 | 
					        data: null,
 | 
				
			||||||
 | 
					        urlPath: 'api/v1/user/plays_by_dayofweek',
 | 
				
			||||||
 | 
					        graphType: 'bar'
 | 
				
			||||||
 | 
					      }],
 | 
				
			||||||
 | 
					      chartData: [{
 | 
				
			||||||
 | 
					        type: 'plays',
 | 
				
			||||||
 | 
					        tooltipLabel: 'Play count',
 | 
				
			||||||
 | 
					      },{
 | 
				
			||||||
 | 
					        type: 'duration',
 | 
				
			||||||
 | 
					        tooltipLabel: 'Watched duration',
 | 
				
			||||||
 | 
					        valueConvertFunction: this.convertSecondsToHumanReadable
 | 
				
			||||||
 | 
					      }],
 | 
				
			||||||
 | 
					      gridColor: getComputedStyle(document.documentElement).getPropertyValue('--text-color-5')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    hasPlexUser() {
 | 
				
			||||||
 | 
					      return store.getters['userModule/plex_userid'] != null ? true : false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    chartTypes() {
 | 
				
			||||||
 | 
					      return this.chartData.map(chart => chart.type)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    selectedChartType() {
 | 
				
			||||||
 | 
					      return this.chartData.filter(data => data.type == this.selectedChartDataType)[0]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  watch: {
 | 
					  watch: {
 | 
				
			||||||
    days: function(newValue) {
 | 
					    hasPlexUser(newValue, oldValue) {
 | 
				
			||||||
      if (newValue !== '')
 | 
					      if (newValue != oldValue && newValue == true) {
 | 
				
			||||||
        this.fetchActivity()
 | 
					        this.fetchChartData(this.charts)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    days(newValue) {
 | 
				
			||||||
 | 
					      if (newValue !== '') {
 | 
				
			||||||
 | 
					        this.fetchChartData(this.charts)
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    selectedChartDataType(selectedChartDataType) {
 | 
				
			||||||
 | 
					      this.fetchChartData(this.charts)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  beforeMount() {
 | 
					  beforeMount() {
 | 
				
			||||||
    this.fetchActivity()
 | 
					    if (typeof(this.days) == 'number') {
 | 
				
			||||||
 | 
					      this.days = this.days.toString()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    generateChart(canvas, labels, datasets) {
 | 
					    fetchChartData(charts) {
 | 
				
			||||||
      this.activityChart = new Chart(canvas, {
 | 
					      if (this.hasPlexUser == false) {
 | 
				
			||||||
        type: 'line',
 | 
					        return
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (let chart of charts) {
 | 
				
			||||||
 | 
					        const url = new URL(chart.urlPath, 'http://10.0.0.10:31459')
 | 
				
			||||||
 | 
					        url.searchParams.append('days', this.days)
 | 
				
			||||||
 | 
					        url.searchParams.append('y_axis', this.selectedChartType.type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const headers = {
 | 
				
			||||||
 | 
					          authorization: localStorage.getItem('token')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fetch(url.href, { headers })
 | 
				
			||||||
 | 
					          .then(resp => resp.json())
 | 
				
			||||||
 | 
					          .then(data => {
 | 
				
			||||||
 | 
					            this.series = data.data.series.filter(group => group.name === 'TV')[0].data;      // plays pr date in groups (movie/tv/music)
 | 
				
			||||||
 | 
					            this.categories = data.data.categories;  // dates
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const x_labels = data.data.categories.map(date => {
 | 
				
			||||||
 | 
					              if (date.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/)) {
 | 
				
			||||||
 | 
					                const [year, month, day] = date.split('-')
 | 
				
			||||||
 | 
					                return `${day}.${month}`
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              return date
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            let y_activityMovies = data.data.series.filter(group => group.name === 'Movies')[0].data
 | 
				
			||||||
 | 
					            let y_activityTV = data.data.series.filter(group => group.name === 'TV')[0].data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const datasets = [{
 | 
				
			||||||
 | 
					                label: `Movies watch last ${ this.days } days`,
 | 
				
			||||||
 | 
					                data: y_activityMovies,
 | 
				
			||||||
 | 
					                backgroundColor: 'rgba(54, 162, 235, 0.2)',
 | 
				
			||||||
 | 
					                borderColor: 'rgba(54, 162, 235, 1)',
 | 
				
			||||||
 | 
					                borderWidth: 1
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                label: `Shows watch last ${ this.days } days`,
 | 
				
			||||||
 | 
					                data: y_activityTV,
 | 
				
			||||||
 | 
					                backgroundColor: 'rgba(255, 159, 64, 0.2)',
 | 
				
			||||||
 | 
					                borderColor: 'rgba(255, 159, 64, 1)',
 | 
				
			||||||
 | 
					                borderWidth: 1
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (chart.data == null) {
 | 
				
			||||||
 | 
					              this.generateChart(chart, x_labels, datasets)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              chart.data.clear();
 | 
				
			||||||
 | 
					              chart.data.data.labels = x_labels;
 | 
				
			||||||
 | 
					              chart.data.data.datasets = datasets;
 | 
				
			||||||
 | 
					              chart.data.update();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    generateChart(chart, labels, datasets) {
 | 
				
			||||||
 | 
					      const chartInstance = new Chart(this.$refs[chart.ref], {
 | 
				
			||||||
 | 
					        type: chart.graphType,
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
            labels: labels,
 | 
					            labels: labels,
 | 
				
			||||||
            datasets: datasets
 | 
					            datasets: datasets
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        options: {
 | 
					        options: {
 | 
				
			||||||
 | 
					          // hitRadius: 8,
 | 
				
			||||||
          maintainAspectRatio: false,
 | 
					          maintainAspectRatio: false,
 | 
				
			||||||
 | 
					          tooltips: {
 | 
				
			||||||
 | 
					            callbacks: {
 | 
				
			||||||
 | 
					              title: (tooltipItem, data) => `Watch date: ${tooltipItem[0].label}`,
 | 
				
			||||||
 | 
					              label: (tooltipItem, data) => {
 | 
				
			||||||
 | 
					                let label = data.datasets[tooltipItem.datasetIndex].label
 | 
				
			||||||
 | 
					                let value = tooltipItem.value;
 | 
				
			||||||
 | 
					                let text = 'Duration watched'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const context = label.split(' ')[0]
 | 
				
			||||||
 | 
					                if (context) {
 | 
				
			||||||
 | 
					                  text = `${context} ${this.selectedChartType.tooltipLabel.toLowerCase()}`
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (this.selectedChartType.valueConvertFunction) {
 | 
				
			||||||
 | 
					                  value = this.selectedChartType.valueConvertFunction(tooltipItem.value)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return ` ${text}: ${value}`
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
          scales: {
 | 
					          scales: {
 | 
				
			||||||
              yAxes: [{
 | 
					              yAxes: [{
 | 
				
			||||||
                  ticks: {
 | 
					                gridLines: {
 | 
				
			||||||
                      beginAtZero: true
 | 
					                    color: this.gridColor
 | 
				
			||||||
                  }
 | 
					                },
 | 
				
			||||||
 | 
					                stacked: chart.graphType === 'bar',
 | 
				
			||||||
 | 
					                ticks: {
 | 
				
			||||||
 | 
					                  // suggestedMax: 10000,
 | 
				
			||||||
 | 
					                  callback: (value, index, values) => {
 | 
				
			||||||
 | 
					                    if (this.selectedChartType.valueConvertFunction) {
 | 
				
			||||||
 | 
					                      return this.selectedChartType.valueConvertFunction(value, values)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    return value
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  beginAtZero: true
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }],
 | 
				
			||||||
 | 
					              xAxes: [{
 | 
				
			||||||
 | 
					                stacked: chart.graphType === 'bar',
 | 
				
			||||||
 | 
					                gridLines: {
 | 
				
			||||||
 | 
					                  display: false,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              }]
 | 
					              }]
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    fetchActivity() {
 | 
					 | 
				
			||||||
      const url = new URL('api/v1/user/plays_by_day', 'http://localhost:31459')
 | 
					 | 
				
			||||||
      url.searchParams.append('days', this.days)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const headers = {
 | 
					      chart.data = chartInstance;
 | 
				
			||||||
        authorization: localStorage.getItem('token')
 | 
					    },
 | 
				
			||||||
 | 
					    convertSecondsToHumanReadable(value, values=null) {
 | 
				
			||||||
 | 
					      const highestValue = values ? values[0] : value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // minutes
 | 
				
			||||||
 | 
					      if (highestValue < 3600) {
 | 
				
			||||||
 | 
					        const minutes = Math.floor(value / 60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = `${minutes} m`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // hours and minutes
 | 
				
			||||||
 | 
					      else if (highestValue > 3600 && highestValue < 86400) {
 | 
				
			||||||
 | 
					        const hours = Math.floor(value / 3600);
 | 
				
			||||||
 | 
					        const minutes = Math.floor(value % 3600 / 60);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = hours != 0 ? `${hours} h ${minutes} m` : `${minutes} m`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // days and hours
 | 
				
			||||||
 | 
					      else if (highestValue > 86400 && highestValue < 31557600) {
 | 
				
			||||||
 | 
					        const days = Math.floor(value / 86400);
 | 
				
			||||||
 | 
					        const hours = Math.floor(value % 86400 / 3600);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = days != 0 ? `${days} d ${hours} h` : `${hours} h`
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // years and days
 | 
				
			||||||
 | 
					      else if (highestValue > 31557600) {
 | 
				
			||||||
 | 
					        const years = Math.floor(value / 31557600);
 | 
				
			||||||
 | 
					        const days = Math.floor(value % 31557600 / 86400);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = years != 0 ? `${years} y ${days} d` : `${days} d`
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      fetch(url.href, { headers })
 | 
					      return value
 | 
				
			||||||
        .then(resp => resp.json())
 | 
					 | 
				
			||||||
        .then(data => {
 | 
					 | 
				
			||||||
          console.log('data from plays by day', data)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          this.series = data.data.series.filter(group => group.name === 'TV')[0].data;      // plays pr date in groups (movie/tv/music)
 | 
					 | 
				
			||||||
          this.categories = data.data.categories;  // dates
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          const x_labels = data.data.categories.map(date => date.replace('2019-', ''))
 | 
					 | 
				
			||||||
          const y_activityMovies = data.data.series.filter(group => group.name === 'Movies')[0].data
 | 
					 | 
				
			||||||
          const y_activityTV = data.data.series.filter(group => group.name === 'TV')[0].data
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          const datasets = [{
 | 
					 | 
				
			||||||
              label: `Movies watch last ${ this.days } days`,
 | 
					 | 
				
			||||||
              data: y_activityMovies,
 | 
					 | 
				
			||||||
              backgroundColor: 'rgba(54, 162, 235, 0.2)',
 | 
					 | 
				
			||||||
              borderColor: 'rgba(54, 162, 235, 1)',
 | 
					 | 
				
			||||||
              borderWidth: 1
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
              label: `Shows watch last ${ this.days } days`,
 | 
					 | 
				
			||||||
              data: y_activityTV,
 | 
					 | 
				
			||||||
              backgroundColor: 'rgba(255, 159, 64, 0.2)',
 | 
					 | 
				
			||||||
              borderColor: 'rgba(255, 159, 64, 1)',
 | 
					 | 
				
			||||||
              borderWidth: 1
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if (this.activityChart === undefined) {
 | 
					 | 
				
			||||||
            this.generateChart(this.$refs.activityCanvas, x_labels, datasets)
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            console.log('this.act', this.activityChart.data)
 | 
					 | 
				
			||||||
            this.activityChart.data.labels = x_labels;
 | 
					 | 
				
			||||||
            this.activityChart.data.datasets = datasets;
 | 
					 | 
				
			||||||
            this.activityChart.update();
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
 | 
					@import "./src/scss/variables";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.wrapper {
 | 
					.wrapper {
 | 
				
			||||||
  padding: 2rem;
 | 
					  padding: 2rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @include mobile-only {
 | 
				
			||||||
 | 
					    padding: 0 0.8rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.filter {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  flex-direction: row;
 | 
				
			||||||
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  margin-bottom: 2rem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  h2 {
 | 
				
			||||||
 | 
					    margin-bottom: 0.5rem;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    font-weight: 400;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &-item:not(:first-of-type) {
 | 
				
			||||||
 | 
					    margin-left: 1rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .dayinput {
 | 
				
			||||||
 | 
					    font-size: 1.2rem;
 | 
				
			||||||
 | 
					    max-width: 3rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.chart-section {
 | 
					.chart-section {
 | 
				
			||||||
@@ -115,8 +306,13 @@ export default {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  .chart {
 | 
					  .chart {
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    height: 50vh;
 | 
					    height: 35vh;
 | 
				
			||||||
    width: 90vw;
 | 
					    width: 90vw;
 | 
				
			||||||
 | 
					    margin-bottom: 2rem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .chart-header {
 | 
				
			||||||
 | 
					    font-weight: 300;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user