devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
647 lines (519 loc) • 21.5 kB
JavaScript
"use strict";
var vizUtils = require("../core/utils"),
isNumeric = require("../../core/utils/type").isNumeric,
extend = require("../../core/utils/extend").extend,
constants = require("./axes_constants"),
circularAxes,
xyAxesLinear = require("./xy_axes").linear,
tick = require("./tick").tick,
polarAxes,
_map = vizUtils.map,
_math = Math,
_abs = _math.abs,
_round = _math.round,
convertPolarToXY = vizUtils.convertPolarToXY,
_extend = extend,
_noop = require("../../core/utils/common").noop,
HALF_PI_ANGLE = 90;
function getPolarQuarter(angle) {
var quarter;
angle = vizUtils.normalizeAngle(angle);
if (angle >= 315 && angle <= 360 || angle < 45 && angle >= 0) {
quarter = 1;
} else if (angle >= 45 && angle < 135) {
quarter = 2;
} else if (angle >= 135 && angle < 225) {
quarter = 3;
} else if (angle >= 225 && angle < 315) {
quarter = 4;
}
return quarter;
}
polarAxes = exports;
circularAxes = polarAxes.circular = {
_applyMargins: function _applyMargins(range) {
return range;
},
_getTranslatorOptions: function _getTranslatorOptions() {
return {
isHorizontal: true,
conversionValue: true,
addSpiderCategory: this._getSpiderCategoryOption(),
stick: this._getStick()
};
},
getCenter: function getCenter() {
return this._center;
},
getRadius: function getRadius() {
return this._radius;
},
getAngles: function getAngles() {
var options = this._options;
return [options.startAngle, options.endAngle];
},
_updateRadius: function _updateRadius(canvas) {
var rad = Math.min(canvas.width - canvas.left - canvas.right, canvas.height - canvas.top - canvas.bottom) / 2;
this._radius = rad < 0 ? 0 : rad;
},
_updateCenter: function _updateCenter(canvas) {
this._center = {
x: canvas.left + (canvas.width - canvas.right - canvas.left) / 2,
y: canvas.top + (canvas.height - canvas.top - canvas.bottom) / 2
};
},
_processCanvas: function _processCanvas(canvas) {
var options = this._options;
this._updateRadius(canvas);
this._updateCenter(canvas);
return { left: 0, right: 0, width: _math.abs(options.endAngle - options.startAngle) };
},
_createAxisElement: function _createAxisElement() {
return this._renderer.circle();
},
_updateAxisElementPosition: function _updateAxisElementPosition() {
var center = this.getCenter();
this._axisElement.attr({ cx: center.x, cy: center.y, r: this.getRadius() });
},
_boundaryTicksVisibility: {
min: true
},
_getSpiderCategoryOption: function _getSpiderCategoryOption() {
// TODO rename spider
return this._options.firstPointOnStartAngle;
},
_getMinMax: function _getMinMax() {
var options = this._options,
min = isNumeric(options.originValue) ? options.originValue : undefined,
max;
if (options.period > 0 && options.argumentType === constants.numeric) {
min = min || 0;
max = min + options.period;
}
return { min: min, max: max };
},
_getStick: function _getStick() {
return this._options.firstPointOnStartAngle || this._options.type !== constants.discrete;
},
_getTranslatedCoord: function _getTranslatedCoord(value, offset) {
return this._translator.translate(value, offset) - HALF_PI_ANGLE;
},
_getCanvasStartEnd: function _getCanvasStartEnd() {
return {
start: 0 - HALF_PI_ANGLE,
end: 360 - HALF_PI_ANGLE
};
},
_getStripGraphicAttributes: function _getStripGraphicAttributes(fromAngle, toAngle) {
var center = this.getCenter(),
angle = this.getAngles()[0],
r = this.getRadius();
return {
x: center.x,
y: center.y,
innerRadius: 0,
outerRadius: r,
startAngle: -toAngle - angle,
endAngle: -fromAngle - angle
};
},
_createStrip: function _createStrip(fromAngle, toAngle, attr) {
var coords = this._getStripGraphicAttributes(fromAngle, toAngle);
return this._renderer.arc(coords.x, coords.y, coords.innerRadius, coords.outerRadius, coords.startAngle, coords.endAngle).attr(attr);
},
_getStripLabelCoords: function _getStripLabelCoords(from, to) {
var that = this,
coords = that._getStripGraphicAttributes(from, to),
angle = coords.startAngle + (coords.endAngle - coords.startAngle) / 2,
cosSin = vizUtils.getCosAndSin(angle),
halfRad = that.getRadius() / 2,
center = that.getCenter(),
x = _round(center.x + halfRad * cosSin.cos),
y = _round(center.y - halfRad * cosSin.sin);
return { x: x, y: y, align: constants.center };
},
_getConstantLineGraphicAttributes: function _getConstantLineGraphicAttributes(value) {
var center = this.getCenter(),
r = this.getRadius();
return {
points: [center.x, center.y, center.x + r, center.y]
};
},
_createConstantLine: function _createConstantLine(value, attr) {
var center = this.getCenter();
return this._createPathElement(this._getConstantLineGraphicAttributes(value).points, attr).rotate(value + this.getAngles()[0], center.x, center.y);
},
_getConstantLineLabelsCoords: function _getConstantLineLabelsCoords(value) {
var that = this,
cosSin = vizUtils.getCosAndSin(-value - that.getAngles()[0]),
halfRad = that.getRadius() / 2,
center = that.getCenter(),
x = _round(center.x + halfRad * cosSin.cos),
y = _round(center.y - halfRad * cosSin.sin);
return { x: x, y: y };
},
_checkAlignmentConstantLineLabels: _noop,
_getScreenDelta: function _getScreenDelta() {
var angles = this.getAngles();
return _abs(angles[0] - angles[1]) * this.getRadius() * Math.PI / 180;
},
_getTickMarkPoints: function _getTickMarkPoints(tick, length) {
var center = this.getCenter(),
corrections = {
inside: -1,
center: -0.5,
outside: 0
},
radiusWithTicks = this.getRadius() + length * corrections[this._options.tickOrientation || "center"];
return [center.x + radiusWithTicks, center.y, center.x + radiusWithTicks + length, center.y];
},
_getLabelAdjustedCoord: function _getLabelAdjustedCoord(tick) {
var that = this,
labelCoords = tick.labelCoords,
labelY = labelCoords.y,
labelAngle = labelCoords.angle,
cosSin = vizUtils.getCosAndSin(labelAngle),
cos = cosSin.cos,
sin = cosSin.sin,
box = tick.labelBBox,
halfWidth = box.width / 2,
halfHeight = box.height / 2,
indentFromAxis = that._options.label.indentFromAxis || 0,
x = labelCoords.x + indentFromAxis * cos,
y = labelY + (labelY - box.y - halfHeight) + indentFromAxis * sin;
switch (getPolarQuarter(labelAngle)) {
case 1:
x += halfWidth;
y += halfHeight * sin;
break;
case 2:
x += halfWidth * cos;
y += halfHeight;
break;
case 3:
x += -halfWidth;
y += halfHeight * sin;
break;
case 4:
x += halfWidth * cos;
y += -halfHeight;
break;
}
return { x: x, y: y };
},
_getGridLineDrawer: function _getGridLineDrawer() {
var that = this;
return function (tick, gridStyle) {
var center = that.getCenter();
return that._createPathElement(that._getGridPoints().points, gridStyle).rotate(tick.coords.angle, center.x, center.y);
};
},
_getGridPoints: function _getGridPoints() {
var r = this.getRadius(),
center = this.getCenter();
return {
points: [center.x, center.y, center.x + r, center.y]
};
},
_getTranslatedValue: function _getTranslatedValue(value, offset) {
var startAngle = this.getAngles()[0],
angle = this._translator.translate(value, -offset),
coords = convertPolarToXY(this.getCenter(), startAngle, angle, this.getRadius());
return { x: coords.x, y: coords.y, angle: angle + startAngle - HALF_PI_ANGLE };
},
_getAdjustedStripLabelCoords: function _getAdjustedStripLabelCoords(strip) {
var box = strip.labelBBox;
return {
translateY: strip.label.attr("y") - box.y - box.height / 2
};
},
coordsIn: function coordsIn(x, y) {
return vizUtils.convertXYToPolar(this.getCenter(), x, y).r > this.getRadius();
},
_rotateTick: function _rotateTick(element, coords) {
var center = this.getCenter();
element.rotate(coords.angle, center.x, center.y);
},
_validateOverlappingMode: function _validateOverlappingMode(mode) {
return constants.validateOverlappingMode(mode);
},
_validateDisplayMode: function _validateDisplayMode() {
return "standard";
},
_getStep: function _getStep(boxes) {
var that = this,
radius = that.getRadius() + (that._options.label.indentFromAxis || 0),
maxLabelBox = boxes.reduce(function (prevValue, box) {
var curValue = prevValue;
if (prevValue.width < box.width) {
curValue.width = box.width;
}
if (prevValue.height < box.height) {
curValue.height = box.height;
}
return curValue;
}, { width: 0, height: 0 }),
angle1 = _abs(2 * _math.atan(maxLabelBox.height / (2 * radius - maxLabelBox.width)) * 180 / _math.PI),
angle2 = _abs(2 * _math.atan(maxLabelBox.width / (2 * radius - maxLabelBox.height)) * 180 / _math.PI);
return constants.getTicksCountInRange(that._majorTicks, "angle", _math.max(angle1, angle2));
},
_checkBoundedLabelsOverlapping: function _checkBoundedLabelsOverlapping(step, majorTicks, boxes) {
var lastVisibleLabelIndex = _math.floor((boxes.length - 1) / step) * step,
labelOpt = this._options.label;
if (!lastVisibleLabelIndex) {
return;
}
if (constants.areLabelsOverlap(boxes[0], boxes[lastVisibleLabelIndex], labelOpt.minSpacing, constants.center)) {
labelOpt.overlappingBehavior.hideFirstOrLast === "first" ? majorTicks[0].label.remove() : majorTicks[lastVisibleLabelIndex].label.remove();
}
},
shift: function shift(margins) {
this._axisGroup.attr({ translateX: margins.right, translateY: margins.bottom });
}
};
exports.circularSpider = _extend({}, circularAxes, {
_createAxisElement: function _createAxisElement() {
return this._renderer.path([], "area");
},
_updateAxisElementPosition: function _updateAxisElementPosition() {
this._axisElement.attr({
points: _map(this.getSpiderTicks(), function (tick) {
return { x: tick.coords.x, y: tick.coords.y };
})
});
},
_getStick: function _getStick() {
return true;
},
_getSpiderCategoryOption: function _getSpiderCategoryOption() {
return true;
},
getSpiderTicks: function getSpiderTicks() {
var that = this,
ticks = that.getFullTicks();
that._spiderTicks = ticks.map(tick(that, that.renderer, {}, {}, that._getSkippedCategory(ticks), true));
that._spiderTicks.forEach(function (tick) {
tick.initCoords();
});
return that._spiderTicks;
},
_getStripGraphicAttributes: function _getStripGraphicAttributes(fromAngle, toAngle) {
var center = this.getCenter(),
spiderTicks = this.getSpiderTicks(),
firstTick,
lastTick,
nextTick,
tick,
points = [],
i = 0,
len = spiderTicks.length;
while (i < len) {
tick = spiderTicks[i].coords;
if (tick.angle >= fromAngle && tick.angle <= toAngle) {
if (!firstTick) {
firstTick = (spiderTicks[i - 1] || spiderTicks[spiderTicks.length - 1]).coords;
points.push((tick.x + firstTick.x) / 2, (tick.y + firstTick.y) / 2);
}
points.push(tick.x, tick.y);
nextTick = (spiderTicks[i + 1] || spiderTicks[0]).coords;
lastTick = { x: (tick.x + nextTick.x) / 2, y: (tick.y + nextTick.y) / 2 };
}
i++;
}
points.push(lastTick.x, lastTick.y);
points.push(center.x, center.y);
return {
points: points
};
},
_createStrip: function _createStrip(fromAngle, toAngle, attr) {
var points = this._getStripGraphicAttributes(fromAngle, toAngle).points;
return this._renderer.path(points, "area").attr(attr);
},
_getTranslatedCoord: function _getTranslatedCoord(value, offset) {
return this._translator.translate(value, offset) - HALF_PI_ANGLE;
},
_setTickOffset: function _setTickOffset() {
this._tickOffset = false;
}
});
polarAxes.linear = {
_getMinMax: circularAxes._getMinMax,
_getStick: xyAxesLinear._getStick,
_getSpiderCategoryOption: _noop,
_getTranslatorOptions: function _getTranslatorOptions() {
return {
isHorizontal: true,
stick: this._getStick()
};
},
_updateRadius: circularAxes._updateRadius,
getRadius: circularAxes.getRadius,
getCenter: circularAxes.getCenter,
getAngles: circularAxes.getAngles,
_updateCenter: circularAxes._updateCenter,
_processCanvas: function _processCanvas(canvas) {
this._updateRadius(canvas);
this._updateCenter(canvas);
return { left: 0, right: 0, width: this.getRadius() };
},
_createAxisElement: xyAxesLinear._createAxisElement,
_updateAxisElementPosition: function _updateAxisElementPosition() {
var centerCoord = this.getCenter();
this._axisElement.attr({
points: [centerCoord.x, centerCoord.y, centerCoord.x + this.getRadius(), centerCoord.y]
}).rotate(this.getAngles()[0] - HALF_PI_ANGLE, centerCoord.x, centerCoord.y);
},
_getScreenDelta: function _getScreenDelta() {
return this.getRadius();
},
_getTickMarkPoints: function _getTickMarkPoints(tick, length) {
var coords = tick.coords;
return [coords.x - length / 2, coords.y, coords.x + length / 2, coords.y];
},
_getLabelAdjustedCoord: function _getLabelAdjustedCoord(tick) {
var that = this,
labelCoords = tick.labelCoords,
labelY = labelCoords.y,
cosSin = vizUtils.getCosAndSin(labelCoords.angle),
indentFromAxis = that._options.label.indentFromAxis || 0,
box = tick.labelBBox,
x,
y;
x = labelCoords.x - _abs(indentFromAxis * cosSin.sin) + _abs(box.width / 2 * cosSin.cos) - box.width / 2;
y = labelY + (labelY - box.y) - _abs(box.height / 2 * cosSin.sin) + _abs(indentFromAxis * cosSin.cos);
return { x: x, y: y };
},
_getGridLineDrawer: function _getGridLineDrawer() {
var that = this;
return function (tick, gridStyle) {
var grid = that._getGridPoints(tick.coords);
return that._renderer.circle(grid.x, grid.y, grid.r).attr(gridStyle).sharp();
};
},
_getGridPoints: function _getGridPoints(coords) {
var pos = this.getCenter();
return {
x: pos.x,
y: pos.y,
r: vizUtils.getDistance(pos.x, pos.y, coords.x, coords.y)
};
},
_getTranslatedValue: function _getTranslatedValue(value, offset) {
var startAngle = this.getAngles()[0],
xy = convertPolarToXY(this.getCenter(), startAngle, 0, this._translator.translate(value, offset));
return { x: xy.x, y: xy.y, angle: startAngle - HALF_PI_ANGLE };
},
_getTranslatedCoord: function _getTranslatedCoord(value, offset) {
return this._translator.translate(value, offset);
},
_getCanvasStartEnd: function _getCanvasStartEnd() {
return {
start: 0,
end: this.getRadius()
};
},
_getStripGraphicAttributes: function _getStripGraphicAttributes(fromPoint, toPoint) {
var center = this.getCenter();
return {
x: center.x,
y: center.y,
innerRadius: fromPoint,
outerRadius: toPoint
};
},
_createStrip: function _createStrip(fromPoint, toPoint, attr) {
var attrs = this._getStripGraphicAttributes(fromPoint, toPoint);
return this._renderer.arc(attrs.x, attrs.y, attrs.innerRadius, attrs.outerRadius, 0, 360).attr(attr);
},
_getAdjustedStripLabelCoords: circularAxes._getAdjustedStripLabelCoords,
_getStripLabelCoords: function _getStripLabelCoords(from, to) {
var that = this,
labelPos = from + (to - from) / 2,
center = that.getCenter(),
y = _round(center.y - labelPos);
return { x: center.x, y: y, align: constants.center };
},
_getConstantLineGraphicAttributes: function _getConstantLineGraphicAttributes(value) {
var center = this.getCenter();
return {
cx: center.x,
cy: center.y,
r: value
};
},
_createConstantLine: function _createConstantLine(value, attr) {
var attrs = this._getConstantLineGraphicAttributes(value);
return this._renderer.circle(attrs.cx, attrs.cy, attrs.r).attr(attr).sharp();
},
_getConstantLineLabelsCoords: function _getConstantLineLabelsCoords(value) {
var that = this,
center = that.getCenter(),
y = _round(center.y - value);
return { x: center.x, y: y };
},
_checkAlignmentConstantLineLabels: _noop,
_rotateTick: function _rotateTick(element, coords) {
element.rotate(coords.angle + HALF_PI_ANGLE, coords.x, coords.y);
},
_validateOverlappingMode: circularAxes._validateOverlappingMode,
_validateDisplayMode: circularAxes._validateDisplayMode,
_getStep: function _getStep(boxes) {
var quarter = getPolarQuarter(this.getAngles()[0]),
spacing = this._options.label.minSpacing,
func = quarter === 2 || quarter === 4 ? function (box) {
return box.width + spacing;
} : function (box) {
return box.height;
},
maxLabelLength = boxes.reduce(function (prevValue, box) {
return _math.max(prevValue, func(box));
}, 0);
return constants.getTicksCountInRange(this._majorTicks, quarter === 2 || quarter === 4 ? "x" : "y", maxLabelLength);
}
};
polarAxes.linearSpider = _extend({}, polarAxes.linear, {
_createPathElement: function _createPathElement(points, attr) {
return this._renderer.path(points, "area").attr(attr).sharp();
},
setSpiderTicks: function setSpiderTicks(ticks) {
this._spiderTicks = ticks;
},
_getGridLineDrawer: function _getGridLineDrawer() {
var that = this;
return function (tick, gridStyle, element) {
return that._createPathElement(that._getGridPoints(tick.coords).points, gridStyle);
};
},
_getGridPoints: function _getGridPoints(coords) {
var pos = this.getCenter(),
radius = vizUtils.getDistance(pos.x, pos.y, coords.x, coords.y);
return this._getGridPointsByRadius(radius);
},
_getGridPointsByRadius: function _getGridPointsByRadius(radius) {
var pos = this.getCenter();
return {
points: _map(this._spiderTicks, function (tick) {
var cosSin = vizUtils.getCosAndSin(tick.coords.angle);
return { x: _round(pos.x + radius * cosSin.cos), y: _round(pos.y + radius * cosSin.sin) };
})
};
},
_getStripGraphicAttributes: function _getStripGraphicAttributes(fromPoint, toPoint) {
var innerPoints = this._getGridPointsByRadius(toPoint).points,
outerPoints = this._getGridPointsByRadius(fromPoint).points;
return {
points: [outerPoints, innerPoints.reverse()]
};
},
_createStrip: function _createStrip(fromPoint, toPoint, attr) {
var points = this._getStripGraphicAttributes(fromPoint, toPoint).points;
return this._renderer.path(points, "area").attr(attr);
},
_getConstantLineGraphicAttributes: function _getConstantLineGraphicAttributes(value) {
return this._getGridPointsByRadius(value);
},
_createConstantLine: function _createConstantLine(value, attr) {
return this._createPathElement(this._getConstantLineGraphicAttributes(value).points, attr);
}
});