Home  >  Article  >  Web Front-end  >  How to implement a nine-square heart-shaped puzzle using canvas (with code)

How to implement a nine-square heart-shaped puzzle using canvas (with code)

不言
不言Original
2018-08-01 13:59:574903browse

This article introduces to you the method of realizing the nine-square heart-shaped puzzle in canvas (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Explanation

I saw this kind of picture several times in the circle of friends a few days ago.

How to implement a nine-square heart-shaped puzzle using canvas (with code)

This kind of picture is a heart shape made of nine pictures.

I thought it was very interesting, so I checked online to see how to do it. Most of the people said that I could use the puzzle function of Meitu Xiu Xiu to do it. There is also a mini program in the WeChat mini program that specializes in making heart-shaped puzzles. I After trying them all, I felt that it could be simpler, so I made a small program myself.

How to implement a nine-square heart-shaped puzzle using canvas (with code)

Ideas of implementing small programs

1. There are two canvases. A small canvas shows what it will look like in the end. A large canvas is used to finally take screenshots, generate pictures, and save them to the album.
Through CSS positioning, just move the large canvas outside the screen so that users cannot see it.
And if you use a small canvas to save the picture, the final picture will be a little blurry.

2. Canvas can be regarded as a 9 * 9 grid.

How to implement a nine-square heart-shaped puzzle using canvas (with code)

is represented by an array called heart. Such.

How to implement a nine-square heart-shaped puzzle using canvas (with code)

Use the small grids to spell out a heart shape, and render it on the canvas according to the content of the array.

Functions of the mini program

This mini program has several functions: select a single picture, select multiple pictures, add pictures, save pictures, reset, recommend, and give feedback.

Select a single picture

When the user clicks on the heart-shaped area, he or she can select a single picture. Call wx.chooseImage to select the picture from the local album, and then select the picture. , drawn on the canvas, the specific drawing position is the position where the user clicks.

Bind the touchend event on the small canvas. After the event is triggered, there is a changedTouches attribute in the event. This is an array that saves the currently changed touch point information. The elements in this array include x and y attribute, which is the distance between the touch point and the upper left corner of the canvas.

// 触摸点在 x 轴的值
var x = e.changedTouches[0].x;
// 触摸点在 y 轴的值
var y = e.changedTouches[0].y;

After knowing the distance between the x-axis and the y-axis, calculate the specific grid on which it should be drawn.

//grid 表示一个格子的宽度

// 确定 x 轴是在第几个格子
x = Math.floor(x / grid);

// 确定 y 轴是在第几个格子
y = Math.floor(y / grid);

After knowing which grid to draw, you need to determine which part of the picture to draw, because all grids are square, but the picture selected by the user is not necessarily square. If compressed into a square, it will be ugly. , so when I drew, I chose the middle part to draw.

Get the picture information through wx.getImageInfo, take the short side as the width of the square, and then start from (long side - short side )/2 place to draw.

// 获取图片的宽和高
var width = res.width;
var height = res.height;

//  如果图片不是正方形,只画中间的部分
// sWidth 表示正方形的宽
var sWidth = width > height ? height : width;
// sx 是源图像的矩形选择框的左上角 X 坐标
var sx = 0;
// sy 是源图像的矩形选择框的左上角 y 坐标
var sy = 0;
if (width > height) {
    sx = (width - height) / 2;
}
if (width <p>After knowing what to draw and where to draw, just call canvasContext.drawImage to draw. </p><h4>Select multiple pictures</h4><p>To select multiple pictures, you also call the wx.chooseImage method. After successfully selecting multiple pictures, the returned object has a tempFilePaths attribute, which is saved. List of local file paths for images. </p><p><span class="img-wrap"><img src="https://img.php.cn//upload/image/676/859/705/1533102912371640.png" title="1533102912371640.png" alt="How to implement a nine-square heart-shaped puzzle using canvas (with code)"></span></p><p>Then traverse the heart array, which is the array that stores heart-shaped data. If the value of an element in the array is 1, that is to say, in the heart Within the shape range, take a picture from tempFilePaths in order and draw it. The same is true when drawing. If it is not a square, just draw the middle part. </p><h4>Supplementary pictures</h4><p>In the image file, there are several pictures saved to supplement the heart shape, and their paths are saved in an array. </p><pre class="brush:php;toolbar:false"> // 用来补充心形的图片
 images: [
   '../../images/1.jpg',
   '../../images/2.jpg',
   '../../images/3.jpg',
   '../../images/4.jpg',
   '../../images/5.jpg',
   '../../images/6.jpg',
   '../../images/7.jpg',
   '../../images/8.jpg',
   '../../images/9.jpg',
   '../../images/10.jpg',
 ]

Then it is to traverse the heart array. If the value of an element of the array is 1, randomly select a picture from this group of pictures to draw.

Draw one picture, draw multiple pictures, and supplement pictures. They all draw pictures on canvas. In order to avoid the location of the picture that has been drawn being overwritten, the levels of the pictures they draw are different.

补充图片:1
画多张图片:2
画一张图片:3

Those with a higher level can cover those with a lower level, and those with a lower level cannot cover those with a higher level. Those of the same level can be covered in both cases except those who draw multiple pictures.

简单意思就是:
补充图片,补充完了之后,再补充会把原来补充的覆盖掉,但是用户选择的图片不会被覆盖掉。            
画多张图片,可以覆盖掉补充的图片,但用户选择的图片也不会覆盖掉。        
画一张图片,不管这个位置有没有图片,都会再画一张。

保存图片

保存图片的时候,就是按顺序对大的 canvas 进行截取,然后保存成图片,主要靠 wx.canvasToTempFilePath  这个API来实现,这个 API ,可以把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径。

这里要注意几个细节

1、为了避免最后保存的图片有黑色背景,最好开始的时候就在 canvas 上画一个 和 canvas 大小一样的矩形,矩形填充上颜色。

2、为了保存的图片,在用户的相册中也能保持心形。需要按下面这个顺序来保存图片

How to implement a nine-square heart-shaped puzzle using canvas (with code)

3、wx.canvasToTempFilePath 中有两个选填的参数 destWidth 和 destHeight,这个两个参数决定 输出图片宽度和高度,如果不是准确的知道是多少,用默认值就可以。

destWidthdestHeight 单位是物理像素(pixel),canvas 绘制的时候用的是逻辑像素(物理像素=逻辑像素 * density),所以这里如果只是使用 canvas 中的 width 和 height(逻辑像素)作为输出图片的长宽的话,生成的图片 width 和 height 实际上是缩放了到 canvas 的 1 / density 大小了,所以就显得比较模糊了。

而默认值是 width * 屏幕像素密度

How to implement a nine-square heart-shaped puzzle using canvas (with code)

文档中提到的屏幕像素密度,应该不是指每英寸屏幕所拥有的像素数,而是指设备像素比(pixelRatio),也就是用多少个物理像素去显示 1px 的 CSS 像素。
用API  wx.getSystemInfo  可以查看设备像素比

wx.getSystemInfo({
  success: function(res) {
    console.log(res.pixelRatio)
  }
})

这里如果我的理解有误,还请知道的小伙伴指出。

说了这么多,主要就是想说用默认的值其实就已经很清晰了。

4、因为要保存9张图片,所以需要一些时间,这个时候就需要一个进度条了,保存图片的时候,显示进度条,禁用保存按钮,毕竟点击一下按钮就是9张图片,所以这个时候还是禁用了好,每保存一张图片进度条的值就 +12 ,超过100的时候,就表示 9张图片都保存好了。

而微信小程序中也刚好有进度条(progress)这个组件。

重置

这个功能就是遍历 heart 数组,用一种颜色,根据数组内容,把心形画出来。然后再在 x 轴 和 y 轴上画两条线,行成九宫格的样子。

推荐 和 意见反馈

 <button>推荐给朋友</button>
 <button>意见反馈</button>

这个两个功能就是用了,微信小程序的 button 组件,这里需要注意的就是,在清除 button 的默认样式时,需要把 button 的 after 伪元素的边框也去掉。

button::after{
  border: 0; 
}

可以优化的地方

有一些地方是小程序在替用户做选择,比如,如果所选择的图片不是正方形,就画中间的部分,但是中间的部分不一定是用户想要的,而如果每张图片都要用户自己来选择画哪部分,一共81张图片,显然是有些麻烦了,这里还可以继续优化下。

还有在补充图片的时候,补充的图片也不一定是用户喜欢的,所以这部分再考虑是不是可以加一些标签,用户选择不同的标签,来补充符合标签的图片,类似 QQ音乐的歌词海报这样。

How to implement a nine-square heart-shaped puzzle using canvas (with code)

总结

这次做的这个九宫格心形拼图的小程序,第一版已经上线了。

开源地址:https://github.com/FEWY/jigsaw  

相关文章推荐:
HTML5 Canvas实现交互式地铁线路图

使用h5 canvas实现时钟的动态效果

The above is the detailed content of How to implement a nine-square heart-shaped puzzle using canvas (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn