内容简介:这篇文章会讲下,如果通过Go来操作canvas,然后画一个类似腾讯文档表格一样的,在线的表格。当然,这肯定是个demo(你懂的)。然后,这篇文章主要会讲下面几个点:这里我们就直接上Go的代码了,如果有对Go如何编译成wasm或者其他的基础问题,可以查看这个系列的之前的几篇文章。前端js的代码:
这篇文章会讲下,如果通过 Go 来操作canvas,然后画一个类似腾讯文档表格一样的,在线的表格。当然,这肯定是个demo(你懂的)。然后,这篇文章主要会讲下面几个点:
- 使用Go来操作canvas绘制表格
- 使用js来操作canvas绘制表格
- 性能问题
使用Go操作canvas绘制表格
这里我们就直接上Go的代码了,如果有对Go如何编译成wasm或者其他的基础问题,可以查看这个系列的之前的几篇文章。
package main import ( "fmt" "syscall/js" "time" ) var drawCtx js.Value var window js.Value func init() { window = js.Global() doc := window.Get("document") body := doc.Get("body") canvas := doc.Call("createElement", "canvas") canvas.Set("height", window.Get("innerHeight")) canvas.Set("width", window.Get("innerWidth")) body.Call("appendChild", canvas) drawCtx = canvas.Call("getContext", "2d") } func drawTable() { width := window.Get("innerWidth").Int() height := window.Get("innerHeight").Int() // 绘制之前清空下画布 drawCtx.Call("clearRect", 0, 0, width, height) // 单元格的宽高 cellHeight := 22 cellWidth := 120 drawCtx.Set("strokeStyle", "#dcdcdc") drawCtx.Set("lineWidth", 1) drawCtx.Call("translate", -0.5, -0.5) drawCtx.Call("beginPath") // 划竖线 for i := 0; i < width; i = i + cellWidth { drawCtx.Call("moveTo", i, 0) drawCtx.Call("lineTo", i, height) drawCtx.Call("stroke") } // 划横线 for j := 0; j < height; j = j + cellHeight { drawCtx.Call("moveTo", 0, j) drawCtx.Call("lineTo", width, j) } drawCtx.Call("stroke") drawCtx.Call("translate", 0.5, 0.5) } func main() { drawTable() // 阻止go程序退出,因为退出了,js端就不能再调用了 signal := make(chan int) <-signal } 复制代码
前端js的代码:
const go = new Go() WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject) .then(async result => { go.run(result.instance); }); 复制代码
上面就是一个平平无奇的使用Go绘制一个二维表格的demo。先看下效果,然后再来讲下代码:
效果就是上面这个样子,看起来跟腾讯文档表格还是挺像的,对不对?
在上面的代码中,我们定义了一个init函数和一个drawTable函数,你可能已经发现了,代码里面,其他任何地方都没有调用init函数,为什么可以正常运行?drawCtx等对象正常初始化了。这是为啥呢?其实如果你熟悉Go的话,就知道,init方法,在每个包加载执行之前,会先执行该包下的init方法。这个是Go语言本身的特性,在我们这个例子中,那就是init方法,会比main方法先执行。这样你应该明白了对不对。
init函数代码说明
drawCtx = canvas.Call("getContext", "2d") 复制代码
在初始化方法中,前面的几行代码,就是往页面中添加一个canvas的dom,然后获取到canvas对象。上面的一行代码最关键,通过canvas对象,获取了canvas的2d上下文对象,有了这个对象之后,我们才能够执行绘制的操作。
drawTable函数代码说明
width := window.Get("innerWidth").Int() height := window.Get("innerHeight").Int() 复制代码
从截图可以看出,我们的表格是占满整个窗口的,所以我们需要先获取窗口的宽高。
drawCtx.Call("translate", -0.5, -0.5) drawCtx.Call("translate", 0.5, 0.5) 复制代码
如果你对canvas的绘制原理不是特别了解,你应该会看不懂这两行代码在干什么。
来看下去掉这两行代码之后的效果:
对比上面的截图,你应该可以发现这两行是用来干嘛的了。
drawCtx.Call("beginPath") // 划竖线 for i := 0; i < width; i = i + cellWidth { drawCtx.Call("moveTo", i, 0) drawCtx.Call("lineTo", i, height) drawCtx.Call("stroke") } // 划横线 for j := 0; j < height; j = j + cellHeight { drawCtx.Call("moveTo", 0, j) drawCtx.Call("lineTo", width, j) } drawCtx.Call("stroke") 复制代码
这里的代码,应该比较简单了,就是分别绘制表格的横线和竖线。应该很容易看懂了对不对。
main函数里面,只有调用了drawTable()函数,没有其他操作,就不说了。
上面大概就是使用Go来操作canvas绘制一个二维的表格了,不过非常简陋,实际项目中肯定不是这么搞的,但是用的东西就是上面这些。你懂我意思吧?
使用js来操作canvas绘制表格
因为后面要对比下,js和wasm的操作canvas的性能,所以,还是给一个js的代码:
let drawCtx ; const width = window.innerWidth const height = window.innerHeight function init() { const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; document.body.appendChild(canvas); drawCtx = canvas.getContext("2d") } function drawTable() { // 绘制之前清空下画布 drawCtx.clearRect(0, 0, width, height) // 单元格的宽高 const cellHeight = 22 const cellWidth = 120 drawCtx.strokeStyle = "#dcdcdc"; drawCtx.lineWidth = 1; drawCtx.translate(-0.5, -0.5) drawCtx.beginPath() // 划竖线 for(let i = 0; i < width; i = i + cellWidth ){ drawCtx.moveTo(i, 0) drawCtx.lineTo(i, height) drawCtx.stroke() } // 划横线 for(let j = 0; j < height; j = j + cellHeight) { drawCtx.moveTo(0, j) drawCtx.lineTo(width, j) } drawCtx.stroke() drawCtx.translate(0.5, 0.5) } init(); // const s = Date.now(); // for (let i=0; i< 100000; i++) { drawTable(); // } // console.log(Date.now() - s) 复制代码
代码跟上面的Go代码,一模一样,因为我就是从上面复制过来,改成js的。 js的代码,我这里就不说明了,你应该都可以看懂的,对不对?
性能问题
绘制1000次
wasm(Go):300ms左右
js: 24ms左右
绘制10000次
wasm(Go):2.7s左右
js: 180ms左右
可以看到,直接使用js来绘制canvas会比wasm要快很多。 这其实也说明一个问题,wasm它的使用场景,并不是让你来操作dom的,它是使用在特定场景下的,比如上篇文章中说的文件md5计算的场景,操作dom这种,我们还是按常规操作就行了。 上面的测试基于我的这个demo代码,然后在Chrome浏览器,iMac下的测试数据,如果有问题,欢迎联系我。
总结
上面的例子可以看出,使用Go可以操作前端的任何东西,包括dom,js对象等等。但是,我们在实际使用的时候,一定要知道,什么场景,使用什么样的技术来实现,能够得到最优的性能,这才是我们在实际的项目开发中,需要考虑的点。这篇文章大概就到这里,有任何问题,欢迎联系我,:pray:。
欢迎关注我们的微信公众号,每天学习Go知识
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 前端交互式图表绘制库GoJS介绍
- ViewGroup 默认顺序绘制子 View,如何修改?什么场景需要修改绘制顺序?
- Shader 绘制基础图形
- css绘制特殊图形
- View 绘制流程分析
- CSS图形绘制总结
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。