UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

264 lines 11.6 kB
"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