Echarts -- ZRender 源码分析

Echarts 源码解读 一:zrender源码分析1var zr = zrender.init(document.getElementById(‘main‘)); 2021SC@SDUSC 因为Echarts是基于zrender进行实现的,所以解读echarts源码前,首先要对zrender有基本的了解。 zrender是canvas的一个类库,zrender是基于canvas实现的。 目录 zrender的src文件夹 文件夹: animation动画相关 contain包含判断 core核心代码,包含一些工具(util.js)、事件(event.js)、唯一ID(guid.js)、矩阵运算有关(matrix.js)等 dom... 阅读详情

背景

ZRender 是 Echarts 的底层图形绘制引擎,它是一个独立发布的基于 Canvas/SVG/VML 的 2D 图形绘制引擎,提供功能:

  • 图形绘制及管理(CRUD、打组)
  • 图形(包含文字)动画管理
  • 图形(包含文字)事件管理(Canvas 中实现 dom 事件)
  • 基于“响应式”(dirty 标记)的高效帧渲染机制
  • 可选择的渲染器机制:Canvas/SVG/VML(5.0 已放弃 VML 支持)

PS:图形特指 2D 矢量图型

整体架构

基于MVC模式的整体架构

在这里插入图片描述

如图所示,ZRender 的整体设计思路是面向对象的 MVC 模式,视图层负责渲染,控制层负责用户输入交互,数据层负责数据模型的编排与存储,其对应的文件和作用如下:

  • Storage.ts(数据模型):用于存储所有需要绘制的图形数据,并且提供相关数据的 LRU 缓存机制,提供数据的 CURD 管理
  • PainterBase.ts(视图绘制):PainterBase 是绘制的基类,系统提供的 Canvas、SVG、VML 视图绘制类都继承于 PainterBase 类,用户也可以自行继承实现如 webgl 的绘制能力
  • Handler.ts(交互控制):事件交互控制模块,为图形元素实现和 HTML、DOM、Element 一样的事件交互逻辑,如图形的选中、单击、触摸等事件

辅助功能模块

除了上述 MVC3 大模块以外,还有以下辅助功能模块:

  • 动画管理模块(animation):管理图形的动画,绘制前会将对象的动画计算成帧对象保存在动画管理器中,伴随着动画触发条件,将帧数据推送给视图绘制模块进行动画绘制
  • 工具类模块(tool、core):提供颜色转换、路径转换、变换矩阵运算、基础事件对象封装、向量计算、基础数据结构等独立辅助计算函数或者类
  • 图形对象模块(graphic):提供元素的对象类(包含 Image、Group、Arc、Rect 等),所有元素其最顶层都继承于 Element 类
  • 图形对象辅助模块(contain):提供用于判断包含关系的算法,比如:坐标点是否在线上,坐标点是否在图形内

PS:上文中“元素”包含 Group 和 2D 图形,而图形只包含 2D 图形,不包含 Group

源码文件结构

目录结构

src/
  -|config.ts
  -|Element.ts
  -|Storage.ts
  -|Handler.ts
  -|PainterBase.ts
  -|zrender.ts //入口文件
  -|export.ts
  -|animation/
    -|Animation.ts
    -|Animator.ts
    -|Clip.ts
    ...
  -|canvas/
    -|Painter.ts
    ...
  -|svg/
    -|Painter.ts
    ...
  -|vml/
    -|Painter.ts
    ...
  -|conatin/
    -|arc.ts
    ...
  -|core/
    -|LRU.ts
    -|matrix.ts
    ...
  -|dom/
  -|graphic/
    -|Group.ts
    -|Image.ts
    -|Path.ts
    -|shape/
      -|Arc.ts
      -|Rect.ts
      -|Circle.ts
      ...
    ...
  -|mixin/
    -|Draggable.ts
  -|tool/
    -|color.ts
    -|ParseSVG.ts
    -|parseXML.ts

目录及文件介绍

