d3. js Горизонтальная гистограмма - PullRequest
1 голос
/ 15 апреля 2020

Я новичок в библиотеке d3 и пробую некоторые графики с использованием библиотеки d3. Я могу сделать горизонтальную гистограмму, используя библиотеку d3. js, но я застрял в некоторых вопросах.

В настоящее время у меня возникли проблемы, поскольку последнее значение по оси x обрезается. Я не хочу добавлять правую границу в свой график. И я хочу показать последний ярлык с галочкой на оси x.

Я выделил обрезанное значение на снимке экрана ниже:

Bar chart Screenshot

Для отладки см. Код ниже:

const margin = {
    top: 30,
    right: 0,
    bottom: 10,
    left: 100
};
const width= 1180;
const data = [{
        name: 'A',
        value: 2
    },
    {
        name: 'B',
        value: 20
    },
    {
        name: 'C',
        value: 15
    },
    {
        name: 'D',
        value: 8
    },
    {
        name: 'E',
        value: 1
    }
];
const barHeight = 20;
const yMax = d3.max(data, d => d.value);

const height =
    Math.ceil((data.length + 0.1) * barHeight) + margin.top + margin.bottom;
const x = d3
    .scaleLinear()
    .domain([0, yMax < 10 ? 10 : yMax])
    .range([margin.left, width - margin.right])
    .nice();
const y = d3
    .scaleBand()
    .domain(d3.range(data.length))
    .range([margin.top, height - margin.bottom])
    .padding(0.1);

const format = x.tickFormat(10, data.format);
const svg = d3.select('body').append('svg').attr('viewBox', [0, 0, width, height]);
const xAxis = g =>
    g
    .attr('class', 'chartxAxisText')
    .attr('transform', `translate(0,${margin.top})`)
    .call(d3.axisTop(x))

    .call(g => g.select('.domain').remove());
const yAxis = g =>
    g
    .attr('class', 'chartyAxisText')
    .attr('transform', `translate(${margin.left},0)`)
    .call(
        d3
        .axisLeft(y)
        .tickFormat(i => data[i].name)
        .tickSizeOuter(0)
    );

svg
    .append('g')
    .selectAll('rect')
    .data(data)
    .enter().append('rect')
    .attr('x', x(0))
    .attr('y', (d, i) => y(i))
    .attr('width', d => x(d.value) - x(0))
    .attr('height', y.bandwidth())
    .attr('class', 'chartbar')

svg
    .append('g')
    .attr('class', 'chartbarTextWrap')
    .selectAll('text')
    .data(data)
    .enter().append('text')
    .attr('x', d => x(d.value) - 4)
    .attr('y', (d, i) => y(i) + y.bandwidth() / 2)
    .attr('dy', '0.35em')
    .text(d => format(d.value))
    .attr('class', 'chartbarText');

svg.append('g').call(xAxis);

svg.append('g').call(yAxis);
.chartbarTextWrap {
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 1px;
    fill: #fff;
    text-anchor: end;
    pointer-events: none;
}
.chartbar {
    fill: red;
}
.chartxAxisText, .chartyAxisText {
    font-family: "Roboto", sans-serif;
    font-size: 16px;
    font-weight: 400;
    letter-spacing: 1px;
    color: #424242;
}
.chartxAxisText, .chartyAxisText {
   
    font-size: 16px;
    font-weight: 400;
    color: #424242;
}
svg {
  width:1180px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<html>
<body></body>
</html>

1 Ответ

2 голосов
/ 15 апреля 2020

Добавление небольшого поля в правой части диаграммы будет действительно самым простым решением.

Если вы действительно этого не хотите, вы можете выровнять текстовые метки оси x вправо:

.chartxAxisText {
    text-anchor: end;
}

Это показано ниже:

const margin = {
    top: 30,
    right: 0,
    bottom: 10,
    left: 100
};
const width= 1180;
const data = [{
        name: 'A',
        value: 2
    },
    {
        name: 'B',
        value: 20
    },
    {
        name: 'C',
        value: 15
    },
    {
        name: 'D',
        value: 8
    },
    {
        name: 'E',
        value: 1
    }
];
const barHeight = 20;
const yMax = d3.max(data, d => d.value);

const height =
    Math.ceil((data.length + 0.1) * barHeight) + margin.top + margin.bottom;
const x = d3
    .scaleLinear()
    .domain([0, yMax < 10 ? 10 : yMax])
    .range([margin.left, width - margin.right]);
const y = d3
    .scaleBand()
    .domain(d3.range(data.length))
    .range([margin.top, height - margin.bottom])
    .padding(0.1);

const format = x.tickFormat(10, data.format);
const svg = d3.select('body').append('svg').attr('viewBox', [0, 0, width, height]);
const xAxis = g =>
    g
    .attr('class', 'chartxAxisText')
    .attr('transform', `translate(0,${margin.top})`)
    .call(d3.axisTop(x))

    .call(g => g.select('.domain').remove());
const yAxis = g =>
    g
    .attr('class', 'chartyAxisText')
    .attr('transform', `translate(${margin.left},0)`)
    .call(
        d3
        .axisLeft(y)
        .tickFormat(i => data[i].name)
        .tickSizeOuter(0)
    );

svg
    .append('g')
    .selectAll('rect')
    .data(data)
    .enter().append('rect')
    .attr('x', x(0))
    .attr('y', (d, i) => y(i))
    .attr('width', d => x(d.value) - x(0))
    .attr('height', y.bandwidth())
    .attr('class', 'chartbar')

svg
    .append('g')
    .attr('class', 'chartbarTextWrap')
    .selectAll('text')
    .data(data)
    .enter().append('text')
    .attr('x', d => x(d.value) - 4)
    .attr('y', (d, i) => y(i) + y.bandwidth() / 2)
    .attr('dy', '0.35em')
    .text(d => format(d.value))
    .attr('class', 'chartbarText');

svg.append('g').call(xAxis);

svg.append('g').call(yAxis);
.chartbarTextWrap {
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 1px;
    fill: #fff;
    text-anchor: end;
    pointer-events: none;
}
.chartbar {
    fill: red;
}
.chartxAxisText, .chartyAxisText {
    font-family: "Roboto", sans-serif;
    font-size: 16px;
    font-weight: 400;
    letter-spacing: 1px;
    color: #424242;
}
.chartxAxisText {
    text-anchor: end;
}
svg {
  width:1180px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<html>
<body></body>
</html>

Другой вариант - оставить все метки такими, какие они есть, и выровнять только последний слева. Это можно сделать также в CSS со следующим правилом:

.chartxAxisText text:last-child {
    text-anchor: end;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...