ChartJS在Vue工作

时间:2018-03-01 03:57:17

标签: javascript vue.js chart.js

我正在制作一个小小的生产力应用程序/游戏,让我在浪费时总是感觉更好。我正在使用vue和chartjs,而且看起来彼此并不好玩。

当我在<canvas>中包含我的<div id="app">元素时,在chartjs上启动的一个vue无法呈现任何内容。没有任何错误或任何错误。但是,当我将<canvas>移到<div id="app">之外时,它的效果非常好。没有人对此有任何见解吗?

HTML

<body>

  <div id="app">
    <div id="header">
      <h1>GAME OF LIFE!</h1>
    </div>
    <div class="character_container">
      <div class="health_bar">
        <div class="life"></div>
      </div>
      <div class="character">
        <img id="sprite" src="imgs/melee/1.png" width="100" height="100px">
        <div class="stats">
          <p>ed</p>
          <p>3</p>
          <p>3</p>
          <p>da</p>
          <p>adf</p>
          <p>adf</p>
        </div>
      </div>
    </div>
    <div id="dashboard">
      <h2>GAME DATA</h2>
      <input type="date" name="viewDate" v-model="viewDate">
    </div>
    <!-- Doesn't work when canvas inside #app -->
    <div class="canvas">
      <canvas></canvas>
    </div>
  </div>
  <!-- Works when the canvas is outside #app -->
  <!-- <div class="canvas">
    <canvas></canvas>
  </div> -->

  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
  <script src="vue.js"></script>
  <script src="app.js"></script>
</body>

的Javascript

    const day = ( x => {
      let date = (t => new Date(t.getFullYear(), t.getMonth(), t.getDate(), 0, 0, 0))(new Date());
      return new Date(date.setDate(date.getDate() + x));
    });
    const padDate = (x => (x.toString().length <= 1? '0'+ x : x));
    const format = (x => formatDate(new Date(x)));
    const formatDate =  (fd => padDate(fd.getUTCMonth() + 1)+'/'+padDate(fd.getUTCDate())+'/'+fd.getUTCFullYear()+' 00:00');

    const serverUrl = 'http://localhost:3000/logs';
    const ctx = document.querySelector("canvas").getContext("2d");

    const chartConfig = {
      type: 'bar',
      data: {
        labels: [],
        datasets: [{
          type: 'bar',
          label: 'Productivity',
          backgroundColor: 'rgba(255, 0, 0, .5)',
          borderColor: 'rgba(255, 0, 0, .5)',
          data: [],
        }, {
          type: 'line',
          label: 'Code Written',
          backgroundColor: 'rgba(0, 255, 0, .5)',
          borderColor: 'rgba(0, 255, 0, .5)',
          fill: false,
          data: [],
        }, ]
      },
      options: {
                title: {
                    text:"Productivity Graph"
                },
        scales: {
          xAxes: [{
            type: "time",
            display: true,
            time: {
              format: 'MM/DD/YYYY HH:mm',
              round: 'day',
              unit: 'day'
            }
          }],
        },
      }
    };

    function fetchData() {
      return fetch(serverUrl).then(function (res){
        return res.json();
      })
    }

    function dateToISO(date) {
      var msec = Date.parse(date);
      return new Date(msec).toISOString().substring(0, 10);
    }



    function updateLog(logData){
      const headers = {
        headers: {
          'Access-Control-Allow-Origin':'*',
          'Content-Type': 'application/json'
        },
        method: "PUT",
        body:  JSON.stringify(logData)
      };
      return fetch('http://localhost:3000/logs',headers).then(function(res){
        return res.json();
      });
    }

    function runSprite(){
      // NOTE https://www.gameart2d.com/the-robot---free-sprites.html
      // NOTE Melee(Good) 8, Run(Normal) 8, DEAD(Bad) 10
      let path = 'imgs/';
      let i = app.sprite.index;
      switch (app.sprite.status) {
        case 'good':
          path += 'melee/';
          i = (i >= 26 ? 1 : ++i);
          break;
        case 'avg':
          path += 'run/';
          i = (i >= 8 ? 1 : ++i);
          break;
        case 'bad':
          path += 'dead/';
          i = (i >= 10 ? 1 : ++i);
          break;  
      }
      path += i;
      app.sprite.index = i;
      document.querySelector('#sprite').src = path + ".png";
    }

    setInterval(runSprite, 100);

    var app = new Vue({
      el: '#app',
      data: {
        viewDate:  new Date().toISOString().substring(0, 10),
        sprite: {
          status: 'good',
          index: 1
        },
        logs: [],
        log:{},
        chart: chartConfig,
        line: '',
        productivityMinutesGoal: 560,
        projectsMinutesGoal: 300,
        health_bar: 100,
        visible: true
      },
      methods : {
        updateChart: function(data, build = false){
          this.logs = data;
          const productivityAverages = this.logs
                                      .map(x => x.productivity)
                                      .reduce((a, b, index, self) => {
                                         const keys = Object.keys(a)
                                         let c = {} 
                                         keys.map((key) => {
                                          c[key] = a[key] + b[key]
                                          if (index + 1 === self.length) {
                                            c[key] = c[key] / self.length
                                          }
                                         })
                                         return c
                                      });

          const projectsAverages = this.logs
                                      .map(x => x.projects.data[0].grand_total)
                                      .reduce((a, b, index, self) => {
                                         const keys = Object.keys(a)
                                         let c = {} 
                                         keys.map((key) => {
                                          c[key] = a[key] + b[key]
                                          if (index + 1 === self.length) {
                                            c[key] = c[key] / self.length
                                          }
                                         })
                                         return c
                                      });

          // above 90% equals + to health_bar;
          // below 90% equals - to health_bar; 
          // below 50% should equal death;
          this.health_bar += ((projectsAverages.hours * 60 + projectsAverages.minutes) / this.projectsMinutesGoal ) - 90;
          this.health_bar += ((productivityAverages.software_development_hours * 60) / this.productivityMinutesGoal ) - 90;
          this.health_bar = Math.round(this.health_bar);
          document.querySelector('.health_bar .life').setAttribute('style','width:'+ (100 + this.health_bar)+'%;');
          const loggedData = this.logs
                            .map(x => {return {
                              date:x.date, 
                              projectTimeMinutes:((x.projects.data[0].grand_total.hours * 60) + x.projects.data[0].grand_total.minutes - (projectsAverages.hours * 60 + projectsAverages.minutes)), 
                              productivitySoftwareMinutes: (x.productivity.software_development_hours * 60 - (productivityAverages.software_development_hours * 60))}
                            })
                            .sort((a,b) => new Date(b.date) - new Date(a.date));

          loggedData.forEach(x => {
            this.chart.data.labels.push(format(x.date));
            this.chart.data.datasets[0].data.push(x.productivitySoftwareMinutes);
            this.chart.data.datasets[1].data.push(x.projectTimeMinutes);

          });
          // Handle Build default update
          if(build){
            this.line = new Chart(ctx, this.chart);
          }else{
            this.line.update();
          }
        }  

      },
      computed: {
        dateIsValid: function (){
          return this.friend.name.length == 0 || this.friend.feature.length == 0;
        }
      },
      created: function (){
        fetchData().then(function (data){
          app.updateChart(data, true);
        });
      }
    });