文件名文件介绍
config.ts全局配置文件,可配置 debug 模式、retina 屏幕高清优化、深/浅主题色值等
Element.ts所有可绘制图形元素和 Group 的基类,其中定义了基础属性、对象的基础成员方法
Storage.tsM层,对象模型层/存储器层,存储并管理元素对象实例,元素对象实例存储在 _displayableList 数组中,每次绘制时会根据 zlevel -> z -> 插入顺序进行排序,提供添加、删除、清空注销元素对象实例的方法
Handler.tsC层,控制层/器,用于向元素上绑定事件,实现 DOM 式事件管理机制
PainterBase.tsV层,视图层/渲染器层,PainterBase 是渲染器的基类,5.0 版本默认提供 Canvas、SVG 渲染器,5.0 之前版本还提供 VML 渲染器,元素的绘制就是由渲染器决定,系统默认 Canvas 渲染器渲染
zrender.tsZRender 入口文件,也是编译主入口
export.ts编译时调用,用于对外导出 API
animation存放动画相关的代码文件,如:Animation,Animator 等
canvas/svg/vml存放 canvas/svg/vml 渲染器相关的代码文件
contain用于补充特殊元素的坐标包含关系计算方法,如贝塞尔曲线上的点包含关系计算
core工具方法文件,包含 LRU 缓存、包围盒计算、浏览器环境判断、变换矩阵、触摸事件实现等方法
dom仅 HandlerProxy.ts 一个程序文件,用于实现 DOM 事件代理,所有画布内元素的事件都是从画布 DOM 的事件进行代理进入
graphic所有元素的实体对象类都存放在这个文件夹,包含 Group、可绘制对象基类 Displayable、路径、圆弧、矩形等
mixin仅 Draggable.ts 一个文件,用于管理元素的拖拽事件,因为 Echarts 用不上拖拽,所以拖拽事件还没有在 ts 版本中实现
tool工具方法,提供颜色计算、SVG 路径转换等工具类

入口文件源码分析(zrender.ts)

ZRender全局暴露的方法

zrender.ts 中对外暴露的全局方法如下所示,全局方法可通过 zrender.xxx 即可调用,如:zrender.init()

全局方法主要用于管理 ZRender 实例,如初始化、删除、查找、注销等操作

// 用于存放渲染器
const painterCtors: Dictionary<PainterBaseCtor> = {};

// 用于存放ZRender实例,后文对于实例统称zr
let instances: { [key: number]: ZRender } = {};

/**
 * 按id删除ZRender实例
 */
function delInstance(id: number) {
  // 代码省略
}

/**
 * 初始化ZRender实例,需要传入dom节点作为canvas父级
 */
 export function init(dom: HTMLElement, opts?: ZRenderInitOpt) {
  const zr = new ZRender(zrUtil.guid(), dom, opts);
  instances[zr.id] = zr;
  return zr;
}

/**
* 注销zr实例,注销后会将zr实例内的图形全部删除,不可恢复
*/
export function dispose(zr: ZRender) {
  zr.dispose();
}

/**
* 注销ZRender中管理的所有zr实例
*/
export function disposeAll() {
  // 代码省略
}

/**
* 通过实例id获取zr实例
*/
export function getInstance(id: number): ZRender {
  return instances[id];
}

/**
 * 注册渲染器,系统在启动时会默认注册Canvas和SVG渲染器
 */
export function registerPainter(name: string, Ctor: PainterBaseCtor) {
  painterCtors[name] = Ctor;
}

class ZRender {
  // 后文详解
}

ZRender对象类

ZRender 类写在入口文件 zrender.ts 中

class ZRender {
  // 画布渲染的容器根节点,必须是一个HTML元素
  dom: HTMLElement
  // zr实例id
  id: number
  // 存储器对象实例
  storage: Storage
  // 渲染器对象实例
  painter: PainterBase
  // 控制器对象实例
  handler: Handler
  // 动画管理器对象实例
  animation: Animation

