如何初始化画布并使用vue做出反应

时间:2019-08-01 09:11:26

标签: vuejs2

我是Vue.js的新手,我学习了一些基本技能。现在,我正在尝试解决实际问题。

我正在尝试使用Vue.js绘制一些甜甜圈。在没有Vue的情况下,我可以轻松实现它,但是在我尝试使用Vue.js时,这使我感到困惑。

/*
  canvas: HTMLCanvas node
  ratio: number range: [0, 1]
*/
function pie (canvas, ratio) {
    function arc (ctx, color, radius, radian) {
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.arc(0, 0, radius, 0, radian);
      ctx.closePath();
      ctx.fill();
    }
    
    var width       = canvas.clientWidth, 
        height      = canvas.clientHeight,
        outRadius   = Math.ceil(width / 2 - 10),
        innerRadius = Math.ceil(outRadius * 0.8);
    var ctx = canvas.getContext("2d");
    
    ctx.save();
    
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, width, height);
    ctx.translate(width / 2, height / 2);
    ctx.rotate(-Math.PI / 2);

    arc(ctx, "steelblue", outRadius, Math.PI * 2);
    arc(ctx, "yellow", outRadius + 5, Math.PI * 2 * ratio);
    arc(ctx, "white", innerRadius, Math.PI * 2);

    ctx.restore();
}

Vue.component("pie", {
    props: ["pies"],
    methods: {
        draw: pie
    },
    template: `
<ul class="pie">
    <li v-for="pie in pies">
       <div class="pie__content">
           <h3 class="pie__header">{{pie.ratio}}</h3>
           <canvas v-on:click="draw($event.target, pie.ratio)" width="200" height="200"></canvas>
       </div>
       <h3 class="pie__name">{{pie.name}}</h3>
    </li>
</ul>
`
});


var vm = new Vue({
    el: "#app",
    data: {
        pies: [
            {ratio: 0.45, name: "CPU"},
            {ratio: 0.75, name: "Memory"},
            {ratio: 0.15, name: "Drive"},
        ]
    }
});
canvas { border: 1px solid gray; }
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
    <pie v-bind:pies="pies"></pie>
</div>

  1. 首先,我不知道如何初始化这些画布。在上面运行这些代码,除非用户单击它们,否则它们将是空白的。绝对不是我想要的,但是看来 event 是使它起作用的唯一方法;

  2. 其次,如果我更改了比率,例如:vm.pies[0].ratio = 0.78, 相关画布没有响应。

任何评论将不胜感激!

1 个答案:

答案 0 :(得分:0)

我想念的是Vue Instance Lifecycle。 Vue实例提供一个mounted属性,该属性将在呈现组件之后运行。

  1. 首先,我为canvas元素提供一个ref属性,以便在以后的操作中易于引用。
  2. 创建一个mounted属性函数,该函数将在呈现组件后运行。这可能是初始化函数。
  3. 创建一个computed getter函数formatRatio,该函数将重绘画布(如果可用)并最终以百分比格式返回格式化的ratio字符串。这部分将使饼图对绑定数据具有反应性。

代码如下:

function pie (canvas, ratio) {
    function arc (ctx, color, radius, radian) {
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.arc(0, 0, radius, 0, radian);
      ctx.closePath();
      ctx.fill();
    }
    
    var width       = canvas.clientWidth, 
        height      = canvas.clientHeight,
        outRadius   = Math.ceil(width / 2 - 10),
        innerRadius = Math.ceil(outRadius * 0.8);
    var ctx = canvas.getContext("2d");
    
    ctx.save();
    
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, width, height);
    ctx.translate(width / 2, height / 2);
    ctx.rotate(-Math.PI / 2);

    arc(ctx, "steelblue", outRadius, Math.PI * 2);
    arc(ctx, "yellow", outRadius + 5, Math.PI * 2 * ratio);
    arc(ctx, "white", innerRadius, Math.PI * 2);

    ctx.restore();
}


Vue.component("pie-canvas", {
    props: ["pie"],
    computed: {
        formatRatio: function () {
            // when component is rendered canvas element will be avaible
            if (this.$refs.canvas) {
                pie(this.$refs.canvas, this.pie.ratio);
            }
            return Math.round(this.pie.ratio * 1000) / 10 + "%";
        }
    },
    mounted: function () {
        pie(this.$refs.canvas, this.pie.ratio);
    },
    template: `
<div class="pie__content">
   <h3 class="pie__header">{{ formatRatio }}</h3>
   <canvas ref="canvas" width="200" height="200"></canvas>
</div>
`
});

var vm = new Vue({
    el: "#app",
    data: {
        pies: [
            {ratio: 0.45, name: "CPU"},
            {ratio: 0.75, name: "Memory"},
            {ratio: 0.15, name: "Drive"},
        ]
    }
});
canvas { border: 1px solid gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
<ul class="pie">
    <li v-for="pie in pies">
       <pie-canvas v-bind:pie="pie"></pie-canvas>
       <h3 class="pie__name">{{pie.name}}</h3>
    </li>
</ul>
</div>