您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在Instagram上悬停在图像上时添加一个圆形缩放镜头,支持平移和通过鼠标滚动调整缩放。
// ==UserScript== // @name IG Zoom Lens // @name:pt-BR IG Zoom Lens // @name:zh-CN IG Zoom Lens // @name:zh-TW IG Zoom Lens // @name:en IG Zoom Lens // @name:es IG Zoom Lens // @name:ja IG Zoom Lens // @name:ko IG Zoom Lens // @name:de IG Zoom Lens // @name:fr IG Zoom Lens // @namespace http://github.com/0H4S // @version 1.0 // @description Adds a circular zoom lens when hovering over images on Instagram, with panning support and zoom adjustment via mouse scroll. // @description:pt-BR Adiciona uma lente de zoom circular ao passar o mouse sobre imagens no Instagram, com suporte a panning e ajuste de zoom via scroll do mouse. // @description:zh-CN 在Instagram上悬停在图像上时添加一个圆形缩放镜头,支持平移和通过鼠标滚动调整缩放。 // @description:zh-TW 在Instagram上懸停在圖像上時添加一個圓形縮放鏡頭,支持平移和通過鼠標滾動調整縮放。 // @description:en Adds a circular zoom lens when hovering over images on Instagram, with panning support and zoom adjustment via mouse scroll. // @description:es Añade una lente de zoom circular al pasar el ratón sobre las imágenes en Instagram, con soporte para paneo y ajuste de zoom mediante la rueda del ratón. // @description:ja Instagramの画像にマウスをホバーすると円形のズームレンズが追加され、パンニングサポートとマウススクロールによるズーム調整が可能になります。 // @description:ko 인스타그램 이미지 위에 마우스를 올리면 원형 줌 렌즈가 추가되며, 팬닝 지원 및 마우스 스크롤을 통한 줌 조정이 가능합니다. // @description:de Fügt eine kreisförmige Zoom-Linse hinzu, wenn Sie mit der Maus über Bilder auf Instagram fahren, mit Unterstützung für Panning und Zoom-Anpassung über das Mausrad. // @description:fr Ajoute une lentille de zoom circulaire lors du survol des images sur Instagram, avec prise en charge du panoramique et ajustement du zoom via la molette de la souris. // @author OHAS // @license CC-BY-NC-ND-4.0 // @copyright 2025 OHAS. All Rights Reserved. // @icon https://i.imgur.com/HH9zLZE.png // @match https://www.instagram.com/* // @require https://update.greasyfork.org/scripts/549920/Script%20Notifier.js // @connect gist.githubusercontent.com // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // @compatible chrome // @compatible firefox // @compatible edge // ==/UserScript== (function() { 'use strict'; if (window.top !== window.self) { return; } const SCRIPT_CONFIG = { notificationsUrl: 'https://gist.githubusercontent.com/0H4S/aa1f90cc844db6c516379befd9ff354c/raw/ig_zoom_lens_notifications.json', scriptVersion: '1.0', }; const notifier = new ScriptNotifier(SCRIPT_CONFIG); notifier.run(); const DEFAULT_LENS_SIZE = 200; const MIN_LENS_SIZE = 100; const MAX_LENS_SIZE = 500; const LENS_SIZE_STEP = 20; const LENS_STORAGE_KEY = 'LensSize'; const MIN_ZOOM = 3; const MAX_ZOOM = 30; const ZOOM_STEP = 0.5; const ZOOM_STORAGE_KEY = 'ZoomLevel'; let currentLensSize = GM_getValue(LENS_STORAGE_KEY, DEFAULT_LENS_SIZE); let currentZoomLevel = GM_getValue(ZOOM_STORAGE_KEY, MIN_ZOOM); let currentImage = null; let isZoomActive = false; let isPanning = false; let panStartClientX = 0; let panStartClientY = 0; let initialBgPosX = 0; let initialBgPosY = 0; let lastMouseEvent = null; function addCursorStyles() { const style = document.createElement('style'); style.textContent = ` .ig-zoom-active-image { cursor: none !important; } `; document.head.appendChild(style); } addCursorStyles(); function createZoomLens() { const lens = document.createElement('div'); lens.id = 'ig-zoom-lens'; lens.style.position = 'fixed'; lens.style.width = `${currentLensSize}px`; lens.style.height = `${currentLensSize}px`; lens.style.borderRadius = '50%'; lens.style.border = '3px solid white'; lens.style.boxShadow = '0 0 0 1px rgba(0,0,0,0.15), 0 4px 15px rgba(0,0,0,0.3)'; lens.style.pointerEvents = 'none'; lens.style.zIndex = '9999'; lens.style.overflow = 'hidden'; lens.style.transition = 'opacity 0.25s, transform 0.25s, border-color 0.15s linear'; lens.style.backgroundRepeat = 'no-repeat'; lens.style.backgroundSize = `${currentZoomLevel * 100}%`; lens.style.display = 'none'; document.body.appendChild(lens); return lens; } const zoomLens = createZoomLens(); function updateLensSize() { if (!zoomLens) return; zoomLens.style.width = `${currentLensSize}px`; zoomLens.style.height = `${currentLensSize}px`; if (isZoomActive && lastMouseEvent && currentImage) { updateZoomPosition(lastMouseEvent, currentImage); } } function provideVisualFeedback() { zoomLens.style.display = 'block'; zoomLens.style.borderColor = '#3897f0'; setTimeout(() => { zoomLens.style.borderColor = isPanning ? '#ff2323ff' : 'white'; if (!isZoomActive) { zoomLens.style.display = 'none'; } }, 200); } function increaseLensSize() { currentLensSize = Math.min(MAX_LENS_SIZE, currentLensSize + LENS_SIZE_STEP); GM_setValue(LENS_STORAGE_KEY, currentLensSize); updateLensSize(); provideVisualFeedback(); } function decreaseLensSize() { currentLensSize = Math.max(MIN_LENS_SIZE, currentLensSize - LENS_SIZE_STEP); GM_setValue(LENS_STORAGE_KEY, currentLensSize); updateLensSize(); provideVisualFeedback(); } function resetLensSize() { currentLensSize = DEFAULT_LENS_SIZE; GM_setValue(LENS_STORAGE_KEY, currentLensSize); updateLensSize(); provideVisualFeedback(); } document.addEventListener('keydown', function(e) { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) { return; } if (e.key === '+' || e.key === '=') { e.preventDefault(); increaseLensSize(); } else if (e.key === '-') { e.preventDefault(); decreaseLensSize(); } else if (e.key === '0') { e.preventDefault(); resetLensSize(); } }); function getHighResImageSrc(img) { if (img.srcset) { const sources = img.srcset.split(',').map(s => { const parts = s.trim().split(' '); return { url: parts[0], width: parseInt(parts[1]) || 0 }; }); sources.sort((a, b) => b.width - a.width); if (sources.length > 0 && sources[0].url) return sources[0].url; } return img.src; } function hideZoom() { if (!isZoomActive) return; isZoomActive = false; isPanning = false; if (currentImage) { currentImage.classList.remove('ig-zoom-active-image'); } currentImage = null; zoomLens.style.borderColor = 'white'; zoomLens.style.opacity = '0'; zoomLens.style.transform = 'scale(0.8)'; setTimeout(() => { if (!isZoomActive) { zoomLens.style.display = 'none'; } }, 250); } function showZoom(img, e) { if (isZoomActive && currentImage === img) return; const src = getHighResImageSrc(img); if (!src || src.includes('profile_pic')) return; currentImage = img; isZoomActive = true; img.classList.add('ig-zoom-active-image'); zoomLens.style.backgroundImage = `url(${src})`; zoomLens.style.backgroundSize = `${currentZoomLevel * 100}%`; zoomLens.style.display = 'block'; setTimeout(() => { if (isZoomActive) { zoomLens.style.opacity = '1'; zoomLens.style.transform = 'scale(1)'; } }, 10); updateZoomPosition(e, img); } function updateZoomPosition(e, img) { if (!isZoomActive || currentImage !== img) return; lastMouseEvent = e; if (isPanning) { const deltaX = e.clientX - panStartClientX; const deltaY = e.clientY - panStartClientY; const deltaPercentX = (deltaX / currentLensSize) * 50; const deltaPercentY = (deltaY / currentLensSize) * 50; const newBgPosX = initialBgPosX + deltaPercentX; const newBgPosY = initialBgPosY + deltaPercentY; zoomLens.style.backgroundPosition = `${newBgPosX}% ${newBgPosY}%`; return; } const rect = img.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; if (x < 0 || y < 0 || x > rect.width || y > rect.height) { hideZoom(); return; } const xPercent = (x / rect.width) * 100; const yPercent = (y / rect.height) * 100; zoomLens.style.left = `${e.clientX - currentLensSize / 2}px`; zoomLens.style.top = `${e.clientY - currentLensSize / 2}px`; zoomLens.style.backgroundPosition = `${xPercent}% ${yPercent}%`; } function applyZoomEffect(img) { if (img.dataset.zoomApplied) return; img.dataset.zoomApplied = 'true'; img.addEventListener('mouseenter', function(e) { showZoom(img, e); }); img.addEventListener('mousemove', function(e) { updateZoomPosition(e, img); }); img.addEventListener('mouseleave', function() { if (!isPanning) { hideZoom(); } }); img.addEventListener('mousedown', function(e) { if (e.button === 0 && isZoomActive) { e.preventDefault(); isPanning = true; zoomLens.style.transition = 'none'; zoomLens.style.borderColor = '#ff2323ff'; panStartClientX = e.clientX; panStartClientY = e.clientY; const bgPos = zoomLens.style.backgroundPosition.split(' '); initialBgPosX = parseFloat(bgPos[0]) || 0; initialBgPosY = parseFloat(bgPos[1]) || 0; } }); img.addEventListener('wheel', function(e) { if (!isZoomActive) return; e.preventDefault(); const delta = e.deltaY < 0 ? ZOOM_STEP : -ZOOM_STEP; const newZoomLevel = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, currentZoomLevel + delta)); if (newZoomLevel !== currentZoomLevel) { currentZoomLevel = newZoomLevel; GM_setValue(ZOOM_STORAGE_KEY, currentZoomLevel); zoomLens.style.backgroundSize = `${currentZoomLevel * 100}%`; if (!isPanning) { updateZoomPosition(e, img); } } }); } document.addEventListener('mouseup', function() { if (isPanning) { isPanning = false; zoomLens.style.transition = 'opacity 0.25s, transform 0.25s, border-color 0.15s linear'; zoomLens.style.borderColor = 'white'; } }); function isOverNavigationButton(element) { if (!element) return false; let current = element; while (current && current !== document.body) { if (current.classList.contains('_afxw') || current.classList.contains('_afxv')) { return true; } current = current.parentElement; } return false; } document.addEventListener('mousemove', function(e) { lastMouseEvent = e; if (isPanning && currentImage) { updateZoomPosition(e, currentImage); return; } if (isOverNavigationButton(e.target) && isZoomActive) { hideZoom(); return; } if (!e.target.closest('img') && isZoomActive) { hideZoom(); } }); function applyToAllImages() { const images = document.querySelectorAll('img.x5yr21d:not([src*="profile_pic"]):not([src*="s150x150"]):not([data-zoom-applied])'); images.forEach(img => { if (img.offsetWidth > 150 || img.offsetHeight > 150) { applyZoomEffect(img); } else { img.onload = () => { if (img.offsetWidth > 150 || img.offsetHeight > 150) { applyZoomEffect(img); } }; } }); } setTimeout(applyToAllImages, 1000); const observer = new MutationObserver(function(mutations) { let shouldReapply = false; mutations.forEach(mutation => { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches && node.matches('img.x5yr21d') || node.querySelector && node.querySelector('img.x5yr21d')) { shouldReapply = true; } } }); } if (mutation.type === 'attributes' && mutation.attributeName === 'src' && mutation.target.matches('img.x5yr21d')) { mutation.target.removeAttribute('data-zoom-applied'); shouldReapply = true; } }); if (shouldReapply) { setTimeout(applyToAllImages, 100); } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src'], characterData: false }); })();