【可视化工具】二维矩形装箱可视化 + JS-Canvas实现

简介: 【可视化工具】二维矩形装箱可视化 + JS-Canvas实现

@[toc]


一、说明

本代码文件为.vue文件,其中使用了Element-UI组件。可视化代码主要用了JS的Canvas画布。

如果需要可视化,需要在程序中按照一定格式输出如下信息,data表示了每个矩形的坐标和长、宽(注意:这里的l是指矩形的高,w是指矩形的宽)。

data:[{x:0.0,y:0.0,l:116.0,w:113.0}, {x:113.0,y:0.0,l:116.0,w:99.0}, {x:212.0,y:0.0,l:116.0,w:111.0}, {x:323.0,y:0.0,l:116.0,w:20.0}, {x:343.0,y:0.0,l:89.0,w:57.0}, {x:343.0,y:89.0,l:95.0,w:57.0}, {x:0.0,y:116.0,l:100.0,w:113.0}, {x:113.0,y:116.0,l:88.0,w:99.0}, {x:212.0,y:116.0,l:79.0,w:111.0}, {x:323.0,y:116.0,l:58.0,w:20.0}, {x:332.0,y:184.0,l:42.0,w:68.0}, {x:230.0,y:195.0,l:31.0,w:102.0}, {x:113.0,y:204.0,l:71.0,w:117.0}, {x:0.0,y:216.0,l:88.0,w:113.0}, {x:230.0,y:226.0,l:81.0,w:102.0}, {x:332.0,y:226.0,l:97.0,w:68.0}, {x:113.0,y:275.0,l:29.0,w:117.0}, {x:0.0,y:304.0,l:96.0,w:98.0}, {x:98.0,y:304.0,l:96.0,w:84.0}, {x:182.0,y:304.0,l:50.0,w:48.0}, {x:230.0,y:307.0,l:53.0,w:102.0}, {x:332.0,y:323.0,l:37.0,w:68.0}, {x:182.0,y:354.0,l:46.0,w:30.0}, {x:212.0,y:360.0,l:40.0,w:106.0}, {x:318.0,y:360.0,l:40.0,w:82.0}],
isRotate:[0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1],

然后将上面的信息复制到前端代码对应位置即可进行可视化展示。

在这里插入图片描述

二、可视化效果展示

可以看到下面的矩形有两种颜色。其中蓝色代表没有旋转,粉色代表进行了90度旋转。

在这里插入图片描述

BACK按钮:往后一步

在这里插入图片描述
NEXT按钮:往前一步

在这里插入图片描述

NUM输入框:展示前n个矩形

在这里插入图片描述

REFRESH按钮:刷新页面

在这里插入图片描述

三、代码

