小程序canvas 缩放/拖动/还原/封装和实例--开箱即用

news2024/11/28 12:36:37

小程序canvas 缩放/拖动/还原/封装和实例

  • 一、预览
  • 二、使用
    • 2.1 创建和配置
    • 方法
  • 三、源码
    • 3.1 实例组件
    • 3.2 核心类

一、预览

之前写过web端的canvas 缩放/拖动/还原/封装和实例。最近小程序也需要用到,但凡是涉及小程序canvas还是比较多坑的,而且难用多了,于是在web的基础上重新写了小程序的相关功能。实现功能有:

  • 支持双指、按钮缩放
  • 支持触摸拖动
  • 支持高清显示
  • 支持节流绘图
  • 支持还原、清除画布
  • 内置简化绘图方法

效果如下:
请添加图片描述

二、使用

案例涉及到2个文件,一个是绘图组件canvas.vue,另一个是canvasDraw.js,核心是canvasDraw.js里定义的CanvasDraw类

2.1 创建和配置

小程序获取#canvas对象后就可以创建CanvasDraw实例了,创建实例时可以根据需要设置各种配置,其中drawCallBack是必须的,是用户自定义的绘图方法,程序会在this.canvasDraw.draw()后再回调drawCallBack()来实现用户的绘图。
拖动、缩放画布都会调用this.canvasDraw.draw()。

    /** 初始化canvas */
    initCanvas() {
      const query = wx.createSelectorQuery().in(this)

      query
        .select('#canvas')
        .fields({ node: true, size: true, rect: true })
        .exec((res) => {
          const ele = res[0]
          this.canvasEle = ele

          // 配置项
          const option = {
            ele: this.canvasEle, // canvas元素
            drawCallBack: this.draw, // 必须:用户自定义绘图方法
            scale: 1, // 当前缩放倍数
            scaleStep: 0.1, // 缩放步长(按钮)
            touchScaleStep: 0.005, // 缩放步长(手势)
            maxScale: 2, // 缩放最大倍数(缩放比率倍数)
            minScale: 0.5, // 缩放最小倍数(缩放比率倍数)
            translate: { x: 0, y: 0 }, // 默认画布偏移
            isThrottleDraw: true, // 是否开启节流绘图(建议开启,否则安卓调用频繁导致卡顿)
            throttleInterval: 20, // 节流绘图间隔,单位ms
            pixelRatio: wx.getSystemInfoSync().pixelRatio, // 像素比(高像素比可以解决高清屏幕模糊问题)
          }
          this.canvasDraw = new CanvasDraw(option) // 创建CanvasDraw实例后就可以使用实例的所有方法了
          this.canvasDraw.draw() // 可以按实际需要调用绘图方法
        })
    },

方法

canvasDraw.draw() // 绘图
canvasDraw.clear() // 清除画布
canvasDraw.reset() // 重置画布(恢复到第一次绘制的状态)
canvasDraw.zoomIn() // 中心放大
canvasDraw.zoomOut() // 中心缩小
canvasDraw.zoomTo(scale, zoomCenter) // 缩放到指定倍数(可指定缩放中心点)
canvasDraw.destory() // 销毁
canvasDraw.drawShape(opt) // 内置简化绘制多边形方法
canvasDraw.drawLines(opt) // 内置简化绘制多线段方法
canvasDraw.drawText(opt) // 内置简化绘制文字方法

三、源码

3.1 实例组件

canvas.vue

<template>
  <view class="canvas-wrap">
    <canvas
      type="2d"
      id="canvas"
      class="canvas"
      disable-scroll="true"
      @touchstart="touchstart"
      @touchmove="touchmove"
      @touchend="touchend"
      @tap="tap"
    ></canvas>
  </view>
</template>
<script>
import { CanvasDraw } from './canvasDraw'

