Думаю, плагин d3-fishey сделает то, что вам нужно:
https://github.com/d3/d3-plugins/tree/master/fisheye
Здесь вы можете найти пример, в котором область рыбьего глаза помещается внутри круг, который может быть ручкой вашего слайдера:
http://bl.ocks.org/fernoftheandes/8637581
Начальная точка может быть в следующих фрагментах:
(function () {
d3.fisheye = {
scale: function (scaleType) {
return d3_fisheye_scale(scaleType(), 3, 0);
},
circular: function () {
var radius = 200,
distortion = 2,
k0,
k1,
focus = [0, 0];
function fisheye(d) {
var dx = d.x - focus[0],
dy = d.y - focus[1],
dd = Math.sqrt(dx * dx + dy * dy);
if (!dd || dd >= radius) return { x: d.x, y: d.y, z: 1 };
var k = ((k0 * (1 - Math.exp(-dd * k1))) / dd) * 0.75 + 0.25;
return {
x: focus[0] + dx * k,
y: focus[1] + dy * k,
z: Math.min(k, 10)
};
}
function rescale() {
k0 = Math.exp(distortion);
k0 = (k0 / (k0 - 1)) * radius;
k1 = distortion / radius;
return fisheye;
}
fisheye.radius = function (_) {
if (!arguments.length) return radius;
radius = +_;
return rescale();
};
fisheye.distortion = function (_) {
if (!arguments.length) return distortion;
distortion = +_;
return rescale();
};
fisheye.focus = function (_) {
if (!arguments.length) return focus;
focus = _;
return fisheye;
};
return rescale();
}
};
function d3_fisheye_scale(scale, d, a) {
function fisheye(_) {
var x = scale(_),
left = x < a,
range = d3.extent(scale.range()),
min = range[0],
max = range[1],
m = left ? a - min : max - a;
if (m == 0) m = max - min;
return ((left ? -1 : 1) * m * (d + 1)) / (d + m / Math.abs(x - a)) + a;
}
fisheye.distortion = function (_) {
if (!arguments.length) return d;
d = +_;
return fisheye;
};
fisheye.focus = function (_) {
if (!arguments.length) return a;
a = +_;
return fisheye;
};
fisheye.copy = function () {
return d3_fisheye_scale(scale.copy(), d, a);
};
fisheye.nice = scale.nice;
fisheye.ticks = scale.ticks;
fisheye.tickFormat = scale.tickFormat;
return d3.rebind(fisheye, scale, "domain", "range");
}
})();
let svg = d3.select("svg");
let g = svg.append("g");
let circle = g
.append("circle")
.attr("cx", 20)
.attr("cy", 70)
.attr("r", 10)
.attr("fill", "transparent")
.attr("stroke", "black")
.attr("mousedown", false);
circle.on("mousedown", function () {
d3.select(this).attr("mousedown", true);
});
circle.on("mouseup", function () {
d3.select(this).attr("mousedown", false);
});
circle.on("mousemove", function () {
let self = d3.select(this);
if (self.attr("mousedown")=="true") {
let coordinates = d3.mouse(this);
let x = coordinates[0];
let y = coordinates[1];
d3.select(this).attr("cx", x);
}
});
let points = [[{x:20, y:50},{x:30, y:50}],[{x:30, y:50},{x:50, y:50}],[{x:50, y:50},{x:70, y:50}], [{x:70, y:50},{x:90,y:50}],[{x:90, y:50},{x:110,y:50}],[{x:110, y:50},{x:130,y:50}],[{x:130, y:50},{x:150,y:50}],[{x:150, y:50},{x:170,y:50}],[{x:170, y:50},{x:200,y:50}]];
let line = g.selectAll('.line')
.data(points)
.enter()
.append('line')
.attr('x1', d=>d[0].x)
.attr('x2', d=>d[1].x)
.attr('y1', d=>d[0].y)
.attr('y2', d=>d[1].y)
.attr("stroke", "black")
.attr("class", "line");
let fisheye = d3.fisheye.circular()
.radius(30)
.distortion(50);
circle.attr('r',fisheye.radius());
g.on('mousemove', function(){
fisheye.focus(d3.mouse(this));
let r = fisheye.radius();
line
.attr("x1", function(d) { return fisheye(d[0]).x; })
.attr("y1", function(d) { return fisheye(d[0]).y; })
.attr("x2", function(d) { return fisheye(d[1]).x; })
.attr("y2", function(d) { return fisheye(d[1]).y; });
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script>
<svg heigth='200' width='200'>
</svg>
вы можете найти редактируемую версию здесь, в моем коде: https://codepen.io/lbrutti/pen/mdVmmpw