537 lines
16 KiB
Java
537 lines
16 KiB
Java
function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
|
|
|
|
function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
|
|
|
|
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
|
|
|
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
|
|
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
|
|
|
|
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
|
|
|
|
/**
|
|
* @fileOverview The base class of continuous legend
|
|
* @author sima.zhang
|
|
*/
|
|
var Util = require('../util');
|
|
|
|
var Legend = require('./base');
|
|
|
|
var Slider = require('./slider');
|
|
|
|
var _require = require('../const'),
|
|
FONT_FAMILY = _require.FONT_FAMILY;
|
|
|
|
var TRIGGER_WIDTH = 8;
|
|
var Event = Util.Event;
|
|
var Group = Util.Group;
|
|
|
|
var Continuous = /*#__PURE__*/function (_Legend) {
|
|
_inheritsLoose(Continuous, _Legend);
|
|
|
|
var _super = _createSuper(Continuous);
|
|
|
|
function Continuous() {
|
|
return _Legend.apply(this, arguments) || this;
|
|
}
|
|
|
|
var _proto = Continuous.prototype;
|
|
|
|
_proto.getDefaultCfg = function getDefaultCfg() {
|
|
var cfg = _Legend.prototype.getDefaultCfg.call(this);
|
|
|
|
return Util.mix({}, cfg, {
|
|
/**
|
|
* 类型
|
|
* @type {String}
|
|
*/
|
|
type: 'continuous-legend',
|
|
|
|
/**
|
|
* 子项
|
|
* @type {Array}
|
|
*/
|
|
items: null,
|
|
|
|
/**
|
|
* 布局方式
|
|
* horizontal 水平
|
|
* vertical 垂直
|
|
* @type {String}
|
|
*/
|
|
layout: 'vertical',
|
|
|
|
/**
|
|
* 宽度
|
|
* @type {Number}
|
|
*/
|
|
width: 20,
|
|
|
|
/**
|
|
* 高度
|
|
* @type {Number}
|
|
*/
|
|
height: 156,
|
|
|
|
/**
|
|
* 默认文本图形属性
|
|
* @type {ATTRS}
|
|
*/
|
|
textStyle: {
|
|
fill: '#333',
|
|
textAlign: 'center',
|
|
textBaseline: 'middle',
|
|
stroke: '#fff',
|
|
lineWidth: 5,
|
|
fontFamily: FONT_FAMILY
|
|
},
|
|
hoverTextStyle: {
|
|
fill: 'rgba(0,0,0,0.25)'
|
|
},
|
|
|
|
/**
|
|
* 连续图例是否可滑动
|
|
* @type {Boolean}
|
|
*/
|
|
slidable: true,
|
|
|
|
/**
|
|
* 两头滑块的样式
|
|
* @type {object}
|
|
*/
|
|
triggerAttr: {
|
|
fill: '#fff',
|
|
// shadowOffsetX: -2,
|
|
// shadowOffsetY: 2,
|
|
shadowBlur: 10,
|
|
shadowColor: 'rgba(0,0,0,0.65)',
|
|
radius: 2
|
|
},
|
|
|
|
/**
|
|
* slider 的范围
|
|
* @type {array}}
|
|
*/
|
|
_range: [0, 100],
|
|
|
|
/**
|
|
* 中间 bar 背景灰色
|
|
* @type {ATTRS}
|
|
*/
|
|
middleBackgroundStyle: {
|
|
fill: '#D9D9D9'
|
|
},
|
|
|
|
/**
|
|
* 文本与图例间距
|
|
* @type {Number}
|
|
*/
|
|
textOffset: 4,
|
|
|
|
/**
|
|
* line segment to seperate the unslidable slider blocks
|
|
* @type {object}
|
|
*/
|
|
lineStyle: {
|
|
lineWidth: 1,
|
|
stroke: '#fff'
|
|
},
|
|
|
|
/**
|
|
* the pointer while activate the legend by mouse hovering or called by outside
|
|
* @type {object}
|
|
*/
|
|
pointerStyle: {
|
|
// color: '#ccc',
|
|
fill: 'rgb(230, 230, 230)'
|
|
}
|
|
});
|
|
};
|
|
|
|
_proto._calStartPoint = function _calStartPoint() {
|
|
var start = {
|
|
x: 10,
|
|
y: this.get('titleGap') - TRIGGER_WIDTH
|
|
};
|
|
var titleShape = this.get('titleShape');
|
|
|
|
if (titleShape) {
|
|
var titleBox = titleShape.getBBox();
|
|
start.y += titleBox.height;
|
|
}
|
|
|
|
return start;
|
|
};
|
|
|
|
_proto.beforeRender = function beforeRender() {
|
|
var items = this.get('items');
|
|
|
|
if (!Util.isArray(items) || Util.isEmpty(items)) {
|
|
return;
|
|
}
|
|
|
|
_Legend.prototype.beforeRender.call(this);
|
|
|
|
this.set('firstItem', items[0]);
|
|
this.set('lastItem', items[items.length - 1]);
|
|
};
|
|
|
|
_proto._formatItemValue = function _formatItemValue(value) {
|
|
var formatter = this.get('formatter') || this.get('itemFormatter');
|
|
|
|
if (formatter) {
|
|
value = formatter.call(this, value);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
_proto.render = function render() {
|
|
_Legend.prototype.render.call(this);
|
|
|
|
if (this.get('slidable')) {
|
|
this._renderSlider();
|
|
} else {
|
|
this._renderUnslidable();
|
|
}
|
|
};
|
|
|
|
_proto._renderSlider = function _renderSlider() {
|
|
var minHandleElement = new Group();
|
|
var maxHandleElement = new Group();
|
|
var backgroundElement = new Group();
|
|
|
|
var start = this._calStartPoint();
|
|
|
|
var group = this.get('group');
|
|
var slider = group.addGroup(Slider, {
|
|
minHandleElement: minHandleElement,
|
|
maxHandleElement: maxHandleElement,
|
|
backgroundElement: backgroundElement,
|
|
layout: this.get('layout'),
|
|
range: this.get('_range'),
|
|
width: this.get('width'),
|
|
height: this.get('height')
|
|
});
|
|
slider.translate(start.x, start.y);
|
|
this.set('slider', slider);
|
|
|
|
var shape = this._renderSliderShape();
|
|
|
|
shape.attr('clip', slider.get('middleHandleElement'));
|
|
|
|
this._renderTrigger();
|
|
} // the middle bar
|
|
;
|
|
|
|
_proto._addMiddleBar = function _addMiddleBar(parent, name, attrs) {
|
|
// background of the middle bar
|
|
parent.addShape(name, {
|
|
attrs: Util.mix({}, attrs, this.get('middleBackgroundStyle'))
|
|
}); // frontground of the middle bar
|
|
|
|
return parent.addShape(name, {
|
|
attrs: attrs
|
|
});
|
|
};
|
|
|
|
_proto._renderTrigger = function _renderTrigger() {
|
|
var min = this.get('firstItem');
|
|
var max = this.get('lastItem');
|
|
var layout = this.get('layout');
|
|
var textStyle = this.get('textStyle');
|
|
var triggerAttr = this.get('triggerAttr');
|
|
var minBlockAttr = Util.mix({}, triggerAttr);
|
|
var maxBlockAttr = Util.mix({}, triggerAttr);
|
|
var minTextAttr = Util.mix({
|
|
text: this._formatItemValue(min.value) + ''
|
|
}, textStyle);
|
|
var maxTextAttr = Util.mix({
|
|
text: this._formatItemValue(max.value) + ''
|
|
}, textStyle);
|
|
|
|
if (layout === 'vertical') {
|
|
this._addVerticalTrigger('min', minBlockAttr, minTextAttr);
|
|
|
|
this._addVerticalTrigger('max', maxBlockAttr, maxTextAttr);
|
|
} else {
|
|
this._addHorizontalTrigger('min', minBlockAttr, minTextAttr);
|
|
|
|
this._addHorizontalTrigger('max', maxBlockAttr, maxTextAttr);
|
|
}
|
|
};
|
|
|
|
_proto._addVerticalTrigger = function _addVerticalTrigger(type, blockAttr, textAttr) {
|
|
var slider = this.get('slider');
|
|
var trigger = slider.get(type + 'HandleElement');
|
|
var width = this.get('width');
|
|
var button = trigger.addShape('rect', {
|
|
attrs: Util.mix({
|
|
x: width / 2 - TRIGGER_WIDTH - 2,
|
|
y: type === 'min' ? 0 : -TRIGGER_WIDTH,
|
|
width: 2 * TRIGGER_WIDTH + 2,
|
|
height: TRIGGER_WIDTH
|
|
}, blockAttr)
|
|
});
|
|
var text = trigger.addShape('text', {
|
|
attrs: Util.mix(textAttr, {
|
|
x: width + this.get('textOffset'),
|
|
y: type === 'max' ? -4 : 4,
|
|
textAlign: 'start',
|
|
lineHeight: 1,
|
|
textBaseline: 'middle'
|
|
})
|
|
});
|
|
var layout = this.get('layout');
|
|
var trigerCursor = layout === 'vertical' ? 'ns-resize' : 'ew-resize';
|
|
button.attr('cursor', trigerCursor);
|
|
text.attr('cursor', trigerCursor);
|
|
this.set(type + 'ButtonElement', button);
|
|
this.set(type + 'TextElement', text);
|
|
};
|
|
|
|
_proto._addHorizontalTrigger = function _addHorizontalTrigger(type, blockAttr, textAttr) {
|
|
var slider = this.get('slider');
|
|
var trigger = slider.get(type + 'HandleElement');
|
|
var button = trigger.addShape('rect', {
|
|
attrs: Util.mix({
|
|
x: type === 'min' ? -TRIGGER_WIDTH : 0,
|
|
y: -TRIGGER_WIDTH - this.get('height') / 2,
|
|
width: TRIGGER_WIDTH,
|
|
height: 2 * TRIGGER_WIDTH
|
|
}, blockAttr)
|
|
});
|
|
var text = trigger.addShape('text', {
|
|
attrs: Util.mix(textAttr, {
|
|
x: type === 'min' ? -TRIGGER_WIDTH - 4 : TRIGGER_WIDTH + 4,
|
|
y: TRIGGER_WIDTH / 2 + this.get('textOffset') + 10,
|
|
textAlign: type === 'min' ? 'end' : 'start',
|
|
textBaseline: 'middle'
|
|
})
|
|
});
|
|
var layout = this.get('layout');
|
|
var trigerCursor = layout === 'vertical' ? 'ns-resize' : 'ew-resize';
|
|
button.attr('cursor', trigerCursor);
|
|
text.attr('cursor', trigerCursor);
|
|
this.set(type + 'ButtonElement', button);
|
|
this.set(type + 'TextElement', text);
|
|
};
|
|
|
|
_proto._bindEvents = function _bindEvents() {
|
|
var _this = this;
|
|
|
|
if (this.get('slidable')) {
|
|
var slider = this.get('slider');
|
|
slider.on('sliderchange', function (ev) {
|
|
var range = ev.range;
|
|
|
|
var firstItemValue = _this.get('firstItem').value;
|
|
|
|
var lastItemValue = _this.get('lastItem').value;
|
|
|
|
var minValue = firstItemValue + range[0] / 100 * (lastItemValue - firstItemValue);
|
|
var maxValue = firstItemValue + range[1] / 100 * (lastItemValue - firstItemValue);
|
|
|
|
_this._updateElement(minValue, maxValue);
|
|
|
|
var itemFiltered = new Event('itemfilter', ev, true, true);
|
|
itemFiltered.range = [minValue, maxValue];
|
|
|
|
_this.emit('itemfilter', itemFiltered);
|
|
});
|
|
}
|
|
|
|
if (this.get('hoverable')) {
|
|
this.get('group').on('mousemove', Util.wrapBehavior(this, '_onMouseMove'));
|
|
this.get('group').on('mouseleave', Util.wrapBehavior(this, '_onMouseLeave'));
|
|
}
|
|
} // update the text of min and max trigger
|
|
;
|
|
|
|
_proto._updateElement = function _updateElement(min, max) {
|
|
var minTextElement = this.get('minTextElement');
|
|
var maxTextElement = this.get('maxTextElement');
|
|
|
|
if (max > 1) {
|
|
// 对于大于 1 的值,默认显示为整数
|
|
min = parseInt(min, 10);
|
|
max = parseInt(max, 10);
|
|
}
|
|
|
|
minTextElement.attr('text', this._formatItemValue(min) + '');
|
|
maxTextElement.attr('text', this._formatItemValue(max) + '');
|
|
};
|
|
|
|
_proto._onMouseLeave = function _onMouseLeave() {
|
|
var hoverPointer = this.get('group').findById('hoverPointer');
|
|
hoverPointer && hoverPointer.destroy();
|
|
var hoverText = this.get('group').findById('hoverText');
|
|
hoverText && hoverText.destroy();
|
|
this.get('canvas').draw();
|
|
} // activate the legend while mouse moving
|
|
;
|
|
|
|
_proto._onMouseMove = function _onMouseMove(ev) {
|
|
var height = this.get('height');
|
|
var width = this.get('width');
|
|
var items = this.get('items');
|
|
var el = this.get('canvas').get('el');
|
|
var el_bbox = el.getBoundingClientRect();
|
|
var bbox = this.get('group').getBBox();
|
|
var value;
|
|
|
|
if (this.get('layout') === 'vertical') {
|
|
var valuePadding = 5;
|
|
|
|
if (this.get('type') === 'color-legend') {
|
|
valuePadding = 30;
|
|
}
|
|
|
|
var titleOffset = this.get('titleGap');
|
|
var titleShape = this.get('titleShape');
|
|
if (titleShape) titleOffset += titleShape.getBBox().maxY - titleShape.getBBox().minY;
|
|
var currentPage = ev.clientY || ev.event.clientY;
|
|
currentPage = currentPage - el_bbox.y - this.get('group').attr('matrix')[7] + bbox.y - valuePadding + titleOffset;
|
|
value = items[0].value + (1 - currentPage / height) * (items[items.length - 1].value - items[0].value);
|
|
} else {
|
|
var _currentPage = ev.clientX || ev.event.clientX;
|
|
|
|
_currentPage = _currentPage - el_bbox.x - this.get('group').attr('matrix')[6];
|
|
value = items[0].value + _currentPage / width * (items[items.length - 1].value - items[0].value);
|
|
}
|
|
|
|
value = value.toFixed(2);
|
|
this.activate(value);
|
|
this.emit('mousehover', {
|
|
value: value
|
|
});
|
|
} // activated by mouse moving or being called
|
|
;
|
|
|
|
_proto.activate = function activate(value) {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
|
|
var hoverPointer = this.get('group').findById('hoverPointer');
|
|
var hoverText = this.get('group').findById('hoverText');
|
|
var items = this.get('items');
|
|
|
|
if (value < items[0].value || value > items[items.length - 1].value) {
|
|
return;
|
|
}
|
|
|
|
var height = this.get('height');
|
|
var width = this.get('width');
|
|
var titleShape = this.get('titleShape');
|
|
var titleGap = this.get('titleGap');
|
|
var points = [];
|
|
var page = (value - items[0].value) / (items[items.length - 1].value - items[0].value);
|
|
var textStyle;
|
|
|
|
if (this.get('layout') === 'vertical') {
|
|
// revise the offset
|
|
var paddingY = 0,
|
|
paddingX = 0;
|
|
|
|
if (this.get('type') === 'color-legend') {
|
|
paddingY = titleGap;
|
|
if (titleShape) paddingY += titleShape.getBBox().height;
|
|
}
|
|
|
|
if (this.get('slidable')) {
|
|
if (this.get('type') === 'color-legend') {
|
|
paddingY -= 13;
|
|
} else {
|
|
paddingY = titleGap - 15;
|
|
if (titleShape) paddingY += titleShape.getBBox().height;
|
|
}
|
|
|
|
paddingX += 10;
|
|
}
|
|
|
|
page = (1 - page) * height;
|
|
points = [[paddingX, page + paddingY], [paddingX - 10, page + paddingY - 5], [paddingX - 10, page + paddingY + 5]];
|
|
textStyle = Util.mix({}, {
|
|
x: width + this.get('textOffset') / 2 + paddingX,
|
|
y: page + paddingY,
|
|
text: this._formatItemValue(value) + '' // 以字符串格式展示
|
|
|
|
}, this.get('textStyle'), {
|
|
textAlign: 'start'
|
|
});
|
|
} else {
|
|
var _paddingY = 0,
|
|
_paddingX = 0;
|
|
|
|
if (this.get('type') === 'color-legend') {
|
|
_paddingY = titleGap;
|
|
if (titleShape) _paddingY += titleShape.getBBox().height;
|
|
}
|
|
|
|
if (this.get('slidable')) {
|
|
if (this.get('type') === 'color-legend') {
|
|
// hoverPointer三角形的高
|
|
_paddingY -= 7;
|
|
} else {
|
|
_paddingY = titleGap;
|
|
if (!titleShape) _paddingY -= 7;
|
|
}
|
|
|
|
_paddingX += 10;
|
|
}
|
|
|
|
page *= width;
|
|
points = [[page + _paddingX, _paddingY], [page + _paddingX - 5, _paddingY - 10], [page + _paddingX + 5, _paddingY - 10]];
|
|
textStyle = Util.mix({}, {
|
|
x: page - 5,
|
|
y: height + this.get('textOffset') + _paddingY,
|
|
text: this._formatItemValue(value) + '' // 以字符串格式展示
|
|
|
|
}, this.get('textStyle'));
|
|
}
|
|
|
|
var hoverTextStyle = Util.mix(textStyle, this.get('hoverTextStyle'));
|
|
|
|
if (!hoverText) {
|
|
// mouse enter the legend, add hoverText
|
|
hoverText = this.get('group').addShape('text', {
|
|
attrs: hoverTextStyle
|
|
});
|
|
hoverText.set('id', 'hoverText');
|
|
} else {
|
|
// mouse move, update hoverText
|
|
hoverText.attr(hoverTextStyle);
|
|
}
|
|
|
|
if (!hoverPointer) {
|
|
// mouse enter the legend, add hoverPointer
|
|
hoverPointer = this.get('group').addShape('Polygon', {
|
|
attrs: Util.mix({
|
|
points: points
|
|
}, this.get('pointerStyle'))
|
|
});
|
|
hoverPointer.set('id', 'hoverPointer');
|
|
} else {
|
|
// mouse move, update hoverPointer
|
|
hoverPointer.attr(Util.mix({
|
|
points: points
|
|
}, this.get('pointerStyle')));
|
|
}
|
|
|
|
this.get('canvas').draw();
|
|
};
|
|
|
|
_proto.deactivate = function deactivate() {
|
|
var hoverPointer = this.get('group').findById('hoverPointer');
|
|
hoverPointer && hoverPointer.destroy();
|
|
var hoverText = this.get('group').findById('hoverText');
|
|
hoverText && hoverText.destroy();
|
|
this.get('canvas').draw();
|
|
};
|
|
|
|
return Continuous;
|
|
}(Legend);
|
|
|
|
module.exports = Continuous; |