  constructor(id: number, dom: HTMLElement, opts?: ZRenderInitOpt) {
    // 初始化容器根节点
    this.dom = dom;
    // 全局init函数会生成guid传入
    this.id = id;
    // new存储器实例
    const storage = new Storage();
    // 默认渲染器类型为canvas
    let rendererType = opts.renderer || 'canvas';
    // 创建渲染器
    const painter = new painterCtors[rendererType](dom, storage, opts, id);
    // 将存储器实例赋值给成员变量
    this.storage = storage;
    // 将渲染器赋值给成员变量
    this.painter = painter;
    // 创建事件管理器
    this.handler = new Handler(storage, painter, handerProxy, painter.root);
    // 创建动画管理器并启动动画管理程序
    this.animation = new Animation({
      stage: {
        update: () => this._flush(true)
      }
    });
    this.animation.start();
  }

  /**
   * 向画布添加元素,等待下一帧渲染
   */
  add(el: Element) {
    // 代码省略,后续的方法体代码如果无特别说明都会省略
  }

  /**
   * 从存储器中间元素删除,下一帧该元素将不会被渲染
   */
  remove(el: Element) { }

  /**
   * 配置图层顺序、开启动态模糊等
   */
  configLayer(zLevel: number, config: LayerConfig) { }

  /**
   * 设置画布背景色
   */
  setBackgroundColor(backgroundColor: string | GradientObject | PatternObject) { }

  /**
   * 获取画布背景色
   */
  getBackgroundColor() { }

  /**
   * 将zr强制设置为深色模式
   */
  setDarkMode(darkMode: boolean) { }

  /**
   * 查询当前zr是否深色模式
   */
  isDarkMode() { }

  /**
   * 执行强制刷新画布
   */
  refreshImmediately(fromInside?: boolean) { }

  /**
   * 执行下一帧刷新画布
   */
  refresh() { }

  /**
   * 执行所有刷新操作
   */
  flush() {
    this._flush(false);
  }

  /**
   * 设置动画静止帧数,动画将会在设置的帧数后停止执行
   */
  setSleepAfterStill(stillFramesCount: number) {
    this._sleepAfterStill = stillFramesCount;
  }

  /**
   * 唤醒动画,等下次渲染时执行
   */
  wakeUp() { }

  /**
   * 下一帧显示鼠标悬浮状态
   */
  refreshHover() { }

  /**
   * 强制执行鼠标悬浮状态
   */
  refreshHoverImmediately() { }

  /**
   * 调整画布大小
   */
  resize(opts?: {
    width?: number | string
    height?: number | string
  }) { }

  /**
   * 强制停止并清空动画
   */
  clearAnimation() { }

  /**
   * 获取画布宽度
   */
  getWidth(): number { }

  /**
   * 获取画布高度
   */
  getHeight(): number { }

  /**
   * 将路径绘制成图片,提高绘制性能
   */
  pathToImage(e: Path, dpr: number) { }

  /**
   * 设置鼠标样式
   * @param cursorStyle='default' 例如 crosshair
   */
  setCursorStyle(cursorStyle: string) { }

  /**
   * 查找鼠标当前位置元素的对象实例
   */
  findHover(x: number, y: number): {
    target: Displayable
    topTarget: Displayable
  } { }

  /**
   * 挂载全局事件,这里是ts的on方法多态
   */
  on<Ctx>(eventName: ElementEventName, eventHandler: ElementEventCallback<Ctx, unknown>, context?: Ctx): this
  on<Ctx>(eventName: string, eventHandler: EventCallback<Ctx, unknown>, context?: Ctx): this
  on<Ctx>(eventName: string, eventHandler: EventCallback<Ctx, unknown> | EventCallback<Ctx, unknown, ElementEvent>, context?: Ctx): this { }

  /**
   * 卸载全局事件
   */
  off(eventName?: string, eventHandler?: EventCallback<unknown, unknown> | EventCallback<unknown, unknown, ElementEvent>) { }

  /**
   * 按照事件名称手动触发事件
   */
  trigger(eventName: string, event?: unknown) { }


  /**
   * 清空画布及其已绘制的图形元素
   */
  clear() { }

  /**
   * 将ZRender对象注销
   */
  dispose() { }
}

案例分析ZRender工作流程

案例

下面代码是绘制一个半径为 30px 的玫红色(色值#FF6EBE)圆形,并为圆形绑定左右移动循环动画。

// 1.声明绘制ZRender实例的DOM容器
let container = document.getElementsById('example-container')[0];
// 2.初始化ZRender实例zr、同时zr会绘制画布与container同宽高
let zr = zrender.init(container);

// 3.获取zr画布的宽高
let w = zr.getWidth();
let h = zr.getHeight();

// 4.设定圆的半径为30px
let r = 30;

// 5.创建圆形对象实例cr
let cr = new zrender.Circle({
  shape: {
    cx: r,
    cy: h / 2,
    r: r
  },
  style: {
    fill: 'transparent',
    stroke: '#FF6EBE'
  },
  silent: true
});

// 6.为圆cicle绑定形状动画,参数true表示循环执行
cr.animate('shape', true)
  .when(5000, {
    cx: w - r
  })
  .when(10000, {
    cx: r
  })
  .start();

// 7.将圆形对象实例cricle添加到zr实例中进行渲染
zr.add(cr);

ZRender绘制流程

以下是上面案例 ZRender 的绘制流程图:

在这里插入图片描述

1)创建 ZRender 实例

使用const zr = zrender.init(),可多 zr 实例,每个实例都拥有自己的画布

2)创建需要绘制的图形实例

图形类名可通过zrender.xxx获得,其中 xxx 为图形类名

3)zr.add 方法将图形实例添加到存储器

// zrender.ts
add(el: Element) {
  // 将el(这里为cr实例)添加到存储器
  this.storage.addRoot(el);

  // 并且将动画放入动画管理器
  el.addSelfToZr(this);

  // 启动绘制程序
  this.refresh();
}

3B、C、D:将图形上绑定的动画添加到动画管理器,生成动画帧,启动动画绘制

4)zr 实例化时就已经启动逐帧扫描程序

这里存储器有可渲染的元素被捕获后才会执行渲染动作

// zrender.ts
class Zrender {
  constructor() {
    this.animation = new Animation({
      stage: {
        // 将渲染程序绑定到帧渲染策略
        update: () => this._flush(true)
      }
    });
    // 启动动画管理器,启动帧渲染扫描rAF程序
    this.animation.start();
  }

  // 下一帧执行渲染
  _flush() {
    this.refreshHoverImmediately();
  }

  // 强制渲染
  refreshHoverImmediately() {

    // 调用渲染器渲染程序
    this.painter.refresh();
  }
}

5)上一步的 this.panter.refresh() 会请求 storage 去获取渲染列表

// canvas/Painter.ts
class Painter {
  refresh() {
    // 获取渲染列表
    const list = this.storage.getDisplayList(true);
  }
}

// Storage.ts
class Storage {
  /**
    * 更新图形的绘制队列。
    * 每次绘制前都会调用,该方法会先深度优先遍历整个树,
    * 更新所有Group和Shape的变换并且把所有可见的Shape保存到数组中,
    * 最后根据绘制的优先级(zlevel > z > 插入顺序)排序得到绘制队列
    */
  getDisplayList() {
    // 返回渲染列表
    return this._displayList
  }

6)启动并执行渲染程序,进行图形的路径绘制

主要方法为:doPaintList -> doPaintEl

echarts问题总结 1.点击事件简单应用 const _this = this// vue中参数传递 this.chartOne = echarts.init(document.getElementById('chartOne')); this.chartTow.setOption(optionOne); //设置option this.chartTow.getZr().on('click', (params) => {// getZr() if (!params.target) { // 点击在 阅读详情

相关推荐

ECharts 3.0底层zrender 3.x源码分析1-总体架构