export default {
  data() {
    this.canvasDraw = null // 绘图对象
    this.canvasEle = null // canvas元素对象
    return {}
  },

  created() {},
  beforeDestroy() {
    /** 销毁对象 */
    if (this.canvasDraw) {
      this.canvasDraw.destroy()
      this.canvasDraw = null
    }
  },
  mounted() {
    /** 初始化 */
    this.initCanvas()
  },
  methods: {
    /** 初始化canvas */
    initCanvas() {
      const query = wx.createSelectorQuery().in(this)

      query
        .select('#canvas')
        .fields({ node: true, size: true, rect: true })
        .exec((res) => {
          const ele = res[0]
          this.canvasEle = ele

          // 配置项
          const option = {
            ele: this.canvasEle, // canvas元素
            drawCallBack: this.draw, // 必须:用户自定义绘图方法
            scale: 1, // 当前缩放倍数
            scaleStep: 0.1, // 缩放步长(按钮)
            touchScaleStep: 0.005, // 缩放步长(手势)
            maxScale: 2, // 缩放最大倍数(缩放比率倍数)
            minScale: 0.5, // 缩放最小倍数(缩放比率倍数)
            translate: { x: 0, y: 0 }, // 默认画布偏移
            isThrottleDraw: true, // 是否开启节流绘图(建议开启,否则安卓调用频繁导致卡顿)
            throttleInterval: 20, // 节流绘图间隔,单位ms
            pixelRatio: wx.getSystemInfoSync().pixelRatio, // 像素比(高像素比可以解决高清屏幕模糊问题)
          }
          this.canvasDraw = new CanvasDraw(option) // 创建CanvasDraw实例后就可以使用实例的所有方法了
          this.canvasDraw.draw() // 可以按实际需要调用绘图方法
        })
    },

    /** 用户自定义绘图内容 */
    draw() {
      // 默认绘图方式-圆形
      const { ctx } = this.canvasDraw
      ctx.beginPath()
      ctx.strokeStyle = '#f00'
      ctx.arc(150, 150, 120, 0, 2 * Math.PI)
      ctx.stroke()

      // 组件方法-绘制多边形
      const shapeOption = {
        points: [
          { x: 127, y: 347 },
          { x: 151, y: 304 },
          { x: 173, y: 344 },
          { x: 214, y: 337 },
          { x: 184, y: 396 },
          { x: 143, y: 430 },
          { x: 102, y: 400 },
        ],
        fillStyle: '#00f',
      }
      this.canvasDraw.drawShape(shapeOption)

      // 组件方法-绘制多线段
      const linesOption = {
        points: [
          { x: 98, y: 178 },
          { x: 98, y: 212 },
          { x: 157, y: 236 },
          { x: 208, y: 203 },
          { x: 210, y: 165 },
        ],
        strokeStyle: '#0f0',
      }
      this.canvasDraw.drawLines(linesOption)

      // 组件方法-绘制文字
      const textOption = {
        text: '组件方法-绘制文字',
        isCenter: true,
        point: { x: 150, y: 150 },
        fillStyle: '#000',
      }
      this.canvasDraw.drawText(textOption)
    },

    /** 中心放大 */
    zoomIn() {
      this.canvasDraw.zoomIn()
    },

    /** 中心缩小 */
    zoomOut() {
      this.canvasDraw.zoomOut()
    },

    /** 重置画布(回复初始效果) */
    reset() {
      this.canvasDraw.reset()
    },

    /** 事件绑定 */
    tap(e) {
      const p = {
        x: (e.detail.x - this.canvasEle.left) / this.canvasDraw.scale,
        y: (e.detail.y - this.canvasEle.top) / this.canvasDraw.scale,
      }
      console.log('点击坐标:', p)
    },
    touchstart(e) {
      this.canvasDraw.touchstart(e)
    },
    touchmove(e) {
      this.canvasDraw.touchmove(e)
    },
    touchend(e) {
      this.canvasDraw.touchend(e)
    },
  },
}
</script>
<style scoped>
.canvas-wrap {
  position: relative;
  flex: 1;
  width: 100%;
  height: 100%;
}

.canvas {
  width: 100%;
  flex: 1;
}
</style>

3.2 核心类

canvasDraw.js

/**
 * @Author: 卢景滔
 * @Date: 2022-05-23 18:54:29
 * @LastEditTime: 2022-05-24 12:46:55
 * @LastEditors: 卢景滔
 * @Description: 自定义小程序绘图类
 */

