马黑黑 发表于 2024-4-10 13:58

9块9包邮的canvas放大镜

本帖最后由 马黑黑 于 2024-4-10 14:23 编辑 <br /><br /><style>
        .outer { left: calc(50% - 81px); transform: translate(-50%, 0); width: fit-content; height: fit-content; text-align: center; background: lightblue;position: relative; z-index: 1; }
        .canv { display: block; cursor: crosshair; }
        .canv:nth-of-type(2) { position: absolute; pointer-events: none; border-radius: 50%; }
        .tb input { margin-left: 10px; }
</style>

<div class="outer">
        <canvas class="canv"></canvas>
        <canvas class="canv" width="150" height="150"></canvas>
        <p class="tb">
                <label for="URI">图片:</label>
                <input id="URI" type="text" size="100" value="" placeholder="请输入图片地址" />
                <input id="btnOkey" type="button" value="中" />
        </p>
</div>

<script type="text/javascript">

var beShown = false, mTimer;
var canvs = document.querySelectorAll('.canv');
var size = {w: 300, h: 150}, msize = {w: canvs.width, h: canvs.height};
var ctx1 = canvs.getContext('2d'), ctx2 = canvs.getContext('2d');

var loadImage = (url) => {
        var promise = new Promise((resolve, reject) => {
                var img = new Image();
                img.onload = () => {
                        var ele = img;
                        resolve(ele);
                };
                img.onerror = (err) => {
                        reject(err);
                };
                img.src = url;
        });
        return promise;
};

var update = (pic) => {
        loadImage(pic).then(e => {
                size.w = e.width;
                size.h = e.height;
                canvs.width = size.w / 2;
                canvs.height = size.h / 2;
                ctx1.clearRect(0, 0, size.w / 2, size.h / 2);
                ctx1.drawImage(e, 0, 0, size.w / 2, size.h / 2);
        }).catch(e => {
                ctx1.save();
                ctx1.font = 'bold 40px sans-serif';
                ctx1.textBaseline = 'middle';
                ctx1.textAlign = 'center';
                ctx1.globalCompositeOperation = 'xor';
                ctx1.fillText('图片加载失败', size.w / 4, size.h / 4);
                ctx1.restore();
        });
};

canvs.onmousemove = (e) => {
        clearTimeout(mTimer);
        var x = e.offsetX, y = e.offsetY;
        if(x - 25 < 0) x = 25;
        if(size.w - x < 25) x = size.w - 25;
        if(y - 25 < 0) y = 25;
        if(size.h - y < 25) y = size.h - 25;
        canvs.style.left = x - msize.w / 2 + 'px';
        canvs.style.top = y - msize.h / 2 + 'px';
        ctx2.clearRect(0, 0, msize.w, msize.h);
        ctx2.drawImage(canvs, x - 25, y - 25, 50, 50, 0, 0, msize.w, msize.h);
        mTimer = setTimeout('ctx2.clearRect(0, 0, msize.w, msize.h)', 3000);
};

canvs.onmouseout = () => ctx2.clearRect(0, 0, msize.w, msize.h);

btnOkey.onclick = () => {
        if(URI.value) update(URI.value.trim());
}

URI.onclick = () => URI.select();

URI.onkeydown = (e) => {
        e = window.event || e;
        var code = e.keyCode || e.which || e.charCode;
        if(code === 13) btnOkey.click();
};

var pic = 'https://638183.freep.cn/638183/t24/webp/magnifier.webp';

update(pic);

</script>

马黑黑 发表于 2024-4-10 14:01

本帖最后由 马黑黑 于 2024-4-10 14:03 编辑 <br /><br /><style>
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); box-shadow: 2px 2px 4px gray; border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>

