web-dev-qa-db-fra.com

d3.js: Aligne les étiquettes de texte entre les graduations sur l'axe

Existe-t-il un moyen simple d’aligner les étiquettes de texte entre les ticks? 

Voici mon axe temporel avec des étiquettes au-dessus des ticks:
enter image description here

Je voudrais placer ces étiquettes comme ici:
enter image description here

34
oluckyman

Je me suis retrouvé avec l'un des conseils de Lars Kotthoff

Chaque fois que je call(axis), je modifie également les étiquettes de texte.
Voici le code simplifié:

function renderAxis() {
    axisContainer
        .transition().duration(300)
        .call(axis)                  // draw the standart d3 axis
        .call(adjustTextLabels);     // adjusts text labels on the axis 
}

function adjustTextLabels(selection) {
    selection.selectAll('.major text')
        .attr('transform', 'translate(' + daysToPixels(1) / 2 + ',0)');
}

// calculate the width of the days in the timeScale
function daysToPixels(days, timeScale) {
    var d1 = new Date();
    timeScale || (timeScale = Global.timeScale);
    return timeScale(d3.time.day.offset(d1, days)) - timeScale(d1);
}

Mettre à jour:
BTW, voici une démo du calendrier qui m’a fini: http://bl.ocks.org/oluckyman/6199145

enter image description here

46
oluckyman

Il n’existe pas de moyen facile (c’est-à-dire intégré) de le faire, mais vous pouvez quand même y parvenir. Il y a quelques options. Le plus simple consiste probablement à utiliser la fonction tickFormat pour spécifier un format avec un nombre approprié d’espaces devant/après les nombres. Cela devrait cependant être réglé manuellement pour chaque application.

Vous pouvez également sélectionner les éléments d'étiquette une fois qu'ils ont été dessinés et ajouter un attribut transform approprié qui les décale en conséquence. Encore une fois, cela devrait être réglé à la main.

Votre troisième option consiste à avoir deux axes différents, un pour les graduations et un pour les libellés. L'idée est que l'axe qui fournit les ticks n'a pas de libellé et l'autre pas de ticks. Vous devez définir les valeurs de ticks de manière appropriée, mais au moins vous n’auriez pas à deviner le bon décalage.

5
Lars Kotthoff

Vous pouvez le faire en utilisant axis.tickSize(major[[,minor],end]) et .tickSubdivide(). Vos ticks sont configurés pour s'aligner sur les ticks principaux, mais si vous définissez la hauteur de ces ticks sur 0, définissez une hauteur pour les ticks mineurs et spécifiez qu'il existe un tick parallèle entre chaque paire de ticks majeurs, avec des étiquettes de tiques entre vos tiques. Votre code ressemblerait à ceci:

var myAxis = d3.svg.axis()
    .ticks(15)
    .tickSubdivide(1)
    .tickSize(0, 6, 0);

Notez que vous devez définir explicitement une taille de fin. Si vous ne fournissez que deux chiffres, ils seront interprétés comme étant major et end et minor seront par défaut à 0.

Voici un violon.

2
ckersch

Déjà quelques bonnes réponses mais juste pour en ajouter une de plus. Notez l'utilisation de text-anchor

Même idée: après votre appel, sélectionnez le texte, repositionnez-le.

.call(xAxis)                
.selectAll(".tick text")
.style("text-anchor", "start")
.attr("x", axisTextAdjust)

Je le fais souvent en empilant plusieurs axes, chacun avec un .tickFormat() personnalisé.

Si je place des étiquettes entre deux dates, je vais souvent faire quelque chose comme ceci:

@timeDaysAxisLabels = d3.svg.axis()
    .scale(@timescale)
    .orient('bottom')
    .ticks(d3.time.hour.utc, 12)  # I want ticks at noon, easiest to just get them ever 12 hours
    .tickFormat((d) =>
        # only draw labels at noon, between the date boundaries
        if d.getUTCHours() == 12
            # draw the label!
            formatter = d3.time.format.utc('%a %d %b')  # "Mon 12 Apr"
            return formatter(d)
        else
            # not noon, don't draw anything
            return null)
    .tickSize(0)
    .tickPadding(30)

Je vais aussi créer un axe séparé sans étiquette, et un .tickSize() différent de zéro pour dessiner les ticks, mais ce bloc situé au-dessus positionne les étiquettes de date au centre de la "colonne".

0
Idan Gazit
        svg.append("g")
          .attr("class", "axis axis-years")
          .attr("transform", "translate(0," + (height + 1) + ")")
          .call(xAxis)
        .selectAll("text")

     .attr("x", "-1.8em")
     .attr("y", ".00em")
     .attr("transform", function (d) {
         return "rotate(-90)"});
0
VINOTH KUMAR