一个图片对比的小工具【小工具制作】

news2025/1/10 23:26:41

目录

  • 逐一击破
    • 确定架构
    • 图片上传
    • 自适应生成对比界面
    • 切换对比模式
    • 打分功能
    • 审核进行提交
    • 项目负责人查看问题并改正
  • 总结

前言:这是一个实际的需求,因为需要设计师给的原图和同学们制作出来的项目成品图进行比对打分,所以就有了一个图片对比的小工具。

需求分析:

  • 设计稿和成品图片上传功能
  • 自适应生成对比界面
  • 可切换对比模式
  • 打分功能
  • 打分者提交问题
  • 项目负责人查看问题并改正

逐一击破

确定架构

因为只是一个针对性的小工具,后期也不会扩展,不需要上框架,所以直接引入JQ库进行代码开发,为方便本地局域网使用,配置webpack作为启动项。

目录结构如下:

图片对比工具目录结构

图片上传

新建upload.js文件,通过构造函数把上传相关方法统一封装在原型上。

相关方法:

  • 初始化
  • 支持拖拽上传,点击上传
  • 适配监听
  • 边界判断

图片对比工具图片上传

自适应生成对比界面

在点击图片对比的时候,界面生成是根据第一张上传的设计稿的比例来确定的,这样就不会出现页面适配问题,部分代码:

// 上传图片
let dragImgUploadOne = new DragImgUpload("#drop_area_one", {
    callback: function (files, imgUrl) {
        // 屏幕高度
        let clientHeight = document.documentElement.clientHeight;
        // 屏幕宽度
        let clientWidth = document.documentElement.clientWidth;
        // 回调函数,可以传递给后台
        let file = files[0];
        let size = file.size / 1000 + 'kb';
        $('.img-name-one span').text(file.name);
        $('.img-size-one span').text(size);
        $('.bacnimg2').attr("src", imgUrl);
        
        // 创建对象
        var img = new Image();
        // 改变图片的src
        img.src = imgUrl;
        img.onload = function(){
            let imgHeigt = img.height / (img.width/clientWidth);
            let imgWidth = img.width / (img.height / clientHeight);
            upimgHeigt = imgHeigt
            upimgWidth = imgWidth
            // 如果计算出来的高度大于屏幕高度
            if(upimgHeigt > clientHeight){
                $('.banner-bg2,.bacnimg').css('width',upimgWidth + 'px')
                $('.banner-bg2,.bacnimg,.bacnimg2').css('height','100vh')
                // 分割边框
                $('.banner-bg2').css('border-right', '1px solid #000')

                // 适配线的位置
                let dragLine = upimgWidth / 2 - 42;
                $('.drag-line').css({'left': dragLine })
            }else{
                // 分割边框
                $('.banner-bg2').css('border-bottom', '1px solid #000')
                // 动态修改imgHeigt
                $('.banner-bg2,.bacnimg,.bacnimg2,.drag-line').css('height',upimgHeigt + 'px')
            }
        };
    }
})
let dragImgUploadTwo = new DragImgUpload("#drop_area_two", {
    callback: function (files, imgUrl) {
        //回调函数,可以传递给后台等等
        let file = files[0];
        let size = file.size / 1000 + 'kb'
        $('.img-name-two span').text(file.name)
        $('.img-size-two span').text(size)
        $('.bacnimg').attr("src", imgUrl);
    }
})

图片对比工具自适应生成对比界面

切换对比模式

对比支持横向对比和竖向对比,当然斜角对比也可以支持,但是没必要,部分代码:

// 图片对比拖拽逻辑
let $drag = $('#drag-line')
$drag.mousedown(function (e) {
    //鼠标按下,计算当前元素距离可视区的距离
    let disY = e.clientY - $drag[0].offsetTop;
    let disX = e.clientX - $drag[0].offsetLeft;
    // 判断对比方式
    if(comparison){
        document.onmousemove = function (e) {
            // 极限位置
            let imgHeight = $('.banner-bg2').height() - 50;
            // 通过事件委托,计算移动的距离
            let distanceTop = e.clientY - disY;

            if(distanceTop < imgHeight) $drag.css({'top': distanceTop + 'px'});
        };
    }else{
        document.onmousemove = function (e) {
            // 极限位置
            let imgWidth = $('.banner-bg2').width() - 50;
            // 通过事件委托,计算移动的距离
            let distanceLeft = e.clientX - disX;

            if(distanceLeft < imgWidth) $drag.css({'left': distanceLeft + 'px'});
        };
    }
    document.onmouseup = function (e) {
        document.onmousemove = null;
        document.onmouseup = null;
    };
    //return false不加的话可能导致黏连,就是拖到一个地方时div粘在鼠标上不下来,相当于onmouseup失效
    return false;
});