<p>一楼,图片会被缩小一半显示。以下提供的代码则是按图片原始尺寸显示,可将代码存为本地HTML文档测试:<br><br></p>
<div class='mum'>
<cl-cd data-idx="1">&lt;!DOCTYPE html&gt;</cl-cd>
<cl-cd data-idx="2">&lt;<span class="tDarkRed">html</span> lang=<span class="tMagenta">"en"</span> xmlns=<span class="tMagenta">"http://www.w3.org/1999/xhtml"</span>&gt;</cl-cd>
<cl-cd data-idx="3">&lt;<span class="tDarkRed">head</span>&gt;</cl-cd>
<cl-cd data-idx="4">&nbsp; &nbsp; &lt;<span class="tDarkRed">meta</span> charset=<span class="tMagenta">"utf-8"</span> /&gt;</cl-cd>
<cl-cd data-idx="5">&nbsp; &nbsp; &lt;<span class="tDarkRed">title</span>&gt;放大镜&lt;<span class="tDarkRed">/title</span>&gt;</cl-cd>
<cl-cd data-idx="6">&nbsp; &nbsp; &lt;<span class="tDarkRed">meta</span> name=<span class="tMagenta">"author"</span> content=<span class="tMagenta">""</span> /&gt;</cl-cd>
<cl-cd data-idx="7">&nbsp; &nbsp; &lt;<span class="tDarkRed">meta</span> name=<span class="tMagenta">"keywords"</span> content=<span class="tMagenta">""</span> /&gt;</cl-cd>
<cl-cd data-idx="8">&nbsp; &nbsp; &lt;<span class="tDarkRed">meta</span> name=<span class="tMagenta">"description"</span> content=<span class="tMagenta">""</span> /&gt;</cl-cd>
<cl-cd data-idx="9">&nbsp; &nbsp; &lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="10">&nbsp; &nbsp; &nbsp; &nbsp; #wrapper { <span class="tBlue">margin:</span> 20px auto; <span class="tBlue">width:</span> fit-content; <span class="tBlue">height:</span> fit-content; <span class="tBlue">position:</span> relative; }</cl-cd>
<cl-cd data-idx="11">&nbsp; &nbsp; &nbsp; &nbsp; #canv { <span class="tBlue">position:</span> absolute; <span class="tBlue">transform:</span> scale(<span class="tBlue">var</span>(--size)); <span class="tBlue">border-radius:</span> 50%; <span class="tBlue">pointer-events:</span> none; <span class="tBlue">--size:</span> 1; }</cl-cd>
<cl-cd data-idx="12">&nbsp; &nbsp; &lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="13">&lt;<span class="tDarkRed">/head</span>&gt;</cl-cd>
<cl-cd data-idx="14">&lt;<span class="tDarkRed">body</span>&gt;</cl-cd>
<cl-cd data-idx="15">&nbsp;</cl-cd>
<cl-cd data-idx="16">&lt;<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"wrapper"</span>&gt;</cl-cd>
<cl-cd data-idx="17">&nbsp; &nbsp; &lt;<span class="tDarkRed">img</span> <span class="tRed">id</span>=<span class="tMagenta">"img1"</span> src=<span class="tMagenta">"https://img.zcool.cn/community/01e8bf5c00a77aa801209252bda875.jpg@1280w_1l_2o_100sh.jpg"</span> alt=<span class="tMagenta">""</span> /&gt;</cl-cd>
<cl-cd data-idx="18">&nbsp; &nbsp; &lt;<span class="tDarkRed">canvas</span> <span class="tRed">id</span>=<span class="tMagenta">"canv"</span> width=<span class="tMagenta">"200"</span> height=<span class="tMagenta">"200"</span>&gt;&lt;<span class="tDarkRed">/canvas</span>&gt;</cl-cd>
<cl-cd data-idx="19">&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
<cl-cd data-idx="20">&nbsp;</cl-cd>
<cl-cd data-idx="21">&lt;<span class="tDarkRed">script</span> type=<span class="tMagenta">"text/javascript"</span>&gt;</cl-cd>
<cl-cd data-idx="22">&nbsp;</cl-cd>
<cl-cd data-idx="23"><span class="tBlue">let</span> ww, hh, beShown = false, mTimer;</cl-cd>
<cl-cd data-idx="24"><span class="tBlue">let</span> ctx = canv.getContext(<span class="tMagenta">'2d'</span>);</cl-cd>
<cl-cd data-idx="25">&nbsp;</cl-cd>
<cl-cd data-idx="26"><span class="tBlue">let</span> getSize = (img) =&gt; {</cl-cd>
<cl-cd data-idx="27">&nbsp; &nbsp; ww = img.width;</cl-cd>
<cl-cd data-idx="28">&nbsp; &nbsp; hh = img.height;</cl-cd>
<cl-cd data-idx="29">};</cl-cd>
<cl-cd data-idx="30">&nbsp;</cl-cd>
<cl-cd data-idx="31">img1.onload = (callback) =&gt; getSize(img1);</cl-cd>
<cl-cd data-idx="32">&nbsp;</cl-cd>
<cl-cd data-idx="33">img1.onmousemove = (e) =&gt; {</cl-cd>
<cl-cd data-idx="34">&nbsp; &nbsp; clearTimeout(mTimer);</cl-cd>
<cl-cd data-idx="35">&nbsp; &nbsp; img1.style.cursor = <span class="tMagenta">'crosshair'</span>;</cl-cd>
<cl-cd data-idx="36">&nbsp; &nbsp; <span class="tBlue">let</span> x = e.offsetX, y = e.offsetY;</cl-cd>
<cl-cd data-idx="37">&nbsp; &nbsp; <span class="tBlue">if</span>(x - 25 &lt; 0) x = 25;</cl-cd>
<cl-cd data-idx="38">&nbsp; &nbsp; <span class="tBlue">if</span>(ww - x &lt; 25) x = ww - 25;</cl-cd>
<cl-cd data-idx="39">&nbsp; &nbsp; <span class="tBlue">if</span>(y - 25 &lt; 0) y = 25;</cl-cd>
<cl-cd data-idx="40">&nbsp; &nbsp; <span class="tBlue">if</span>(hh - y &lt; 25) y = hh - 25;</cl-cd>
<cl-cd data-idx="41">&nbsp; &nbsp; canv.style.left = x - 100 + <span class="tMagenta">'px'</span>;</cl-cd>
<cl-cd data-idx="42">&nbsp; &nbsp; canv.style.top = y - 100 + <span class="tMagenta">'px'</span>;</cl-cd>
<cl-cd data-idx="43">&nbsp; &nbsp; ctx.clearRect(0, 0, 200, 200);</cl-cd>
<cl-cd data-idx="44">&nbsp; &nbsp; ctx.drawImage(img1, x - 25, y - 25, 50, 50, 0, 0, 200, 200);</cl-cd>
<cl-cd data-idx="45">&nbsp; &nbsp; mTimer = setTimeout(<span class="tMagenta">'ctx.clearRect(0, 0, 200, 200)'</span>, 1000);</cl-cd>
<cl-cd data-idx="46">};</cl-cd>
<cl-cd data-idx="47">&nbsp;</cl-cd>
<cl-cd data-idx="48">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
<cl-cd data-idx="49">&nbsp;</cl-cd>
<cl-cd data-idx="50">&lt;<span class="tDarkRed">/body</span>&gt;</cl-cd>
<cl-cd data-idx="51">&lt;<span class="tDarkRed">/html</span>&gt;</cl-cd>
</div>

