canvas-editor icon indicating copy to clipboard operation
canvas-editor copied to clipboard

编辑器支持rtl渲染

Open HerbertHe opened this issue 1 year ago • 11 comments

实现仓库:https://github.com/HerbertHe/canvas-editor/tree/feature/rtl

目前还在对此部分进行实现,已经完成进度如下:

  • [x] 支持 mock 渲染 rtl
  • [x] 支持 mock rtl 和 ltr 的切换
  • [x] 支持 setDirection getDirection command
  • [x] 修正了 rtl 下的 demo 布局
  • [x] 修正了 rtl 下的 range
  • [x] 修正了 rtl 下,canvas 文本与非文本绘制的差异,重新计算差异坐标
  • [x] 修正了 rtl 下,光标的碰撞检测
  • [x] 修正了非文本的绘制
  • [x] 修正了普通文本的绘制
  • [x] 修正了 separator 不正确的坐标问题
  • [x] ~~underline 绘制坐标的偏移错误~~ #469
  • [x] ~~strikeout 绘制坐标的偏移错误~~ #469
  • [x] table tool rtl 下进行反方向绘制
  • [x] 在 rtl 下,普通文本和带特殊格式的文本存在定位混排错误的问题 #468
  • [x] ~~超链接渲染缺陷,没有遵守 rtl 的文字排版~~ 将 hyperlink 的绘制交给 textParticle 完成

已知需要修复的问题:

  • [ ] 计算 rtl 下,居中和左对齐坐标
  • [ ] highlight 块错误的绘制坐标
  • [ ] table 的绘制问题适配
  • [ ] 在 rtl 下,富文本 command 操作存在差异
  • [ ] 在 rtl 下,富文本 keydown 存在差异
  • [ ] 修复文本重排导致的 element 选择错误问题
  • [ ] 修复 checkbox 文本绘制的问题 #477
  • [ ] 修复上下角标的绘制问题

HerbertHe avatar Mar 10 '24 17:03 HerbertHe

还有就是数字列表的渲染,实际上来看似乎列表渲染和文字渲染是分开割裂的

HerbertHe avatar Mar 10 '24 17:03 HerbertHe

非常好!期待pr,之前渲染没有考虑rtl,默认从左到右绘制会存在坐标问题

Hufe921 avatar Mar 11 '24 13:03 Hufe921

@Hufe921 还在计算坐标,现在已知的情况是文本绘制不存在问题,也已经完成了rtl模式下的鼠标碰撞检测计算镜像坐标。但是图片这些仍然存在问题,感觉是这部分渲染坐标导致的。

  • [x] 完成 mousedown event 下碰撞检测计算问题

HerbertHe avatar Mar 12 '24 06:03 HerbertHe

已知问题是 ctx.fillRect 方法不支持 ctx.direction='rtl',表现与文本绘制完全不一致

HerbertHe avatar Mar 12 '24 06:03 HerbertHe

@Hufe921 #457 我仍然觉得这是一个单独的可以改善的地方,下面是我对此的一些看法;

我完整阅读了您的理由,觉得可能您误解了我的意思,所以这部分即使是单独绘制的,仍然需要针对 RTL 字符进行改善。先回复您的回答原因,然后我再举例说明实际的问题,这里面涉及到阿拉伯字母连字的问题。

我认为 ctx.direction 的实现是一个最好的方案,原因如下:

  1. 这个属性并不是实验性的 Browser compatibility
  2. ctx.direction 解决的是 LTR 和 RTL 混排的问题,而不是 RTL 布局的问题,即使完全不依赖浏览器的渲染逻辑,对于文本来说,自行绘制只是对这个属性的重新实现。因为在适配 RTL 过程中,其实只有文本才是交给浏览器处理的,其他的并不受此属性的影响。

针对原因 2,我列举一个混排的例子:

在LTR中,你好 سالەم

RTL中,应该渲染为 سالەم 你好,而不是 سالەم 好你,非 RTL 标点符号(比如:空格)混排渲染取决于后一个字符的类型,而不是轴对称。在 canvas-editor 的 RTL 针对富文本绘制的逻辑中,ctx.direction 是正确的,并且处理了光标的异常问题,我重新实现了 rtl 情况下的光标碰撞检测定位。因此,我才觉得这个特性是最好的文本处理方案。

  1. 针对您所说的开发瓶颈的问题,RTL 实际上是没法通过统一计算进行解决的,上面我已经列举了混排的例子。针对某个组件或者文字需要 LTR,在我分析源码之后,认为是不存在瓶颈的。绘制需要传递 ctx 引用,渲染函数内进行强制 ctx.direction='ltr' 就完全规避了这个问题。

但对文本绘制这一块,逐字符绘制,我必须要举一个例子,这是导致 Date 异常的根本性原因。如果仍然要以逐字符绘制的话,这是最优的改进方案。

上面说到的 سالەم,您所看到的,其实已经是浏览器绘制连字之后的。实际上,如果是单字符渲染,得到的结果是 س ا ل ە م (用空格作为截断),这是缺陷所在,不符合阿拉伯文字的书写渲染。同样,بولادى 渲染也不是 ب و ل ا د ى

上面的两个例子,为哈萨克语的阿拉伯-波斯字母形式。

所以,我仍然认为需要改进的方向是,重新实现 date.render 方法,应该采用对富文本同样处理的方式,对这部分字符进行处理,阿拉伯字母语言也有年月日。

根据 canvas-editor 对普通文本的渲染表现来看,其实是已经进行了合并处理的,单个渲染一定会出现我上面所述的问题,连字的问题无法进行自行实现计算坐标解决。

HerbertHe avatar Mar 12 '24 14:03 HerbertHe

所有 RTL 渲染的逻辑其实都是先按照 RTL 进行处理,遇到 LTR 字符全部按 LTR 处理,但是总体上保持 RTL 的方向和顺序。一旦不以 LTR 为第一渲染计算根本,就带来了 left 和 right 概念错误的问题,因为不存在左右,而是前后。RTL 在排版上,默认为右对齐,左对齐才是 canvas-editor 进行填充偏移绘制的方法,其实是:前对齐/后对齐

HerbertHe avatar Mar 12 '24 14:03 HerbertHe

@Hufe921 对此问题进行了修复

else if (element.type === ElementType.DATE) {
          const before = curRow.elementList[j - 1]
          const next = curRow.elementList[j + 1]
          // 设置释放之前的
          if (!before || (!!before && before.type !== 'date')) {
            this._drawRichText(ctx)
          }

          this.textParticle.record(ctx, element, x, y + offsetY)
          if (!next) {
            // 手动触发渲染
            this.textParticle.complete()
          }
        }

借用了 textParticle 的绘制能力

HerbertHe avatar Mar 13 '24 06:03 HerbertHe

https://github.com/Hufe921/canvas-editor/issues/451#issuecomment-1991805739 提到的连写问题,在两端对齐中就表现出来了

image

右对齐就不存在这个问题

image

两端对齐断开,其实也符合情况,右对齐就不能出现字符连写断开的情况了

内容来源于中国哈萨克语广播网 http://www.kazakcnr.com/zdgz2019/toutiao/202403/t20240311_1515669.html

HerbertHe avatar Mar 13 '24 07:03 HerbertHe

存在超链接渲染的缺陷,具体表现如 Date

image

HerbertHe avatar Mar 13 '24 09:03 HerbertHe

#468 @Hufe921

image

重构之后文本 rtl 渲染结果相对正常,只需要处理 underline、strikeout 等重绘坐标即可

HerbertHe avatar Mar 14 '24 18:03 HerbertHe