Инверсия с порядковой шкалой
Есть ли способ найти инверсию порядковой шкалы?
Я использую строковое значение по оси х, которое использует порядковый масштаб и я на перемещении мыши. Я хочу найти инверсию с осью x, чтобы найти, какая строка находится в позиции мыши?
Есть ли способ найти это?
var barLabels = dataset.map(function(datum) {
return datum.image;
});
console.log(barLabels);
var imageScale = d3.scale.ordinal()
.domain(barLabels)
.rangeRoundBands([0, w], 0.1);
// divides bands equally among total width, with 10% spacing.
console.log("imageScale....................");
console.log(imageScale.domain());
.
.
var xPos = d3.mouse(this)[0];
xScale.invert(xPos);
Ответы
Ответ 1
Я действительно думаю, что не имеет смысла, что для порядковых масштабов нет метода инвертирования, но вы можете понять его с помощью метода ordinal.range(), который вернет вам начальные значения для каждого бара, и метод ordinal.rangeBand() для их ширины.
Пример здесь:
http://fiddle.jshell.net/dMpbh/2/
Соответствующий код
.on("click", function(d,i) {
var xPos = d3.mouse(this)[0];
console.log("Clicked at " + xPos);
//console.log(imageScale.invert(xPos));
var leftEdges = imageScale.range();
var width = imageScale.rangeBand();
var j;
for(j=0; xPos > (leftEdges[j] + width); j++) {}
//do nothing, just increment j until case fails
console.log("Clicked on " + imageScale.domain()[j]);
});
Ответ 2
Я нашел более короткую реализацию здесь в этом отклонил запрос на отрыв, который работал отлично.
var ypos = domain[d3.bisect(range, xpos) - 1];
где домен и диапазон - это масштабный домен и диапазон:
var domain = x.domain(),
range = x.range();
Ответ 3
Я в прошлом менял домен и диапазон, когда это необходимо
> var a = d3.scale.linear().domain([0,100]).range([0, w]);
> var b = d3.scale.linear().domain([0,w]).range([0, 100]);
> b(a(5));
5
Однако с порядковым ответом не так просто. Я проверил документацию и код, и это не похоже на простой способ. Я бы начал с отображения элементов из домена и разработки точки старта и остановки. Вот начало.
imageScale.domain().map(function(d){
return {
'item':d,
'start':imageScale(d)
};
})
Рассмотрите возможность размещения вашего вопроса в виде запроса функции https://github.com/mbostock/d3/issues?state=open в случае
- Существует достаточный спрос на такую функцию
- Что я ничего не забыл или что что-то более скрытое ниже документации, которая поможет в этом случае
Ответ 4
Недавно я оказался в той же ситуации, что и OP.
Мне нужно было получить инверсию категориальной шкалы для слайдера. Ползунок имеет 3 дискретных значения и выглядит и ведет себя как трехходовой тумблер. Он изменяет режим смешивания на некоторых элементах SVG. Я создал обратную шкалу с scaleQuantize()
следующим образом:
var modeArray = ["normal", "multiply", "screen"];
var modeScale = d3.scalePoint()
.domain(modeArray)
.range([0, 120]);
var inverseModeScale = d3.scaleQuantize()
.domain(modeScale.range())
.range(modeScale.domain());
Я передаю эту inverseModeScale
x-позицию мыши (d3.mouse(this)[0]
) при перетаскивании:
.call( d3.drag()
.on("start.interrupt", function() { modeSlider.interrupt(); })
.on("start drag", function() { inverseModeScale(d3.mouse(this)[0]); })
)
Он возвращает элемент из modeArray
, который ближе всего к x-позиции мыши. Даже если это значение выходит за пределы (-400 или 940), оно возвращает правильный элемент.
Ответ может показаться немного специфичным для слайдеров, но все равно, поскольку он действителен (я думаю), и этот вопрос находится в верхних результатах для "d3 инвертирования порядкового номера" в Google.
Примечание. В этом ответе используется d3 v4.
Ответ 5
Я понимаю, почему Майк Босток может неохотно включать invert
в порядковые шкалы, так как вы не можете вернуть единственное истинное значение. Однако, вот моя версия.
Функция принимает позицию и возвращает окружающие данные. Возможно, я продолжу бинарную версию поиска позже: -)
function ordinalInvert(pos, scale) {
var previous = null
var domain = scale.domain()
for(idx in domain) {
if(scale(datum[idx]) > pos) {
return [previous, datum[idx]];
}
previous = datum[idx];
}
return [previous, null];
}
Ответ 6
Я решил его, построив вторую линейную шкалу с тем же доменом и диапазоном, а затем вызвал инверсию на этом.
var scale = d3.scale.ordinal()
.domain(domain)
.range(range);
var continousScale = d3.scale.linear()
.domain(domain)
.range(range)
var data = _.map(range, function(i) {
return continousScale.invert(i);
});
Ответ 7
Если вам просто нужно знать, какая позиция мыши соответствует данным, то d3 уже делает это для вас.
.on("click", function(d,i) {
console.log("Clicked on " + d);
});
Я обновил Fiddle от @AmeliaBR http://fiddle.jshell.net/dMpbh/17/
Ответ 8
Вы можете легко получить индекс объекта/данные в обратном вызове
.on("click", function(d,i) {
console.log("Clicked on index = " + i);
console.log("Clicked on data = " + d);
// d == imageScale.domain()[1]
});
d - это значение самого инвертированного значения.
Вам не нужно использовать obj.domain() [index].