javascript - Markera linjeserie vid hovring över legend


Gillar verkligen chart.js, men jag har svårt att skapa anpassade händelser (inte särskilt erfaren så jag lär mig fortfarande)

Jag försöker markera en hel rad, eller stapelserie när legendverktygstipset är hovrat, i princip visa alla element i en datamängd med hovringsstil.

Jag försöker göra detta via legendens onHover-callback, men är inte säker på om det är korrekt. Jag har lyckats hitta datasetet som hovras över men har svårt att kunna köra updateHoverStyle för att markera serien.

Någon hjälp eller tips om var jag bör leta?

Det här är var jag har kommit hittills...

legend: {
      labels: {
        usePointStyle: true
      },
      onHover: function(event, legendItem) {
        var me = this;
        var options = me.options || {};
        var hoverOptions = options.hover;
        var index = legendItem.datasetIndex;
        var ci = this.chart;
        var elements = ci.getDatasetMeta(index).data;
        ci.updateHoverStyle(elements, hoverOptions.mode, true)
      }
    }

Svar #1

Du var absolut på rätt spår, men låt mig hjälpa dig med ett fungerande exempel på ett stapeldiagram tillsammans med lite förklaring.

För att implementera detta beteende vill du definitivt använda legendens onHover-egenskap (precis som du gjorde). Men när du uppdaterar hover-stilen måste du rendera om diagrammet för att ändringen ska träda i kraft. Här är ett exempel.

legend: {
  labels: {
    usePointStyle: true
  },
  onHover: function(event, legendItem) {
    var options = this.options || {};
    var hoverOptions = options.hover || {};
    var ci = this.chart;
    hoveredDatasetIndex = legendItem.datasetIndex;
    ci.updateHoverStyle(ci.getDatasetMeta(hoveredDatasetIndex).data, hoverOptions.mode, true);
    ci.render();
  }
}

Med det fungerande behöver vi nu ett sätt att avmarkera eller rensa hover-stilen när legendobjektet inte längre hovras över. Annars kommer varje gång användaren hovrar över ett legendobjekt serien i grafen att bli mörkare och mörkare tills den bara är svart.

Så vi behöver ett sätt att rensa hover-stilen. Det skulle ha varit fantastiskt om det fanns en onMouseLeave-egenskap, men tyvärr... det finns ingen. Så för att komma runt detta måste vi till slut "lura" chart.js att göra det vi vill. Tricket är att använda tooltips custom-funktionen. Här är ett exempel nedan.

tooltips: {
  mode: 'index',
  intersect: false,
  custom: function(tooltip) {
    if (hoveredDatasetIndex != -1) {
      var options = this.options || {};
      var hoverOptions = options.hover || {};
      var ci = this._chartInstance.chart.controller;
      ci.updateHoverStyle(ci.getDatasetMeta(hoveredDatasetIndex).data, hoverOptions.mode, false);
      hoveredDatasetIndex = -1;
      ci.render();
    }
  }
}

Vad detta gör är att rensa hover-stilen (genom att skicka in false till det sista argumentet i updateHoverStyle). Eftersom vi är utanför legenden-kontexten använde jag helt enkelt en variabel utanför mina callbacks för att lagra indexet för den dataset som tidigare hovrades över.

Anledningen till att detta 'hack' fungerar är att verktygstipsens callback anropas varje gång musen flyttas någonstans på hela diagrammet (men inte på legenden). Så det representerar allt utom legenden. På grund av detta kan vi använda det precis som vi skulle ha använt den icke-existerande men praktiska legendens onMouseLeave-callback.

Förhoppningsvis är allt detta begripligt. Här är en fungerande CodePen för att demonstrera den fullständiga lösningen.

Svar #2

Det finns bara en sak som saknas i din kod: uppdatering av diagrammet med ci.render();

legend: {
      labels: {
        usePointStyle: true
      },
      onHover: function(event, legendItem) {
        var me = this;
        var options = me.options || {};
        var hoverOptions = options.hover;
        var index = legendItem.datasetIndex;
        var ci = this.chart;
        var elements = ci.getDatasetMeta(index).data;
        ci.updateHoverStyle(elements, hoverOptions.mode, true)
        ci.render();  //    <<---- commit changes
      }
    }

Men detta kommer att sluta med att alla spår markeras: du måste ta bort markeringen av alla andra spår innan du markerar det som hovras, genom att cykla igenom dem:

legend: {
      labels: {
        usePointStyle: true
      },
      onHover: function(event, legendItem) {
        var me = this;
        var options = me.options || {};
        var hoverOptions = options.hover;
        var index = legendItem.datasetIndex;
        var ci = this.chart;
        for (var i=0; i < ci.datasets.length-1; i++) {
           var elements = ci.getDatasetMeta(i).data;
           ci.updateHoverStyle(elements, hoverOptions.mode, false) ; // <<<--- turn off higlight
        }
        var elements = ci.getDatasetMeta(index).data;
        ci.updateHoverStyle(elements, hoverOptions.mode, true) // <<-- Turn on 
        ci.render();  
      }
    }