2017-03-06 3 views
0

Ich habe ein Balkendiagramm auf einer Seite, die Daten angezeigt hat, die dynamisch aktualisiert wird. Das Problem, das ich habe, ist, dass ich den Typ der y-Achse basierend auf den Daten ändern muss, die angezeigt werden. Ich brauche es eine lineare Skala, wenn die Daten einen Bereich von weniger als 100 (z. B. 0-99) und logarithmische, wenn es größer ist (z. B. 0-1000).dynamisch aktualisieren Sie die Skalartyp Diagrammgrafik

Ich kann berechnen, ob ich eine logarithmische Skala oder nicht gut, aber wenn es um die Änderung der Skala geht, bin ich ratlos. Ich habe versucht, das options Objekt des Diagramms zu ändern und ruft update():

myChart.options/scales.yAxes.map(function (axis) { axis.type = 'logarithmic' }); 
myChart.update(); 

und auch versucht, das Ausmaß ändert sich direkt an:

Object.keys(mychart.scales).forEach((function (axisName) { 
      var axis = myChart.scales[axisName]; 
      if (axis && axis.id.startsWith('y')) { 
       axis.options.type = 'logarithmic' 
      } 
     })); 
myChart.update(); 

dann habe ich versucht, den beforeBuildTicks Rückruf verwenden, zu denken, dass die Art zu ändern während der Aktualisierung der Daten und Neuzeichnen des Diagramms möglicherweise zu spät oder nur zur falschen Zeit:

beforeBuildTicks: function (scale) { 
           if (scale.chart) { 
            console.log('logarithmic'); 
            scale.options.type = 'logarithmic'; 
           } 
          } 

alle diese approac hes ändert das Diagrammobjekt, aber die Anzeige ist nicht betroffen.

Gibt es eine Möglichkeit, den Skalierungstyp eines Diagramms Balkendiagramm dynamisch zu ändern, ohne das gesamte Diagramm zu zerstören und neu zu erstellen?

Antwort

0

Ich habe endlich eine Lösung gefunden, aber es ist nicht einfach.

Dank @jordanwillis für den Zeiger in die richtige Richtung in Bezug auf die Verwendung der "scaleMerge" Hilfsfunktion.

ich eine plugin geschaffen, die die ganze Arbeit:

var changeScaleTypePlugin = { 
beforeUpdate: function (chartInstance) { 
    var self = this; 
    chartInstance.beforeInit = null; 
    if (chartInstance.options.changeScale) { 
     self.changeScales(chartInstance); 
     if (chartInstance.options.scaleTypeChanged) { 
      chartInstance.options.scaleTypeChanged = false; 
      Object.keys(chartInstance.scales).forEach(function (axisName) { 
       var scale = chartInstance.scales[axisName]; 
       Chart.layoutService.removeBox(chartInstance, scale); 
      }); 
      chartInstance.initialize(); 
     } 
    } 
}, 
changeScales: function (chartInstance) { 
    var maxValue = Math.max.apply(null, chartInstance.data.datasets.map(function (dataset) { return Math.max.apply(null, dataset.data); })); 
    var minValue = Math.min.apply(null, chartInstance.data.datasets.map(function (dataset) { return Math.min.apply(null, dataset.data); })); 
    var logMax = Math.floor(Math.log(maxValue)/Math.LN10); 
    var logMin = Math.floor(Math.log(minValue)/Math.LN10); 
    if (logMax - logMin > chartInstance.options.maxRankDifference) { 
     if (!chartInstance.options.scaleTypeChanged && chartInstance.options.scales.yAxes.filter(function (axis) { return axis.type !== 'logarithmic'; }).length) { 
      console.log('logarithmic'); 
      chartInstance.options.scaleTypeChanged = true; 
      chartInstance.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, { yAxes: chartInstance.options.logarithmicScaleOptions }).yAxes;     
     } 
    } else { 
     if (!chartInstance.options.scaleTypeChanged && chartInstance.options.scales.yAxes.filter(function (axis) { return axis.type !== 'linear'; }).length) { 
      console.log('linear'); 
      chartInstance.options.scaleTypeChanged = true; 
      chartInstance.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, { yAxes: chartInstance.options.linearScaleOptions }).yAxes; 
     } 
    } 
} 

};