打分功能

用户点击成品图的某个位置,就会自动生成节点标签,在input标签中输入扣分项和说明,以便开发同学后期更改,部分代码:

// 扣分填写弹窗模板
function anchorPopup(obj = {}) {
    let imgAllWidth = $('.banner-bg2').width();
    let imgAllHeight = $('.banner-bg2').height();

    let objLeft = obj.left;
    let objTop = obj.top;

    let particularLeft = obj.left;
    let particularTop = obj.top;
    if (imgAllWidth - 220 < obj.left) {
        objLeft = obj.left - 230
        objTop = obj.top + 15

        // 计算生产模式打分文字位置
        particularLeft = obj.left - 165
        particularTop = obj.top
    }
    if (imgAllHeight - 200 < obj.top) {
        objTop = obj.top - 200

        // 计算生产模式打分文字位置
        particularTop = obj.top -100
    }
    // 生成扣分填写窗口,重复使用的
    $('.anchor-popup-content').html(`
        <div class="anchor-popup" style="top:${objTop + 8 + 'px'};left:${objLeft + 20 + 'px'};z-index: -1;">
            <p><span style = "color:#fff">扣分:</span><input type="text" class="fill-in"
                            maxlength="3"
                            placeholder = "扣除的分数"
                            name = "deductMarks"
                            autocomplete="off"
                            value = "${obj.deductMarks ? obj.deductMarks : ''}"
                    >
            </p>
            <p><span style = "color:#fff">评语:</span><input maxlength="30" placeholder="您的评价" autocomplete="off" name = "remark" value = "${obj.remark ? obj.remark : ''}" /></p>
            <div class="buttons">
                <button οnclick="confirmClick(${obj.myDataLength},${particularTop},${particularLeft})">确定</button>
                <button οnclick="cancelClick(${obj.myDataLength})">取消</button>
            </div>
            
        </div>`
    )
}

图片对比工具打分功能

审核进行提交

完成上述一系列操作了,我们就可以把结果推送到可视化平台了,部分代码:

// 使用html2canvas进行截图保存
html2canvas($('.banner-bg2'), {
    allowTaint: true,
    taintTest: false,
    onrendered: function (canvas) {
        var dataUrl = canvas.toDataURL();
        $("#img_pre").attr("src", dataUrl);
    }
});

// 前端
function submitUp(){
    // 扣分说明
    let scoreList = "";
    collectArray.forEach((value, index) => {
        scoreList +=
            `扣分项${index + 1} (扣${value.deductMarks}分) : ${value.remark}。\n`
    });
    var file=confirmData($('#img_pre').attr('src'));
    var data=new FormData();
    let authorStr = $('.img-name-two span').text();
    let author = authorStr.substring(0,authorStr.length - 4)
    data.append("author",author);
    data.append("reviewScreenshot",file);
    data.append("finalScore",$('.score-num').text() + '分');
    data.append("approvedMemo",scoreList);
    data.append("filename","t.png");
    
    $.ajax({
        url:'http://www.xxxx.com/api/imgGrade',
        type: 'post',
        data: data,
        contentType: false,
        // 告诉jQuery不要去设置Content-Type请求头
        processData: false,
        success: function (data) {
            if (data.code == 200) {
                $('.popup-post-content').hide()
                $('.popup-good').show()
            } else {
                alert("服务器返回错误!")
            }
        }
    })
}

// node
async function imgGrade(dataList,imgUrl) {
    let queryData = {
        "appKey":"xxx",
        "sign":"xxxx",
        "worksheetId":"xxxx",
        "controls":
            [
                // 作者名字
                {
                    "controlId": "author",
                    "value": dataList.author ? dataList.author : ''
                },
                // 审核截图
                {
                    "controlId": "reviewScreenshot",
                    // "value": 'https://www.xxxx.com/guide/image/homePage/banner/imagination-bg.jpg'
                    "value": imgUrl ? imgUrl : ''
                },
                // 最终得分
                {
                    "controlId": "finalScore",
                    "value": dataList.finalScore ? dataList.finalScore : ''
                },
                // 审核记录
                {
                    "controlId": "approvedMemo",
                    "value": dataList.approvedMemo ? dataList.approvedMemo : ''
                }
        ]
    }
    let options = {
        method: 'POST',
        uri: 'https://api.xxxx.com/v2/open/xxx/xxx',
        body: queryData,
        json: true
    };
    try {
        var data = await RequestAsync('post', options.uri, { json: options.body });
        var result = JSON.parse(data.getBody('utf8'));
        if (result.success) {
            return {
                code: 200
            }
        } else{
            return {
                code: 500,
                msg: result.error_msg
            }
        }    
    } catch (err) {
        console.log(err);
        return {
            code: 500,
            msg: error.message
        }
    }
}

