update
This commit is contained in:
48
libs/ZoomableSlider/ZoomableSlider.css
Normal file
48
libs/ZoomableSlider/ZoomableSlider.css
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
.zs_widget{
|
||||
padding: 2px;
|
||||
height: 30px;
|
||||
border: 1px solid green;
|
||||
user-select: none;
|
||||
}
|
||||
.zs_core{
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
.zs_handle{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
border: 1px solid green;
|
||||
background-color: green;
|
||||
width: 8px;
|
||||
user-select: none;
|
||||
}
|
||||
.zs_handle:hover{
|
||||
background-color: lightgreen;
|
||||
}
|
||||
.zs_inside{
|
||||
position: absolute;
|
||||
}
|
||||
.zs_outside{
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: black;
|
||||
top: 50%;
|
||||
}
|
||||
.zs_visible_range_label{
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
}
|
||||
.zs_visible_range_label_left{
|
||||
left: 0px;
|
||||
}
|
||||
.zs_visible_range_label_right{
|
||||
right: 0px;
|
||||
}
|
||||
.zs_chosen_range_label{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
31
libs/ZoomableSlider/ZoomableSlider.html
Normal file
31
libs/ZoomableSlider/ZoomableSlider.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" type="text/css" href="ZoomableSlider.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="target" style="position: absolute; left: 10px; top: 10px; width: 300px;">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="ZoomableSlider.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
let el = document.getElementById("target");
|
||||
let slider = new ZoomableSlider();
|
||||
|
||||
el.appendChild(slider.element);
|
||||
slider.update();
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
133
libs/ZoomableSlider/ZoomableSlider.js
Normal file
133
libs/ZoomableSlider/ZoomableSlider.js
Normal file
@@ -0,0 +1,133 @@
|
||||
|
||||
class ZoomableSlider{
|
||||
constructor(){
|
||||
this.visibleRange = [0, 10];
|
||||
this.chosenRange = [2, 7];
|
||||
this.step = 0.01;
|
||||
this.clipDragToVisible = true;
|
||||
this.element = document.createElement("div");
|
||||
this.element.innerHTML = `
|
||||
<div name="zoomable_slider_widget" class="zs_widget">
|
||||
<div name="core" class="zs_core">
|
||||
<span name="outside" class="zs_outside"> </span>
|
||||
<span name="inside" class="zs_inside"> </span>
|
||||
<span name="left" class="zs_handle"> </span>
|
||||
<span name="right" class="zs_handle"> </span>
|
||||
<span name="label_visible_left" class="zs_visible_range_label zs_visible_range_label_left"></span>
|
||||
<span name="label_visible_right" class="zs_visible_range_label zs_visible_range_label_right"></span>
|
||||
<span name="label_chosen_left" class="zs_chosen_range_label zs_chosen_range_label_left"></span>
|
||||
<span name="label_chosen_right" class="zs_chosen_range_label zs_chosen_range_label_right"></span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
this.elCore = this.element.querySelector('[name=core]');
|
||||
this.elLeft = this.element.querySelector('[name=left]');
|
||||
this.elRight = this.element.querySelector('[name=right]');
|
||||
this.elInside = this.element.querySelector('[name=inside]');
|
||||
this.elOutside = this.element.querySelector('[name=outside]');
|
||||
this.elLabelVisibleLeft = this.element.querySelector('[name=label_visible_left]');
|
||||
this.elLabelVisibleRight = this.element.querySelector('[name=label_visible_right]');
|
||||
this.elLabelChosenLeft = this.element.querySelector('[name=label_chosen_left]');
|
||||
this.elLabelChosenRight = this.element.querySelector('[name=label_chosen_right]');
|
||||
this.elRight.style.left = "100px";
|
||||
let dragStart = null;
|
||||
let onMouseDown = (e) => {
|
||||
e.preventDefault();
|
||||
let value = (e.target === this.elLeft) ?
|
||||
this.chosenRange[0] :
|
||||
this.chosenRange[1];
|
||||
dragStart = {
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
handle: e.target,
|
||||
value: value,
|
||||
};
|
||||
document.onmouseup = onMouseUp;
|
||||
document.onmousemove = onMouseMove;
|
||||
};
|
||||
let onMouseUp = (e) => {
|
||||
document.onmouseup = null;
|
||||
document.onmousemove = null;
|
||||
};
|
||||
let onMouseMove = (e) => {
|
||||
let dx = e.clientX - dragStart.x;
|
||||
let dy = e.clientY - dragStart.y;
|
||||
let normalizedDelta = dx / this.elCore.clientWidth;
|
||||
let valueDelta = (this.visibleRange[1] - this.visibleRange[0]) * normalizedDelta;
|
||||
let newValue = dragStart.value + valueDelta;
|
||||
newValue = Math.round(newValue / this.step) * this.step;
|
||||
|
||||
let newRange;
|
||||
if(dragStart.handle === this.elLeft){
|
||||
newRange = [newValue, this.chosenRange[1]];
|
||||
}else{
|
||||
newRange = [this.chosenRange[0], newValue];
|
||||
}
|
||||
if(this.clipDragToVisible){
|
||||
newRange[0] = Math.max(newRange[0], this.visibleRange[0]);
|
||||
newRange[1] = Math.min(newRange[1], this.visibleRange[1]);
|
||||
}
|
||||
this.setRange(newRange);
|
||||
};
|
||||
for(let handle of [this.elLeft, this.elRight]){
|
||||
handle.onmousedown = onMouseDown;
|
||||
}
|
||||
let onWheel = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
let delta = Math.sign(e.deltaY);
|
||||
|
||||
let zoom = 1;
|
||||
if(delta < 0){
|
||||
zoom = 0.8;
|
||||
}else if(delta > 0){
|
||||
zoom = 1.2;
|
||||
}
|
||||
let oldRangeWidth = this.visibleRange[1] - this.visibleRange[0];
|
||||
let rect = this.elCore.getBoundingClientRect();
|
||||
let pivotPixels = e.clientX - rect.left;
|
||||
let pivotNormalized = (pivotPixels / this.elCore.clientWidth);
|
||||
let pivot = (oldRangeWidth * pivotNormalized) + this.visibleRange[0];
|
||||
let leftRatio = (pivot - this.visibleRange[0]) / oldRangeWidth;
|
||||
let rightRatio = (this.visibleRange[1] - pivot) / oldRangeWidth;
|
||||
let newRangeWidth = oldRangeWidth * zoom;
|
||||
let newVisibleRange = [
|
||||
pivot - (newRangeWidth * leftRatio),
|
||||
pivot + (newRangeWidth * rightRatio),
|
||||
];
|
||||
this.setVisibleRange(newVisibleRange);
|
||||
};
|
||||
this.elCore.onmousewheel = onWheel;
|
||||
this.update();
|
||||
}
|
||||
setRange(range){
|
||||
this.chosenRange = range;
|
||||
this.update();
|
||||
}
|
||||
setVisibleRange(range){
|
||||
this.visibleRange = range;
|
||||
this.update();
|
||||
}
|
||||
update(){
|
||||
let {elLeft, elRight, visibleRange, chosenRange} = this;
|
||||
let pixelWidth = this.elCore.clientWidth;
|
||||
let normalizedLeft = (chosenRange[0] - visibleRange[0]) / (visibleRange[1] - visibleRange[0]);
|
||||
let normalizedRight = (chosenRange[1] - visibleRange[0]) / (visibleRange[1] - visibleRange[0]);
|
||||
let pixelLeft = Math.round(normalizedLeft * pixelWidth) - elLeft.clientWidth;
|
||||
let pixelRight = Math.round(normalizedRight * pixelWidth) - elRight.clientWidth;
|
||||
|
||||
elLeft.style.left = `${pixelLeft}px`;
|
||||
elRight.style.left = `${pixelRight}px`;
|
||||
let precision = Math.ceil(Math.log(1 / this.step) / Math.log(10));
|
||||
this.elLabelVisibleLeft.style.left = "0px";
|
||||
this.elLabelVisibleLeft.innerHTML = `${visibleRange[0].toFixed(precision)}`;
|
||||
this.elLabelVisibleRight.style.right = "0px";
|
||||
this.elLabelVisibleRight.innerHTML = `${visibleRange[1].toFixed(precision)}`;
|
||||
this.elLabelChosenLeft.style.left = `${pixelLeft}px`;
|
||||
this.elLabelChosenLeft.innerHTML = `${chosenRange[0].toFixed(precision)}`;
|
||||
this.elLabelChosenRight.style.left = `${pixelRight}px`;
|
||||
this.elLabelChosenRight.innerHTML = `${chosenRange[1].toFixed(precision)}`;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user