'Easing the scaling of a line in Javascript
I am trying to scale a line along the dot product in X between its start and end point in Javascript with an ease that goes from 0 to 1. I am seeking something like the red line in this image:

I have the linear scale working, but I'm not sure how to ease the scale. I have tried applying the ease to the linear points then subtracting that amount from the linear amount, but it's not right: the eased points surpass the start point. Running the snippet below should demonstrate the issue. Could anyone please help me get this working? I would very greatly appreciate it.
function magnitude(p) {
return Math.sqrt(p.x ** 2 + p.y ** 2);
}
function normalize(p) {
let m = magnitude(p);
if (m > 0) {
return { x: p.x / m, y: p.y / m };
}
}
function dot(pt1, pt2) {
return pt1.x * pt2.x + pt1.y * pt2.y;
}
//ease functions
function easeInQuad(n) {
return n ** 2;
}
function easeOutQuad(n) {
return -n * (n - 2);
}
function render_line_graph() {
let points = [
{ x: 2, y: 2 },
{ x: 3, y: 1 },
{ x: 4, y: 4 },
{ x: 5, y: 3 },
{ x: 6, y: 6 },
{ x: 7, y: 5 },
{ x: 8, y: 6 }
];
let scale_amount = 1-slider.value/100;
//first & last points x,y respectively
let x1 = points[0].x;
let y1 = points[0].y;
let x2 = points.slice(-1)[0].x;
let y2 = points.slice(-1)[0].y;
//distance between the first & last points' coordinates
let x_dist = x2 - x1;
let y_dist = y2 - y1;
let vec = { x: x2 - x1, y: y2 - y1 };
let line = normalize(vec);
let normal_data = [];
let linear_data = [];
let ease_data = [];
let chart = null;
for (let i = 0; i < points.length; i++) {
let p = points[i];
let dot_product = dot({ x: p.x - x1, y: p.y - y1 }, line);
if (normal_check.checked)
{
normal_data.push({ x: p.x, y: p.y });
}
if (linear_check.checked)
{
let linear_x = p.x - dot_product * scale_amount * line.x;
let linear_y = p.y - dot_product * scale_amount * line.y;
linear_data.push({ x: linear_x, y: linear_y });
}
if (ease_check.checked)
{
let alpha = dot({ x: p.x - x1, y: p.y - y1 }, line) / magnitude(vec);
let alpha_eased = 1 - easeInQuad(1 - alpha);
let ease_x = p.x - alpha_eased * scale_amount * vec.x;
let ease_y = p.y - alpha_eased * scale_amount * vec.y;
ease_data.push({ x: ease_x, y: ease_y });
}
}
chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: false,
theme: "light2",
title: {
text: "Scaling a Line with Ease"
},
data: [
{
type: "line",
color: "blue",
lineDashType: "dash",
indexLabelFontSize: 16,
dataPoints: [points[0],points.slice(-1)[0]]
},
{
type: "line",
color: "blue",
indexLabelFontSize: 16,
dataPoints: normal_data
},
{
type: "line",
color: "green",
indexLabelFontSize: 16,
dataPoints: linear_data
},
{
type: "line",
color: "red",
indexLabelFontSize: 16,
dataPoints: ease_data
},
]
});
chart.render();
}
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
var normal_check = document.getElementById("normal");
var linear_check = document.getElementById("linear");
var ease_check = document.getElementById("ease");
output.innerHTML = slider.value + "%"; // Display the default slider value
render_line_graph();
slider.oninput = function () {
scale_amount = this.value / 100;
output.innerHTML = this.value + "%";
render_line_graph();
};
normal_check.oninput = function () {
render_line_graph();
};
linear_check.oninput = function () {
render_line_graph();
};
ease_check.oninput = function () {
render_line_graph();
};
html
{
font-family: sans-serif;
}
#controls
{
display: flex;
flex-direction: column;
border: 1px solid #ddd;
padding: 20px;
width: fit-content;
position: absolute;
top: 0;
right: 0;
}
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<div id="chartContainer" style="height: 180px; width: 320px;"></div>
<div id="controls">
<div><input type="checkbox" id="normal" name="normal" value="True" checked>
<label for="normal"> Normal Line</label>
</div>
<div><input type="checkbox" id="linear" name="linear" value="True" checked>
<label for="linear"> Linear Scale</label>
</div>
<div><input type="checkbox" id="ease" name="ease" value="True" checked>
<label for="ease"> Scale with Ease</label>
</div>
<div class="slidecontainer">
<input type="range" min="0" max="100" value="50" class="slider" id="myRange">
<p>Scale: <span id="demo"></span></p>
</div>
</div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