zrender是一个轻量级的Canvas类库,作为百度Echarts 3.0的底层基础。截至目前查看的zrender源码和文档,包括官网文档都还停留在2.x时代,我打算用一个系列介绍下zrender 3.x的使用和源码,一些demo和没有在博客中介绍的源码请进我的github仓库。 https://github.com/zrysmt/echarts3/tree/master/zrender 基于

前端-后端学习之路 2万+

探索ZRender:一个强大的JavaScript图形渲染库

是由阿里巴巴E-Commerce前端团队开发的一个轻量级、高性能的2D图形渲染引擎。这个项目致力于提供一套完整的API和工具集,帮助开发者在Web环境中进行各种复杂的图形绘制,包括但不限于数据可视化、图表制作、游戏场景搭建等。 ## 技术分析 1. **WebGL兼容**:ZRender基于Canvas和WebGL两种渲染方式,能自动选择最合适的渲染模式,保证在各类设备上都能流畅运行。 2....

gitblog_00043的博客 1793

ECharts 3.0底层zrender 3.x源码分析2-Painter(V层)

上一篇介绍了zrender的总体结构,这一篇我们就详细介绍View层–Painter(Painter.js)。一些demo和没有在博客中介绍的源码请进我的github仓库。 https://github.com/zrysmt/echarts3/tree/master/zrender Painter利用canvas负责真正的绘图操作。 * 1.负责canvas及其周边DOM元素的创建与处理

前端-后端学习之路 1万+

zrender源码学习笔记(一):认识zrender

入门echarts的渲染引擎zrender,了解其渲染原理

weixin_45853098的博客 2296

ECharts 3.0底层zrender 3.x源码分析3-Handler(C层)

