#javascript #d3.js #svg
#javascript #d3.js #svg
Вопрос:
Я пытаюсь сделать простой визуальный столбец, в котором прямоугольники имеют высоту, определяемую масштабом:
var heightScale = d3.scaleLinear()
.domain([150,2500])
.range([10,80]);
Мой код выглядит так
var margins = {top:100, left:80, bottom:40, right:20};
var width = 950;
var height = 600;
var totalWidth = width margins.left margins.right;
var totalHeight = height margins.top margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append("g")
.attr("transform", "translate(" margins.left "," margins.top ")");
var q12018Data = [{'fmc': 'UBS', 'value': 2308.78},
{'fmc': 'Fidelity', 'value': 976.76},
{'fmc': 'JP Morgan', 'value': 837.19},
{'fmc': 'Value Partners', 'value': 787.39},
{'fmc': 'BlackRock', 'value': 664.42},
{'fmc': 'Krane', 'value': 445.13},
{'fmc': 'Investec', 'value': 407.40},
{'fmc': 'Nikko', 'value': 356.07},
{'fmc': 'Yuanta', 'value': 202.71},
{'fmc': 'Cathay Securities Invest', 'value': 174.46}];
var q22018Data = [{'fmc': 'UBS', 'value': 2193.05},
{'fmc': 'BlackRock', 'value': 817.24},
{'fmc': 'Yuanta', 'value': 676.87},
{'fmc': 'Fubon', 'value': 660.11},
{'fmc': 'JP Morgan', 'value': 577.26},
{'fmc': 'Investec', 'value': 384.65},
{'fmc': 'Hang Seng', 'value': 289.92},
{'fmc': 'Cathay Securities Invest', 'value': 289.43},
{'fmc': 'Pictet', 'value': 232.74},
{'fmc': 'Nikko', 'value': 224.73}];
var q32018Data = [{'fmc': 'ChinaAMC', 'value': 1074},
{'fmc': 'Fubon', 'value': 466.32},
{'fmc': 'Heungkuk', 'value': 458.23},
{'fmc': 'BlackRock', 'value': 361.34},
{'fmc': 'UBS', 'value': 350.01},
{'fmc': 'CSOP', 'value': 263.60},
{'fmc': 'Legal amp; General', 'value': 218.79},
{'fmc': 'SSgA', 'value': 188.35},
{'fmc': 'Fidelity', 'value': 134.06},
{'fmc': 'Morgan Stanley', 'value': 112.70}];
var q42018Data = [{'fmc': 'ChinaAMC', 'value': 1994.02},
{'fmc': 'Fubon', 'value': 808.34},
{'fmc': 'Heungkuk', 'value': 676.26},
{'fmc': 'BlackRock', 'value': 668.64},
{'fmc': 'UBS', 'value': 595.27},
{'fmc': 'CSOP', 'value': 424.83},
{'fmc': 'Legal amp; General', 'value': 380.30},
{'fmc': 'SSgA', 'value': 366.85},
{'fmc': 'Fidelity', 'value': 285.09},
{'fmc': 'Morgan Stanley', 'value': 273.55}];
var q12019Data = [{'fmc': 'UBS', 'value': 938.23},
{'fmc': 'BlackRock', 'value': 474.45},
{'fmc': 'Yuanta', 'value': 385.32},
{'fmc': 'Fubon', 'value': 349.73},
{'fmc': 'JP Morgan', 'value': 246.86},
{'fmc': 'Investec', 'value': 235.12},
{'fmc': 'Hang Seng', 'value': 230.23},
{'fmc': 'Cathay Securities Invest', 'value': 220.02},
{'fmc': 'Pictet', 'value': 213.76},
{'fmc': 'Nikko', 'value': 190.73}];
var heightScale = d3.scaleLinear()
.domain([150,2500])
.range([10,80]);
var column = graphGroup.selectAll("g")
.data(q12018Data)
.enter().append("g");
column.append("rect")
.attr("width", 150)
.attr("height", function(d) {return heightScale(d.value)})
.attr('y', function(d,i) {
if (i!=0) {
var prevData = column.data()[i-1];
var prevHeight = heightScale(prevData.value);
var currentHeight = heightScale(d.value);
return prevHeight;
} else {
return 0;
}
})
.style('fill','gray');
column.append("text")
.attr("x", 75)
.attr('y', function(d,i) {
if (i!=0) {
var prevData = column.data()[i-1];
var prevHeight = heightScale(prevData.value);
var currentHeight = heightScale(d.value);
return prevHeight;
} else {
return 0;
}
})
.attr('text-anchor','middle')
.text(function(d) { return d.fmc; });
<!DOCTYPE html>
<meta charset="utf-8">
<style>
</style>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
Вопрос
Почему моя высота прямой кишки по сравнению с предыдущей прямой кишкой вычисляется неправильно? Результат должен быть похож на сложенный столбик по внешнему виду. Однако масштаба y нет, я просто хочу добавить последующий прямоугольник, чтобы было всего несколько пикселей отступа, скажем, 2 пикселя.
Ответ №1:
Вы не суммируете значения! Вы просто передаете индивидуальное значение для каждого объекта… вы должны их накапливать.
Мы можем сделать это, просто объявив два счетчика с начальным значением, равным нулю…
let counterRect = 0,
counterText = 0;
… который мы позже увеличим, используя:
.attr('y', function(d, i) {
let previous = counterRect;
return (counterRect = heightScale(d.value), previous)
})
Вот ваш код с этим изменением (и белыми границами для прямоугольников):
var margins = {
top: 100,
left: 80,
bottom: 40,
right: 20
};
var width = 950;
var height = 600;
var totalWidth = width margins.left margins.right;
var totalHeight = height margins.top margins.bottom;
var svg = d3.select('body')
.append('svg')
.attr('width', totalWidth)
.attr('height', totalHeight);
var graphGroup = svg.append("g")
.attr("transform", "translate(" margins.left "," margins.top ")");
var q12018Data = [{
'fmc': 'UBS',
'value': 2308.78
},
{
'fmc': 'Fidelity',
'value': 976.76
},
{
'fmc': 'JP Morgan',
'value': 837.19
},
{
'fmc': 'Value Partners',
'value': 787.39
},
{
'fmc': 'BlackRock',
'value': 664.42
},
{
'fmc': 'Krane',
'value': 445.13
},
{
'fmc': 'Investec',
'value': 407.40
},
{
'fmc': 'Nikko',
'value': 356.07
},
{
'fmc': 'Yuanta',
'value': 202.71
},
{
'fmc': 'Cathay Securities Invest',
'value': 174.46
}
];
var q22018Data = [{
'fmc': 'UBS',
'value': 2193.05
},
{
'fmc': 'BlackRock',
'value': 817.24
},
{
'fmc': 'Yuanta',
'value': 676.87
},
{
'fmc': 'Fubon',
'value': 660.11
},
{
'fmc': 'JP Morgan',
'value': 577.26
},
{
'fmc': 'Investec',
'value': 384.65
},
{
'fmc': 'Hang Seng',
'value': 289.92
},
{
'fmc': 'Cathay Securities Invest',
'value': 289.43
},
{
'fmc': 'Pictet',
'value': 232.74
},
{
'fmc': 'Nikko',
'value': 224.73
}
];
var q32018Data = [{
'fmc': 'ChinaAMC',
'value': 1074
},
{
'fmc': 'Fubon',
'value': 466.32
},
{
'fmc': 'Heungkuk',
'value': 458.23
},
{
'fmc': 'BlackRock',
'value': 361.34
},
{
'fmc': 'UBS',
'value': 350.01
},
{
'fmc': 'CSOP',
'value': 263.60
},
{
'fmc': 'Legal amp; General',
'value': 218.79
},
{
'fmc': 'SSgA',
'value': 188.35
},
{
'fmc': 'Fidelity',
'value': 134.06
},
{
'fmc': 'Morgan Stanley',
'value': 112.70
}
];
var q42018Data = [{
'fmc': 'ChinaAMC',
'value': 1994.02
},
{
'fmc': 'Fubon',
'value': 808.34
},
{
'fmc': 'Heungkuk',
'value': 676.26
},
{
'fmc': 'BlackRock',
'value': 668.64
},
{
'fmc': 'UBS',
'value': 595.27
},
{
'fmc': 'CSOP',
'value': 424.83
},
{
'fmc': 'Legal amp; General',
'value': 380.30
},
{
'fmc': 'SSgA',
'value': 366.85
},
{
'fmc': 'Fidelity',
'value': 285.09
},
{
'fmc': 'Morgan Stanley',
'value': 273.55
}
];
var q12019Data = [{
'fmc': 'UBS',
'value': 938.23
},
{
'fmc': 'BlackRock',
'value': 474.45
},
{
'fmc': 'Yuanta',
'value': 385.32
},
{
'fmc': 'Fubon',
'value': 349.73
},
{
'fmc': 'JP Morgan',
'value': 246.86
},
{
'fmc': 'Investec',
'value': 235.12
},
{
'fmc': 'Hang Seng',
'value': 230.23
},
{
'fmc': 'Cathay Securities Invest',
'value': 220.02
},
{
'fmc': 'Pictet',
'value': 213.76
},
{
'fmc': 'Nikko',
'value': 190.73
}
];
let counterRect = 0,
counterText = 0;
var heightScale = d3.scaleLinear()
.domain([150, 2500])
.range([10, 80]);
var column = graphGroup.selectAll("g")
.data(q12018Data)
.enter().append("g");
column.append("rect")
.attr("width", 150)
.attr("height", function(d) {
return heightScale(d.value)
})
.attr('y', function(d, i) {
let previous = counterRect;
return (counterRect = heightScale(d.value), previous)
})
.style('fill', 'gray')
.style("stroke", "white");
column.append("text")
.attr("x", 75)
.attr('y', function(d, i) {
let previous = counterText;
return (counterText = heightScale(d.value), previous (heightScale(d.value)/2))
})
.attr("dominant-baseline", "central")
.attr('text-anchor', 'middle')
.text(function(d) {
return d.fmc;
});
<script src="https://d3js.org/d3.v5.min.js"></script>
Комментарии:
1. Блестяще! Просто интересно, как передать счетчику правильное значение, чтобы текст отображался как вертикально центрированный в прямоугольнике, а не вверху.
2. Просто используйте
dominant-baseline: central
и добавьте половину текущего значения. Взгляните на фрагмент еще раз.