1 个答案:

答案 0 :(得分:1)

这是一个包含组件的codepen供您参考。所有这一切都让Vue能够意识到你在做什么。请告诉我您还有其他任何问题。

https://codepen.io/anon/pen/qxgPqB

Vue.component("me", {
  template: '<canvas id="canvas" width="800px" height="800px"></canvas>',
  methods: {
    draw: function(ctx) {
      var myChart = new Chart(ctx, {
        type: "bar",
        data: {
          labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
          datasets: [
            {
              label: "# of Votes",
              data: [12, 19, 3, 5, 2, 3],
              backgroundColor: [
                "rgba(255, 99, 132, 0.2)",
                "rgba(54, 162, 235, 0.2)",
                "rgba(255, 206, 86, 0.2)",
                "rgba(75, 192, 192, 0.2)",
                "rgba(153, 102, 255, 0.2)",
                "rgba(255, 159, 64, 0.2)"
              ],
              borderColor: [
                "rgba(255,99,132,1)",
                "rgba(54, 162, 235, 1)",
                "rgba(255, 206, 86, 1)",
                "rgba(75, 192, 192, 1)",
                "rgba(153, 102, 255, 1)",
                "rgba(255, 159, 64, 1)"
              ],
              borderWidth: 1
            }
          ]
        },
        options: {
          scales: {
            yAxes: [
              {
                ticks: {
                  beginAtZero: true
                }
              }
            ]
          }
        }
      });
    }
  },
  mounted: function() {
    var c = document.getElementById("canvas");
    var ctx = c.getContext("2d");
    ctx.translate(0.5, 0.5);
    ctx.imageSmoothingEnabled = false;
    this.draw(ctx);
  }
});

var app = new Vue({
  el: "#app",
  data: {}
});