<template>
  <div style="margin: 20px;display: flex">
    <div style="margin-right: 20px">
      <el-card style="text-align: center;width: 180px;height: 83vh">
        <div slot="header" class="clearfix">
          <el-image src="https://picgo-wskh.oss-cn-guangzhou.aliyuncs.com/公文包,工具箱,手提包,行李包.svg"></el-image>
        </div>
        <div>
          <el-button icon="el-icon-d-arrow-left" type="danger" @click="diff()" style="margin-top: 10px">BACK</el-button>
          <el-input v-model="n" style="margin-top: 10px;" @change="draw()">
            <template slot="prepend">NUM<b>:</b></template>
          </el-input>
          <el-button icon="el-icon-d-arrow-right" type="success" @click="add()" style="margin-top: 10px">NEXT
          </el-button>
          <el-button icon="el-icon-refresh" type="primary" @click="refresh()" style="margin-top: 10px">REFRESH
          </el-button>
        </div>
      </el-card>
    </div>
    <div style="width:100%">
      <el-card style="text-align: center;height: 83vh;overflow: auto">
        <h1>矩形绘制:</h1>
        <div ref="cardCanvas" id="canvasDiv">
          <canvas id="canvas" style="border: 2px solid #409EFF;background-color: #f6f6fd;" ref="canvas"
                  :width="canvasWidth" :height="canvasHeight"
          ></canvas>
        </div>
        <h3>信息:{{ data }}</h3>
      </el-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'index',
  data() {
    return {
      n: 0,
      stander: 500,
      canvas: {},
      context: {},
      canvasWidth: 400,
      canvasHeight: 400,
      data:[{x:0.0,y:0.0,l:115.0,w:59.0}, {x:59.0,y:0.0,l:115.0,w:21.0}, {x:80.0,y:0.0,l:115.0,w:46.0}, {x:374.0,y:0.0,l:99.0,w:26.0}, {x:258.0,y:0.0,l:99.0,w:116.0}, {x:179.0,y:0.0,l:99.0,w:79.0}, {x:126.0,y:0.0,l:102.0,w:53.0}, {x:179.0,y:99.0,l:118.0,w:79.0}, {x:258.0,y:99.0,l:111.0,w:116.0}, {x:374.0,y:99.0,l:102.0,w:26.0}, {x:138.0,y:102.0,l:63.0,w:41.0}, {x:0.0,y:115.0,l:39.0,w:59.0}, {x:59.0,y:115.0,l:60.0,w:21.0}, {x:90.0,y:115.0,l:50.0,w:48.0}, {x:0.0,y:154.0,l:86.0,w:55.0}, {x:80.0,y:165.0,l:33.0,w:58.0}, {x:146.0,y:165.0,l:114.0,w:33.0}, {x:55.0,y:175.0,l:97.0,w:25.0}, {x:80.0,y:198.0,l:82.0,w:66.0}, {x:379.0,y:201.0,l:108.0,w:21.0}, {x:291.0,y:210.0,l:99.0,w:88.0}, {x:258.0,y:210.0,l:66.0,w:33.0}, {x:179.0,y:217.0,l:111.0,w:79.0}, {x:0.0,y:240.0,l:87.0,w:55.0}, {x:55.0,y:272.0,l:55.0,w:24.0}, {x:258.0,y:276.0,l:47.0,w:27.0}, {x:149.0,y:279.0,l:46.0,w:30.0}, {x:79.0,y:280.0,l:76.0,w:70.0}, {x:285.0,y:309.0,l:44.0,w:94.0}, {x:380.0,y:309.0,l:58.0,w:20.0}, {x:258.0,y:323.0,l:56.0,w:27.0}, {x:149.0,y:325.0,l:73.0,w:30.0}, {x:0.0,y:327.0,l:73.0,w:55.0}, {x:55.0,y:327.0,l:61.0,w:24.0}, {x:196.0,y:328.0,l:51.0,w:62.0}, {x:285.0,y:353.0,l:44.0,w:49.0}, {x:334.0,y:353.0,l:47.0,w:34.0}, {x:81.0,y:356.0,l:42.0,w:68.0}, {x:179.0,y:379.0,l:21.0,w:103.0}],
      isRotate:[0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0],
    }
  },
  created() {
    let max = Math.max(this.canvasWidth, this.canvasHeight)
    this.r = this.stander / max
    this.canvasWidth = this.canvasWidth * this.r
    this.canvasHeight = this.canvasHeight * this.r
  },
  mounted() {
    this.canvas = document.getElementById('canvas')
    // 坐标矫正
    this.context = this.canvas.getContext('2d')
    this.context.translate(0, this.canvasHeight)
    this.context.rotate(this.getRad(180))
    this.context.scale(-1, 1)
    this.n = this.data.length
    this.draw()
  },
  methods: {
    refresh() {
      location.reload()
    },
    clearCanvas() {
      this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
    },
    diff() {
      this.n = -1 + parseInt(this.n)
      this.draw()
    },
    add() {
      this.n = 1 + parseInt(this.n)
      this.draw()
    },
    draw() {
      if (this.judgeN()) {
        this.clearCanvas()
        for (let i = 0; i < this.n; i++) {
          let tube = this.data[i]
          this.drawRect(tube.x, tube.y, tube.l, tube.w, this.isRotate[i])
        }
      }
    },
    judgeN() {
      if (this.n < 0) {
        this.n = 0
        this.$message.warning('矩形数量已经为0了!')
        return false
      } else if (this.n > this.data.length) {
        this.n = this.data.length
        this.$message.warning('所有的矩形已经放置完毕!')
        return false
      }
      return true
    },
    drawRect(x, y, l, w, isRotate) {

      let r = this.r

      w = w * r
      l = l * r
      x = x * r
      y = y * r

      this.context.strokeStyle = '#5190da'
      this.context.lineWidth = 2
      this.context.beginPath()
      this.context.rect(x, y, w, l)
      this.context.stroke()

      // this.context.fillStyle = '#d1e4f9';
      if(isRotate === 1){
        this.context.fillStyle = 'rgba(212,152,218,0.29)'
      }else{
        this.context.fillStyle = 'rgba(123,159,199,0.29)'
      }
      this.context.beginPath()
      this.context.rect(x, y, w, l)
      this.context.fill()

    },
    getRad(degree) {
      return degree / 180 * Math.PI
    }
  }
}
</script>