/**
 * 绘图类
 * @param {object} option
 */
export function CanvasDraw(option) {
  if (!option.ele) {
    console.error('canvas对象不存在')
    return
  }
  if (!option.drawCallBack) {
    console.error('缺少必须配置项:drawCallBack')
    return
  }
  const { ele } = option

  /** 外部可访问属性 */
  this.canvasNode = ele.node // wx的canvas节点
  this.canvasNode.width = ele.width // 设置canvas节点宽度
  this.canvasNode.height = ele.height // 设置canvas节点高度
  this.ctx = this.canvasNode.getContext('2d')
  this.zoomCenter = { x: ele.width / 2, y: ele.height / 2 } // 缩放中心点
  this.touchMoveEvent = null // 触摸移动事件

  /** 内部使用变量 */
  let startPoint = { x: 0, y: 0 } // 拖动开始坐标
  let startDistance = 0 // 拖动开始时距离(二指缩放)
  let curTranslate = {} // 当前偏移
  let curScale = 1 // 当前缩放
  let preScale = 1 // 上次缩放
  let drawTimer = null // 绘图计时器,用于节流
  let touchEndTimer = null // 触摸结束计时器,用于节流
  let fingers = 1 // 手指触摸个数

  /**
   * 根据像素比重设canvas尺寸
   */
  this.resetCanvasSize = () => {
    this.canvasNode.width = ele.width * this.pixelRatio
    this.canvasNode.height = ele.height * this.pixelRatio
  }

  /**
   * 初始化
   */
  this.init = () => {
    const optionCopy = JSON.parse(JSON.stringify(option))
    this.scale = optionCopy.scale ?? 1 // 当前缩放倍数
    this.scaleStep = optionCopy.scaleStep ?? 0.1 // 缩放步长(按钮)
    this.touchScaleStep = optionCopy.touchScaleStep ?? 0.005 // 缩放步长(手势)
    this.maxScale = optionCopy.maxScale ?? 2 // 缩放最大倍数(缩放比率倍数)
    this.minScale = optionCopy.minScale ?? 0.5 // 缩放最小倍数(缩放比率倍数)
    this.translate = optionCopy.translate ?? { x: 0, y: 0 } // 默认画布偏移
    this.isThrottleDraw = optionCopy.isThrottleDraw ?? true // 是否开启节流绘图(建议开启,否则安卓调用频繁导致卡顿)
    this.throttleInterval = optionCopy.throttleInterval ?? 20 // 节流绘图间隔,单位ms
    this.pixelRatio = optionCopy.pixelRatio ?? 1 // 像素比(高像素比解决高清屏幕模糊问题)

    startPoint = { x: 0, y: 0 } // 拖动开始坐标
    startDistance = 0 // 拖动开始时距离(二指缩放)
    curTranslate = JSON.parse(JSON.stringify(this.translate)) // 当前偏移
    curScale = this.scale // 当前缩放
    preScale = this.scale // 上次缩放
    drawTimer = null // 绘图计时器,用于节流
    fingers = 1 // 手指触摸个数

    this.resetCanvasSize()
  }

  this.init()

  /**
   * 绘图(会进行缩放和位移)
   */
  this.draw = () => {
    this.clear()
    this.ctx.translate(this.translate.x * this.pixelRatio, this.translate.y * this.pixelRatio)
    this.ctx.scale(this.scale * this.pixelRatio, this.scale * this.pixelRatio)
    // console.log('当前位移', this.translate.x, this.translate.y, '当前缩放倍率', this.scale)
    option.drawCallBack()
    drawTimer = null
  }

  /**
   * 设置默认值(
   */
  this.setDefault = () => {
    curTranslate.x = this.translate.x
    curTranslate.y = this.translate.y
    curScale = this.scale
    preScale = this.scale
  }

  /**
   * 清除画布(重设canvas尺寸会清空地图并重置canvas内置的scale/translate等)
   */
  this.clear = () => {
    this.resetCanvasSize()
  }

  /**
   * 绘制多边形
   */
  this.drawShape = (opt) => {
    this.ctx.beginPath()
    this.ctx.lineWidth = '1'
    this.ctx.fillStyle = opt.isSelect ? opt.HighlightfillStyle : opt.fillStyle
    this.ctx.strokeStyle = opt.HighlightStrokeStyle

    for (let i = 0; i < opt.points.length; i++) {
      const p = opt.points[i]
      if (i === 0) {
        this.ctx.moveTo(p.x, p.y)
      } else {
        this.ctx.lineTo(p.x, p.y)
      }
    }
    this.ctx.closePath()
    if (opt.isSelect) {
      this.ctx.stroke()
    }
    this.ctx.fill()
  }

  /**
   * 绘制多条线段
   */
  this.drawLines = (opt) => {
    this.ctx.beginPath()
    this.ctx.strokeStyle = opt.strokeStyle
    for (let i = 0; i < opt.points.length; i++) {
      const p = opt.points[i]
      if (i === 0) {
        this.ctx.moveTo(p.x, p.y)
      } else {
        this.ctx.lineTo(p.x, p.y)
      }
    }
    this.ctx.stroke()
  }

  /**
   * 绘制文字
   */
  this.drawText = (opt) => {
    this.ctx.fillStyle = opt.isSelect ? opt.HighlightfillStyle : opt.fillStyle
    if (opt.isCenter) {
      this.ctx.textAlign = 'center'
      this.ctx.textBaseline = 'middle'
    }
    this.ctx.fillText(opt.text, opt.point.x, opt.point.y)
  }

  /**
   * 重置画布(恢复到第一次绘制的状态)
   */
  this.reset = () => {
    this.init()
    this.draw()
  }

  /**
   * 中心放大
   */
  this.zoomIn = () => {
    this.zoomTo(this.scale + this.scaleStep)
  }

  /**
   * 中心缩小
   */
  this.zoomOut = () => {
    this.zoomTo(this.scale - this.scaleStep)
  }

  /**
   * 缩放到指定倍数
   * @param {number} scale 缩放大小
   * @param {object} zoomCenter 缩放中心点(可选
   */
  this.zoomTo = (scale, zoomCenter0) => {
    // console.log('缩放到:', scale, '缩放中心点:', zoomCenter0)
    this.scale = scale
    this.scale = this.scale > this.maxScale ? this.maxScale : this.scale
    this.scale = this.scale < this.minScale ? this.minScale : this.scale

    const zoomCenter = zoomCenter0 || this.zoomCenter
    this.translate.x = zoomCenter.x - ((zoomCenter.x - this.translate.x) * this.scale) / preScale
    this.translate.y = zoomCenter.y - ((zoomCenter.y - this.translate.y) * this.scale) / preScale
    this.draw()
    preScale = this.scale
    curTranslate.x = this.translate.x
    curTranslate.y = this.translate.y
  }

  /**
   * 触摸开始
   */
  this.touchstart = (e) => {
    fingers = e.touches.length
    if (fingers > 2) return
    this.setDefault()
    // 单指
    if (fingers === 1) {
      startPoint.x = e.touches[0].x
      startPoint.y = e.touches[0].y
    } else if (fingers === 2) {
      startDistance = this.get2PointsDistance(e)
    }
  }

  /**
   * 触摸移动
   */
  this.touchmove = (e) => {
    if (fingers > 2) return
    if (this.isThrottleDraw) {
      if (drawTimer) return
      this.touchMoveEvent = e
      drawTimer = setTimeout(this.touchmoveSelf, this.throttleInterval)
    } else {
      this.touchMoveEvent = e
      this.touchmoveSelf()
    }
  }

  /**
   * 触摸移动实际执行
   */
  this.touchmoveSelf = () => {
    const e = this.touchMoveEvent
    // 单指移动
    if (fingers === 1) {
      this.translate.x = curTranslate.x + (e.touches[0].x - startPoint.x)
      this.translate.y = curTranslate.y + (e.touches[0].y - startPoint.y)
      this.draw()
    } else if (fingers === 2 && e.touches.length === 2) {
      // 双指缩放
      const newDistance = this.get2PointsDistance(e)
      const distanceDiff = newDistance - startDistance
      const zoomCenter = {
        x: (e.touches[0].x + e.touches[1].x) / 2,
        y: (e.touches[0].y + e.touches[1].y) / 2,
      }
      this.zoomTo(curScale + this.touchScaleStep * distanceDiff, zoomCenter)
    } else {
      drawTimer = null
    }
  }

  /**
   * 触摸结束
   */
  this.touchend = () => {
    if (this.isThrottleDraw) {
      touchEndTimer = setTimeout(this.setDefault, this.throttleInterval)
    } else {
      this.setDefault()
    }
  }

  /**
   * 销毁
   */
  this.destroy = () => {
    clearTimeout(drawTimer)
    clearTimeout(touchEndTimer)
    drawTimer = null
    touchEndTimer = null
    this.canvasNode = null
    this.ctx = null
    this.touchMoveEvent = null
    option.drawCallBack = null
  }

  /**
   * 获取2触摸点距离
   * @param {object} e 触摸对象
   * @returns 2触摸点距离
   */
  this.get2PointsDistance = (e) => {
    if (e.touches.length < 2) return 0
    const xMove = e.touches[1].x - e.touches[0].x
    const yMove = e.touches[1].y - e.touches[0].y
    return Math.sqrt(xMove * xMove + yMove * yMove)
  }
}

