【sgUploadTileImage】自定义组件:浏览器端生成瓦片图,并转换为File文件序列上传瓦片图

news2024/12/24 2:11:23

特性:

  1. 支持自定义瓦片图尺寸
  2. 支持显示预览最小尺寸100x100像素大小,切换为实际切割尺寸
  3. 支持获取切割后的文件Files数组

 sgUploadTileImage源码

<template>
    <div :class="$options.name">
        <div class="sg-ctrl">
            <div class="px">
                <span>瓦片图边长</span>
                <el-input-number style="width: 130px;" v-model.trim="tileSize" :precision="0" :step="100" :min="100"
                    :max="500" :controls-position="`left`" /><span>像素</span>

            </div>
            <div class="btns">
                <el-switch v-model="view100px" inactive-color="#ccc" active-color="#409EFF" inactive-text=""
                    active-text="固定100宽高显示预览" :inactive-value="false" :active-value="true" />

                <el-button :loading="loading" type="primary" icon="el-icon-upload2"
                    @click="d => $refs.sgUpload.triggerUploadFile()">上传大图</el-button>

                <el-button :loading="loading" type="success" icon="el-icon-s-promotion" @click="uploadTiles"
                    v-if="loadingPercent === 100">上传瓦片图</el-button>
            </div>

            <div class="tip-text">
                <p>{{ loadingText }}</p>
                <p style="color: #67C23A;" v-if="!(loadingPercent === 0 || loadingPercent === 100)">{{ loadingPercent }}%
                </p>
            </div>
        </div>
        <div class="sg-tiles" :view100px="view100px">
            <div :style="{ width: `${(view100px ? 100 : tileSize) * colCount}px` }">
                <img v-for="(a, i) in tiles" :key="i" :src="a" :width="view100px ? 100 : tileSize"
                    :height="view100px ? 100 : tileSize">
            </div>
        </div>

        <!-- 上传组件 -->
        <sgUpload drag ref="sgUpload" :data="{
            maxSize: 1000,
            accept: `*`,
        }" @resultBase64Image="resultBase64Image" @success="uploadSuccess" @error="uploadError" hideUploadTray
            @showFakeLoading="showFakeLoading" @hideFakeLoading="hideFakeLoading" />
    </div>
</template>
    
