- Go backend (server/)
- Frontend (web/, server/static/)
- Database and deployment files
- Scripts and docs
Co-Authored-By: 狸花猫/Claude-Qwen3.6-Plus 🐾
454 lines
15 KiB
JavaScript
454 lines
15 KiB
JavaScript
var __assign = this && this.__assign || function () {
|
||
__assign = Object.assign || function (t) {
|
||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||
s = arguments[i];
|
||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||
}
|
||
return t;
|
||
};
|
||
return __assign.apply(this, arguments);
|
||
};
|
||
/**
|
||
* 基于 G 的刻度时间轴组件
|
||
*/
|
||
import { ext } from '@antv/matrix-util';
|
||
import { isNumber, isString } from '@antv/util';
|
||
import TimeBarTooltip from './timeBarTooltip';
|
||
import ControllerBtn from './controllerBtn';
|
||
import { VALUE_CHANGE, TIMELINE_START, TIMELINE_END, PLAY_PAUSE_BTN, NEXT_STEP_BTN, PRE_STEP_BTN, TIMEBAR_CONFIG_CHANGE } from './constant';
|
||
var transform = ext.transform;
|
||
var DEFAULT_SELECTEDTICK_STYLE = {
|
||
fill: '#5B8FF9'
|
||
};
|
||
var DEFAULT_UNSELECTEDTICK_STYLE = {
|
||
fill: '#e6e8e9'
|
||
};
|
||
var TimeBarSlice = /** @class */function () {
|
||
function TimeBarSlice(cfgs) {
|
||
this.frameCount = 0;
|
||
this.fontFamily = 'Arial, sans-serif';
|
||
var graph = cfgs.graph,
|
||
canvas = cfgs.canvas,
|
||
group = cfgs.group,
|
||
width = cfgs.width,
|
||
height = cfgs.height,
|
||
padding = cfgs.padding,
|
||
data = cfgs.data,
|
||
start = cfgs.start,
|
||
end = cfgs.end,
|
||
_a = cfgs.x,
|
||
x = _a === void 0 ? 0 : _a,
|
||
_b = cfgs.y,
|
||
y = _b === void 0 ? 0 : _b,
|
||
tickLabelFormatter = cfgs.tickLabelFormatter,
|
||
_c = cfgs.selectedTickStyle,
|
||
selectedTickStyle = _c === void 0 ? DEFAULT_SELECTEDTICK_STYLE : _c,
|
||
_d = cfgs.unselectedTickStyle,
|
||
unselectedTickStyle = _d === void 0 ? DEFAULT_UNSELECTEDTICK_STYLE : _d,
|
||
tooltipBackgroundColor = cfgs.tooltipBackgroundColor,
|
||
tooltipFomatter = cfgs.tooltipFomatter,
|
||
tickLabelStyle = cfgs.tickLabelStyle,
|
||
_e = cfgs.controllerCfg,
|
||
controllerCfg = _e === void 0 ? {
|
||
speed: 1
|
||
} : _e;
|
||
this.graph = graph;
|
||
this.group = group;
|
||
this.sliceGroup = group.addGroup({
|
||
name: 'slice-group'
|
||
});
|
||
this.canvas = canvas;
|
||
this.width = width;
|
||
this.height = height;
|
||
this.padding = padding;
|
||
this.data = data;
|
||
this.start = start;
|
||
this.end = end;
|
||
this.tickLabelFormatter = tickLabelFormatter;
|
||
this.tickLabelStyle = tickLabelStyle || {};
|
||
this.selectedTickStyle = selectedTickStyle;
|
||
this.unselectedTickStyle = unselectedTickStyle;
|
||
this.controllerCfg = controllerCfg;
|
||
this.currentSpeed = controllerCfg.speed || 1;
|
||
this.x = x;
|
||
this.y = y;
|
||
this.tooltipBackgroundColor = tooltipBackgroundColor;
|
||
this.tooltipFomatter = tooltipFomatter;
|
||
// 初始化 fontFamily,如果有浏览器,取 body 上的字体,防止文字更新时局部渲染造成的重影
|
||
this.fontFamily = typeof window !== 'undefined' ? window.getComputedStyle(document.body, null).getPropertyValue('font-family') || 'Arial, sans-serif' : 'Arial, sans-serif';
|
||
this.renderSlices();
|
||
this.initEvent();
|
||
}
|
||
TimeBarSlice.prototype.renderSlices = function () {
|
||
var _this = this;
|
||
var _a = this,
|
||
width = _a.width,
|
||
height = _a.height,
|
||
padding = _a.padding,
|
||
data = _a.data,
|
||
start = _a.start,
|
||
end = _a.end,
|
||
tickLabelFormatter = _a.tickLabelFormatter,
|
||
selectedTickStyle = _a.selectedTickStyle,
|
||
unselectedTickStyle = _a.unselectedTickStyle,
|
||
tickLabelStyle = _a.tickLabelStyle;
|
||
var realWidth = width - 2 * padding;
|
||
var fontSize = 10;
|
||
var labelLineHeight = 4;
|
||
var labelAreaHeight = 3 * padding + labelLineHeight + fontSize;
|
||
var ticksAreaHeight = height - labelAreaHeight - 2 * padding;
|
||
var gap = 2;
|
||
var ticksLength = data.length;
|
||
var tickWidth = (realWidth - gap * (ticksLength - 1)) / ticksLength;
|
||
this.tickWidth = tickWidth;
|
||
var sliceGroup = this.sliceGroup;
|
||
var tickRects = [];
|
||
var labels = [];
|
||
var startTickId = Math.round(ticksLength * start);
|
||
var endTickId = Math.round(ticksLength * end);
|
||
this.startTickRectId = startTickId;
|
||
this.endTickRectId = endTickId;
|
||
var rotate = tickLabelStyle.rotate;
|
||
delete tickLabelStyle.rotate;
|
||
data.forEach(function (d, i) {
|
||
// draw the tick rects
|
||
var selected = i >= startTickId && i <= endTickId;
|
||
var tickStyle = selected ? selectedTickStyle : unselectedTickStyle;
|
||
var rect = sliceGroup.addShape('rect', {
|
||
attrs: __assign({
|
||
x: padding + i * (tickWidth + gap),
|
||
y: padding,
|
||
width: tickWidth,
|
||
height: ticksAreaHeight
|
||
}, tickStyle),
|
||
draggable: true,
|
||
name: "tick-rect-".concat(i)
|
||
});
|
||
// draw the pick tick rects
|
||
var pickRect = sliceGroup.addShape('rect', {
|
||
attrs: {
|
||
x: padding + i * tickWidth + gap * (2 * i - 1) / 2,
|
||
y: padding,
|
||
width: i === 0 || i === ticksLength - 1 ? tickWidth + gap / 2 : tickWidth + gap,
|
||
height: ticksAreaHeight,
|
||
fill: '#fff',
|
||
opacity: 0
|
||
},
|
||
draggable: true,
|
||
name: "pick-rect-".concat(i)
|
||
});
|
||
pickRect.toFront();
|
||
var rectBBox = rect.getBBox();
|
||
var centerX = (rectBBox.minX + rectBBox.maxX) / 2;
|
||
tickRects.push({
|
||
rect: rect,
|
||
pickRect: pickRect,
|
||
value: d.date,
|
||
x: centerX,
|
||
y: rectBBox.minY
|
||
});
|
||
var label;
|
||
if (tickLabelFormatter) {
|
||
label = tickLabelFormatter(d);
|
||
if (!isString(label) && label) {
|
||
// return true
|
||
label = d.date;
|
||
}
|
||
} else if (i % Math.round(ticksLength / 10) === 0) {
|
||
label = d.date;
|
||
}
|
||
if (label) {
|
||
labels.push(label);
|
||
// draw tick lines
|
||
var lineStartY = rectBBox.maxY + padding * 2;
|
||
sliceGroup.addShape('line', {
|
||
attrs: {
|
||
stroke: '#BFBFBF',
|
||
x1: centerX,
|
||
y1: lineStartY,
|
||
x2: centerX,
|
||
y2: lineStartY + labelLineHeight
|
||
},
|
||
name: 'tick-line'
|
||
});
|
||
var labelStartY = lineStartY + labelLineHeight + padding;
|
||
var text = sliceGroup.addShape('text', {
|
||
attrs: __assign({
|
||
fill: '#8c8c8c',
|
||
stroke: '#fff',
|
||
lineWidth: 1,
|
||
x: centerX,
|
||
y: labelStartY,
|
||
textAlign: 'center',
|
||
text: label,
|
||
textBaseline: 'top',
|
||
fontSize: 10,
|
||
fontFamily: _this.fontFamily || 'Arial, sans-serif'
|
||
}, tickLabelStyle),
|
||
capture: false,
|
||
name: 'tick-label'
|
||
});
|
||
var textBBox = text.getBBox();
|
||
if (textBBox.maxX > width) {
|
||
text.attr('textAlign', 'right');
|
||
} else if (textBBox.minX < 0) {
|
||
text.attr('textAlign', 'left');
|
||
}
|
||
if (isNumber(rotate) && labels.length !== 10) {
|
||
var matrix = transform([1, 0, 0, 0, 1, 0, 0, 0, 1], [['t', -centerX, -labelStartY], ['r', rotate], ['t', centerX - 5, labelStartY + 2]]);
|
||
text.attr({
|
||
textAlign: 'left',
|
||
matrix: matrix
|
||
});
|
||
}
|
||
if (labels.length === 1) {
|
||
text.attr({
|
||
textAlign: 'left'
|
||
});
|
||
} else if (labels.length === 10) {
|
||
text.attr({
|
||
textAlign: 'right'
|
||
});
|
||
}
|
||
// draw tick labels
|
||
}
|
||
});
|
||
this.tickRects = tickRects;
|
||
// 渲染播放、快进和后退的控制按钮
|
||
var group = this.group;
|
||
this.currentSpeed = 1;
|
||
this.controllerBtnGroup = new ControllerBtn(__assign({
|
||
group: group,
|
||
x: this.x,
|
||
y: this.y + height + 5,
|
||
width: width,
|
||
height: 40,
|
||
hideTimeTypeController: true,
|
||
speed: this.currentSpeed,
|
||
fontFamily: this.fontFamily || 'Arial, sans-serif'
|
||
}, this.controllerCfg));
|
||
};
|
||
TimeBarSlice.prototype.initEvent = function () {
|
||
var _this = this;
|
||
var sliceGroup = this.sliceGroup;
|
||
sliceGroup.on('click', function (e) {
|
||
var targetRect = e.target;
|
||
if (targetRect.get('type') !== 'rect' || !targetRect.get('name')) return;
|
||
var id = parseInt(targetRect.get('name').split('-')[2], 10);
|
||
if (!isNaN(id)) {
|
||
var tickRects_1 = _this.tickRects;
|
||
// cancel the selected ticks
|
||
var unselectedTickStyle_1 = _this.unselectedTickStyle;
|
||
tickRects_1.forEach(function (tickRect) {
|
||
tickRect.rect.attr(unselectedTickStyle_1);
|
||
});
|
||
var selectedTickStyle = _this.selectedTickStyle;
|
||
tickRects_1[id].rect.attr(selectedTickStyle);
|
||
_this.startTickRectId = id;
|
||
_this.endTickRectId = id;
|
||
var ticksLength = tickRects_1.length;
|
||
var start = id / ticksLength;
|
||
_this.graph.emit(VALUE_CHANGE, {
|
||
value: [start, start]
|
||
});
|
||
}
|
||
});
|
||
sliceGroup.on('dragstart', function (e) {
|
||
var tickRects = _this.tickRects;
|
||
// cancel the selected ticks
|
||
var unselectedTickStyle = _this.unselectedTickStyle;
|
||
tickRects.forEach(function (tickRect) {
|
||
tickRect.rect.attr(unselectedTickStyle);
|
||
});
|
||
var targetRect = e.target;
|
||
var id = parseInt(targetRect.get('name').split('-')[2], 10);
|
||
var selectedTickStyle = _this.selectedTickStyle;
|
||
tickRects[id].rect.attr(selectedTickStyle);
|
||
_this.startTickRectId = id;
|
||
var ticksLength = tickRects.length;
|
||
var start = id / ticksLength;
|
||
_this.graph.emit(VALUE_CHANGE, {
|
||
value: [start, start]
|
||
});
|
||
_this.dragging = true;
|
||
});
|
||
sliceGroup.on('dragover', function (e) {
|
||
if (!_this.dragging) return;
|
||
if (e.target.get('type') !== 'rect') return;
|
||
var id = parseInt(e.target.get('name').split('-')[2], 10);
|
||
var startTickRectId = _this.startTickRectId;
|
||
var tickRects = _this.tickRects;
|
||
var selectedTickStyle = _this.selectedTickStyle;
|
||
var unselectedTickStyle = _this.unselectedTickStyle;
|
||
for (var i = 0; i < tickRects.length; i++) {
|
||
var style = i >= startTickRectId && i <= id ? selectedTickStyle : unselectedTickStyle;
|
||
tickRects[i].rect.attr(style);
|
||
}
|
||
var ticksLength = tickRects.length;
|
||
_this.endTickRectId = id;
|
||
var start = startTickRectId / ticksLength;
|
||
var end = id / ticksLength;
|
||
_this.graph.emit(VALUE_CHANGE, {
|
||
value: [start, end]
|
||
});
|
||
});
|
||
sliceGroup.on('drop', function (e) {
|
||
if (!_this.dragging) return;
|
||
_this.dragging = false;
|
||
if (e.target.get('type') !== 'rect') return;
|
||
var startTickRectId = _this.startTickRectId;
|
||
var id = parseInt(e.target.get('name').split('-')[2], 10);
|
||
if (id < startTickRectId) return;
|
||
var selectedTickStyle = _this.selectedTickStyle;
|
||
var tickRects = _this.tickRects;
|
||
tickRects[id].rect.attr(selectedTickStyle);
|
||
_this.endTickRectId = id;
|
||
var ticksLength = tickRects.length;
|
||
var start = startTickRectId / ticksLength;
|
||
var end = id / ticksLength;
|
||
_this.graph.emit(VALUE_CHANGE, {
|
||
value: [start, end]
|
||
});
|
||
});
|
||
// tooltip
|
||
var _a = this,
|
||
tooltipBackgroundColor = _a.tooltipBackgroundColor,
|
||
tooltipFomatter = _a.tooltipFomatter,
|
||
canvas = _a.canvas;
|
||
var tooltip = new TimeBarTooltip({
|
||
container: canvas.get('container'),
|
||
backgroundColor: tooltipBackgroundColor
|
||
});
|
||
var tickRects = this.tickRects;
|
||
tickRects.forEach(function (tickRect) {
|
||
var pickRect = tickRect.pickRect;
|
||
pickRect.on('mouseenter', function (e) {
|
||
var rect = e.target;
|
||
if (rect.get('type') !== 'rect') return;
|
||
var id = parseInt(rect.get('name').split('-')[2], 10);
|
||
var clientPoint = canvas.getClientByPoint(tickRects[id].x, tickRects[id].y);
|
||
tooltip.show({
|
||
x: tickRects[id].x,
|
||
y: tickRects[id].y,
|
||
clientX: clientPoint.x,
|
||
clientY: clientPoint.y,
|
||
text: tooltipFomatter ? tooltipFomatter(tickRects[id].value) : tickRects[id].value
|
||
});
|
||
});
|
||
pickRect.on('mouseleave', function (e) {
|
||
tooltip.hide();
|
||
});
|
||
});
|
||
// play controller events
|
||
var group = this.group;
|
||
// 播放区按钮控制
|
||
/** 播放/暂停事件 */
|
||
group.on("".concat(PLAY_PAUSE_BTN, ":click"), function () {
|
||
_this.isPlay = !_this.isPlay;
|
||
_this.changePlayStatus();
|
||
});
|
||
// 处理前进一步的事件
|
||
group.on("".concat(NEXT_STEP_BTN, ":click"), function () {
|
||
_this.updateStartEnd(1);
|
||
});
|
||
// 处理后退一步的事件
|
||
group.on("".concat(PRE_STEP_BTN, ":click"), function () {
|
||
_this.updateStartEnd(-1);
|
||
});
|
||
group.on(TIMEBAR_CONFIG_CHANGE, function (_a) {
|
||
var type = _a.type,
|
||
speed = _a.speed;
|
||
_this.currentSpeed = speed;
|
||
});
|
||
};
|
||
TimeBarSlice.prototype.changePlayStatus = function (isSync) {
|
||
if (isSync === void 0) {
|
||
isSync = true;
|
||
}
|
||
this.controllerBtnGroup.playButton.update({
|
||
isPlay: this.isPlay
|
||
});
|
||
if (this.isPlay) {
|
||
// 开始播放
|
||
this.playHandler = this.startPlay();
|
||
this.graph.emit(TIMELINE_START, null);
|
||
} else {
|
||
// 结束播放
|
||
if (this.playHandler) {
|
||
if (typeof window !== 'undefined') window.cancelAnimationFrame(this.playHandler);
|
||
if (isSync) {
|
||
this.graph.emit(TIMELINE_END, null);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
TimeBarSlice.prototype.startPlay = function () {
|
||
var _this = this;
|
||
return typeof window !== 'undefined' ? window.requestAnimationFrame(function () {
|
||
var speed = _this.currentSpeed;
|
||
// 一分钟刷新一次
|
||
if (_this.frameCount % (60 / speed) === 0) {
|
||
_this.frameCount = 0;
|
||
_this.updateStartEnd(1);
|
||
}
|
||
_this.frameCount++;
|
||
if (_this.isPlay) {
|
||
_this.playHandler = _this.startPlay();
|
||
}
|
||
}) : undefined;
|
||
};
|
||
TimeBarSlice.prototype.updateStartEnd = function (sign) {
|
||
var self = this;
|
||
var tickRects = this.tickRects;
|
||
var ticksLength = tickRects.length;
|
||
var unselectedTickStyle = this.unselectedTickStyle;
|
||
var selectedTickStyle = this.selectedTickStyle;
|
||
var previousEndTickRectId = self.endTickRectId;
|
||
if (sign > 0) {
|
||
self.endTickRectId++;
|
||
} else {
|
||
tickRects[self.endTickRectId].rect.attr(unselectedTickStyle);
|
||
self.endTickRectId--;
|
||
}
|
||
// 若此时 start 与 end 不同,范围前进/后退/播放
|
||
if (previousEndTickRectId !== self.startTickRectId) {
|
||
if (self.endTickRectId < self.startTickRectId) {
|
||
self.startTickRectId = self.endTickRectId;
|
||
}
|
||
} else {
|
||
// 否则是单帧的前进/后退/播放
|
||
for (var i = self.startTickRectId; i <= self.endTickRectId - 1; i++) {
|
||
tickRects[i].rect.attr(unselectedTickStyle);
|
||
}
|
||
self.startTickRectId = self.endTickRectId;
|
||
}
|
||
if (tickRects[self.endTickRectId]) {
|
||
tickRects[self.endTickRectId].rect.attr(selectedTickStyle);
|
||
var start = self.startTickRectId / ticksLength;
|
||
var end = self.endTickRectId / ticksLength;
|
||
this.graph.emit(VALUE_CHANGE, {
|
||
value: [start, end]
|
||
});
|
||
}
|
||
};
|
||
TimeBarSlice.prototype.destory = function () {
|
||
var group = this.sliceGroup;
|
||
group.off('click');
|
||
group.off('dragstart');
|
||
group.off('dragover');
|
||
group.off('drop');
|
||
this.tickRects.forEach(function (tickRect) {
|
||
var pickRect = tickRect.pickRect;
|
||
pickRect.off('mouseenter');
|
||
pickRect.off('mouseleave');
|
||
});
|
||
this.tickRects.length = 0;
|
||
group.off("".concat(PLAY_PAUSE_BTN, ":click"));
|
||
group.off("".concat(NEXT_STEP_BTN, ":click"));
|
||
group.off("".concat(PRE_STEP_BTN, ":click"));
|
||
group.off(TIMEBAR_CONFIG_CHANGE);
|
||
this.sliceGroup.destroy();
|
||
};
|
||
return TimeBarSlice;
|
||
}();
|
||
export default TimeBarSlice; |