<style scoped>

</style>
目录
相关文章
|
3月前
|
存储 自然语言处理 前端开发
抖音快手小红书虚拟评论截图生成器,模拟对话制作工具,html+js+css
这是一款纯前端实现的多平台虚拟评论生成器,支持抖音、快手、小红书风格,适用于产品演示与UI设计。采用Vanilla JS与Flexbox布局,利用IndexedDB存储数据,CSS Variables切换主题。
|
2月前
|
JavaScript 前端开发 API
淘宝店铺阿里旺旺采集工具,连接批量转旺旺ID,用Js接口实现效果
以下是淘宝店铺阿里旺旺采集工具的JS实现代码,包含批量获取店铺旺旺ID功能,当然仅
|
1月前
|
编解码 JavaScript 前端开发
如何在网页播放英文的m3u8文件(基于Javascript搭建的在线网页工具)
什么是m3u8?又该如何在网页中高效、便捷地播放英文的m3u8文件呢?今天这篇文章就带你一起了解,并推荐一种基于Javascript搭建的在线网页工具,让你轻松解决播放问题。
608 0
|
3月前
|
存储 前端开发 安全
病历单生成器在线制作,病历单生成器app,HTML+CSS+JS恶搞工具
本项目为医疗病历模拟生成器,旨在为医学教学和软件开发测试提供数据支持,严格遵守《医疗机构病历管理规定》。
|
3月前
|
存储 前端开发 JavaScript
仿真银行app下载安装, 银行卡虚拟余额制作app,用html+css+js实现逼真娱乐工具
这是一个简单的银行账户模拟器项目,用于学习前端开发基础。用户可进行存款、取款操作,所有数据存储于浏览器内存中
|
4月前
|
人工智能 监控 前端开发
基于 Next.js 的书法字体生成工具架构设计与 SSR 优化实践
本项目是一款书法字体生成工具,采用 Next.js 14(App Router)与 Tailwind CSS 构建前端,阿里云 Serverless 部署后端。通过混合渲染策略(SSG/SSR/CSR)、Web Worker 异步计算及 CDN 字体分片加载优化性能。服务端借助阿里云函数计算处理计算密集型任务,将平均耗时从 1200ms 降至 280ms,支持 1000+ QPS。动态路由与 ARMS 监控提升工程化水平,未来计划引入 WebGPU 和 AI 字体风格迁移技术,进一步优化用户体验。
|
7月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
221 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
10月前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
323 62
|
9月前
|
数据采集 人工智能 自然语言处理
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
Midscene.js 是一款基于 AI 技术的 UI 自动化测试框架,通过自然语言交互简化测试流程,支持动作执行、数据查询和页面断言,提供可视化报告,适用于多种应用场景。
2387 1
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告