Апплет использует Canvas для рисования изображений и вертикального текста.

внешний интерфейс WeChat Открытый исходный код Canvas

введение

В свободное время нашел время написать небольшую программку для мануала по убийству генералов в Трех королевствах.Необходимо спроектировать синтетическую карту скинов генералов, вертикальную строку имён генералов и небольшой программный код, а затем предоставьте возможность сохранять изображения в альбом и, наконец, разрешите пользователям делиться ими. Перейдите на Moments или другие платформы. Составное изображение должно следоватьCanvasДокументы не имеют проблем, есть спрос на основной вертикальный текст, здесь и поделитесь с вами.

# реклама Продвигайте свою небольшую программу, если вам нравится Убийство Троецарствия, можете обратить на нее внимание, а если возникнут вопросы, можете добавить меня в WeChat для обсуждения.

扫码体验小程序

扫码添加好友,请备注:三国杀

текст

Сначала поместите изображение, которое в конечном итоге будет сохранено в альбоме~

Я чувствую себя хорошо, по крайней мере, я оправдал свои ожидания~~~

Давайте пошагово рассмотрим, как это сделать.

Вся картина делится на три части:

  1. Общие фотографии
  2. код апплета
  3. Общая текстовая информация

Давайте взглянемwxmlКод внутри, в основном, положилcanvasМетка, которая управляет свойствами высоты и ширины.

<view>
  <canvas class='share-canvas' style="width:100%;height:{{canvasHeight}}px" canvas-id="share_canvas"></canvas>
</view>

Общие фотографии

drawHeroImage: function (path) {
    var that = this;
    // 拿到canvas context
    let ctx = wx.createCanvasContext('share_canvas');
    // 为了保证图片比例以及绘制的位置,先要拿到图片的大小
    wx.getImageInfo({
      src: path,
      success: function (res) {
			
		  // 计算图片占比信息	
        let maxWidth = Math.min(res.width, that.data.canvasWidth * 0.65);
        let radio = maxWidth / res.width;

        let offsetY = (that.data.canvasHeight - res.height * radio) / 2;
        console.log('offsetY=' + offsetY);
        that.setData({
          imageWidth: res.width * radio,
          imageHeight: res.height * radio,
          offsetY: offsetY,
        });
        
        // 绘制canvas背景,不属于绘制图片部分
        ctx.setFillStyle('white')
        ctx.fillRect(0, 0, that.data.canvasWidth, that.data.canvasHeight);
        // 绘制武将图片,path是本地路径,不可以传网络url,如果是网络图片需要先下载
        ctx.drawImage(path, 10, offsetY, res.width * radio, res.height * radio)
        // 绘制小程序码
        that.drawQrCodeImage(ctx);
        // 绘制势力汉字:吴
        that.drawInfluence(ctx, that.data.hero.HERO.INFLUENCE);
        // 绘制武将姓名:陆逊
        that.drawName(ctx, that.data.hero.HERO.NAME);
        // 绘制武将称号:江陵侯
        that.drawHorner(ctx, that.data.hero.HERO.HORNER);
        // 最终调用draw函数,生成预览图
        // 一个坑点:只能调用一次,否则后面的会覆盖前面的
        ctx.draw();
      }
    });
  }

код апплета

Код апплета и изображение генерала однотипны, и это не что иное, как позиция, где нужно просчитать рисунок, соответствующий код здесь не будет показан.

Общая текстовая информация

Как вы можете видеть из кода только что, я разделил его на 3 части для рисования, на самом делеа также陆逊Его можно было бы собрать вместе, но когда я рисовал, я обнаружил, что пробел вызывает исключение при рисовании, так что текст за пробелом нельзя нарисовать, поэтому я здесьа также陆逊Пустое пространство в середине сделано смещением позиции.

Здесь мы покажем вам, как нарисовать звание генералов.

// 绘制武将称号:江陵侯
drawHorner: function (ctx, text) {
	// 设置字号
    ctx.setFontSize(26);
    // 设置字体颜色
    ctx.setFillStyle("#000000");
    // 计算绘制起点
    let x = this.data.offsetX + 35;
    let y = this.data.offsetY + 10;
    console.log('drawHorner' + text);
    console.log(x);
    console.log(y);
    // 绘制竖排文字,这里是个Util函数,具体实现请继续看
    Canvas.drawTextVertical(ctx, text, x, y);
  }

Для отрисовки вертикального текста нашел в интернете открытый исходник.Если нужно посмотреть принцип, смотритездесь

Конечно, я сделал здесь некоторые изменения, чтобы применить их к апплету.Прототип функции выглядит так:

CanvasRenderingContext2D.prototype.letterSpacingText = function (text, x, y, letterSpacing)

Прости меня не очень хорошоjs, я вообще не понимаю, что это за синтаксис.Я не понял его после прочтения некоторое время.Ощущение, что добавляют новые атрибуты в класс, независимо от него.

Неважно, белая это кошка или черная, пока она ловит мышей, она хорошая кошка.

Модифицированная функция выглядит так:

canvas.js

/**
* @author zhangxinxu(.com)
* @licence MIT
* @description http://www.zhangxinxu.com/wordpress/?p=7362
*/
function drawTextVertical(context, text, x, y) {
  var arrText = text.split('');
  var arrWidth = arrText.map(function (letter) {
    return 26;
    // 这里为了找到那个空格的 bug 做了许多努力,不过似乎是白费力了
    // const metrics = context.measureText(letter);
    // console.log(metrics);
    // const width = metrics.width;
    // return width;
  });
  
  var align = context.textAlign;
  var baseline = context.textBaseline;

  if (align == 'left') {
    x = x + Math.max.apply(null, arrWidth) / 2;
  } else if (align == 'right') {
    x = x - Math.max.apply(null, arrWidth) / 2;
  }
  if (baseline == 'bottom' || baseline == 'alphabetic' || baseline == 'ideographic') {
    y = y - arrWidth[0] / 2;
  } else if (baseline == 'top' || baseline == 'hanging') {
    y = y + arrWidth[0] / 2;
  }

  context.textAlign = 'center';
  context.textBaseline = 'middle';

  // 开始逐字绘制
  arrText.forEach(function (letter, index) {
    // 确定下一个字符的纵坐标位置
    var letterWidth = arrWidth[index];
    // 是否需要旋转判断
    var code = letter.charCodeAt(0);
    if (code <= 256) {
      context.translate(x, y);
      // 英文字符,旋转90°
      context.rotate(90 * Math.PI / 180);
      context.translate(-x, -y);
    } else if (index > 0 && text.charCodeAt(index - 1) < 256) {
      // y修正
      y = y + arrWidth[index - 1] / 2;
    }
    context.fillText(letter, x, y);
    // 旋转坐标系还原成初始态
    context.setTransform(1, 0, 0, 1, 0, 0);
    // 确定下一个字符的纵坐标位置
    var letterWidth = arrWidth[index];
    y = y + letterWidth;
  });
  // 水平垂直对齐方式还原
  context.textAlign = align;
  context.textBaseline = baseline;
}

module.exports = {
  drawTextVertical: drawTextVertical
}

рисовать веб-картинки

Поскольку сетевое изображение нельзя нарисовать напрямую, его необходимо сначала загрузить на локальный компьютер, а затем снова нажать и удерживать процесс рисования локального изображения.

downloadHeroImage: function () {
    // 微信不支持非https的图片下载,这里了个替换
    let url = this.data.hero.HERO.ICON.replace(/http/, "https");
    var that = this;
    wx.downloadFile({
      url: url,
      success: function (res) {
        // 下载成功后拿到图片的路径,然后开始绘制
        var path = res.tempFilePath;
        that.drawHeroImage(path);
      }, fail: function (res) {
        console.log(res)
      }
    });
  }

сохранить изображение

Сказав так много, последний шаг, естественно, необходим, который будет обращен кcanvasСнимок сохраняется в альбом мобильного телефона, здесь требуется авторизация пользователя, и вам нужно управлять им самостоятельно.

Мы используем интерфейс, предоставляемый WeChatwx.canvasToTempFilePath. Нам нужно передать координаты начальной точки(x, y)и размер холста(width, height)так же какcanvasId.

saveShareImage: function () {
    wx.showLoading({
      title: '正在保存图片..',
    });
    let that = this;
    wx.canvasToTempFilePath({
      x: 0,
      y: 0,
      width: that.data.canvasWidth,
      height: that.data.canvasHeight,
      canvasId: 'share_canvas',
      success: function (res) {
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success(res) {
            console.log(res);
            wx.showToast({
              title: '保存到相册成功',
              duration: 1500,
            })
          },
          fail(res) {
            console.log(res)
            wx.showToast({
              title: '保存到相册失败',
              icon: 'fail'
            })
          },
          complete(res) {
            console.log(res)
          }
        })
      }
    })
  }

Открытый исходный код

В духе открытого исходного кода исходный код был помещен вGithubВыше вы можете перейти к вышеуказанному, чтобы просмотреть конкретный код.

GitHub.com/history Z кричит…

Если это поможет вам, пожалуйста, дайтеStarбар~