Я рисую гистограмму с осями, а yScale ведет себя по-другому на моем yAxis, чем на моих присоединенных барах.
Я установил диапазон yScale для начала (h - yPadding), чтобы оставить дополнительную комнату внизу для ярлыков xAxis.
var yScale = d3.scale.linear()
.domain([0, d3.max(val)])
.range([h - yPadding, 0]);
- Диапазон инвертирован, в противном случае ярлыки yAxis перевернуты.
Когда я вызываю yAxis с помощью yScale, он подчиняется начальной точке (h - yPadding) и оставляет комнату внизу.
Но все "исправления", которые я добавляю к диаграмме, начинаются с h, а не (h - yPadding), хотя я называю yScale на этих "прямых", как на yAxis.
Если я изменю диапазон до [h, 0] вместо [h - yPadding, 0], то только изменение yAx реагирует на изменение, и бары все еще начинаются с h.
Почему бары игнорируют yScale?
<script type="text/javascript">
var xhr = new XMLHttpRequest();
function makeRequest(){
xhr.open("GET", "https://api.coinmarketcap.com/v1/ticker/", true);
xhr.send();
xhr.onreadystatechange = processRequest;
}
function processRequest(){
console.log("testing, state: ", xhr.readyState)
if(xhr.readyState == 4 && xhr.status == 200){
dataset = [];
for(var i = 0; i < 10; i++){
addingId = JSON.parse(xhr.responseText)[i];
addingId.id = i;
dataset.push(addingId);
}
console.log("this is dataset: ", dataset);
makeChart();
}
}
function makeChart(){
var w = 1000;
var h = 600;
var padding = 40;
var yPadding = 80;
var val = [];
dataset.forEach(function(ele){
val.push(parseInt(ele.market_cap_usd));
})
var max = d3.max(val)
var xAxisNames = []
dataset.forEach(function(ele){ xAxisNames.push(ele.name); })
// console.log(">>>>>>>>", xAxisNames)
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([padding, w - padding], 0.05)
var yScale = d3.scale.linear()
.domain([0, d3.max(val)])
.range([h - yPadding, 0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(function(d){
if(d > 0){ return d / 1000000000 + " b"; }
return "";
})
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.tickFormat(function(d, i){
return xAxisNames[i]
})
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i){
return xScale(i);
})
.attr("y", function(d){
return yScale(d.market_cap_usd);
})
.attr("width", xScale.rangeBand())
.attr("height", function(d, i){
return h - yScale(d.market_cap_usd)
})
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding + ", 0)")
.call(yAxis);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + (h - yPadding) + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 15)
.attr("font-size", 12)
.attr("x", xScale.rangeBand() / 2)
.attr("transform", "rotate(45)")
}
makeRequest();
</script>
Масштаб просто отображает входной домен в выходной диапазон, не более того. Вы должны соответственно установить позиции и размеры элементов SVG. Давайте посмотрим:
Прямо сейчас, учитывая ваш масштаб, когда вы передадите ему минимальное значение в своем домене, оно вернется:
h - yPadding
Конечно, вы хотите, чтобы такие бары имели высоту в нулевые пиксели. Для получения этого нуля уравнение простое, вы должны вычесть из этого значения:
(h - yPadding) - yScale(minimumDomainValue)
Это даст вам нуль для минимального значения в домене.
Следовательно, это должна быть высота прямоугольников:
.attr("height", function(d, i){
return (h - yPadding) - yScale(d.market_cap_usd)
})
PS: Кстати, в D3 одна из немногих ситуаций, когда масштаб определяет размеры элемента SVG, это путь/линии, созданные генератором оси. Вот почему вы видите другое поведение на своей оси.