Ответ Toon Krijthe работает большую часть времени. Но иногда это приведет к избыточному количеству тиков. Он также не будет работать с отрицательными числами. Общий подход к проблеме в порядке, но есть лучший способ справиться с этим. Алгоритм, который вы хотите использовать, будет зависеть от того, что вы действительно хотите получить. Ниже я представляю вам мой код, который я использовал в своей библиотеке JS Ploting. Я проверил это, и оно всегда работает (надеюсь;)). Вот основные шаги:
- получить глобальные экстремумы xMin и xMax (включая все графики, которые вы хотите распечатать в алгоритме)
- рассчитать диапазон между xMin и xMax
- вычислите порядок величины вашего диапазона
- рассчитать размер тика путем деления диапазона на количество тиков минус один
- это необязательно. Если вы хотите, чтобы нулевой тик был напечатан всегда, вы используете размер тика для вычисления количества положительных и отрицательных тиков. Общее количество тиков будет их суммой + 1 (нулевой тик)
- этот не нужен, если у вас всегда напечатан нулевой тик. Вычислите нижнюю и верхнюю границу, но не забудьте центрировать график
Давайте начнем. Сначала основные расчеты
var range = Math.abs(xMax - xMin); //both can be negative
var rangeOrder = Math.floor(Math.log10(range)) - 1;
var power10 = Math.pow(10, rangeOrder);
var maxRound = (xMax > 0) ? Math.ceil(xMax / power10) : Math.floor(xMax / power10);
var minRound = (xMin < 0) ? Math.floor(xMin / power10) : Math.ceil(xMin / power10);
Я округляю минимальные и максимальные значения, чтобы быть на 100% уверенным, что мой график охватит все данные. Также очень важно напечатать log10 диапазона или нет, это отрицательно и вычесть 1 позже. В противном случае ваш алгоритм не будет работать для чисел, меньших единицы.
var fullRange = Math.abs(maxRound - minRound);
var tickSize = Math.ceil(fullRange / (this.XTickCount - 1));
//You can set nice looking ticks if you want
//You can find exemplary method below
tickSize = this.NiceLookingTick(tickSize);
//Here you can write a method to determine if you need zero tick
//You can find exemplary method below
var isZeroNeeded = this.HasZeroTick(maxRound, minRound, tickSize);
Я использую «красивые тики», чтобы избежать тиков, таких как 7, 13, 17 и т. Д. Метод, который я здесь использую, довольно прост. Также хорошо иметь нулевую отметку, когда это необходимо. Сюжет выглядит гораздо более профессионально. Вы найдете все методы в конце этого ответа.
Теперь вам нужно вычислить верхнюю и нижнюю границы. Это очень легко с нулевым тактом, но требует немного больше усилий в другом случае. Зачем? Потому что мы хотим красиво расположить сюжет в пределах верхней и нижней границ. Посмотрите на мой код. Некоторые из переменных определены вне этой области, а некоторые из них являются свойствами объекта, в котором хранится весь представленный код.
if (isZeroNeeded) {
var positiveTicksCount = 0;
var negativeTickCount = 0;
if (maxRound != 0) {
positiveTicksCount = Math.ceil(maxRound / tickSize);
XUpperBound = tickSize * positiveTicksCount * power10;
}
if (minRound != 0) {
negativeTickCount = Math.floor(minRound / tickSize);
XLowerBound = tickSize * negativeTickCount * power10;
}
XTickRange = tickSize * power10;
this.XTickCount = positiveTicksCount - negativeTickCount + 1;
}
else {
var delta = (tickSize * (this.XTickCount - 1) - fullRange) / 2.0;
if (delta % 1 == 0) {
XUpperBound = maxRound + delta;
XLowerBound = minRound - delta;
}
else {
XUpperBound = maxRound + Math.ceil(delta);
XLowerBound = minRound - Math.floor(delta);
}
XTickRange = tickSize * power10;
XUpperBound = XUpperBound * power10;
XLowerBound = XLowerBound * power10;
}
А вот методы, о которых я упоминал ранее, которые вы можете написать самостоятельно, но вы также можете использовать мои
this.NiceLookingTick = function (tickSize) {
var NiceArray = [1, 2, 2.5, 3, 4, 5, 10];
var tickOrder = Math.floor(Math.log10(tickSize));
var power10 = Math.pow(10, tickOrder);
tickSize = tickSize / power10;
var niceTick;
var minDistance = 10;
var index = 0;
for (var i = 0; i < NiceArray.length; i++) {
var dist = Math.abs(NiceArray[i] - tickSize);
if (dist < minDistance) {
minDistance = dist;
index = i;
}
}
return NiceArray[index] * power10;
}
this.HasZeroTick = function (maxRound, minRound, tickSize) {
if (maxRound * minRound < 0)
{
return true;
}
else if (Math.abs(maxRound) < tickSize || Math.round(minRound) < tickSize) {
return true;
}
else {
return false;
}
}
Есть только одна вещь, которая здесь не включена. Это «красивые границы». Это нижние границы, которые являются числами, похожими на числа в «красивых галочках». Например, лучше иметь нижнюю границу, начинающуюся с 5 с размером тика 5, чем иметь график, начинающийся с 6 с тем же размером тика. Но это мой уволенный, я оставляю это тебе.
Надеюсь, это поможет.
Ура!