@leafer-in/scroll
Version:
121 lines (117 loc) • 4.72 kB
JavaScript
import { Group, DataHelper, isString, Box, Bounds, DragEvent, RenderEvent, ResizeEvent, Plugin } from "@leafer-ui/core";
class ScrollBar extends Group {
get isOutside() {
return true;
}
constructor(target, userConfig) {
super();
this.config = {
theme: "light",
padding: 0,
minSize: 10
};
if (target.isApp) {
target.sky.add(this);
target = target.tree;
}
this.target = target;
if (userConfig) DataHelper.assign(this.config, userConfig);
this.changeTheme(this.config.theme);
this.waitLeafer(this.__listenEvents, this);
}
changeTheme(theme) {
let style;
if (isString(theme)) {
style = {
fill: "black",
stroke: "rgba(255,255,255,0.8)"
};
if (theme === "dark") {
style.fill = "white";
style.stroke = "rgba(0,0,0,0.2)";
}
} else {
style = theme;
}
if (!this.scrollXBar) this.addMany(this.scrollXBar = new Box, this.scrollYBar = new Box);
style = Object.assign({
strokeAlign: "center",
opacity: .5,
width: 6,
cornerRadius: 3,
hoverStyle: {
opacity: .6
},
pressStyle: {
opacity: .7
}
}, style);
if (!style.height) style.height = style.width;
this.scrollXBar.set(Object.assign(Object.assign({}, style), {
visible: false
}));
this.scrollYBar.set(Object.assign(Object.assign({}, style), {
visible: false
}));
if (this.leafer) this.update();
}
update(check) {
if (this.dragScrolling) return;
const {minSize: minSize, padding: padding} = this.config;
const {zoomLayer: zoomLayer, canvas: canvas} = this.target.leafer;
const {worldRenderBounds: worldRenderBounds} = zoomLayer;
if (check && this.scrollBounds && this.scrollBounds.isSame(worldRenderBounds)) return;
this.scrollBounds = new Bounds(worldRenderBounds);
const bounds = canvas.bounds.clone().shrink(padding);
const totalBounds = bounds.clone().add(worldRenderBounds);
const ratioX = this.ratioX = bounds.width / totalBounds.width;
const ratioY = this.ratioY = bounds.height / totalBounds.height;
const scrollRatioX = (bounds.x - totalBounds.x) / totalBounds.width;
const scrollRatioY = (bounds.y - totalBounds.y) / totalBounds.height;
const showScrollXBar = ratioX < 1;
const showScrollYBar = ratioY < 1;
const {scrollXBar: scrollXBar, scrollYBar: scrollYBar} = this;
const {x: x, y: y, width: width, height: height} = bounds.shrink([ 2, showScrollYBar ? scrollYBar.width + 6 : 2, showScrollXBar ? scrollXBar.height + 6 : 2, 2 ]);
scrollXBar.set({
x: x + width * scrollRatioX,
y: y + height + 2,
width: Math.max(width * ratioX, minSize),
visible: showScrollXBar
});
scrollYBar.set({
x: x + width + 2,
y: y + height * scrollRatioY,
height: Math.max(height * ratioY, minSize),
visible: showScrollYBar
});
}
onDrag(e) {
this.dragScrolling = true;
this.__dragOut = this.app.config.move.dragOut;
this.app.config.move.dragOut = false;
const scrollX = e.current === this.scrollXBar;
const move = this.target.leafer.getValidMove(scrollX ? -e.moveX / this.ratioX : 0, scrollX ? 0 : -e.moveY / this.ratioY);
this.target.moveWorld(move.x, move.y);
e.current.moveWorld(move.x && -move.x * this.ratioX, move.y && -move.y * this.ratioY);
}
onDragEnd() {
this.dragScrolling = false;
this.app.config.move.dragOut = this.__dragOut;
}
__listenEvents() {
const {scrollXBar: scrollXBar, scrollYBar: scrollYBar} = this;
this.__eventIds = [ scrollXBar.on_(DragEvent.DRAG, this.onDrag, this), scrollYBar.on_(DragEvent.DRAG, this.onDrag, this), scrollXBar.on_(DragEvent.END, this.onDragEnd, this), scrollYBar.on_(DragEvent.END, this.onDragEnd, this), this.target.on_(RenderEvent.BEFORE, () => this.update(true)), this.target.leafer.on_(ResizeEvent.RESIZE, () => this.update()) ];
}
__removeListenEvents() {
this.off_(this.__eventIds);
}
destroy() {
if (!this.destroyed) {
this.__removeListenEvents();
this.target = this.config = null;
super.destroy();
}
}
}
Plugin.add("scroll");
export { ScrollBar };