<script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {
    name: 'sgUploadTileImage',
    components: {
        sgUpload,
    },
    data() {
        return {
            loading: false,
            view100px: true,
            loadingText: '',
            colCount: 0,
            rowCount: 0,
            loadingPercent: 0,
            src: '',
            fileFormat: '',
            tileSize: 500,
            tiles: [],//瓦片图数组
            loadingInterval: null,//虚假加载动画
            dur: 100,
        }
    },
    methods: {
        uploadTiles(d) {
            let r = [];
            let format = this.fileFormat.toLocaleLowerCase().split('/')[1];
            this.tiles.forEach((base64, i) => {
                let fileName = `${i}.${format}`;
                let file = this.$g.image.getFileFromBase64(base64, fileName);
                r.push(file);
            });
            this.$emit(`uploadTiles`, r);
        },
        getRowColIndex(itemIndex = 0, colCount = 3) {
            //必选参数:itemIndex是当前元素的索引值,从0开始计算(如果是从1开始,则需将传入值-1,即itemIndex--)
            //必选参数:colCount是每一行显示多少个元素
            return {
                colIndex: itemIndex % colCount,//计算列索引(从0开始)
                rowIndex: Math.floor(itemIndex / colCount),//计算行索引(从0开始)        
            }
        },
        // 获取瓦片图
        getTiles({ img, format = "image/png", cb } = {}) {
            this.fileFormat = format;
            let canvas = document.createElement('canvas'), ctx = canvas.getContext('2d');
            canvas.width = this.tileSize, canvas.height = this.tileSize;

            // let imgArea = img.width * img.height;//图片的面积
            // let tileArea = this.tileSize * this.tileSize;//瓦片图的面积
            this.loadingText = `已经为您生成${len}个瓦片图(尺寸:${this.tileSize}像素×${this.tileSize}像素)。`;

            let tiles = [];
            let colCount = Math.ceil(img.width / this.tileSize);//列数量
            let rowCount = Math.ceil(img.height / this.tileSize);//行数量
            let len = colCount * rowCount;//瓦片图总数
            this.colCount = colCount;
            this.rowCount = rowCount;
            for (let i = 0; i < len; i++) {
                let { colIndex, rowIndex } = this.getRowColIndex(i, colCount);
                let drawImageWidth = colIndex === colCount - 1 ? (img.width % this.tileSize) : this.tileSize;
                let drawImageHeight = rowIndex === rowCount - 1 ? (img.height % this.tileSize) : this.tileSize;
                canvas.width = drawImageWidth, canvas.height = drawImageHeight;
                ctx.drawImage(img,
                    this.tileSize * colIndex, this.tileSize * rowIndex,//绘制图片起始点的横纵坐标
                    drawImageWidth, drawImageHeight,//切割图片的宽高
                    0, 0,//绘制canvas的起始点横纵坐标
                    drawImageWidth, drawImageHeight);//绘制canvas的宽高
                tiles.push(canvas.toDataURL(format));
            }
            cb && cb(tiles);
        },
        /* 将图片(路径)转换为Base64 */
        resultBase64Image(url, f) {
            this.tiles = [];
            this.$el.style.setProperty("--last-img-scale", (100 - 1) / (this.tileSize - 1)); //js往css传递局部参数
            this.loadingText = '正在为您分解图片,请稍候!';
            this.__showFakeLoading();
            let img = new Image(); img.crossOrigin = 'Anonymous';
            img.onload = d => {
                this.getTiles({
                    img,
                    cb: tiles => {
                        this.tiles = tiles;
                        this.loading = false;
                        this.__hideFakeLoading();
                        this.loadingPercent = 100;
                    }
                })
            }
            img.src = url;
        },
        uploadSuccess(d, f) { }, uploadError(d, f) { },
        showFakeLoading(d) {
            this.loadingText = '图片上传中,请稍候!';
            this.loading = true;
            this.__showFakeLoading();
        },
        __showFakeLoading() {
            clearInterval(this.loadingInterval);
            this.loadingInterval = setInterval(() => {
                this.loadingPercent >= 99 ? this.__hideFakeLoading() : this.loadingPercent++;
            }, this.dur);
        },
        hideFakeLoading(d) {
        },
        __hideFakeLoading() {
            clearInterval(this.loadingInterval);
            this.loadingPercent = 0;
        },
    }
};
</script>
<style lang="scss" scoped>
.sgUploadTileImage {
    display: flex;
    flex-direction: column;

    .sg-ctrl {
        display: flex;
        flex-shrink: 0;
        flex-wrap: nowrap;
        align-items: center;

        .px {
            margin-right: 10px;

            span {
                margin-left: 5px;
            }
        }

        .tip-text {
            margin-left: 10px;
            display: flex;
            align-items: center;
        }
    }

    .sg-tiles {
        overflow: auto;
        // max-height: calc(100vh - 100px);
        flex-grow: 1;

        div {
            display: flex;
            flex-wrap: wrap;

            img {
                box-sizing: border-box;
                border: 0.5px solid white;
                object-position: top left;
                object-fit: scale-down;
            }
        }

        &[view100px] {
            div {
                img {

                    &:last-of-type {
                        width: revert;
                        height: revert;
                        transform-origin: left top;
                        transform: scale(var(--last-img-scale));
                    }
                }
            }
        }
    }
}
</style>

用例

<template>
  <div>
    <el-button type="primary" @click="dialogVisible = true">上传超大文件</el-button>
    <el-dialog :custom-class="'sgUploadTileImage-el-dialog'" :append-to-body="true" :close-on-click-modal="true"
      :close-on-press-escape="true" :destroy-on-close="true" :fullscreen="true" :show-close="true" :title="`瓦片图上传`"
      :width="'100%'" :visible.sync="dialogVisible">
      <div style="width: 100%;height: 100%;">
        <sgUploadTileImage @uploadTiles="uploadTiles" />
      </div>
    </el-dialog>
  </div>
