1
0
Fork 0
This commit is contained in:
Atridad Lahiji 2025-01-21 15:25:47 -06:00
commit 5232019b84
Signed by: atridad
SSH key fingerprint: SHA256:LGomp8Opq0jz+7kbwNcdfTcuaLRb5Nh0k5AchDDb438
5 changed files with 276 additions and 0 deletions

57
background.js Normal file
View file

@ -0,0 +1,57 @@
// Dynamic Icon generator
function createIcon(text, size = 16) {
const canvas = new OffscreenCanvas(size, size);
const ctx = canvas.getContext("2d");
// Wipe canvas
ctx.clearRect(0, 0, size, size);
// Background
ctx.fillStyle = "#4285F4"; // Google Blue
ctx.fillRect(0, 0, size, size);
// Text
ctx.fillStyle = "white";
ctx.font = `bold ${Math.floor(size * 0.5625)}px Arial`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, size / 2, size / 2);
return ctx.getImageData(0, 0, size, size);
}
// Update the extension icon
function updateExtensionIcon(zoomLevel, accelerationMultiplier) {
const zoomText = zoomLevel.toFixed(2);
const accelText = accelerationMultiplier.toFixed(2);
// Create icons of different sizes
const icon16 = createIcon(zoomText, 16);
const icon32 = createIcon(zoomText, 32);
const icon48 = createIcon(zoomText, 48);
const icon128 = createIcon(zoomText, 128);
// Set the icon
chrome.action.setIcon({
imageData: {
16: icon16,
32: icon32,
48: icon48,
128: icon128,
},
});
// Update badge with multiplier
chrome.action.setBadgeText({ text: accelText + "x" });
chrome.action.setBadgeBackgroundColor({ color: "#34A853" }); // Google Green
}
// Listen for messages
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "updateZoomInfo") {
updateExtensionIcon(request.zoomLevel, request.accelerationMultiplier);
}
});
// Set icon
updateExtensionIcon(1, 1);

93
content.js Normal file
View file

@ -0,0 +1,93 @@
let zoomLevel = 1;
let lastGestureTime = 0;
let lastGestureScale = 1;
const minZoom = 0.1;
const maxZoom = 5;
let accelerationCurve = [1, 1, 1, 1, 1];
function interpolateAcceleration(speed) {
const index = Math.min(
Math.floor((speed * (accelerationCurve.length - 1)) / 2),
accelerationCurve.length - 2,
);
const t = ((speed * (accelerationCurve.length - 1)) / 2) % 1;
return accelerationCurve[index] * (1 - t) + accelerationCurve[index + 1] * t;
}
function applyZoom(delta, speed) {
const accelerationMultiplier = interpolateAcceleration(speed);
const zoomChange = delta * accelerationMultiplier;
zoomLevel *= 1 + zoomChange;
zoomLevel = Math.min(Math.max(zoomLevel, minZoom), maxZoom);
document.body.style.transform = `scale(${zoomLevel})`;
document.body.style.transformOrigin = "center top";
// Update Icon via Messages
chrome.runtime.sendMessage({
action: "updateZoomInfo",
zoomLevel: zoomLevel,
accelerationMultiplier: accelerationMultiplier,
});
}
window.addEventListener(
"wheel",
(event) => {
if (event.ctrlKey || event.metaKey) {
event.preventDefault();
const currentTime = performance.now();
const timeDiff = (currentTime - lastGestureTime) / 1000;
const delta = event.deltaY * -0.001;
const speed = Math.abs(delta / timeDiff);
applyZoom(delta, speed);
lastGestureTime = currentTime;
}
},
{ passive: false },
);
window.addEventListener(
"gesturestart",
(event) => {
event.preventDefault();
lastGestureScale = 1;
lastGestureTime = performance.now();
},
{ passive: false },
);
window.addEventListener(
"gesturechange",
(event) => {
event.preventDefault();
const currentTime = performance.now();
const timeDiff = (currentTime - lastGestureTime) / 1000;
const delta = event.scale - lastGestureScale;
const speed = Math.abs(delta / timeDiff);
applyZoom(delta, speed);
lastGestureScale = event.scale;
lastGestureTime = currentTime;
},
{ passive: false },
);
window.addEventListener(
"gestureend",
(event) => {
event.preventDefault();
},
{ passive: false },
);
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "updateSettings") {
accelerationCurve = request.settings;
}
});
chrome.storage.sync.get("accelerationCurve", (data) => {
if (data.accelerationCurve) {
accelerationCurve = data.accelerationCurve;
}
});

20
manifest.json Normal file
View file

@ -0,0 +1,20 @@
{
"manifest_version": 3,
"name": "Zoom Accelerator",
"version": "1.0",
"description": "Adds customizable smooth zoom acceleration to Chrome",
"permissions": ["activeTab", "storage"],
"host_permissions": ["<all_urls>"],
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}

31
popup.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<style>
body {
width: 300px;
padding: 10px;
font-family: Arial, sans-serif;
}
.slider-container {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.slider {
flex-grow: 1;
margin: 0 10px;
}
.value {
width: 40px;
text-align: right;
}
</style>
</head>
<body>
<h2>Zoom Acceleration Curve</h2>
<div id="sliders"></div>
<script src="popup.js"></script>
</body>
</html>

75
popup.js Normal file
View file

@ -0,0 +1,75 @@
const numSliders = 5;
const defaultMultiplier = 1;
function createSliders() {
const slidersContainer = document.getElementById("sliders");
for (let i = 0; i < numSliders; i++) {
const sliderContainer = document.createElement("div");
sliderContainer.className = "slider-container";
const label = document.createElement("label");
label.textContent = `${(i / (numSliders - 1) * 2).toFixed(2)} zoom units/s`;
const slider = document.createElement("input");
slider.type = "range";
slider.min = "1";
slider.max = "10";
slider.step = "0.1";
slider.value = defaultMultiplier;
slider.className = "slider";
const value = document.createElement("span");
value.className = "value";
value.textContent = `${defaultMultiplier}x`;
sliderContainer.appendChild(label);
sliderContainer.appendChild(slider);
sliderContainer.appendChild(value);
slidersContainer.appendChild(sliderContainer);
slider.addEventListener("input", () => {
value.textContent = `${parseFloat(slider.value).toFixed(1)}x`;
saveSettings();
});
}
}
function saveSettings() {
const sliders = document.querySelectorAll(".slider");
const settings = Array.from(sliders).map((slider) => parseFloat(slider.value));
chrome.storage.sync.set({ accelerationCurve: settings }, () => {
sendSettingsToActiveTab(settings);
});
}
function sendSettingsToActiveTab(settings) {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) {
chrome.tabs.sendMessage(
tabs[0].id,
{ action: "updateSettings", settings },
(response) => {
if (chrome.runtime.lastError) {
console.log("Could not send settings to content script.");
}
}
);
}
});
}
function loadSettings() {
chrome.storage.sync.get("accelerationCurve", (data) => {
if (data.accelerationCurve) {
const sliders = document.querySelectorAll(".slider");
data.accelerationCurve.forEach((value, index) => {
sliders[index].value = value;
sliders[index].nextElementSibling.textContent = `${value.toFixed(1)}x`;
});
}
});
}
createSliders();
loadSettings();