RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1532227
Accepted
WTFisGoingOn
WTFisGoingOn
Asked:2023-07-24 18:18:20 +0000 UTC2023-07-24 18:18:20 +0000 UTC 2023-07-24 18:18:20 +0000 UTC

如何为Canvas制作放大镜?

  • 772

任务是制作一个“屏幕放大镜”的类似物,以便在画布上使用它,您可以在画布上绘图。

保存的点是预先从数据库中加载的,并且需要增加它们。我对 Js 不是很强,所以我开始寻找现成的解决方案,但我发现只有使用图像、文本或画布中加载的静态图像的选项。

您能告诉我如何实施吗?

我想实现这样的目标,同时不使用图像,而仅使用预加载的点(它们是动态的)。
代码片段不是我的,取自codepen。

class Experience {
    constructor(container) {
        this.canvas = document.createElement("canvas");
        container.appendChild(this.canvas);
        this.context = this.canvas.getContext("2d");

        const fps = 60;//60
        this.fpsInterval = 1000 / fps;
        this.then = Date.now();
        
        this.point = { x: 0, y: 0 };
    this.distPoint = { x: 0, y: 0 };
    this.pos = { x: 0, y: 0 };

        this.resize();
        this.bind();
        
        this.image = new Image();
    this.image.src = "https://robindelaporte.fr/codepen/slide.jpg";
        
        this.image.onload = () => {
      this.loop();
        };
    }

    bind() {
        window.addEventListener("resize", this.resize.bind(this), false);
        
        this.canvas.addEventListener("mousemove", this.onMouseMove.bind(this));
        
        this.canvas.addEventListener("touchmove", this.onTouchMove.bind(this));

    }

    render() {
        this.clear();
        // this.context.save()
          this.context.drawImage(this.image, 0, 0, this.canvas.width, this.canvas.height);
        
        this.pos.x += (this.point.x - this.pos.x) * 0.2;
    this.pos.y += (this.point.y - this.pos.y) * 0.2;

    this.context.save();
    this.context.beginPath();
    this.context.arc(this.pos.x, this.pos.y, this.canvas.height * 0.15, 0, Math.PI * 2, true);
    this.context.strokeStyle = "white";
    this.context.lineWidth = 6;
    // this.context.globalCompositeOperation = "screen";
    this.context.stroke();
    this.context.closePath();
    this.context.clip();
        
        this.context.drawImage(
      this.image,
      -this.canvas.width * 0.2 +
        (this.canvas.width - this.canvas.width * 1.4) * (this.distPoint.x * 1), //0.05,
      -this.canvas.height * 0.2 +
        (this.canvas.height - this.canvas.height * 1.4) * (this.distPoint.y * 1), //0.05,
      this.canvas.width * 1.4,
      this.canvas.height * 1.4
    );
    // this.context.opacity = 1;

    this.context.restore();

    }

    loop() {
        this.raf = window.requestAnimationFrame(this.loop.bind(this));

        const now = Date.now();
        const delta = now - this.then;

        if (delta > this.fpsInterval) {
            // this.context.clearRect( 0, 0, this.canvas.width, this.canvas.height )
            this.render();
            this.then = now;
        }
    }
    
    onMouseMove(ev){
        var rect = this.canvas.getBoundingClientRect();
        this.point = {
      x:
        (ev.clientX - 7) - rect.left,
      y: (ev.clientY - 7) - rect.top
    };

    this.distPoint = {
      x: (this.point.x - this.canvas.width * 0.5) / this.canvas.width,
      y: (this.point.y - this.canvas.height * 0.5) / this.canvas.height
    };  
    }
    
    onTouchMove(ev){
        var rect = this.canvas.getBoundingClientRect();
        this.point = {
      x:
        ev.touches[0].clientX - rect.left,
      y: ev.touches[0].clientY - rect.top
    };

    this.distPoint = {
      x: (this.point.x - this.canvas.width * 0.5) / this.canvas.width,
      y: (this.point.y - this.canvas.height * 0.5) / this.canvas.height
    };  
    }