export default CanvasDraw

兄弟,如果帮到你,点个赞再走

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/85515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Node.js计算机毕业设计订餐系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Linux中如何查看ntp是否同步?

Linux中如何查看ntp是否同步?在Linux中&#xff0c;查看ntp是否同步的方法主要有三种&#xff0c;分别是&#xff1a;ntpd命令、ntpstat命令、timedatectl命令&#xff0c;接下来是详细的内容介绍。  NTP用于将计算机客户或服务器的时间同步到另一服务器或参考时钟源。它使用…

Java基于微信小程序的计算机等级考试考练 毕业设计

网络的广泛应用给生活带来了十分的便利。所以把计算机等级考试考练与现在网络相结合&#xff0c;利用java技术建设计算机等级考试考练APP&#xff0c;实现计算机等级考试考练的信息化。则对于进一步提高计算机等级考试考练发展&#xff0c;丰富计算机等级考试考练经验能起到不少…

[附源码]Python计算机毕业设计电商后台系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

web前端期末大作业——HTML+CSS+JavaScript仿王者荣耀游戏网站设计与制作

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

基于kmeans算法的数据聚类matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 聚类算法也许是机器学习中“新算法”出现最多、最快的领域&#xff0c;一个重要的原因是聚类不存在客观标准&#xff0c;给定数据集总能从某个角度找到以往算法未覆盖的某种标准从而设计出新算法…