图片对比工具审核进行提交

项目负责人查看问题并改正

到此,项目负责人就知道哪有问题,然后就去改正啦!

图片对比工具项目负责人查看问题并改正

总结

小工具的完成完成文章,这中间已经过去了一年多的时间了,现在想起来这个小工具都很有意思,以后有时间的话会把这个继续完善并且脱敏,做成一个真正的小工具,部署到线上,供各位看官使用。

水平有限,还不能写到尽善尽美,希望大家多多交流,跟春野一同进步!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用 Python 调用 GPT-3 API

用 Python 调用 GPT-3 API GPT-3 是去年由 Open AI 推出的语言机器学习模型。它因其能够写作、写歌、写诗&#xff0c;甚至写代码而获得了广泛的媒体关注&#xff01;该工具免费使用&#xff0c;只需要注册一个电子邮件即可。 GPT-3 是一种叫 transformer 的机器学习模型。具体…

C语言(输入printf()函数)

printf()的细节操作很多&#xff0c;对于现阶段的朋友来说&#xff0c;主要还是以理解为主。因为很多的确很难用到。 目录 一.转换说明&#xff08;占位符&#xff09; 二.printf()转换说明修饰符 1.数字 2.%数字1.数字2 3.整型转换字符补充 4.标记 -符号 符号 空格符…

JavaWEB必知必会-Servlet

目录 Servlet简介Servlet快速入门Servlet配置详解ServletContext 1 Servlet简介 Servlet 运行在服务端的Java小程序&#xff0c;是sun公司提供一套规范&#xff08;接口&#xff09;&#xff0c;用来处理客户端请求、响应给浏览器的动态资源。但servlet的实质就是java代码&a…

电脑里的连接速度双工模式是什么?怎么设置

双工模式包括全双工、半双工模式。1.半双工1、半双工数据传输允许数据在两个方向上传输&#xff0c;但是&#xff0c;在某一时刻&#xff0c;只允许数据在一个方向上传输&#xff0c;它实际上是一种切换方向的单工通信。所谓半双工就是指一个时间段内只有一个动作发生。早期的对…

十二、Linux文件 - fseek函数讲解

目录 一、fseek函数讲解 二、fseek函数实战 一、fseek函数讲解 重定向文件内部的指针 注&#xff1a;光标 ---- 文件内部的指针 函数原型&#xff1a; int fseek(FILE *stream,long offset,int framewhere) 参数&#xff1a; stream&#xff1a;文件指针offset&#xff1a;…

golang由浅入深

简介 Go语言&#xff08;Golang&#xff09;是由Google公司的Robert Griesemer、Rob Pike、Ken Thompson三位工程师开发的一种静态强类型、编译型、并发型、快速运行的编程语言。 Go语言诞生于2007年&#xff0c;旨在创造一种具有现代特性的编程语言&#xff0c;可以替代C和Jav…

DS期末复习卷(二)

选择题 1&#xff0e;下面关于线性表的叙述错误的是&#xff08; D &#xff09;。 (A) 线性表采用顺序存储必须占用一片连续的存储空间 (B) 线性表采用链式存储不必占用一片连续的存储空间 © 线性表采用链式存储便于插入和删除操作的实现 (D) 线性表采用顺序存储便于插…

2023春招100道软件测试高频面试题

给大家整理了2023春招的100道软件测试高频面试题&#xff0c;篇幅较长&#xff0c;所以只放出了题目&#xff0c;答案在文末&#xff0c;自行获取哦&#xff01; 1.项目测试流程你是怎么开展的&#xff1f; 2.接口测试用例的编写要点有哪些&#xff1f; 3.APP测试和Web测试有…

ubuntu20.04安装docker与docker-compose

安装docker 查看系统发行版本 cat /proc/version1、更新apt包 sudo apt-get update2、安装必备的软件包以允许apt通过 HTTPS 使用存储库&#xff08;repository&#xff09;&#xff1a; sudo apt-get install ca-certificates curl gnupg lsb-release3、添加Docker官方版本…