</template>
<script>
import sgUploadTileImage from "@/vue/components/admin/sgUploadTileImage";
export default {
  components: { sgUploadTileImage, },
  data() {
    return { dialogVisible: false, }
  },
  methods: {
    uploadTiles(files) {
      console.log(`瓦片图files:`, files);
    },
  },
};
</script> 
<style lang="scss">
.sgUploadTileImage-el-dialog {
  .el-dialog__body {
    padding: 0;

    .sg-tiles {
      max-height: calc(100vh - 100px);
    }
  }
}
</style>

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

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

相关文章

使用datax将数据从InfluxDB抽取到TDengine过程记录

1. 编写InfluxDB数据查询语句 select time as ts,device as tbname, ip,device as district_code from "L2_CS" limit 1000 2. 创建TDengine表 create database if not exists sensor; create stable if not exists sensor.water(ts timestamp, ip varchar(50), …

App Inventor 2 模拟sleep函数

App Inventor 2 原生没有 sleep 及相关函数&#xff0c;需要模拟实现&#xff0c;经过测试这里给出一个既简单又相对高效率的实现方案&#xff1a; 需要用到计时器组件&#xff1a; 实现代码如下&#xff1a; 代码原理非常简单&#xff0c;就是计算好要 sleep 到的时刻&#x…

MySQL - 关于约束类型和作用的介绍

约束的概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 约束的作用&#xff1a;用于保证数据库中数据的正确性、完整性和一致性。 约束分类&#xff1a; 约束类型作用关键字非空约束限制该字段的数据不能为nullnot null唯一约束保证该…

UE5 ChaosVehicles载具研究

一、基本组成 载具Actor类名称&#xff1a;WheeledVehiclePawn Actor最原始的结构 官方增加了两个摇臂相机&#xff0c;可以像驾驶游戏那样切换多机位、旋转观察 选择骨骼网格体、动画蓝图类、开启物理模拟 二、SportsCar_Pawn 角阻尼&#xff1a;物体旋转的阻力。数值越大…

C# OpenCvSharp 基于直线检测的文本图像倾斜校正

效果 项目 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using OpenCvSharp;namespace OpenCvSharp_基于直线检测的文…

.balckhoues-V-XXXXXXX勒索病毒数据怎么处理|数据解密恢复

引言&#xff1a; 随着网络犯罪的不断演进&#xff0c;勒索病毒已成为当前数字时代的威胁之一&#xff0c;其中包括.balckhoues-V-XXXXXXX勒索病毒。本文将深入介绍.balckhoues-V-XXXXXXX勒索病毒的特点、数据恢复方法以及预防措施&#xff0c;以帮助您更好地理解和应对这一威…

【区块链 | DID】白话数字身份

《十四五数字经济发展规划》提出建立健全政务数据共享协调机制&#xff0c;加快数字身份统一认证和电子证照、电子签章、电子公文等互信互任&#xff0c;推进发票电子化改革&#xff0c;促进政务数据共享、流程优化和业务协同。在数字经济逐渐成形的背景下&#xff0c;推进数字…

【RabbitMQ实战】05 RabbitMQ后台管理

一、多租户与权限 1.1 vhost的概念 每一个 RabbitMQ服务器都能创建虚拟的消息服务器&#xff0c;我们称之为虚拟主机(virtual host),简称为 vhost。每一个 vhost本质上是一个独立的小型RabbitMQ服务器&#xff0c;拥有自己独立的队列、交换器及绑定关系等&#xff0c;并且它拥…

高级时钟项目(2)Json文件解析学习---C语言版本

笔者来介绍一下json文件解析 1、背景介绍 笔者在获取天气数据的时候&#xff0c;是通过MCU的WIFI去获取&#xff0c;但是获取到的数据json数据&#xff0c;需要解析&#xff0c;C语言没那么解析库&#xff0c;所以就需要找一些开源的解析库。 笔者找到cjson这个适用于C语言…

洗衣行业在线预约小程序系统源码搭建 支持直播功能+在线预约下单+上门取件

目前&#xff0c;人们对生活品质的追求不断提高&#xff0c;但生活节奏却也不断加快。对品质的追求遇到了忙碌的生活节奏&#xff0c;人们更渴望以最简单、便捷的方式达到追求品质的目的。同时&#xff0c;由于线上支付的普及&#xff0c;大家更希望足不出户就可以解决自己生活…

基于规则架构-架构案例2019(三十九)

电子商务 某电子商务公司为了更好地管理用户&#xff0c;提升企业销售业绩&#xff0c;拟开发一套用户管理系统。该系统的基本功能是根据用户的消费级别、消费历史、信用情况等指标将用户划分为不同的等级&#xff0c;并针对不同等级的用户提供相应的折扣方案。在需求分析与架…

AGV小车、机械臂协同作业实战06-任务分配算法(图解蚁群算法)代码示例java

什么是蚁群算法&#xff1f; 蚁群系统(Ant System(AS)或Ant Colony System(ACS))是由意大利学者Dorigo、Maniezzo等人于20世纪90年代首先提出来的。他们在研究蚂蚁觅食的过程中&#xff0c;发现蚁群整体会体现一些智能的行为&#xff0c;例如蚁群可以在不同的环境下&#xff0c…

计算机竞赛 深度学习乳腺癌分类

文章目录 1 前言2 前言3 数据集3.1 良性样本3.2 病变样本 4 开发环境5 代码实现5.1 实现流程5.2 部分代码实现5.2.1 导入库5.2.2 图像加载5.2.3 标记5.2.4 分组5.2.5 构建模型训练 6 分析指标6.1 精度&#xff0c;召回率和F1度量6.2 混淆矩阵 7 结果和结论8 最后 1 前言 &…

【湖科大教书匠】计算机网络随堂笔记第5章(计算机网络运输层)

目录 5.1、运输层概述 概念 进程之间的通信 进程之间通信流程 总结 5.2、运输层端口号、复用与分用的概念 为什么用端口号 发送方的复用和接收方的分用 ​编辑 ​编辑 运输层传输流程 5.3、UDP和TCP的对比 概念 用户数据报协议UDP&#xff08;User Datagram Protocol&#xf…

P2PNet-Soy原理梳理

前文总结了P2PNet源码以及P2PNet-Soy源码实现方法&#xff0c;相关链接如下&#xff1a; 人群计数P2PNet论文&#xff1a;[2107.12746] Rethinking Counting and Localization in Crowds:A Purely Point-Based Framework (arxiv.org) p2p人群计数源码&#xff1a;GitHub - Te…

商品秒杀系统整理

1、使用redis缓存商品信息 2、互斥锁解决缓存击穿问题&#xff0c;用缓存空值解决缓存穿透问题。 3、CAS乐观锁解决秒杀超卖的问题 4、使用redission实现一人一单。&#xff08;分布式锁lua&#xff09;脚本。 5、使用lua脚本进行秒杀资格判断&#xff08;将库存和用户下单…

三维模型3DTile格式轻量化压缩在移动智能终端应用方面的重要性分析

三维模型3DTile格式轻量化压缩在移动智能终端应用方面的重要性分析 随着移动智能终端设备的不断发展和普及&#xff0c;如智能手机、平板电脑等&#xff0c;以及5G网络技术的推广应用&#xff0c;使得在这些设备上频繁使用三维地理空间数据成为可能。然而&#xff0c;由于这类数…

协议-TCP协议-基础概念02-TCP握手被拒绝-内核参数-指数退避原则-TCP窗口-TCP重传

协议-TCP协议-基础概念02-TCP握手被拒绝-TCP窗口 参考来源&#xff1a; 《极客专栏-网络排查案例课》 TCP连接都是TCP协议沟通的吗&#xff1f; 不是 如果服务端不想接受这次握手&#xff0c;它会怎么做呢&#xff1f; 内核参数中与TCP重试有关的参数(两个) -net.ipv4.tc…

umi+React项目引入字体文件

1. 在public下新建文件夹fonts&#xff0c;将字体文件复制到该文件夹下 2. 在public文件下新建font.css文件 font-face {font-family: YouSheBiaoTiHei;src: url(./fonts/YouSheBiaoTiHei-2.ttf); }3. 在app.ts里面加上导入语句即可引入该字体 import ../public/font.css;

似然和概率

前言 高斯在处理正态分布的首次提出似然&#xff0c;后来英国物理学家&#xff0c;费歇尔 概率是抛硬币之前&#xff0c;根据环境推断概率 似然则相反&#xff0c;根据结果推论环境 P是关于x的函数&#xff0c;比如x为正面朝上的结果&#xff0c;或者反面朝上的结果&#xf…