Búsqueda de sitios web

javascript - Resaltar serie de líneas al pasar el cursor sobre la leyenda


Realmente me gusta chart.js, pero estoy teniendo dificultades para crear eventos personalizados (no tengo mucha experiencia, así que todavía estoy aprendiendo)

Estoy tratando de resaltar una línea completa, o una serie de barras cuando se pasa el cursor sobre la leyenda, esencialmente mostrar todos los elementos de un conjunto de datos con el estilo de hover.

Estoy intentando hacer esto a través del callback onHover de la leyenda, pero no estoy seguro de si esto es correcto. He logrado encontrar el conjunto de datos sobre el que se está pasando el cursor, pero estoy teniendo problemas para poder ejecutar updateHoverStyle para resaltar la serie.

¿Alguna ayuda o indicación sobre dónde debería estar buscando?

Esto es hasta donde he llegado hasta ahora...

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)
      }
    }

Respuesta #1

Ciertamente estabas en el camino correcto, pero déjame ayudarte con un ejemplo funcional de un gráfico de barras junto con alguna explicación.

Para implementar este comportamiento, definitivamente querrás hacer uso de la propiedad onHover de la leyenda (tal como lo hiciste). Sin embargo, una vez que actualices el estilo al pasar el cursor, debes volver a renderizar el gráfico para que el cambio surta efecto. Aquí hay un ejemplo.

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();
  }
}

Con eso funcionando, ahora necesitamos una forma de desactivar o borrar el estilo de desplazamiento una vez que el elemento de la leyenda ya no esté bajo el cursor. De lo contrario, cada vez que el usuario pase el cursor sobre un elemento de la leyenda, la serie en el gráfico se volverá más y más oscura hasta que sea completamente negra.

Así que necesitamos algún modo de eliminar el estilo de hover. Hubiera sido genial si hubiera una propiedad onMouseLeave en la leyenda, pero, lamentablemente... no la hay. Así que, para resolver esto, terminamos teniendo que "engañar" a chart.js para que haga lo que queremos. El truco es usar la función custom de tooltips. Aquí hay un ejemplo a continuación.

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();
    }
  }
}

Lo que esto está haciendo es limpiar el estilo de hover (pasando false como el último argumento de updateHoverStyle). Dado que estamos fuera del contexto de la leyenda, simplemente utilicé una variable externa a mis callbacks para almacenar el índice del dataset que había sido seleccionado anteriormente.

La razón por la que este 'truco' funciona es porque la función de devolución de llamada de las descripciones emergentes se llama cada vez que se mueve el ratón en cualquier parte del gráfico completo (pero no en la leyenda). Por lo tanto, representa todo excepto la leyenda. Debido a esto, podemos usarla tal como hubiéramos usado la no existente pero útil devolución de llamada onMouseLeave de la leyenda.

Con suerte, todo esto tiene sentido. Aquí hay un codepen funcional para demostrar la solución completa.

Respuesta #2

Solo falta una cosa en tu código: refrescar el gráfico usando 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
      }
    }

Pero esto acabará destacando todas las trazas: debes eliminar el resaltado de todas las demás trazas antes de resaltar la que está bajo el cursor, recorriéndolas:

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();  
      }
    }