VR工厂:助力工厂数字化升级

近年来&#xff0c;疫情全球常态化和数字化进程加速&#xff0c;给传统制造业工厂在生产制作、业务销售上带来巨大考验。随着物联网、云计算、大数据和5G等信息技术的发展&#xff0c;制造工厂面临着第四次工业革命。2021年&#xff0c;国家发布“十四五规划”&#xff0c;着重…

Geometry空间几何数据的处理应用(全)

学前小故事 学前必备基础知识 WTK格式的Geomotry GeoJSON格式的Geomotry JTS(Java Topology Suite) Java拓扑套件 JTS(Java Topology Suite) 可视化界面 泰森多边形 向空间数据库插入数据 栅格 GDAL GeoTools QGIS 学前小故事 项目需求是跟用户当前位置判断是否在…

基于Android的校园新闻APP

功能需求&#xff1a; 客户端&#xff1a; 1&#xff1a;登录注册&#xff1a;用户可以通过自己的信息进行账号的注册和登录 2&#xff1a;校园新闻&#xff1a;本模块主要是介绍在本校的网站上面关于校园新闻的介绍&#xff0c;而本部分所针对的对象是所有人&#xff08;包括了…

数字孪生赋能农业与农村的背景

数字乡村是伴随网络化、信息化和数字化在农业农村经济社会发展中的应用&#xff0c;以及农民现代信息技能的提高而内生的农业农村现代化发展和转型进程&#xff0c;既是乡村振兴的战略方向&#xff0c;也是数字孪生赋能、推动构建数字中国的重要内容。 数字孪生赋能农业与农村的…

