UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

421 lines (368 loc) • 15.9 kB
"use strict"; var _math = Math, _min = _math.min, _max = _math.max, _round = _math.round, _floor = _math.floor, _sqrt = _math.sqrt, vizUtils = require("../core/utils"), _parseScalar = vizUtils.parseScalar, parseHorizontalAlignment = vizUtils.enumParser(["left", "center", "right"]), parseVerticalAlignment = vizUtils.enumParser(["top", "bottom"]), COMMAND_RESET = "command-reset", COMMAND_MOVE_UP = "command-move-up", COMMAND_MOVE_RIGHT = "command-move-right", COMMAND_MOVE_DOWN = "command-move-down", COMMAND_MOVE_LEFT = "command-move-left", COMMAND_ZOOM_IN = "command-zoom-in", COMMAND_ZOOM_OUT = "command-zoom-out", COMMAND_ZOOM_DRAG_LINE = "command-zoom-drag-line", COMMAND_ZOOM_DRAG = "command-zoom-drag", EVENT_TARGET_TYPE = "control-bar", FLAG_CENTERING = 1, FLAG_ZOOMING = 2, // TODO: This should be specified in options - seems like everything can be calculated from "buttonSize" and "zoomSliderLength" SIZE_OPTIONS = { bigCircleSize: 58, smallCircleSize: 28, buttonSize: 10, arrowButtonOffset: 20, incDecButtonSize: 11, incButtonOffset: 66, decButtonOffset: 227, sliderLineStartOffset: 88.5, sliderLineEndOffset: 205.5, sliderLength: 20, sliderWidth: 8, trackerGap: 4 }, OFFSET_X = 30.5, OFFSET_Y = 30.5, TOTAL_WIDTH = 61, TOTAL_HEIGHT = 274, COMMAND_TO_TYPE_MAP = {}; COMMAND_TO_TYPE_MAP[COMMAND_RESET] = ResetCommand; COMMAND_TO_TYPE_MAP[COMMAND_MOVE_UP] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_RIGHT] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_DOWN] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_LEFT] = MoveCommand; COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_IN] = COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_OUT] = ZoomCommand; COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_DRAG] = ZoomDragCommand; function ControlBar(parameters) { var that = this; that._params = parameters; that._createElements(parameters.renderer, parameters.container, parameters.dataKey); parameters.layoutControl.addItem(that); that._subscribeToProjection(parameters.projection); that._subscribeToTracker(parameters.tracker); that._createCallbacks(parameters.projection); } ControlBar.prototype = { constructor: ControlBar, _flags: 0, dispose: function dispose() { var that = this; that._params.layoutControl.removeItem(that); that._root.linkRemove().linkOff(); that._offProjection(); that._offTracker(); that._params = that._root = that._offProjection = that._offTracker = that._callbacks = null; }, _subscribeToProjection: function _subscribeToProjection(projection) { var that = this; that._offProjection = projection.on({ "engine": function engine() { that._update(); }, "zoom": updateZoom, "max-zoom": function maxZoom() { that._zoomPartition = projection.getZoomScalePartition(); that._sliderUnitLength = that._sliderLineLength / that._zoomPartition; updateZoom(); } }); function updateZoom() { that._adjustZoom(projection.getScaledZoom()); } }, _subscribeToTracker: function _subscribeToTracker(tracker) { var that = this, isActive = false; that._offTracker = tracker.on({ "start": function start(arg) { isActive = arg.data.name === EVENT_TARGET_TYPE; if (isActive) { that._processStart(arg.data.index, arg); } }, "move": function move(arg) { if (isActive) { that._processMove(arg.data.index, arg); } }, "end": function end() { if (isActive) { that._processEnd(); isActive = false; } } }); }, _createCallbacks: function _createCallbacks(projection) { var that = this; that._callbacks = { reset: function reset(isCenter, isZoom) { if (isCenter) { projection.setCenter(null); } if (isZoom) { projection.setZoom(null); } }, beginMove: function beginMove() { projection.beginMoveCenter(); }, endMove: function endMove() { projection.endMoveCenter(); }, move: function move(shift) { projection.moveCenter(shift); }, zoom: function zoom(_zoom) { projection.setScaledZoom(_zoom); } }; }, _createElements: function _createElements(renderer, container, dataKey) { var that = this, buttonsGroups, trackersGroup; that._root = renderer.g().attr({ "class": "dxm-control-bar" }).linkOn(container, "control-bar"); buttonsGroups = that._buttonsGroup = renderer.g().attr({ "class": "dxm-control-buttons" }).append(that._root); trackersGroup = renderer.g().attr({ stroke: "none", "stroke-width": 0, fill: "#000000", opacity: 0.0001 }).css({ cursor: "pointer" }).append(that._root); that._createButtons(renderer, dataKey, buttonsGroups); that._createTrackers(renderer, dataKey, trackersGroup); }, _createButtons: function _createButtons(renderer, dataKey, group) { var that = this, options = SIZE_OPTIONS, size = options.buttonSize / 2, offset1 = options.arrowButtonOffset - size, offset2 = options.arrowButtonOffset, incDecButtonSize = options.incDecButtonSize / 2, directionOptions = { "stroke-linecap": "square", fill: "none" }, line = "line"; renderer.circle(0, 0, options.bigCircleSize / 2).append(group); renderer.circle(0, 0, size).attr({ fill: "none" }).append(group); renderer.path([-size, -offset1, 0, -offset2, size, -offset1], line).attr(directionOptions).append(group); renderer.path([offset1, -size, offset2, 0, offset1, size], line).attr(directionOptions).append(group); renderer.path([size, offset1, 0, offset2, -size, offset1], line).attr(directionOptions).append(group); renderer.path([-offset1, size, -offset2, 0, -offset1, -size], line).attr(directionOptions).append(group); renderer.circle(0, options.incButtonOffset, options.smallCircleSize / 2).append(group); renderer.path([[-incDecButtonSize, options.incButtonOffset, incDecButtonSize, options.incButtonOffset], [0, options.incButtonOffset - incDecButtonSize, 0, options.incButtonOffset + incDecButtonSize]], "area").append(group); renderer.circle(0, options.decButtonOffset, options.smallCircleSize / 2).append(group); renderer.path([-incDecButtonSize, options.decButtonOffset, incDecButtonSize, options.decButtonOffset], "area").append(group); that._zoomLine = renderer.path([], "line").append(group); that._zoomDrag = renderer.rect(_floor(-options.sliderLength / 2), _floor(options.sliderLineEndOffset - options.sliderWidth / 2), options.sliderLength, options.sliderWidth).append(group); that._sliderLineLength = options.sliderLineEndOffset - options.sliderLineStartOffset; }, _createTrackers: function _createTrackers(renderer, dataKey, group) { var options = SIZE_OPTIONS, size = _round((options.arrowButtonOffset - options.trackerGap) / 2), offset1 = options.arrowButtonOffset - size, offset2 = _round(_sqrt(options.bigCircleSize * options.bigCircleSize / 4 - size * size)), size2 = offset2 - offset1; renderer.rect(-size, -size, size * 2, size * 2).data(dataKey, { index: COMMAND_RESET, name: EVENT_TARGET_TYPE }).append(group); renderer.rect(-size, -offset2, size * 2, size2).data(dataKey, { index: COMMAND_MOVE_UP, name: EVENT_TARGET_TYPE }).append(group); renderer.rect(offset1, -size, size2, size * 2).data(dataKey, { index: COMMAND_MOVE_RIGHT, name: EVENT_TARGET_TYPE }).append(group); renderer.rect(-size, offset1, size * 2, size2).data(dataKey, { index: COMMAND_MOVE_DOWN, name: EVENT_TARGET_TYPE }).append(group); renderer.rect(-offset2, -size, size2, size * 2).data(dataKey, { index: COMMAND_MOVE_LEFT, name: EVENT_TARGET_TYPE }).append(group); renderer.circle(0, options.incButtonOffset, options.smallCircleSize / 2).data(dataKey, { index: COMMAND_ZOOM_IN, name: EVENT_TARGET_TYPE }).append(group); renderer.circle(0, options.decButtonOffset, options.smallCircleSize / 2).data(dataKey, { index: COMMAND_ZOOM_OUT, name: EVENT_TARGET_TYPE }).append(group); renderer.rect(-2, options.sliderLineStartOffset - 2, 4, options.sliderLineEndOffset - options.sliderLineStartOffset + 4).css({ cursor: "default" }).data(dataKey, { index: COMMAND_ZOOM_DRAG_LINE, name: EVENT_TARGET_TYPE }).append(group); this._zoomDragTracker = renderer.rect(-options.sliderLength / 2, options.sliderLineEndOffset - options.sliderWidth / 2, options.sliderLength, options.sliderWidth).data(dataKey, { index: COMMAND_ZOOM_DRAG, name: EVENT_TARGET_TYPE }).append(group); }, // BEGIN: Implementation of LayoutTarget interface resize: function resize(size) { if (this._isActive) { this._root.attr({ visibility: size !== null ? null : "hidden" }); } }, getLayoutOptions: function getLayoutOptions() { return this._isActive ? this._layoutOptions : null; }, locate: function locate(x, y) { this._root.attr({ translateX: x + this._margin + OFFSET_X, translateY: y + this._margin + OFFSET_Y }); }, // END: Implementation of LayoutTarget interface _update: function _update() { var that = this; that._isActive = that._isEnabled && that._flags && that._params.projection.isInvertible(); if (that._isActive) { that._root.linkAppend(); } else { that._root.linkRemove(); } that._processEnd(); that.updateLayout(); }, setInteraction: function setInteraction(interaction) { var that = this; if (_parseScalar(interaction.centeringEnabled, true)) { that._flags |= FLAG_CENTERING; } else { that._flags &= ~FLAG_CENTERING; } if (_parseScalar(interaction.zoomingEnabled, true)) { that._flags |= FLAG_ZOOMING; } else { that._flags &= ~FLAG_ZOOMING; } that._update(); }, setOptions: function setOptions(options) { var that = this; that._isEnabled = !!_parseScalar(options.enabled, true); that._margin = options.margin || 0; that._layoutOptions = { width: 2 * that._margin + TOTAL_WIDTH, height: 2 * that._margin + TOTAL_HEIGHT, horizontalAlignment: parseHorizontalAlignment(options.horizontalAlignment, "left"), verticalAlignment: parseVerticalAlignment(options.verticalAlignment, "top") }; that._buttonsGroup.attr({ "stroke-width": options.borderWidth, stroke: options.borderColor, fill: options.color, "fill-opacity": options.opacity }); that._update(); }, _adjustZoom: function _adjustZoom(zoom) { var that = this, transform, y, start = SIZE_OPTIONS.sliderLineStartOffset, end = SIZE_OPTIONS.sliderLineEndOffset, h = SIZE_OPTIONS.sliderWidth; that._zoomFactor = _max(_min(_round(zoom), that._zoomPartition), 0); transform = { translateY: -_round(that._zoomFactor * that._sliderUnitLength) }; y = end - h / 2 + transform.translateY; that._zoomLine.attr({ points: [[0, start, 0, _max(start, y)], [0, _min(end, y + h), 0, end]] }); that._zoomDrag.attr(transform); that._zoomDragTracker.attr(transform); }, _applyZoom: function _applyZoom() { this._callbacks.zoom(this._zoomFactor); }, _processStart: function _processStart(command, arg) { var commandType; if (this._isActive) { commandType = COMMAND_TO_TYPE_MAP[command]; this._command = commandType && commandType.flags & this._flags ? new commandType(this, command, arg) : null; } }, _processMove: function _processMove(command, arg) { this._command && this._command.update(command, arg); }, _processEnd: function _processEnd() { this._command && this._command.finish(); this._command = null; } }; function disposeCommand(command) { delete command._owner; command.update = function () {}; command.finish = function () {}; } function ResetCommand(owner, command) { this._owner = owner; this._command = command; } ResetCommand.flags = FLAG_CENTERING | FLAG_ZOOMING; ResetCommand.prototype.update = function (command) { command !== this._command && disposeCommand(this); }; ResetCommand.prototype.finish = function () { var flags = this._owner._flags; this._owner._callbacks.reset(!!(flags & FLAG_CENTERING), !!(flags & FLAG_ZOOMING)); disposeCommand(this); }; function MoveCommand(owner, command, arg) { this._command = command; var timeout = null, interval = 100, dx = 0, dy = 0; switch (this._command) { case COMMAND_MOVE_UP: dy = -10;break; case COMMAND_MOVE_RIGHT: dx = 10;break; case COMMAND_MOVE_DOWN: dy = 10;break; case COMMAND_MOVE_LEFT: dx = -10;break; } function callback() { owner._callbacks.move([dx, dy]); timeout = setTimeout(callback, interval); } this._stop = function () { clearTimeout(timeout); owner._callbacks.endMove(); this._stop = owner = null; return this; }; arg = null; owner._callbacks.beginMove(); callback(); } MoveCommand.flags = FLAG_CENTERING; MoveCommand.prototype.update = function (command) { this._command !== command && this.finish(); }; MoveCommand.prototype.finish = function () { disposeCommand(this._stop()); }; function ZoomCommand(owner, command) { this._owner = owner; this._command = command; var timeout = null, interval = 150, dZoom = this._command === COMMAND_ZOOM_IN ? 1 : -1; function callback() { owner._adjustZoom(owner._zoomFactor + dZoom); timeout = setTimeout(callback, interval); } this._stop = function () { clearTimeout(timeout); this._stop = owner = null; return this; }; callback(); } ZoomCommand.flags = FLAG_ZOOMING; ZoomCommand.prototype.update = function (command) { this._command !== command && this.finish(); }; ZoomCommand.prototype.finish = function () { this._owner._applyZoom(); disposeCommand(this._stop()); }; function ZoomDragCommand(owner, command, arg) { this._owner = owner; this._zoomFactor = owner._zoomFactor; this._pos = arg.y; } ZoomDragCommand.flags = FLAG_ZOOMING; ZoomDragCommand.prototype.update = function (command, arg) { var owner = this._owner; owner._adjustZoom(this._zoomFactor + owner._zoomPartition * (this._pos - arg.y) / owner._sliderLineLength); }; ZoomDragCommand.prototype.finish = function () { this._owner._applyZoom(); disposeCommand(this); }; exports.ControlBar = ControlBar; ///#DEBUG var COMMAND_TO_TYPE_MAP__ORIGINAL = COMMAND_TO_TYPE_MAP; exports._TESTS_stubCommandToTypeMap = function (map) { COMMAND_TO_TYPE_MAP = map; }; exports._TESTS_restoreCommandToTypeMap = function () { COMMAND_TO_TYPE_MAP = COMMAND_TO_TYPE_MAP__ORIGINAL; }; ///#ENDDEBUG