dojo.provide("dojox.charting.scaler.linear"); dojo.require("dojox.charting.scaler.common"); (function(){ var deltaLimit = 3, // pixels dc = dojox.charting, dcs = dc.scaler, dcsc = dcs.common, findString = dcsc.findString, getLabel = dcsc.getNumericLabel; var calcTicks = function(min, max, kwArgs, majorTick, minorTick, microTick, span){ kwArgs = dojo.delegate(kwArgs); if(!majorTick){ if(kwArgs.fixUpper == "major"){ kwArgs.fixUpper = "minor"; } if(kwArgs.fixLower == "major"){ kwArgs.fixLower = "minor"; } } if(!minorTick){ if(kwArgs.fixUpper == "minor"){ kwArgs.fixUpper = "micro"; } if(kwArgs.fixLower == "minor"){ kwArgs.fixLower = "micro"; } } if(!microTick){ if(kwArgs.fixUpper == "micro"){ kwArgs.fixUpper = "none"; } if(kwArgs.fixLower == "micro"){ kwArgs.fixLower = "none"; } } var lowerBound = findString(kwArgs.fixLower, ["major"]) ? Math.floor(kwArgs.min / majorTick) * majorTick : findString(kwArgs.fixLower, ["minor"]) ? Math.floor(kwArgs.min / minorTick) * minorTick : findString(kwArgs.fixLower, ["micro"]) ? Math.floor(kwArgs.min / microTick) * microTick : kwArgs.min, upperBound = findString(kwArgs.fixUpper, ["major"]) ? Math.ceil(kwArgs.max / majorTick) * majorTick : findString(kwArgs.fixUpper, ["minor"]) ? Math.ceil(kwArgs.max / minorTick) * minorTick : findString(kwArgs.fixUpper, ["micro"]) ? Math.ceil(kwArgs.max / microTick) * microTick : kwArgs.max; if(kwArgs.useMin){ min = lowerBound; } if(kwArgs.useMax){ max = upperBound; } var majorStart = (!majorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major"])) ? min : Math.ceil(min / majorTick) * majorTick, minorStart = (!minorTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor"])) ? min : Math.ceil(min / minorTick) * minorTick, microStart = (! microTick || kwArgs.useMin && findString(kwArgs.fixLower, ["major", "minor", "micro"])) ? min : Math.ceil(min / microTick) * microTick, majorCount = !majorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major"]) ? Math.round((max - majorStart) / majorTick) : Math.floor((max - majorStart) / majorTick)) + 1, minorCount = !minorTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor"]) ? Math.round((max - minorStart) / minorTick) : Math.floor((max - minorStart) / minorTick)) + 1, microCount = !microTick ? 0 : (kwArgs.useMax && findString(kwArgs.fixUpper, ["major", "minor", "micro"]) ? Math.round((max - microStart) / microTick) : Math.floor((max - microStart) / microTick)) + 1, minorPerMajor = minorTick ? Math.round(majorTick / minorTick) : 0, microPerMinor = microTick ? Math.round(minorTick / microTick) : 0, majorPrecision = majorTick ? Math.floor(Math.log(majorTick) / Math.LN10) : 0, minorPrecision = minorTick ? Math.floor(Math.log(minorTick) / Math.LN10) : 0, scale = span / (max - min); if(!isFinite(scale)){ scale = 1; } return { bounds: { lower: lowerBound, upper: upperBound, from: min, to: max, scale: scale, span: span }, major: { tick: majorTick, start: majorStart, count: majorCount, prec: majorPrecision }, minor: { tick: minorTick, start: minorStart, count: minorCount, prec: minorPrecision }, micro: { tick: microTick, start: microStart, count: microCount, prec: 0 }, minorPerMajor: minorPerMajor, microPerMinor: microPerMinor, scaler: dcs.linear }; }; dojo.mixin(dojox.charting.scaler.linear, { buildScaler: function(/*Number*/ min, /*Number*/ max, /*Number*/ span, /*Object*/ kwArgs){ var h = {fixUpper: "none", fixLower: "none", natural: false}; if(kwArgs){ if("fixUpper" in kwArgs){ h.fixUpper = String(kwArgs.fixUpper); } if("fixLower" in kwArgs){ h.fixLower = String(kwArgs.fixLower); } if("natural" in kwArgs){ h.natural = Boolean(kwArgs.natural); } } // update bounds if("min" in kwArgs){ min = kwArgs.min; } if("max" in kwArgs){ max = kwArgs.max; } if(kwArgs.includeZero){ if(min > 0){ min = 0; } if(max < 0){ max = 0; } } h.min = min; h.useMin = true; h.max = max; h.useMax = true; if("from" in kwArgs){ min = kwArgs.from; h.useMin = false; } if("to" in kwArgs){ max = kwArgs.to; h.useMax = false; } // check for erroneous condition if(max <= min){ return calcTicks(min, max, h, 0, 0, 0, span); // Object } var mag = Math.floor(Math.log(max - min) / Math.LN10), major = kwArgs && ("majorTickStep" in kwArgs) ? kwArgs.majorTickStep : Math.pow(10, mag), minor = 0, micro = 0, ticks; // calculate minor ticks if(kwArgs && ("minorTickStep" in kwArgs)){ minor = kwArgs.minorTickStep; }else{ do{ minor = major / 10; if(!h.natural || minor > 0.9){ ticks = calcTicks(min, max, h, major, minor, 0, span); if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } } minor = major / 5; if(!h.natural || minor > 0.9){ ticks = calcTicks(min, max, h, major, minor, 0, span); if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } } minor = major / 2; if(!h.natural || minor > 0.9){ ticks = calcTicks(min, max, h, major, minor, 0, span); if(ticks.bounds.scale * ticks.minor.tick > deltaLimit){ break; } } return calcTicks(min, max, h, major, 0, 0, span); // Object }while(false); } // calculate micro ticks if(kwArgs && ("microTickStep" in kwArgs)){ micro = kwArgs.microTickStep; ticks = calcTicks(min, max, h, major, minor, micro, span); }else{ do{ micro = minor / 10; if(!h.natural || micro > 0.9){ ticks = calcTicks(min, max, h, major, minor, micro, span); if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } } micro = minor / 5; if(!h.natural || micro > 0.9){ ticks = calcTicks(min, max, h, major, minor, micro, span); if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } } micro = minor / 2; if(!h.natural || micro > 0.9){ ticks = calcTicks(min, max, h, major, minor, micro, span); if(ticks.bounds.scale * ticks.micro.tick > deltaLimit){ break; } } micro = 0; }while(false); } return micro ? ticks : calcTicks(min, max, h, major, minor, 0, span); // Object }, buildTicks: function(/*Object*/ scaler, /*Object*/ kwArgs){ var step, next, tick, nextMajor = scaler.major.start, nextMinor = scaler.minor.start, nextMicro = scaler.micro.start; if(kwArgs.microTicks && scaler.micro.tick){ step = scaler.micro.tick, next = nextMicro; }else if(kwArgs.minorTicks && scaler.minor.tick){ step = scaler.minor.tick, next = nextMinor; }else if(scaler.major.tick){ step = scaler.major.tick, next = nextMajor; }else{ // no ticks return null; } // make sure that we have finite bounds var revScale = 1 / scaler.bounds.scale; if(scaler.bounds.to <= scaler.bounds.from || isNaN(revScale) || !isFinite(revScale) || step <= 0 || isNaN(step) || !isFinite(step)){ // no ticks return null; } // loop over all ticks var majorTicks = [], minorTicks = [], microTicks = []; while(next <= scaler.bounds.to + revScale){ if(Math.abs(nextMajor - next) < step / 2){ // major tick tick = {value: nextMajor}; if(kwArgs.majorLabels){ tick.label = getLabel(nextMajor, scaler.major.prec, kwArgs); } majorTicks.push(tick); nextMajor += scaler.major.tick; nextMinor += scaler.minor.tick; nextMicro += scaler.micro.tick; }else if(Math.abs(nextMinor - next) < step / 2){ // minor tick if(kwArgs.minorTicks){ tick = {value: nextMinor}; if(kwArgs.minorLabels && (scaler.minMinorStep <= scaler.minor.tick * scaler.bounds.scale)){ tick.label = getLabel(nextMinor, scaler.minor.prec, kwArgs); } minorTicks.push(tick); } nextMinor += scaler.minor.tick; nextMicro += scaler.micro.tick; }else{ // micro tick if(kwArgs.microTicks){ microTicks.push({value: nextMicro}); } nextMicro += scaler.micro.tick; } next += step; } return {major: majorTicks, minor: minorTicks, micro: microTicks}; // Object }, getTransformerFromModel: function(/*Object*/ scaler){ var offset = scaler.bounds.from, scale = scaler.bounds.scale; return function(x){ return (x - offset) * scale; }; // Function }, getTransformerFromPlot: function(/*Object*/ scaler){ var offset = scaler.bounds.from, scale = scaler.bounds.scale; return function(x){ return x / scale + offset; }; // Function } }); })();