马黑黑 发表于 2024-4-10 14:09

一楼放大三倍,二楼的代码放大放大四倍。

二楼代码,CSS变量 --size 为 1,表示以 canvas 画布的实际尺寸即 200*200 渲染,画布则将图片鼠标指针所在的 50*50 区域方法,所以是 4 倍。画布以像素为单位操作图像,放大效果会失真。

一楼的实现机制和二楼的代码的实现机制不同,它有两个画布,一个显示图片,一个显示放大的图片区域。

庶民 发表于 2024-4-10 17:35

路过,就点赞。

马黑黑 发表于 2024-4-10 17:57

庶民 发表于 2024-4-10 17:35
路过,就点赞。

谢谢

红影 发表于 2024-4-10 18:50

可以放大很多呢,这个代码真神奇{:4_187:}

南无月 发表于 2024-4-10 19:01

放大发丝,衣服上的花纹,还有眼睛鼻子等试了一下,蓝眼睛的最有冲击力{:4_170:}

红影 发表于 2024-4-10 19:05

把楼层二的图片地址输进去,一下子变很小了。原来楼层一的原始图片那么大{:4_173:}

红影 发表于 2024-4-10 19:05

这个标题有趣,还是包邮的放大镜{:4_173:}

南无月 发表于 2024-4-10 19:09

换成《家乡的绿》的图片,试了一下。。
二者有点相通之处。。

马黑黑 发表于 2024-4-10 19:10

南无月 发表于 2024-4-10 19:09
换成《家乡的绿》的图片,试了一下。。
二者有点相通之处。。

在效果上有形似之处,不过完全不是一个机制

马黑黑 发表于 2024-4-10 19:11

红影 发表于 2024-4-10 19:05
这个标题有趣,还是包邮的放大镜

就是效果差一点哈

马黑黑 发表于 2024-4-10 19:11

红影 发表于 2024-4-10 19:05
把楼层二的图片地址输进去,一下子变很小了。原来楼层一的原始图片那么大

有说明的,一楼的图片原始尺寸会压缩50%

马黑黑 发表于 2024-4-10 19:12

南无月 发表于 2024-4-10 19:01
放大发丝,衣服上的花纹,还有眼睛鼻子等试了一下,蓝眼睛的最有冲击力

这个放大还是有点失真的

马黑黑 发表于 2024-4-10 19:13

红影 发表于 2024-4-10 18:50
可以放大很多呢,这个代码真神奇

canvas画布的drawImage方法的功劳。可惜它基于像素,放大后多少失真

南无月 发表于 2024-4-10 19:15

马黑黑 发表于 2024-4-10 19:10
在效果上有形似之处,不过完全不是一个机制

{:4_170:}
好哒,不同机制可以实现相似效果,这两个贴子一起投放还是挺好的呀

马黑黑 发表于 2024-4-10 19:15

南无月 发表于 2024-4-10 19:15
好哒,不同机制可以实现相似效果,这两个贴子一起投放还是挺好的呀

好玩吧

南无月 发表于 2024-4-10 19:16

马黑黑 发表于 2024-4-10 19:12
这个放大还是有点失真的

放大一般都会失真。。
无损放大PS好像不容易~~
代码放大同理。。应该也不容易

马黑黑 发表于 2024-4-10 19:17

南无月 发表于 2024-4-10 19:16
放大一般都会失真。。
无损放大PS好像不容易~~
代码放大同理。。应该也不容易

svg可以

南无月 发表于 2024-4-10 19:33

马黑黑 发表于 2024-4-10 19:15
好玩吧

前后脚放~~我是没想到机制完全不同。。。
能互动的效果都挺好玩的。。{:4_170:}
页: [1] 2 3 4 5 6 7
查看完整版本: 9块9包邮的canvas放大镜