Odpowiedź Toon Krijthe działa przez większość czasu. Ale czasami spowoduje to nadmierną liczbę kleszczy. Nie zadziała również z liczbami ujemnymi. Ogólne podejście do problemu jest w porządku, ale istnieje lepszy sposób rozwiązania tego problemu. Algorytm, którego chcesz użyć, będzie zależał od tego, co naprawdę chcesz uzyskać. Poniżej przedstawiam mój kod, którego użyłem w mojej bibliotece JS Ploting. Przetestowałem to i zawsze działa (miejmy nadzieję;)). Oto główne kroki:
- pobierz globalne ekstremum xMin i xMax (w tym wszystkie wykresy, które chcesz wydrukować w algorytmie)
- oblicz zakres od xMin do xMax
- obliczyć rząd wielkości swojego zasięgu
- obliczyć wielkość taktów, dzieląc zakres przez liczbę taktów minus jeden
- ten jest opcjonalny. Jeśli chcesz, aby zawsze drukowano zero ticków, użyj rozmiaru tick do obliczenia liczby dodatnich i ujemnych ticków. Całkowita liczba ticków będzie ich sumą + 1 (zero tick)
- ten nie jest potrzebny, jeśli zawsze drukowane jest zero znaczników. Oblicz dolną i górną granicę, ale pamiętaj, aby wycentrować działkę
Zaczynajmy. Najpierw podstawowe obliczenia
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);
Zaokrąglam wartości minimalne i maksymalne, aby mieć 100% pewności, że mój wykres obejmie wszystkie dane. Bardzo ważne jest również, aby log10 podłogi zakresu, czy jest ujemny, czy nie, a następnie odjąć 1. W przeciwnym razie algorytm nie będzie działał dla liczb mniejszych niż jeden.
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);
Używam „ładnie wyglądających kleszczy”, aby uniknąć kleszczy typu 7, 13, 17 itp. Metoda, której tu używam, jest dość prosta. Dobrze jest też mieć zeroTick w razie potrzeby. W ten sposób fabuła wygląda znacznie bardziej profesjonalnie. Znajdziesz wszystkie metody na końcu tej odpowiedzi.
Teraz musisz obliczyć górną i dolną granicę. Jest to bardzo łatwe przy zerowym ticku, ale w innym przypadku wymaga trochę więcej wysiłku. Czemu? Ponieważ chcemy ładnie wyśrodkować działkę w górnej i dolnej granicy. Spójrz na mój kod. Część zmiennych jest zdefiniowana poza tym zakresem, a część z nich jest właściwością obiektu, w którym przechowywany jest cały prezentowany kod.
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;
}
A oto metody, o których wspomniałem wcześniej, a które możesz pisać samodzielnie, ale możesz też użyć moich
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;
}
}
Jest jeszcze jedna rzecz, której nie ma tutaj. To jest „ładnie wyglądające granice”. Są to dolne granice, które są liczbami podobnymi do liczb w „ładnie wyglądających kleszczach”. Na przykład lepiej jest mieć dolną granicę zaczynającą się od 5 przy wielkości tiku 5, niż mieć wykres, który zaczyna się od 6 o tej samej wielkości tiku. Ale to mój ogień, zostawiam to tobie.
Mam nadzieję, że to pomoże. Twoje zdrowie!