使用Java绘制图片边框,解决微信小程序map组件中marker与label层级关系问题,label增加外边框后显示不能置与marker上面
今天上线的时候发现系统不同显示好像不一样,苹果手机打开的时候是正常的,但是一旦用安卓手机打开就会出现label不置顶的情况。尝试了很多种办法,也在官方查看了map相关的文档,发现并没有给label设置zIndex的属性,只看到了一个叫什么碰撞类型的属性,但是这个东西设置了如果两个目标有接触就会被隐藏掉,并不是我们想要的结果。
想了一下,如果我们不使用label生成边框呢,直接在服务器那边把图片绘制成有边框的不就好了,这样子只用marker就行了,就能得到iOS的效果了
问题截图
原本js代码
getBallCourtInfoByPoint(info).then((res) => {
const len = res.length;
for (let i = 0; i < len; i++) {
const element = res[i];
//获取质量最小的图片用于展示
let newUrl = element.ballCourtImageList[0].ballCourtImage.replace(/(\.(jpg|jpeg|png|gif))$/, '-min100\$1');
element['id'] = Number(element.id)
element['markerId'] = Number(element.id)
element['title'] = element.ballCourtName
element['latitude'] = Number(element.lat)
element['longitude'] = Number(element.lng)
element['lat'] = Number(element.lat)
element['lng'] = Number(element.lng)
element['iconPath'] = newUrl
element['width'] = 38
element['height'] = 38
let label = {
borderRadius: 8,
borderWidth: 4,
borderColor: '#fff',
width: 38,
height: 38,
anchorX: -18,
anchorY: -36,
}
element['label'] = label
});
在后端绘制好图片,编写ImageWithRoundedCorners类
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageWithRoundedCorners {
public static void main(String[] args) {
try {
// 加载原始图像
BufferedImage originalImage = ImageIO.read(new File("C:\\Users\\Admin\\Desktop\\feitu\\img100\\tmp_8abe0efd9e58dfd1608a6f9affd987ef-e67efe7a-3fd8-482f-8f5d-30e686491a73.jpg"));
// 设置padding和圆角半径
int padding = 50; // 白色圆角区域的内边距(可以根据需求调整)
int cornerRadius = 120; // 圆角的半径
// 将图像裁剪成正方形,设置宽高400*400 (注意:一定要固定宽高)
BufferedImage squareImage = cropToSquare(originalImage, 400, 400);
// 创建带padding的圆角图像
BufferedImage paddedRoundedImage = createPaddedRoundedImage(squareImage, cornerRadius, padding, Color.WHITE);
// 保存结果图像
ImageIO.write(paddedRoundedImage, "PNG", new File("C:\\Users\\Admin\\Desktop\\feitu\\img100\\1tmp_8abe0efd9e58dfd1608a6f9affd987ef-e67efe7a-3fd8-482f-8f5d-30e686491a73.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
//调用时候使用这个方法,把main注释掉
// public static BufferedImage startImageWithRounded(BufferedImage originalImage) {
//
// // 设置padding和圆角半径
// int padding = 50; // 白色圆角区域的内边距(可以根据需求调整)
// int cornerRadius = 120; // 圆角的半径
//
// // 将图像裁剪成正方形,设置宽高400*400 (注意:一定要固定宽高)
// BufferedImage squareImage = cropToSquare(originalImage, 400, 400);
//
// // 创建带padding的圆角图像
// BufferedImage paddedRoundedImage = createPaddedRoundedImage(squareImage, cornerRadius, padding, Color.WHITE);
//
// return paddedRoundedImage;
//
// }
public static BufferedImage cropToSquare(BufferedImage originalImage, int targetWidth, int targetHeight) {
int width = originalImage.getWidth();
int height = originalImage.getHeight();
// 计算目标区域与图像的宽高比
double widthRatio = (double) targetWidth / width;
double heightRatio = (double) targetHeight / height;
// 选择较大的比例来保持图像的长宽比
double scaleRatio = Math.max(widthRatio, heightRatio); // 使用较大的比例
// 计算缩放后的图像尺寸
int newWidth = (int) (width * scaleRatio);
int newHeight = (int) (height * scaleRatio);
// 创建一个新的图像用于缩放
BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
Graphics2D g2d = scaledImage.createGraphics();
g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
g2d.dispose();
// 创建目标图像(固定宽高)
BufferedImage finalImage = new BufferedImage(targetWidth, targetHeight, originalImage.getType());
Graphics2D g2dFinal = finalImage.createGraphics();
// 计算裁剪区域的位置,居中显示
int xOffset = (newWidth - targetWidth) / 2;
int yOffset = (newHeight - targetHeight) / 2;
// 将缩放后的图像裁剪并绘制到目标图像上
g2dFinal.drawImage(scaledImage, -xOffset, -yOffset, null);
g2dFinal.dispose();
return finalImage;
}
// 创建带padding和圆角的图像
public static BufferedImage createPaddedRoundedImage(BufferedImage originalImage, int cornerRadius, int padding, Color backgroundColor) {
int originalWidth = originalImage.getWidth();
int originalHeight = originalImage.getHeight();
// 计算新图像的宽度和高度,包含padding
int newWidth = Math.max(originalWidth, originalHeight) + 2 * padding; // 选择最大宽度或高度,确保裁剪时是正方形
int newHeight = newWidth; // 确保是正方形的裁剪区域
// 动态调整cornerRadius,确保不会超过图像的宽度或高度的一半
int maxCornerRadius = Math.min(originalWidth, originalHeight) / 2;
cornerRadius = Math.min(cornerRadius, maxCornerRadius); // 防止圆角半径太大
// 创建一个新的BufferedImage来包含带有padding的图像
BufferedImage paddedRoundedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
// 获取Graphics2D对象
Graphics2D g2d = paddedRoundedImage.createGraphics();
// 启用抗锯齿渲染提示
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 启用抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); // 设置高质量插值
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // 优化质量
// 填充背景颜色
g2d.setColor(backgroundColor);
g2d.fillRoundRect(0, 0, newWidth, newHeight, cornerRadius, cornerRadius); // 绘制带圆角的背景
// 设置裁剪区域为圆角矩形,确保裁剪区域大小是填充后的正方形区域
g2d.setClip(new RoundRectangle2D.Double(padding, padding, originalWidth, originalHeight, cornerRadius, cornerRadius));
// 在新的图像上绘制原始图像(原图绘制到内边距后的区域)
g2d.drawImage(originalImage, padding, padding, null);
// 清理资源
g2d.dispose();
return paddedRoundedImage;
}
}
这个时候我们只需要读取生成好的图片即可,直接使用marker把label注释即可。
修改后的js代码
getBallCourtInfoByPoint(info).then((res) => {
const len = res.length;
for (let i = 0; i < len; i++) {
const element = res[i];
//获取质量最小的图片用于展示
let newUrl = element.ballCourtImageList[0].ballCourtImage.replace(/(\.(jpg|jpeg|png|gif))$/, '-min100\$1');
element['id'] = Number(element.id)
element['markerId'] = Number(element.id)
element['title'] = element.ballCourtName
element['latitude'] = Number(element.lat)
element['longitude'] = Number(element.lng)
element['lat'] = Number(element.lat)
element['lng'] = Number(element.lng)
element['iconPath'] = newUrl
element['width'] = 38
element['height'] = 38
// let label = {
// borderRadius: 8,
// borderWidth: 4,
// borderColor: '#fff',
// width: 38,
// height: 38,
// anchorX: -18,
// anchorY: -36,
// }
// element['label'] = label
});
还有一个问题,就是微信小程序读取较大的图片的时候会非常的慢,比如1M左右的图片就非常的慢了。我这里使用了MinIO文件系统存储图片,我会将用户上传的图片分割成两张图片,一张是原图,另一张是质量最小的图片,大概就是几十KB,读取的时候只需要读取几十KB的图片即可,等到用户查看详情再读取原图,所以为什么我这里读取了-min64结尾的图片。
//获取质量最小的图片用于展示
let newUrl = element.ballCourtImageList[0].ballCourtImage.replace(/(\.(jpg|jpeg|png|gif))$/, '-min100\$1');
详细请参考我的另一篇MinIO文章:https://blog.csdn.net/weixin_44912902/article/details/140353870