Zoom lens 2
by PhilQ
HTML
<svg id="diagram" xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="-200 0 800 100" fill="none">
<!-- <rect y="50" x="50" width="50" height="50" fill="#ff0000"/> -->
<line x1="-100%" x2="200%" y1="50%" y2="50%" stroke="#ccc" />
<g id="rays"></g>
</svg>
<div class="controls">
<div class="input">
<label>Zoom</label>
<input type="range" id="zoom" value="44" min="18" max="70" step="1">
</div>
</div>
SCSS
body {
background-color: #eee;
}
.controls {
display: flex;
width: 100%;
max-width: 1024px;
margin: 2rem auto 0;
flex-direction: row;
gap: 1rem;
background: #ddd;
padding: 1rem;
}
.input {
width: 25%;
display: flex;
flex-direction: column;
gap: 0.5rem;
justify-content: flex-start;
align-items: stretch;
}
JavaScript
function easeOutSine(x) {
return Math.sin((x * Math.PI) / 2);
}
function easeInSine(x) {
return 1 - Math.cos((x * Math.PI) / 2);
}
function easeInOutSine(x) {
return -(Math.cos(Math.PI * x) - 1) / 2;
}
const createTag = (tag, props = {}, content = '') => {
const ns = 'http://www.w3.org/2000/svg';
const el = document.createElementNS(ns, tag);
if (false && 'svg' === tag) {
el.setAttributeNS(
'http://www.w3.org/2000/xmlns/',
'xmlns:xlink',
'http://www.w3.org/1999/xlink'
);
}
for (const prop in props) {
el.setAttribute(prop, props[prop]);
}
if (content?.length) {
el.textContent = content;
}
return el;
}
const N_GLASS = 1.458;
const N_AIR = 1.000273;
const SVG_NS = 'http://www.w3.org/2000/svg';
const DEG2RAD = Math.PI / 180;
const RAD2DEG = 180 / Math.PI;
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
class Lens {
static defaults = {
cx: 0,
cy: 0,
height: 80,
min_thickness: 0,
r1: 100,
r2: 100,
n: 1.458,
};
/**
* Source properties
*/
#cx;
#cy;
#height;
#min_thickness;
#r1;
#r2;
#n;
/**
* Derived properties
*/
#shape;
#p1;
#p2;
#sag1;
#sag2;
#width;
#edge_thickness;
#center_thickness;
#x1l;
#x1r;
#x2l;
#x2r;
#c1x;
#c2x;
#focal_length;
#focal_offset1;
#focal_offset2;
#power;
constructor(params = {}) {
const p = { ...Lens.defaults, ...params, };
this.#validateSetRecalc(p);
}
#validateSetRecalc(params) {
if ('r1' in params && params.r1 === 0) params.r1 = Infinity;
if ('r2' in params && params.r2 === 0) params.r2 =...