    resize() {
        this.canvas.width = window.innerWidth * 0.7;
        this.canvas.height = window.innerWidth * 0.7 / 1.77;
        this.screen = {
            center: { x: this.canvas.width / 2, y: this.canvas.height / 2 }
        };

        //this.reset();
    }
    
    clear(){
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    }

    reset() {
        window.cancelAnimationFrame(this.raf);
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.loop();
    }
}

const experience = new Experience(document.body);
body {
    width: 100vw;
    height: 100vh;
    background: #fff;
    margin: 0;
    padding: 0;
    position: relative;
    overflow: hidden;
}

canvas {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border: 7px solid rgba(255, 255, 255, .1);
  box-shadow: 0px 0px 10px #00000038;
    cursor: pointer;
    box-sizing: border-box;
}

.info {
    position: absolute;
    bottom: 1rem;
    left: 0;
    font-family: monospace;
    width: 100%;
    text-align: center;
    font-size: 1rem;
}

在为我的任务编辑此代码时,我遇到了一个问题,此代码在画布本身上绘制放大镜并再次绘制图像,这不太适合数据库中的动态点(它们闪烁)

javascript
  • 1 1 个回答
  • 43 Views

1 个回答

  • Voted
  1. Best Answer
    gord1402
    2023-07-24T23:13:39Z2023-07-24T23:13:39Z

    您可以使用第二个画布来放大:

    var main = document.getElementById("main");
    var zoom = document.getElementById("zoom");
    
    // разрешения canvas
    var scale = 1;
    
    main.style.width = main.width + 'px';
    main.style.height = main.height + 'px';
    main.width = main.width * scale;
    main.height = main.height * scale;
    
    var ctx = main.getContext("2d")
    var zoomCtx = zoom.getContext("2d");
    ctx.lineWidth = 1;
    
    // Тут можно рисовать что угодно
    ctx.fillRect(25 * scale, 25 * scale, 100 * scale, 100 * scale);
    ctx.clearRect(45 * scale, 45 * scale, 60 * scale, 60 * scale);
    ctx.strokeRect(50 * scale, 50 * scale, 50 * scale, 50 * scale);
    
    
    main.addEventListener("pointermove", function(e) {
      zoomCtx.beginPath();
      zoomCtx.arc(50, 50, 30, Math.PI * 2, false);
      zoomCtx.strokeStyle = "white";
      zoomCtx.lineWidth = 6;
      zoomCtx.stroke();
      zoomCtx.closePath();
      zoomCtx.clip();
    
      zoomCtx.fillStyle = "white";
      zoomCtx.fillRect(0, 0, zoom.width, zoom.height);
      zoomCtx.imageSmoothingEnabled = false;
      zoomCtx.drawImage(main,
        (e.x - 25 + document.scrollingElement.scrollLeft) * scale,
        (e.y - 25 + document.scrollingElement.scrollTop) * scale,
        10 * scale, 10 * scale, 20, 20, 80, 80);
    
    
      zoom.style.top = (e.pageY - 50) + "px"
      zoom.style.left = (e.pageX - 50) + "px"
      zoom.style.display = "block";
    });
    
    main.addEventListener("pointerout", function() {
      zoom.style.display = "none";
    });
    body {
      background-color: red;
    }
    <canvas id="main" width="500" height="200"></canvas>
    <canvas id="zoom" width="100" height="100" style="position:absolute; top:0; left:0;pointer-events: none; display:none"></canvas>

    UPD
    为了避免模糊画布分辨率增加

    • 4

相关问题

  • 第二个 Instagram 按钮的 CSS 属性

  • 由于模糊,内容不可见

  • 弹出队列。消息显示不正确

  • 是否可以在 for 循环中插入提示?

  • 如何将 JSON 请求中的信息输出到数据表 Vuetify vue.js?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5