【问题标题】:tween does not update text label format in Vue/ D3补间不更新 Vue/D3 中的文本标签格式
【发布时间】:2020-11-23 04:05:29
【问题描述】:

我一直在尝试将在简单 D3 中完美运行的代码传递给 Vue。这部分代码应该更新条形图的标签文本,但不起作用。这是data.csv:

country,population
China,2535
India,1654
United States,700
Indonesia,680
Brazil,1785
Total,1821

这是管理条形图的代码:

import formatCurrency from '../mixins/formatCurrency';
import formatTime from '../mixins/formatTime';

import {
    select,
    scaleLinear,
    max,
    scaleBand,
    interpolate,
    axisLeft,
    axisBottom,
    forceX,
    csv,
    filter
} from 'd3';


//..
data: () => ({
        dataset: [],
        dataFiltrada: [],
    }),
//..

async mounted() {
        let datos = await csv('/datasets/data.csv')
        this.dataset = Object.freeze(datos)
        //..
        this.graph()
    },
computed: {
    //..
    filtrarData() {
       this.dataFiltrada = this.dataset.filter(d => { return d.country !=='Total'})},
},

methods: {
  graph(){
//..
    const numeros = g.selectAll(this.label).data(this.dataFiltrada)
    numeros
       .enter().append("text")
         .attr("class", this.label)                        
         .attr('x', this.xEtiqueta)
         .attr('y', d => { return -yScale(d.country); })
         .attr('dy', this.yEtiqueta)
         .text(0)                 

      .merge(numeros)
        .transition().duration(this.time)
        .tween(this.label, d => {
             var i = interpolate(1, d.population);
             if (d.population != 0)
             return function(t) {    
                 select(this).text(d => {
                     return (this.label === 'labelg1')                                            
                            ? this.formatCurrency(i(t))
                            : this.formatTime(i(t))
}                                    
//..
mixins: [
        formatCurrency,
        formatTime,
    ],
}

过渡正常,但格式未更新。当我 console.log formatCurrency 具有 function(t) 之外的任何值时,它可以,但 function(t) 的范围内不起作用。 formatCurrency 函数是这样的:

import { format } from 'd3';

export default {
    methods: {
        formatCurrency:(() => {
          var cantNum;
          var formatofinal;
          var simbol = "$";

          function digits_count(n) {
              var count = 0;
              if (n >= 1) ++count;

              while (n / 10 >= 1) {
                  n /= 10;
                  ++count;
              }
              return count;
          };

          function processCantNumAndFormatOfinal(n){
              if (digits_count(n) === 0) {
                  cantNum = 0;
                  formatofinal ='r';
              }
              else if (digits_count(n) === 1) {
                  cantNum = 1;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 2) {
                  cantNum = 2;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 3) {
                  cantNum = 3;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 4) {
                  cantNum = 2;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 5) {
                  cantNum = 3;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 6) {
                  cantNum = 3;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 7) {
                  cantNum = 2;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 8) {
                  cantNum = 3;
                  formatofinal ='s';
              }
              else if (digits_count(n) === 9) {
                  cantNum = 3;
                  formatofinal ='s';
              }
              else {
                  cantNum = 2;
                  formatofinal ='s';
              };
          }

          function formatear(n) {
            // Process cantNum and formatofinal here ... function call
            processCantNumAndFormatOfinal(n);
            const formato = simbol + format(",."+ cantNum +formatofinal)(n)
                .replace('.', ',')
                .replace('G', 'B');
                return formato;
          };

          return function(n)
          {
            return formatear(n);
          }
        }
    })()
}

我也尝试过箭头功能,但数据归零。

.merge(numeros)
     .transition().duration(this.tiempo)
     .tween(this.label, d => {
         var i = interpolate(1, d.population);
         if (d.population != 0)
         return (t) => { //..}

已编辑:

现在我注意到了两件事:

  1. this.label 在函数 (t) 中无法识别。当我改变这个时:
(this.label === 'labelg1')

进入这个:

(this.label != 'labelg1')

条件已被识别,但我现在收到的错误消息是:

Uncaught TypeError: _this3.formatCurrency is not a function

编辑 2:

我改变了 formatCurrency 的方法,这是新的结构:

import { format } from 'd3';

export default {
    methods: {
        formatCurrency(n) {
           let count = digitsCount(n)
           let numeros = processCantNumAndFormatOfinal(count)[0]
           let formatoF = processCantNumAndFormatOfinal(count)[1]
           let final = formatear(numeros, formatoF, n)
           console.log(final)
           return final
       }
    }
}

function digitsCount(n) {
            let count = 0;
            if (n >= 1) ++count;

            while (n / 10 >= 1) {
              n /= 10;
              ++count;
            }
            return count;
        }

function processCantNumAndFormatOfinal(n) {
            let cantNum;
            let formatofinal;
            if (n === 0) {
              cantNum = 0;
              formatofinal ='r';
            }
            else if (n === 1) {
              cantNum = 1;
              formatofinal ='s';
            }
            else if (n === 2) {
              cantNum = 2;
              formatofinal ='s';
            }
            else if (n === 3) {
              cantNum = 3;
              formatofinal ='s';
            }
            else if (n === 4) {
              cantNum = 2;
              formatofinal ='s';
            }
            else if (n === 5) {
              cantNum = 3;
              formatofinal ='s';
            }
            else if (n === 6) {
              cantNum = 3;
              formatofinal ='s';
            }
            else if (n === 7) {
              cantNum = 2;
              formatofinal ='s';
            }
            else if (n === 8) {
              cantNum = 3;
              formatofinal ='s';
            }
            else if (n === 9) {
              cantNum = 3;
              formatofinal ='s';
            }
            else {
              cantNum = 2;
              formatofinal ='s';
            }
            return [cantNum,formatofinal]
        }

function formatear(cantNum, formatofinal, n) {

            let formato = format(",."+ cantNum + formatofinal)(n)

            return formato;
         }

对于组件:

<template>

</template>

<script>

import formatCurrency from '../mixins/formatCurrency';
import formatTime from '../mixins/formatTime';

//...
async mounted() {
        let datos = await csv('/datasets/data.csv')
        this.dataset = Object.freeze(datos)
        this.dataNumero
        this.filtrarData
        this.graph()
        this.formatearData
    },
//...
computed: {
//...
        dataNumero() {
            this.dataset.forEach( function(d) { return d.population = +d.population})
        },
        filtrarData() {
            this.dataFiltrada = this.dataset.filter(function(d) { return d.country !== 'Total'})
        },
        formatearData() {
            this.dataFiltrada.forEach( function(d) { return d.population = this.formatCurrency(d.population) })
        },

methods: {
        graph() {
        //..
        const numeros = g.selectAll(this.label).data(this.dataFiltrada)
                numeros
                    .enter().append("text")
                        .attr("class", this.label)
                        /* esto les da posición a las etiquetas en x e y */
                        .attr('x', this.xEtiqueta)
                        .attr('y', d => { return -yScale(d.country); })
                        .attr('dy', this.yEtiqueta)
                        .text(0)

                    /* esto agrega las transiciones */
                    .merge(numeros)
                        .transition().duration(this.tiempo)
                        .tween(this.label, function(d) {
                            var i = interpolate(1, d.population);
                            if (d.population != 0)
                            return function(t) {
                                select(this).text(Math.round(i(t)))
                            };
                        })
//..
    mixins: [
    formatCurrency,
    formatTime
    ],


使用formatearData() {this.dataFiltrada.forEach(d =&gt; //.. 中的箭头函数,控制台显示结果正常,但是当我更改formatearData() 删除箭头函数@987654334 时,图表显示所有高于3 位数的数字中的NaN 值(?????) @错误是:Error in mounted hook (Promise/async): "TypeError: Cannot read property 'formatCurrency' of undefined"下面是图片供参考。

编辑 3:

好的,不工作的函数是 d3 格式,问题是我试图用特殊格式格式化 d3 条形图的文本标签编号,但是当这种情况发生时,数字会转换为字符串并呈现 NaN 值,所以相关的问题是:有没有办法在补间过渡期间或其他方法在 vue 中格式化 D3 条形图标签数字?,因为这段代码与简单的 javascript 和 webpack 完美配合,但在 vue 中是另一回事。

【问题讨论】:

    标签: vue.js d3.js tween


    【解决方案1】:

    避免arrow functions 使用this 关键字。用作:

    select(this).text(function(d){
        return (this.label === 'labelg1')                                            
             ? this.formatCurrency(i(t))                   
              : this.formatTime(i(t))                                   
    } 
    

    更多详情Read这个。

    【讨论】:

    • 现在我没有收到错误但 formatCurrency 不适用,当我将代码更改为 select(this).text(function(d){ return (this.label != 'labelg1') } 以检查是否错误时,错误消息为 this.formatCurrency is not a function
    • 你已经嵌套了arrow function。请删除它们
    • 我已经按照你所说的进行了更改并更新了上面的结果,但仍然无法正常工作。
    • 在计算的属性中仍然有arrow function。所以this关键字在那里不起作用
    • 已更新,现在我得到了这个Cannot read property 'formatCurrency' of undefined"
    【解决方案2】:

    我找到了这个库numeral.js,我的代码现在看起来像这样:

    methods: {
            graph() {
                  ...
                  var numeral = require("numeral");
                  const sin = this;
                  ...
                  const numeros = g.selectAll(this.label).data(this.dataFiltrada)
                    numeros
                        .enter().append("text")
                            .attr("class", this.label)
                            /* esto les da posición a las etiquetas en x e y */
                            .attr('x', this.xEtiqueta)
                            .attr('y', function(d) { return -yScale(d.Segmento); })
                            .attr('dy', this.yEtiqueta)
                            .text(0)
    
                        /* esto agrega las transiciones */
                        .merge(numeros)
                            .transition().duration(this.tiempo)
                            .tween(this.label, function(d) {
                                var i = interpolate(0, d.Valor);
                                if (d.Valor != 0)
                                return function(t) {
                                    const formatoNum = sin.formatoNum;
                                    select(this).text(numeral(i(t)).format(formatoNum))
                                }
                            });
    
    

    另一个重要的事情是在 Home.vue 中这样设置组件:

    <template>
    ...
    <graph id="graficoBarras1" v-bind='props1' :dataFiltrada="data1" v-if="data1.length" :key="gbKey"/>
    ...
    
    data() {
            return {
                ...
                props1: {
                    ...
                    formatoNum      : '$0.0a'
                },
                ...
                data1       : [],
                gbKey       : 0,
                ...
    methods: {
            forceRerender() {
              this.gbKey += 1;
            },
    

    有了这个,我的过渡终于奏效了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 2017-10-24
      • 1970-01-01
      • 2016-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多