这一篇,介绍下Handler处理机制。Handler负责事件处理,包括’click’, ‘dblclick’, ‘mousewheel’, ‘mouseout’, ‘mouseup’, ‘mousedown’, ‘mousemove’, ‘contextmenu’等。我们知道canvas API没有提供监听每个元素的机制,这就需要一些处理。处理的思路是:监听事件的作用坐标(如点击时候的

前端-后端学习之路 4343

ECharts 3.0源码简要分析1-总体架构

百度的Echarts 3.0作为前端领域可视化重要的开源库,是我们在日常工作生活中经常使用的,所以有必要一起来了解下Echarts的源码。我打算用一个系列介绍下Echarts 3.x的使用和源码,一些demo和没有在博客中介绍的源码请进我的github仓库。 https://github.com/zrysmt/echarts3/tree/master/echarts 本博文Echarts版本基于

前端-后端学习之路 1万+

ZRender: 强大的轻量级 Canvas 类库

ZRender 是一个轻量级的 Canvas 类库,由百度 ECharts 团队开发,它提供了丰富的图形绘制能力和交互能力。作为一个独立的 Canvas 渲染引擎,ZRender 不仅为 ECharts 提供底层支持,也可以独立使用来开发各种 2D 图形应用。// 创建自定义图形类// 自定义绘制逻辑// ...ZRender 作为一个成熟的 Canvas 类库,为开发者提供了强大而灵活的 2D 绘图能力。无论是开发数据可视化应用,还是制作互动性的图形界面,ZRender 都是一个值得考虑的选择。

exlink2012的专栏 1150

Echarts源码分析项目综述

Echarts简介 ECharts(Apache ECharts),一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。 Echarts提供丰富的可视化类型,多种数据格式无需转换就可直接使用,拥有千万数据的前端展示、深度的交互式数据探索、多维数据的支持以及丰富的视...

Lingfur的博客 790

ECharts 3.0底层zrender 3.x源码分析3-Handler(C层)canvas事件

这一篇,介绍下Handler处理机制。 Handler负责事件处理,包括’click’, ‘dblclick’, ‘mousewheel’, ‘mouseout’, ‘mouseup’, ‘mousedown’, ‘mousemove’, ‘contextmenu’等。我们知道canvas API没有提供监听每个元素的机制,这就需要一些处理。处理的思路是:监听事件的作用坐标(如点击时候的坐标),...

細水、長流√的专栏 774

ZRender 和 Echarts:数据可视化的强大工具

在当今信息爆炸的时代,数据的可视化变得越来越重要。ZRender 和 Echarts 是两个功能强大的工具,它们为开发人员提供了丰富的数据可视化功能和灵活的定制选项。本文将介绍 ZRender 和 Echarts 的特点和用法,并提供相应的源代码示例。

FpwgTcl的博客 586

你真的了解Canvas吗--解密一【ZRender篇】

本文讲讲zrender的初始化init过程

swj的博客 555

zrender源码分析1:总体结构

为什么80%的码农都做不了架构师?>>> ...

weixin_34357887的博客 301

Echarts-ZRender源码解析

Echarts-ZRender的源码非常庞大,并且由于篇幅限制,无法在这里进行详细的源码解析。渲染器是Echarts-ZRender的关键组件,负责将图形元素绘制到画布上。生成GUID的方法是基于时间戳和随机数的组合,保证了生成的ID在一定程度上的唯一性。核心模块是Echarts-ZRender的基础,它包含了一些通用的工具函数和基本的绘图方法。图形类是Echarts-ZRender的重要组成部分,它定义了各种图形元素的属性和行为。图形类定义了各种图形元素的属性和行为,每个图形元素都对应一个独立的类。

FpwgTcl的博客 415

动态渲染拓扑图方案探究

前言 拓扑图是数据可视化领域一种比较常见的展示类型,目前业界常见的可视化展现的方案有ECharts、HighCharts、D3、AntV等。当前的项目使用的是基于ECharts的静态关系图渲染,为了后续可能扩展成动态的拓扑图渲染,本文探索了ECharts的原理以及G6的原理,也算是对自研一个可视化库的基本实现方法做了一个梳理。 方案选择 ECharts 关系图 AntV G6 Graphin 源码解析 ECharts源码 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来.

we452366的博客 1485

SAP ABAP VL09 BAPI VL 216

ls_batch_item-fact_unit_denom = ls_lips_split-umvkn. "销售数量转换为 SKU 的值(分母)ls_batch_item-fact_unit_nom = ls_lips_split-umvkz. "销售数量转换成SKU的分子(因子)ls_batch_item-sales_unit_iso = ls_lips_split-meins. "被拆分DN基本单位。

ChampaignWolf的专栏 2300

Claude code-review 插件深度解析:AI 驱动的智能代码审查系统

Claude Code Review 插件深度解析:AI 驱动的智能代码审查系统 该插件通过多 Agent 并行工作方式自动审查 PR,采用置信度评分机制(80+分保留)过滤误报,确保高质量反馈。核心功能包括: 5个专业化 Agent 并行审查(规范合规性、bug检测、历史分析等) 8步工作流程:从资格检查到 GitHub 评论发布 创新性置信度评分系统(0-100分),严格过滤7类误报 结合 CLAUDE.md 规范和历史 PR 评论实现一致性审查 技术亮点: 多 Agent 架构(Haiku/Sonne

虚心若愚 2266

echarts.js源代码分析

listProto.mapArray = function (dimensions, cb, context, contextCompat) { // listProto是var List = function (dimensions, hostModel) { 的属性。var resetDefines = context.resetDefines = normalizeToArray(context.reset( // context.reset就是上述reset函数。

u013384469的博客 534

STM32N6:MCU+NPU架构如何重塑边缘AI部署新范式

STM32N6作为业界首款MCU+NPU架构的通用微控制器,通过集成600 GOPS算力的NPU与800MHz Cortex-M55内核,实现了边缘AI部署的革命性突破。该方案在工业视觉和智能家居等场景中,以超低功耗和成本提供实时AI处理能力,性能较传统MCU提升超100倍,重塑了边缘智能设备的设计范式。

g8f9d0s1a2的博客 1292

echarts 源码分析 —— 基本框架

一:基本介绍 1、echarts 底层依赖 ZRender,一个轻量级的二维绘制库。 2、echarts 源码可以编译成三个版本,分别为完整版本、常用版本和精简版本,入口是下面三个文件。 3、echarts 的基本使用: /** * 1、基于准备好的 dom,初始化 echarts 实例,参数分别是 dom、theme 和 opts。 * 1)、dom 是 echarts 挂载的容器。 * 2)、theme 是图表主题,可以在 主题下载 - Apache E...

weixin_42756155的博客 4709

【黑马点评】项目知识点及面经整理

【黑马点评】项目知识点及面经整理

m0_52031708的博客 6605

STK与Matlab连接报错?手把手教你解决mexConnect函数执行问题(附完整避坑指南)

本文针对STK与Matlab连接时常见的“mexConnect函数执行”报错,提供了完整的诊断与解决方案。文章深入剖析了错误根源在于路径冲突或文件损坏,并手把手指导用户通过定位STK连接器文件、正确配置Matlab路径(包括使用addpath命令)以及执行初始化测试三步走策略,彻底解决问题。同时附上版本兼容性检查、安装避坑指南及构建稳健工作流的建议,帮助用户建立可靠的STK-Matlab联合仿真环境。

yolo5detector的博客 473

zrender源码分析(1)

今天有点累,改天再写了。先简单说一下,也是看echarts的源码,发现它的底层用的zrender,再往下看是用了google的excanvas.js兼容ie(使用了vml)。使用的过程中用的是连式编程,猜到内部简单实现了promise,做了个Deferred,为了简单咱们从它的低版本研究开始,只为弄懂原理,循序渐进么,提升一下自己的逼格

u013067420的博客 1597

UE5 StateTree实战:用分层状态机重构你的AI行为逻辑(附蓝图配置避坑点)

本文详细介绍了UE5中StateTree分层状态机的实战应用,帮助开发者重构AI行为逻辑。通过核心概念解析、迁移策略、高级技巧和避坑指南,展示了StateTree在灵活性、可维护性和并行处理方面的优势,特别适合复杂AI行为的开发与优化。

weixin_42558257的博客 249

ECharts内存泄漏的3个诊断技巧与5种根治方案

在数据可视化项目中,ECharts作为业界领先的图表库,其强大的功能背后隐藏着内存管理的挑战。随着应用运行时间的增长,未经优化的ECharts实例可能悄然吞噬系统资源,导致页面卡顿甚至崩溃。本文将深入剖析ECharts内存泄漏的核心成因,提供从诊断到根治的完整解决方案。 ## 问题诊断:识别内存泄漏的蛛丝马迹 ### 风险等级评估框架 在深入技术细节前,我们需要建立风险意识。不同的使用场景对

gitblog_00770的博客 1087

STM32驱动数码管:从硬件连接到动态显示实现

本文详细介绍了使用STM32单片机驱动数码管的完整流程,从硬件连接到软件实现。内容涵盖共阳/共阴数码管原理、GPIO配置、段码表生成,并重点解析了多位数码管动态显示的核心技术,包括动态扫描原理、消影处理及实战代码,帮助开发者快速掌握这一嵌入式开发基础技能。

p5l2m9n4o6q的博客 575

redhawk:使用rh_setup.pl产生gsr模板

必须加的option工具会在rh_setup.pl给出提示,按照要求填写即可,另外工具会把所有填写的输入文件和信息放到rh_setup.init文件中,拷贝这个文件可在任何平级运行目录下,直接rh_setup.pl产生gsr以及run sta/dyn/em的脚本。rhsetup.pl -top top_cell_name -vdd_nets VDD 1.2 VDD2 1.2 -vss_nets VSS -frequency 100e6 (100m是默认值)更多学习内容请关注「拾陆楼」知识星球。

m0_61544122的博客 1055
上一篇: nginx实战分析
下一篇: Vue 项目 JSON 在线编辑、校验如何选?
ZoeLandia
博客等级 码龄6年 734粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值