// ==UserScript==
// @name 边读边看图
// @namespace http://tampermonkey.net/
// @version 0.3.1
// @description 图片预览:通过双击按键,把图片固定在页面上,边读文字边看图,同时支持缩放、移动功能
// @author Enjoy
// @icon https://foruda.gitee.com/avatar/1671100286067517749/4867929_enjoy_li_1671100285.png!avatar60
// @match *://*/*
// @exclude *hrwork*
// @exclude *zhaopinyun*
// @exclude *localhost*
// @exclude *127.0.0.1*
// @grant GM_addElement
// @grant GM_setClipboard
// @license GPL License
// ==/UserScript==
(()=>{// webpackBootstrap
/******/"use strict";// CONCATENATED MODULE: ./src/ImgPreview.js
// 函数文档 https://www.tampermonkey.net/documentation.php#api:GM_addElement
// @match *://mp.weixin.qq.com/s/*
!function(){!// CONCATENATED MODULE: ./tools/GM.js
// 函数文档 https://www.tampermonkey.net/documentation.php#api:GM_addElement
function(t,e){var o=document.createElement(t);for(const i in e)Object.hasOwnProperty.call(e,i)&&"el"!==i&&(o[i]=e[i]);let{el:s=document.documentElement}=e;(s="string"==typeof s?document.querySelector(s):s).appendChild(o)}("style",{innerHTML:".pages_skin_pc .rich_media_area_primary_inner{margin-left:initial;}",id:"img_preview_style"});class a{constructor(t,e,o){this.state=Object.assign({},this.state,this.mergeOptions(t,e,o));t=this.appendImg(o);return this.state.cloneEl=t,this.fixPosition(t),this.addEvents(t),t}state={scale:1,offset:{left:0,top:0},origin:"center",initialData:{offset:{},origin:"center",scale:1},startPoint:{x:0,y:0},
// 记录初始触摸点位
isTouching:!1,
// 标记是否正在移动
isMove:!1,
// 正在移动中,与点击做区别
touches:new Map,
// 触摸点数组
lastDistance:0,lastScale:1,
// 记录下最后的缩放值
scaleOrigin:{x:0,y:0}};mergeOptions(t,e,o){var{innerWidth:s,innerHeight:i}=window,{offsetWidth:n,offsetHeight:a}=e,{top:r,left:l}=e.getBoundingClientRect();return{shadowRoot:t,originalEl:e,src:o,winWidth:s,winHeight:i,offsetWidth:n,offsetHeight:a,top:r,left:l,maskContent:t.querySelector(".modal")}}
/** @描述 添加图片 */appendImg(t){var e=document.createElement("img");return e.src=t,this.state.maskContent.appendChild(e),e}
/** @描述 添加监听事件 */addEvents(e,t=["dblclick","mousewheel","pointerdown","pointerup","pointermove","pointercancel"]){let o=this;t.forEach(t=>{"mousewheel"===t?e.addEventListener("mousewheel",o["on"+t],{passive:!1}):e.addEventListener(t,o["on"+t])})}
/** @描述 双击事件 */ondblclick=t=>{t.preventDefault();let e=this,o=e.state;setTimeout(()=>{o.isMove?o.isMove=!1:(e.changeStyle(o.cloneEl,["transition: all .3s",`left: ${o.left}px`,`top: ${o.top}px`,"transform: translate(0,0)",`width: ${o.offsetWidth}px`]),setTimeout(()=>{o.maskContent.removeChild(o.cloneEl),
// originalEl.style.opacity = 1
o.cloneEl.removeEventListener("dblclick",e.ondblclick)},300))},280)}
/** @描述 指针按下事件*/;onpointerdown=t=>{t.preventDefault();var e=this.state;e.touches.set(t.pointerId,t),
// TODO: 点击存入触摸点
e.isTouching=!0,e.startPoint={x:t.clientX,y:t.clientY},2===e.touches.size&&(
// TODO: 判断双指触摸,并立即记录初始数据
e.lastDistance=this.getDistance(),e.lastScale=e.scale)}
/** @描述 滚轮缩放 */;onmousewheel=t=>{var e;t.preventDefault(),t.deltaY&&((e=this.state).origin=`${t.offsetX}px ${t.offsetY}px`,
// 缩放执行
t.deltaY<0?
// 放大
e.scale+=.1:0<t.deltaY&&.2<=e.scale&&(e.scale-=.1),e.scale<e.initialData.scale&&this.reduction(),e.offset=this.getOffsetPageCenter(t.offsetX,t.offsetY),this.changeStyle(e.cloneEl,["transition: all .15s","transform-origin: "+e.origin,`transform: translate(${e.offset.left+"px"}, ${e.offset.top+"px"}) scale(${e.scale})`]))}
/** @描述 获取中心改变的偏差 */;getOffsetPageCenter(t=0,e=0){var o=this.state,s=Array.from(o.touches),i=(2===s.length&&(i=s[0][1],s=s[1][1],t=(i.offsetX+s.offsetX)/2,e=(i.offsetY+s.offsetY)/2),o.origin=t+`px ${e}px`,(o.scale-1)*(t-o.scaleOrigin.x)+o.offset.left),s=(o.scale-1)*(e-o.scaleOrigin.y)+o.offset.top;return o.scaleOrigin={x:t,y:e},{left:i,top:s}}
/** @描述 获取距离*/getDistance(){var t,e=Array.from(this.state.touches);return e.length<2?0:(t=e[0][1],e=e[1][1],Math.hypot(e.x-t.x,e.y-t.y))}
/** @描述 修改样式,减少回流重绘*/changeStyle(t,e){var o=t.style.cssText.split(";");o.pop(),t.style.cssText=o.concat(e).join(";")+";"}
/** @描述 还原记录,用于边界处理 */reduction(){let t=this,e=t.state;t.timer&&clearTimeout(t.timer),t.timer=setTimeout(()=>{t.changeStyle(e.cloneEl,[`transform: translate(${e.offset.left+"px"}, ${e.offset.top+"px"}) scale(${e.scale})`,"transform-origin: "+e.origin])},300)}
/** @描述 松开指针 事件 */onpointerup=t=>{t.preventDefault();let e=this.state;e.touches.delete(t.pointerId),
// TODO: 抬起移除触摸点
e.touches.size<=0?e.isTouching=!1:(t=Array.from(e.touches),
// 更新点位
e.startPoint={x:t[0][1].clientX,y:t[0][1].clientY}),setTimeout(()=>{e.isMove=!1},300)}
/** @描述 指针移动事件 */;onpointermove=t=>{t.preventDefault();var e=this,o=e.state;o.isTouching&&(o.isMove=!0,o.touches.size<2?(
// 单指滑动
o.offset={left:o.offset.left+(t.clientX-o.startPoint.x),top:o.offset.top+(t.clientY-o.startPoint.y)},e.changeStyle(o.cloneEl,["transition: all 0s",`transform: translate(${o.offset.left+"px"}, ${o.offset.top+"px"}) scale(${o.scale})`,"transform-origin: "+origin]),
// 更新点位
o.startPoint={x:t.clientX,y:t.clientY}):(
// 双指缩放
o.touches.set(t.pointerId,t),t=e.getDistance()/o.lastDistance,o.scale=t*o.lastScale,o.offset=e.getOffsetPageCenter(),o.scale<o.initialData.scale&&e.reduction(),e.changeStyle(o.cloneEl,["transition: all 0s",`transform: translate(${o.offset.left+"px"}, ${o.offset.top+"px"}) scale(${o.scale})`,"transform-origin: "+o.origin])))}
/** @描述 取消指针事件 */;onpointercancel=t=>{t.preventDefault(),this.state.touches.clear()}
/** @描述 移动图片到屏幕中心位置 */;fixPosition(t){let e=this;var o=e.state
/** @描述 原图片 中心点 */;const s=o.offsetWidth/2+o.left
/** @描述 页面 中心点 */,i=o.offsetHeight/2+o.top,n=o.winWidth/2
/** @描述 新建图片的定位点:通过原图片中心点到页面中心点的 偏移量*/,a=o.winHeight/2,r={left:n-s+o.left,top:a-i+o.top}
/** @描述 放大后的 */;var l=this.adaptScale();const c={left:(l-1)*o.offsetWidth/2,top:(l-1)*o.offsetHeight/2};this.changeStyle(t,[`left: ${o.left}px`,`top: ${o.top}px`,"transition: all 0.3s","width: "+o.offsetWidth*l+"px",`transform: translate(${r.left-o.left-c.left}px, ${r.top-o.top-c.top}px)`])
/** @描述 消除偏差:让图片相对于window 0 0定位,通过translate设置中心点重合*/,setTimeout(()=>{e.changeStyle(t,["transition: all 0s","left: 0","top: 0",`transform: translate(${r.left-c.left}px, ${r.top-c.top}px)`]),e.state.offset={left:r.left-c.left,top:r.top-c.top},
// 记录值
e.record()},300)}
/** @描述 记录初始化数据 */record(){var t=this.state;t.initialData=Object.assign({},{offset:t.offset,origin:t.origin,scale:t.scale})}
/** @描述 计算自适应屏幕的缩放 */adaptScale(){var{winWidth:t,winHeight:e,originalEl:o}=this.state,{offsetWidth:o,offsetHeight:s}=o;let i=t/o;return i=s*i>e-80?(e-80)/s:i}}new class{constructor(t={}){return this.state=this.mergeOptions(t),this.shadowRoot=this.createShadowRoot(),this.onPreviwerEvent(),this.shadowRoot}
/** @描述 状态 */state=null;shadowRoot=null
/** @描述 创建 shadowRoot */;createShadowRoot(t="#imgPreview"){let e=document.querySelector(""+t);return e||((e=document.createElement("div")).setAttribute("id",t.replace(/[.#]/g,"")),e.setAttribute("style","width:0;height:0"),document.documentElement.appendChild(e)),e.shadowRoot||((t=document.createElement("div")).classList.add("modal"),t.appendChild(this.createStyle(this.state)),
// 添加在body下
e.attachShadow({mode:"open"}),e.shadowRoot.appendChild(t)),e.shadowRoot}
/** @描述 合并选项 */mergeOptions(t){var e={};return Object.assign(e,{contentSelector:"body",selector:"img",showRootSelector:"#img_preview",backgroundColor:"rgba(0,0,0,0)",extraStyle:""},t),e}
/** @描述 创建shadowbox中的样式 */createStyle({contentSelector:t,selector:e,backgroundColor:o,extraStyle:s}){var i=document.createElement("style");return i.innerHTML=t+` ${e} {
cursor: zoom-in;
}
/* 图片预览 */
.modal {
touch-action: none;
position: fixed;
z-index: 99;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: ${o};
user-select: none;
pointer-events: none;
}
.modal>*{
pointer-events: auto;
}
.modal>img {
position: absolute;
padding: 0;
margin: 0;
box-shadow: #09818f 0px 0px 15px 0px;
border-radius: 10px;
/* transition: all var(--delay_time); */
transform: translateZ(0);
}
img.active {
animation: activeImg 0.5s 4 ease-out forwards;
transition: all;
}
@keyframes activeImg {
0% {
box-shadow: #09818f 0px 0px 15px 0px;
}
50% {
box-shadow: red 0px 0px 50px 0px;
}
100% {
box-shadow: #09818f 0px 0px 15px 0px;
}
}
${s}
`,i}
/** @描述 预览操作 */onPreviwerEvent(){let s=this,{contentSelector:t,selector:i}=s.state,n=document.querySelector(t)||window.document.body;n.addEventListener("dblclick",function(e){let o=e.target.src||window.getComputedStyle(e.target).backgroundImage.match(/^url\("([^\s]+)"\)$/i)?.[1];if(o&&(e.preventDefault(),[...n.querySelectorAll(i)].find(t=>t===e.target))){let t=[...s.shadowRoot.querySelectorAll(i)].find(t=>t.src===o);if(t){if(!t.classList.contains("active"))return void t.classList.add("active");t.remove(),t=null}t||
// originalEl.style.opacity = 0
new a(s.shadowRoot,e.target,o)}})}}({backgroundColor:"rgba(0,0,0,0)"})}
/******/()})();