UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

265 lines (213 loc) 8.69 kB
import Axis from './axis'; import NumericAxis from './numeric-axis'; import AxisLabel from './axis-label'; import { DateLabelFormats } from './constants'; import { BLACK, DATE, COORD_PRECISION, DEFAULT_PRECISION } from '../common/constants'; import { setDefaultOptions, deepExtend, limitValue, round } from '../common'; import autoMajorUnit from './utils/auto-major-unit'; import ceil from './utils/ceil'; import { toDate, toTime, floorDate, ceilDate, duration, addDuration, addTicks, dateDiff, absoluteDateDiff, dateComparer, parseDate, parseDates, firstDay } from '../date-utils'; import { HOURS, DAYS, WEEKS, MONTHS, YEARS, TIME_PER_DAY, TIME_PER_WEEK, TIME_PER_MONTH, TIME_PER_YEAR, TIME_PER_UNIT } from '../date-utils/constants'; const MIN_VALUE_RANGE = 1000; class DateValueAxis extends Axis { constructor(seriesMin, seriesMax, axisOptions, chartService) { const min = toDate(seriesMin); const max = toDate(seriesMax); const intlService = chartService.intl; let options = axisOptions || {}; options = deepExtend(options || {}, { min: parseDate(intlService, options.min), max: parseDate(intlService, options.max), axisCrossingValue: parseDates(intlService, options.axisCrossingValues || options.axisCrossingValue), weekStartDay: firstDay(options, intlService) }); options = applyDefaults(min, max, options); super(options, chartService); this.intlService = intlService; this.seriesMin = min; this.seriesMax = max; const weekStartDay = options.weekStartDay || 0; this.totalMin = toTime(floorDate(toTime(min) - 1, options.baseUnit, weekStartDay)); this.totalMax = toTime(ceilDate(toTime(max) + 1, options.baseUnit, weekStartDay)); } clone() { return new DateValueAxis(this.seriesMin, this.seriesMax, Object.assign({}, this.options), this.chartService); } range() { const options = this.options; return { min: options.min, max: options.max }; } getDivisions(stepValue) { const options = this.options; return Math.floor( duration(options.min, options.max, options.baseUnit) / stepValue + 1 ); } getTickPositions(step) { const options = this.options; const { axisDir: dir, lineSize, lineStart: start } = this.lineInfo(); const divisions = this.getDivisions(step); const timeRange = dateDiff(options.max, options.min); const scale = lineSize / timeRange; const weekStartDay = options.weekStartDay || 0; const positions = [ start ]; for (let i = 1; i < divisions; i++) { const date = addDuration(options.min, i * step, options.baseUnit, weekStartDay); const pos = start + dateDiff(date, options.min) * scale * dir; positions.push(round(pos, COORD_PRECISION)); } return positions; } getMajorTickPositions() { return this.getTickPositions(this.options.majorUnit); } getMinorTickPositions() { return this.getTickPositions(this.options.minorUnit); } getSlot(a, b, limit) { return NumericAxis.prototype.getSlot.call( this, parseDate(this.intlService, a), parseDate(this.intlService, b), limit ); } getValue(point) { const value = NumericAxis.prototype.getValue.call(this, point); return value !== null ? toDate(value) : null; } labelsCount() { return this.getDivisions(this.options.majorUnit); } createAxisLabel(index, labelOptions, labelContext) { const options = this.options; const offset = index * options.majorUnit; const weekStartDay = options.weekStartDay || 0; let date = options.min; if (offset > 0) { date = addDuration(date, offset, options.baseUnit, weekStartDay); } const unitFormat = labelOptions.dateFormats[options.baseUnit]; labelOptions.format = labelOptions.format || unitFormat; const text = this.axisLabelText(date, labelOptions, labelContext); return new AxisLabel(date, text, index, null, labelOptions); } translateRange(delta) { const options = this.options; const lineBox = this.lineBox(); const { vertical, reverse } = options; const size = vertical ? lineBox.height() : lineBox.width(); const range = this.range(); const scale = size / dateDiff(range.max, range.min); let offset = round(delta / scale, DEFAULT_PRECISION); if ((vertical || reverse) && !(vertical && reverse )) { offset = -offset; } let from = addTicks(options.min, offset); let to = addTicks(options.max, offset); return { min: from, max: to, offset: offset }; } shouldRenderNote(value) { const range = this.range(); return dateComparer(value, range.min) >= 0 && dateComparer(value, range.max) <= 0; } pan(delta) { const range = this.translateRange(delta, true); const limittedRange = this.limitRange(toTime(range.min), toTime(range.max), this.totalMin, this.totalMax, range.offset); if (limittedRange) { return { min: toDate(limittedRange.min), max: toDate(limittedRange.max) }; } } pointsRange(start, end) { const startValue = this.getValue(start); const endValue = this.getValue(end); const min = Math.min(startValue, endValue); const max = Math.max(startValue, endValue); return { min: toDate(min), max: toDate(max) }; } scaleRange(scale, cursor) { const position = Math.abs(this.pointOffset(cursor)); const range = this.options.max - this.options.min; const delta = this.scaleToDelta(scale, range); const minDelta = position * delta; const maxDelta = (1 - position) * delta; const min = toDate(toTime(this.options.min) + minDelta); let max = toDate(toTime(this.options.max) - maxDelta); if (max - min < MIN_VALUE_RANGE) { max = toDate(toTime(min) + MIN_VALUE_RANGE); } return { min: min, max: max }; } zoomRange(scale, cursor) { const range = this.scaleRange(scale, cursor); const min = toDate(limitValue(toTime(range.min), this.totalMin, this.totalMax)); const max = toDate(limitValue(toTime(range.max), this.totalMin, this.totalMax)); return { min, max }; } } function timeUnits(delta) { let unit = HOURS; if (delta >= TIME_PER_YEAR) { unit = YEARS; } else if (delta >= TIME_PER_MONTH) { unit = MONTHS; } else if (delta >= TIME_PER_WEEK) { unit = WEEKS; } else if (delta >= TIME_PER_DAY) { unit = DAYS; } return unit; } function applyDefaults(seriesMin, seriesMax, options) { const min = options.min || seriesMin; const max = options.max || seriesMax; const baseUnit = options.baseUnit || (max && min ? timeUnits(absoluteDateDiff(max, min)) : HOURS); const baseUnitTime = TIME_PER_UNIT[baseUnit]; const weekStartDay = options.weekStartDay || 0; const autoMin = floorDate(toTime(min) - 1, baseUnit, weekStartDay) || toDate(max); const autoMax = ceilDate(toTime(max) + 1, baseUnit, weekStartDay); const userMajorUnit = options.majorUnit ? options.majorUnit : undefined; const majorUnit = userMajorUnit || ceil( autoMajorUnit(autoMin.getTime(), autoMax.getTime()), baseUnitTime ) / baseUnitTime; const actualUnits = duration(autoMin, autoMax, baseUnit); const totalUnits = ceil(actualUnits, majorUnit); const unitsToAdd = totalUnits - actualUnits; const head = Math.floor(unitsToAdd / 2); const tail = unitsToAdd - head; if (!options.baseUnit) { delete options.baseUnit; } options.baseUnit = options.baseUnit || baseUnit; options.min = options.min || addDuration(autoMin, -head, baseUnit, weekStartDay); options.max = options.max || addDuration(autoMax, tail, baseUnit, weekStartDay); options.minorUnit = options.minorUnit || majorUnit / 5; options.majorUnit = majorUnit; return options; } setDefaultOptions(DateValueAxis, { type: DATE, majorGridLines: { visible: true, width: 1, color: BLACK }, labels: { dateFormats: DateLabelFormats } }); export default DateValueAxis;