Как установить динамический или статический размер галочки на участке Rickshaw.js?

Я создаю график Rickshaw.js, как и в этом примере: http://code.shutterstock.com/rickshaw/tutorial/example_07.html на основе моих собственных данных, которые возвращаются через вызов AJAX. Данные либо измеряются в байтах (диапазон типичных значений - несколько гигабайт или сотни МБ), либо секунды (в пределах от 10 до 50 минут). Я попытался использовать форматер Rickshaw.Fixtures.Number.formatBase1024KMGTP для байтов и написал свои собственные для секунд, что делает его часть хорошо. Проблема в том, что мне нужно позиционировать тиковые линии умным способом - желательно динамически, но даже статические настройки (например, пометить каждый 1024*1024*1024=1 GB или каждый 60 s) будут в порядке.

Я попытался установить tickSize на 1024^3 следующим образом:

var y_axis = new Rickshaw.Graph.Axis.Y({
    graph: graph,
    tickSize: 1073741824 // 1 GB
});
y_axis.render();

но я не заметил никаких тиков. Что я делаю неправильно и что будет правильным?

Ответ 1

В принципе, вам нужно адаптировать функцию tickOffsets() Axis.X, Axis.Y и Axis.Time классы в Rickshaw.

tickSize не поможет вам с тем, что как @Old Pro указано правильно - это указывает размер выделенных жирных линий в пикселях. Это не имеет никакого отношения к интервалу.

Для осей, основанных на времени

Мое решение состоит, главным образом, в замене стандартной tickOffsets() функции в этих файлах

this.tickOffsets = function() {
    var domain = this.graph.x.domain();

    var unit = this.fixedTimeUnit || this.appropriateTimeUnit();
    var count = Math.ceil((domain[1] - domain[0]) / unit.seconds);

    var runningTick = domain[0];
    var offsets = [];

    for (var i = 0; i < count; i++) {
        var tickValue = time.ceil(runningTick, unit);
        runningTick = tickValue + unit.seconds / 2;

        offsets.push( { value: tickValue, unit: unit } );
    }

    return offsets;
};

с помощью специальной процедуры. Это будет трюк:

this.tickOffsets = function() {
    var domain = this.graph.x.domain();
    var unit = this.fixedTimeUnit || this.appropriateTimeUnit();

    var tickSpacing = args.tickSpacing || unit.seconds;
    var count = Math.ceil((domain[1] - domain[0]) / tickSpacing);

    var runningTick = domain[0];
    var offsets = [];

    for (var i = 0; i < count; i++) {
        var tickValue = time.ceil(runningTick, unit);
        runningTick = tickValue + tickSpacing;

        offsets.push( { value: tickValue, unit: unit } );
    }
    return offsets;
};

С помощью этого вы можете написать что-то вроде

var time = new Rickshaw.Fixtures.Time();
var timeUnit = time.unit('year');

var x_axis = new Rickshaw.Graph.Axis.ExtendedTime( 
    { 
        graph: graph, 
        tickSpacing: 60*60*24*365*13, // 13 years
        timeUnit: timeUnit
    } );

чтобы тики были равномерно распределены каждые 13 лет.

Для осей, основанных на значении

Для осей, основанных на значении, вам необходимо расширить функцию render(), чтобы включить объект, который "вручную" устанавливает тики для оси. Я сделал это так:

this.render = function() {

    if (this.graph.height !== this._renderHeight) this.setSize({ auto: true });

    var axis = d3.svg.axis().scale(this.graph.y).orient(this.orientation);

    if (this.tickSpacing) {
        var tickValues = [];

        var min = Math.ceil(axis.scale().domain()[0]/this.tickSpacing);
        var max = Math.floor(axis.scale().domain()[1]/this.tickSpacing);

        for (i = min * this.tickSpacing; i < max; i += 1) {
            console.log(i);
            tickValues.push(i * this.tickSpacing);
        }
        axis.tickValues(tickValues);
    }

    axis.tickFormat( args.tickFormat || function(y) { return y } );

    if (this.orientation == 'left') {
        var berth = this.height * berthRate;
        var transform = 'translate(' + this.width + ', ' + berth + ')';
    }

    if (this.element) {
        this.vis.selectAll('*').remove();
    }

    this.vis
        .append("svg:g")
        .attr("class", ["y_ticks", this.ticksTreatment].join(" "))
        .attr("transform", transform)
        .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));

    var gridSize = (this.orientation == 'right' ? 1 : -1) * this.graph.width;

    this.graph.vis
        .append("svg:g")
        .attr("class", "y_grid")
        .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));

    this._renderHeight = this.graph.height;
};

Важной частью здесь являются утверждения в предложении if (this.tickSpacing). Они вычисляют тики, заданные переменной tickSpacing в массиве config, и назначают их оси в выражении axis.tickValues(tickValues). Обратите внимание, что this.tickValues назначается в инструкции this.tickSpacing = args.tickSpacing в функции initialize(), не указанной выше.

Попробуйте сами

Посмотрите на jsfiddle, где доступен полный код. Это, безусловно, даст вам несколько указателей. Если вы хотите, вы можете создать свой собственный jsfiddle с вашими значениями и рассказать мне, если вам нужно что-нибудь еще.

Ответ 2

tickSize - размер тиков в пикселях. Не то, что вы хотите установить на огромное количество.

Установите ticks количество тиков, которые вы хотите на графике, и Rickshaw (на самом деле d3) будет делать какую-то магию, чтобы дать вам красивые значения тиков, которые генерируют около этого количества тиков на графике.

Если вам нужен дальнейший контроль, вам придется копать в d3, где вы сможете явно установить галочку значения с помощью axis.tickValues ​​(). Скорее всего, я скопирую существующий Rickshaw.Graph.Axis.Y код и создаю свой собственный класс оси Y, который включает в себя доступ к tickValues или возможность использовать мой собственный scale. Это немного нечисто, потому что Rickshaw создает шкалу Y в функции graph.render(), поэтому вы не можете легко переопределить масштаб Y, но у R-образной шкалы Y-шкалы есть диапазон, заданный из данных графика, который является информацией, которую вы будете при создании собственных значений тика.