Document Dewarping with Control Points学习笔记

1 核心思想 论文&#xff1a;Document Dewarping with Control Points 代码&#xff1a;https://github.com/gwxie/document-dewarping-with-control-points 一种通过估计控制点和参考点来纠正失真文档图像的简单而有效的方法。 控制点和参考点由相同数量的顶点组成&#xff0…

MIT张锋教授的Science论文,成功转化出一家新公司,融资2亿美元

基因治疗或基因疗法&#xff08;Gene therapy&#xff09;是利用分子生物学方法将目的基因导入患者体内&#xff0c;使之达成目的基因产物&#xff0c;从而使疾病得到治疗。作为疾病治疗的新手段&#xff0c;基因治疗已有一些成功的应用&#xff0c;并且科学突破将继续推动基因…

全栈Jmeter接口测试(八):jmeter接口自动化测试操作流程,计数器,定时器

Jmeter(16)&#xff1a;jmeter接口自动化测试操作流程 在企业使用jmeter开展实际的接口自动化测试工具&#xff0c;建议按如下操作流程&#xff0c; 可以使整个接口测试过程更规范&#xff0c;更有效。 接口自动化的流程&#xff1a; 1、获取到接口文档&#xff1a;swagger、…

用openCV在图片上绘画标记

1.在图片上画图&#xff08;直线&#xff0c;矩形&#xff0c;圆形&#xff0c;多边形&#xff09; import numpy as np import cv2img cv2.imread(watch.jpg,cv2.IMREAD_COLOR)#给图片加线#参数分别表示&#xff0c;起始和终止点的坐标…

Git---本地仓库有多条commit,如何push某一条commit到远端

默认情况下&#xff0c;git push会推送暂存区所有提交&#xff08;也即HEAD及其之前的提交&#xff09;&#xff0c;使用下面的命令可以改变此默认行为&#xff1a; $ git push <remotename> <commit SHA>:<remotebranchname>举例如下&#xff1a; git pus…

小美,这篇查询SQL执行流程你一定要看

前言 宿舍里&#xff0c;小A兴致满满的将刚写好的查询SQL执行流程文章通过微信发给小美&#xff0c;回想起昨晚透过窗户意外看到小美哭的梨花带雨&#xff0c;问过她室友才知道竟然是因为面试被SQL执行流程给难住了。心里暗自下决心&#xff1a;作为小美背后的男人&#xff0c…

MongoDB Node 驱动简介

MongoDB Node 驱动介绍 1. MongoDB数据库连接指南 使用原生的mongodb Node驱动连接MongoDB数据库。 1.1 数据库连接URI 数据库连接URI是一个指明了数据库地址、名称、用户名、密码的字符串&#xff0c;类似于网页链接。 1.2 Node驱动安装 使用Npm或者Yarn安装数据库驱动程…

LeetCode题解13 (102,226) 二叉树的层序遍历,翻转二叉树

文章目录二叉树的层序遍历(102)代码解答&#xff1a;翻转二叉树(226)代码解答:二叉树的层序遍历(102) 思路(前序,后序,中序遍历): 二叉树的层序遍历不同于二叉树的前序,后序,中序遍历,层序遍历是将二叉树的每一层从根部开始进行遍历&#xff0c; 将每一层的节点都放到1个集合中…

推断统计 | 学习笔记

一.概率与概率分布 概率论&#xff1a;为解决不确定性问题提供方法 1.随机事件及其概率 基本概念 试验&#xff1a;在相同条件下&#xff0c;对事物或现象所进行的观察。特点是可以在相同的条件下重复进行&#xff1b;每次试验的可能结果不止一个&#xff0c;但试验的所有可…

l2a股接口的委托队列有什么作用?

l2a股接口的委托队列是Level 2行情特有的功能&#xff0c;如下图&#xff0c;在传统交易页面中&#xff0c;可以看到个股封板涨停有35994手&#xff0c;但是不能具体看到各笔委托单的数量&#xff0c;不利于我们甄别究竟是主力在强势封板还是散户在跟风。 而在Level 2行情中可以…