Diagramm.pluginService.register (changeScaleTypePlugin);

und anzuwenden dies einfach ein paar Eigenschaften zu den Optionen des Diagramms hinzu:

options: { 
        linearScaleOptions: [{ 
         id: 'y-axis-0', 
         type: 'linear', 
         tick: { 
          // callback: Chart.Ticks.formatters.linear, 
          min: 0 
         } 
        }], 
        logarithmicScaleOptions: [{ 
         id: 'y-axis-0', 
         type: 'logarithmic', 
         ticks: { 
          // callback: function (tickValue, index, ticks) { 
          //  var remain = tickValue/(Math.pow(10, Math.floor(Math.log(tickValue)/Math.LN10))); 

          //  if (tickValue === 0) { 
          //   return '0'; 
          //  } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) { 
          //   return tickValue; 
          //  } 
          //  return ''; 
          //}, 
          min: 0 
         } 
        }], 
        changeScale: true, 
        maxRankDifference: 1, 

der Kommentar gesetzt Rückruf auf die Zecken für die Situation ist, wo (wie ich) Sie wollen nicht die Zecke Werte in wissenschaftlicher Notation auf der Log-Skala angezeigt.

Dies ergibt die Ausgabe, die wie folgt aussieht:

logarithmic

mit max Rang Eigenschaft auf 1

oder

linear

damit auf 3 gesetzt

oder mit dem Callback-Set:

logarithmic with natural ticks

0

Sie waren auf der richtigen Spur, aber das Problem ist für jeden Maßstabstyp, es gibt einen entsprechenden Satz von Eigenschaften, die vom zugrunde liegenden Maßstabsdienst verwendet werden, um den Maßstab zu rendern.

Wenn Sie also Ihre Skalierung so konfigurieren, dass sie "linear" ist, wird ein Satz verdeckter Achseneigenschaften ausgelöst, die die gerenderte lineare Skalierung festlegen. Wenn Sie Ihre Skalierung jedoch als "logarithmisch" konfigurieren, müssen die Eigenschaften der ausgeblendeten Achsen unterschiedlich festgelegt werden, um die gerenderte logarithmische Skalierung zu erhalten.

Lange Rede, kurzer Sinn, Sie müssen die Chart.helpers.scaleMerge() Funktion verwenden, um all dies für Sie zu handhaben (Sie können nicht einfach den Skalierungstyp in den Diagrammoptionen ändern und neu rendern).

Ich erstellte eine working example zeigt, wie Sie erreichen, was Sie wollen. Die Essenz davon, wie das funktioniert, wird unten angezeigt.

document.getElementById('changeScaleAndData').addEventListener('click', function() { 
    if (isLinear) { 
    myBar.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {yAxes: logarithmicScaleOptions}).yAxes; 
    isLinear = false; 
    } else { 
    myBar.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {yAxes: linearScaleOptions}).yAxes; 
    isLinear = true; 
    } 

    myBar.data.datasets[0].data = [ 
    randomScalingFactor(), 
    randomScalingFactor(), 
    randomScalingFactor(), 
    ]; 

    myBar.update(); 
}); 
+0

dies scheint nicht wirklich auf die Waage zu einem logarithmischen zu ändern, wird die Differenz zwischen dem tick auf dem yscale, wenn die ‚Änderung‘ wird, den Maßstab zu setzen, wie logarithmisch das gleiche zwischen allen Zecken wie die räumliche Trennung, die definitionsgemäß eine lineare Skala ist. Ich habe endlich eine Lösung gefunden (die ich dir für den Hinweis auf 'scaleMerge' danken muss) siehe meine Antwort – MikeW

Verwandte Themen