C语言学习笔记(一):了解C语言

什么是C语言 C语言是一种高级编程语言&#xff0c;最早由丹尼斯里奇在1972年开发。它是一种通用编程语言&#xff0c;提供了高级编程语言的方便和易用性&#xff0c;同时又有较低级别的编程语言的灵活性和效率。C语言在许多操作系统、编译器和应用程序开发中广泛使用&#xff…

使用Naticat同步数据库结构

现象&#xff1a; 开发环境对数据库结构进行了修改&#xff0c;如何同步到测试环境 例: 开发环境&#xff08;dev&#xff09;&#xff1a;my_test_data 测试环境&#xff08;test&#xff09;&#xff1a;my_test_data_1 方法&#xff1a; 使用Naticat同步两个数据库结构 选中…

PLC是什么?PLC相关知识小科普

欢迎各位来到东用知识小课堂1.PLC是什么&#xff1a;●PLC就是可编程控制器&#xff0c;它应用于工业环境&#xff0c;必须具有很强的抗干扰能力、广泛的适应能力和应用范围。●PLC是“数字运算操作的电子系统”&#xff0c;也是一种计算机&#xff0c;它是“专为在工业环境下应…

EdgeX Foundry (一)安装和部署

系统版本uname -rdocker 版本docker --versiondocker-compose版本安装参考链接&#xff1a;https://blog.csdn.net/chezong/article/details/128917107拉取edgex foundry 配置文件 docker-compose.yml; curl https://raw.githubusercontent.com/edgexfoundry/edgex-compose/ire…

【C语言学习笔记】:通讯录管理系统

系统中需要实现的功能如下&#xff1a; ✿ 添加联系人&#xff1a;向通讯录中添加新人&#xff0c;信息包括&#xff08;姓名、性别、年龄、联系电话、家庭住址&#xff09;最多记录1000人 ✿ 显示联系人&#xff1a;显示通讯录中所有的联系人信息 ✿ 删除联系人&#xff1a;按…

冒泡排序详解

冒泡排序是初学C语言的噩梦&#xff0c;也是数据结构中排序的重要组成部分&#xff0c;本章内容我们一起探讨冒泡排序&#xff0c;从理论到代码实现&#xff0c;一步步深入了解冒泡排序。排序算法作为较简单的算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&am…

信道建模(大尺度、小尺度、莱斯衰落、瑞利衰落、莱斯信道、瑞利信道)

一、大尺度衰落与小尺度衰落 大尺度衰落由收发两端的距离决定&#xff0c;功率上建模为&#xff1a; 小尺度衰落由收发两端的环境决定&#xff0c;比如是否有遮挡&#xff0c;场景有室内、室外、平原、山村、城镇等&#xff0c;这些环境影响到收发两端是否有直达链路&#xff0…

电子电路中的各种接地(接地保护与GND)

前言多年以前&#xff0c;雷雨天气下&#xff0c;建筑会遭遇雷击&#xff0c;从而破坏建筑以及伤害建筑内的人&#xff0c;为了避免雷击的伤害&#xff0c;人们发明了避雷针&#xff0c;并将避雷针接地线&#xff0c;从而引导雷击产生的电流经过地线流入到地下。地线&#xff1…

传统目标检测实战:HOG+SVM

传统目标检测实战&#xff1a;HOGSVM 文章目录传统目标检测实战&#xff1a;HOGSVM1. 前言1.1 传统和深度1.2 何为传统目标检测1.3 传统目标检测方法不足2. 先验知识3. 项目框架3.1 文件架构3.2 方法简要介绍4. 工具函数&#xff08;utils.py&#xff09;5. 特征提取&#xff0…

我是如何转岗成为数据分析师?

Datawhale干货 作者&#xff1a;孟禹&#xff0c;数据分析师&#xff0c;Datawhale邀约作者笔者背景介绍&#xff1a;工作5年半&#xff0c;前4年在K12在线教育负责教研和用户转化&#xff0c;21年双减之后跳槽到一家新消费品牌公司做数据分析师&#xff0c;跨了行转了岗。现在…

领英LinkedIn的个人商务会员和企业销售会员我们应该怎么选?

在详细介绍领英LinkedIn会员之前先解释下为什么要开通。也就是领英免费用户会有哪些限制以至于我们需要付费去开通会员&#xff1a;1.有限的搜索次数使用免费的 LinkedIn 帐户&#xff0c;您将在一个月内搜索约 300 次后达到商业使用限制。一旦达到商业使用限制&#xff0c;您将…