@antv/s2
Version:
effective spreadsheet render core lib
264 lines • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScrollBar = exports.ScrollType = void 0;
const g_1 = require("@antv/g");
const lodash_1 = require("lodash");
const common_1 = require("../../common/");
var ScrollType;
(function (ScrollType) {
ScrollType["ScrollChange"] = "scroll-change";
ScrollType["ScrollEnd"] = "scroll-end";
})(ScrollType || (exports.ScrollType = ScrollType = {}));
class ScrollBar extends g_1.Group {
constructor(scrollBarCfg) {
super();
this.eventHandlers = [];
this.scrollFrameId = null;
this.getCoordinatesName = () => {
const from = this.isHorizontal ? 'x1' : 'y1';
const to = this.isHorizontal ? 'x2' : 'y2';
return { from, to };
};
/**
* Antv/g 5.0 环境下坐标修正
*
* 当 lineCap 设置为非 'butt' 后,实际绘制左右两端会多两个头,且不计入 getBBox 的计算
* 如长100,strokeWidth=10,实际渲染110长度的线,getBBox 仍返回100
*/
this.getCoordinatesWithBBoxExtraPadding = () => {
const { lineCap = 'butt', size = 0 } = this.theme;
if (lineCap === 'butt') {
return {
start: this.thumbOffset,
end: this.thumbOffset + this.thumbLen,
};
}
const startPadding = this.isHorizontal ? 0 : size / 2;
const endPadding = this.isHorizontal ? size : size / 2;
return {
start: this.thumbOffset + startPadding,
end: this.thumbOffset + this.thumbLen - endPadding,
};
};
/**
* 当前滑块滑动的位置 0 ~ 1
*/
this.current = () => {
const thumbRate = this.thumbLen / this.trackLen;
const offsetRate = this.thumbOffset / this.trackLen;
return offsetRate / (1 - thumbRate);
};
/**
* 更新滑块长度
* @param newThumbLen 新的滑道长度
*/
this.updateThumbLen = (newThumbLen) => {
// 如果更新后的 thumbLen 没改变,无需执行后续逻辑
if (this.thumbLen === newThumbLen) {
return;
}
this.thumbLen = newThumbLen;
const coordinate = this.getCoordinatesName();
this.thumbShape.attr(coordinate.to, this.thumbOffset + newThumbLen);
this.emitScrollChange((this.thumbOffset / (this.trackLen - this.thumbLen)) *
this.scrollTargetMaxOffset, false);
};
/**
* 更新滑块的 offset 值
* @param offset
*/
this.updateThumbOffset = (offset, emitScrollChange = true) => {
const newOffset = this.validateRange(offset);
const isNotChanged = this.thumbOffset === newOffset && newOffset !== 0;
if (isNotChanged) {
return;
}
this.thumbOffset = newOffset;
const { from, to } = this.getCoordinatesName();
const { start, end } = this.getCoordinatesWithBBoxExtraPadding();
this.thumbShape.attr({
[from]: start,
[to]: end,
});
if (emitScrollChange) {
this.emitScrollChange((newOffset / (this.trackLen - this.thumbLen)) *
this.scrollTargetMaxOffset, false);
}
};
/**
* 只更新位置属性,而不emit滚动事件
* @param offset
*/
this.onlyUpdateThumbOffset = (offset) => {
this.updateThumbOffset(offset, false);
};
this.emitScrollChange = (offset, updateThumbOffset = true) => {
cancelAnimationFrame(this.scrollFrameId);
this.scrollFrameId = requestAnimationFrame(() => {
this.dispatchEvent(new g_1.CustomEvent(ScrollType.ScrollChange, {
offset,
updateThumbOffset,
}));
});
};
this.bindEventListener = (target, eventType, callback) => {
target === null || target === void 0 ? void 0 : target.addEventListener(eventType, callback, false);
return {
remove: () => {
target === null || target === void 0 ? void 0 : target.removeEventListener(eventType, callback, false);
},
};
};
this.addEvent = (target, type, handler) => {
target.addEventListener(type, handler);
this.eventHandlers.push({ target, type, handler });
};
this.initScrollBar = () => {
this.scrollBarGroup = this.createScrollBarGroup();
this.scrollBarGroup.setPosition(this.position.x, this.position.y);
this.bindEvents();
};
// 创建 scrollBar 的 group
this.createScrollBarGroup = () => {
const group = this.appendChild(new g_1.Group({
className: this.isHorizontal ? 'horizontalBar' : 'verticalBar',
}));
this.trackShape = this.createTrackShape(group);
this.thumbShape = this.createThumbShape(group);
return group;
};
// 创建滑道的 shape
this.createTrackShape = (group) => {
const { lineCap = 'round', trackColor, size = 0 } = this.theme;
const baseAttrs = {
lineWidth: size,
stroke: trackColor,
lineCap,
};
if (this.isHorizontal) {
return group.appendChild(new g_1.Line({
style: Object.assign(Object.assign({}, baseAttrs), { x1: 0, y1: size / 2, x2: this.trackLen, y2: size / 2 }),
}));
}
return group.appendChild(new g_1.Line({
style: Object.assign(Object.assign({}, baseAttrs), { x1: size / 2, y1: 0, x2: size / 2, y2: this.trackLen }),
}));
};
// 创建滑块的 shape
this.createThumbShape = (group) => {
const { size = 0, lineCap = 'round', thumbColor } = this.theme;
const baseAttrs = {
lineWidth: size,
stroke: thumbColor,
lineCap,
cursor: 'default',
};
const { start, end } = this.getCoordinatesWithBBoxExtraPadding();
if (this.isHorizontal) {
return group.appendChild(new g_1.Line({
style: Object.assign(Object.assign({}, baseAttrs), { x1: start, y1: size / 2, x2: end, y2: size / 2 }),
}));
}
return group.appendChild(new g_1.Line({
style: Object.assign(Object.assign({}, baseAttrs), { x1: size / 2, y1: start, x2: size / 2, y2: end }),
}));
};
this.bindEvents = () => {
this.addEventListener(common_1.OriginEventType.POINTER_DOWN, this.onStartEvent);
this.addEventListener(common_1.OriginEventType.POINTER_UP, this.onPointerUp);
this.trackShape.addEventListener('click', this.onTrackClick);
this.thumbShape.addEventListener(common_1.OriginEventType.POINTER_OVER, this.onTrackPointerOver);
this.thumbShape.addEventListener(common_1.OriginEventType.POINTER_OUT, this.onTrackPointerOut);
};
this.onStartEvent = (e) => {
e.preventDefault();
const { clientX, clientY } = e;
// 将开始的点记录下来
this.startPos = this.isHorizontal ? clientX : clientY;
this.bindLaterEvent();
};
this.bindLaterEvent = () => {
const canvas = this.ownerDocument.defaultView;
const containerDOM = document.body;
const events = [
this.bindEventListener(containerDOM, common_1.OriginEventType.POINTER_MOVE, this.onPointerMove),
this.bindEventListener(containerDOM, common_1.OriginEventType.POINTER_UP, this.onPointerUp),
// 为了保证划出 canvas containerDom 时还没触发 pointerup
this.bindEventListener(containerDOM, common_1.OriginEventType.POINTER_LEAVE, this.onPointerUp),
];
this.addEvent(canvas, common_1.OriginEventType.POINTER_UP, this.onPointerUp);
this.clearEvents = () => {
events.forEach((e) => {
e === null || e === void 0 ? void 0 : e.remove();
});
(0, lodash_1.each)(this.eventHandlers, (eh) => {
var _a;
(_a = eh.target) === null || _a === void 0 ? void 0 : _a.removeEventListener(eh.type, eh.handler);
});
this.eventHandlers.length = 0;
};
};
// 点击滑道的事件回调,移动滑块位置
this.onTrackClick = (event) => {
const offset = this.isHorizontal
? event.x - this.position.x - this.thumbLen / 2
: event.y - this.position.y - this.thumbLen / 2;
const newOffset = this.validateRange(offset);
this.updateThumbOffset(newOffset);
};
/*
* 拖拽滑块的事件回调
* 这里是 dom 原生事件,绑定在 dom 元素上的
*/
this.onPointerMove = (e) => {
e.preventDefault();
const clientX = e.clientX;
const clientY = e.clientY;
// 鼠标松开的位置
const endPos = this.isHorizontal ? clientX : clientY;
// 滑块需要移动的距离, 由于这里是对滑块监听,所以移动的距离就是 diffDis, 如果监听对象是 container dom,则需要算比例
const diff = endPos - this.startPos;
// 更新 startPos
this.startPos = endPos;
this.updateThumbOffset(this.thumbOffset + diff);
};
this.onPointerUp = (e) => {
var _a;
this.dispatchEvent(new g_1.CustomEvent(ScrollType.ScrollEnd, {}));
e.preventDefault();
(_a = this.clearEvents) === null || _a === void 0 ? void 0 : _a.call(this);
};
this.onTrackPointerOver = () => {
const { thumbHoverColor, hoverSize } = this.theme;
this.thumbShape.attr('stroke', thumbHoverColor);
this.thumbShape.attr('lineWidth', hoverSize);
};
this.onTrackPointerOut = () => {
const { thumbColor, size } = this.theme;
this.thumbShape.attr('stroke', thumbColor);
this.thumbShape.attr('lineWidth', size);
};
// 判断滑块位置是否超出滑道区域
this.validateRange = (offset) => {
let newOffset = offset;
if (offset + this.thumbLen > this.trackLen) {
newOffset = this.trackLen - this.thumbLen;
}
else if (offset + this.thumbLen < this.thumbLen) {
newOffset = 0;
}
return newOffset;
};
const { isHorizontal = false, trackLen, thumbLen, position, thumbOffset = 0, theme, scrollTargetMaxOffset, } = scrollBarCfg;
this.isHorizontal = isHorizontal;
this.thumbOffset = thumbOffset;
this.trackLen = trackLen;
this.thumbLen = thumbLen;
this.position = position;
this.theme = theme;
this.scrollTargetMaxOffset = scrollTargetMaxOffset;
this.initScrollBar();
}
}
exports.ScrollBar = ScrollBar;
//# sourceMappingURL=index.js.map