【可视化工具】二维矩形装箱可视化 + 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>
目录
相关文章
|
1月前
|
编解码 数据可视化 前端开发
如何使用 D3.js 创建一个交互式的地图可视化?
如何使用 D3.js 创建一个交互式的地图可视化?
|
2月前
|
数据可视化 前端开发 JavaScript
可视化工具D3.js
可视化工具D3.js
104 2
|
22天前
|
Web App开发 JavaScript 前端开发
使用 Chrome 浏览器的内存分析工具来检测 JavaScript 中的内存泄漏
【10月更文挑战第25天】利用 Chrome 浏览器的内存分析工具,可以较为准确地检测 JavaScript 中的内存泄漏问题,并帮助我们找出潜在的泄漏点,以便采取相应的解决措施。
138 9
|
24天前
|
监控 前端开发 JavaScript
React 静态网站生成工具 Next.js 入门指南
【10月更文挑战第20天】Next.js 是一个基于 React 的服务器端渲染框架,由 Vercel 开发。本文从基础概念出发,逐步探讨 Next.js 的常见问题、易错点及解决方法,并通过具体代码示例进行说明,帮助开发者快速构建高性能的 Web 应用。
60 10
|
1月前
|
存储 JavaScript 前端开发
Node.js 常用工具
10月更文挑战第6天
25 2
|
1月前
|
Web App开发 JavaScript 前端开发
Node.js:JavaScript世界的全能工具
Node.js:JavaScript世界的全能工具
|
1月前
|
JavaScript 网络协议
Node.js 工具模块
10月更文挑战第7天
20 0
|
2月前
|
JavaScript Linux 开发者
一个用于管理多个 Node.js 版本的安装和切换开源工具
【9月更文挑战第14天】nvm(Node Version Manager)是一个开源工具,用于便捷地管理多个 Node.js 版本。其特点包括:版本安装便捷,支持 LTS 和最新版本;版本切换简单,不影响开发流程;多平台支持,包括 Windows、macOS 和 Linux;社区活跃,持续更新。通过 nvm,开发者可以轻松安装、切换和管理不同项目的 Node.js 版本,提高开发效率。
|
1月前
|
数据可视化 前端开发 JavaScript
可视化工具D3.js
可视化工具D3.js
|
2月前
|
C++
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
下一篇
无影云桌面