小智 23
文本选择有许多组件,一些是视觉的,一些是非视觉的.
首先,使文本可选择您必须保留一个数组,文本的位置,文本的内容以及使用的字体.您将使用Canvas函数measureText来使用此信息.
通过使用measureText和文本字符串,您可以识别单击图像时光标应该落在哪个字母上.
ctx.fillText("My String", 100, 100);
textWidth = ctx.measureText("My String").width;
Run Code Online (Sandbox Code Playgroud)
您仍然需要从"font"属性解析字体高度,因为它当前未包含在文本度量标准中.默认情况下,Canvas文本与基线对齐.
有了这些信息,您现在有一个边界框,您可以检查.如果光标在边界框内,你现在有一个不幸的任务,即推断出故意选择了哪个字母; 应该放置光标的开头.这可能涉及多次调用measureText.
那时你知道光标应该去哪里; 当然,您需要将文本字符串存储为变量中的文本字符串.
一旦定义了范围的起点和终点,就必须绘制选择指标.这可以在新图层(第二个画布元素)中完成,也可以使用XOR合成模式绘制矩形.它也可以通过简单地清除和重绘填充矩形顶部的文本来完成.
总而言之,在Canvas中进行文本选择,文本编辑是非常费力的,并且重新使用已经编写的组件是明智的,Bespin是一个很好的例子.
如果我遇到其他公开示例,我会编辑我的帖子.我相信Bespin使用基于网格的选择方法,可能需要等宽字体.字体渲染的连字,字距调整,双向性和其他高级功能需要额外的编程; 这是一个复杂的问题.
首先让我说我不是文本控制方面的专家,但现在我确信这无关紧要,因为我可以帮助您安全进出树林。这些事情本质上很复杂,需要大量的直觉和关于事物如何运作的知识。但是,您可以在此处检查senpai-js/senpai-stage存储库中运行的代码。
我们应该预先定义一些事情:
/^.$/uInsert, Selection, Basic(我使用SelectionState库中的枚举并insertMode在舞台上检查属性)textScrollwhich 始终为负数现在我将详细介绍每个函数来描述它的行为,以准确描述文本框控件应该如何工作。
碰撞检测是一个怪物。标准化鼠标和触摸事件之间的点移动是本文未涵盖的复杂问题。处理点事件后,您必须对矩形执行某种常规碰撞检测。这意味着进行 AABB 碰撞。如果文本框精灵本身被旋转,你将不得不“取消旋转”点本身。但是,如果鼠标/触摸点已经在文本框上方,我们会绕过此检查。这是因为一旦您开始选择文本,您就希望此函数始终返回true。然后我们转到窄相碰撞,它实际上检查“未转换”的鼠标/触摸点是否在文本框的内边距内。如果是,或者文本框处于活动状态,我们将在此处返回一个真值。
一旦我们知道鼠标/触摸点在我们的文本框的边界内,我们就将画布的 css 更改为cursor: text;可视化。
当我们在文本框上按下鼠标按钮时,我们需要计算插入符号的移动位置。插入符号可以存在于从0到text.length包含的范围内。请注意,这并不完全正确,因为 unicode 字符的长度可以为2. 您必须跟踪添加到数组中文本中的每个字符,以断言您没有测量错误的 unicode 字符。计算目标索引意味着遍历当前文本的每个字符并将其附加到一个临时字符串中,每次测量直到测量的宽度大于当前的 textScroll + 测量的 textWidth。
一旦我们确定该点已落在文本框的顶部并设置了起点,我们就可以启动“选择”模式。拖动该点应将选择从起始 caretIndex 移动到新计算的结束索引。这是双向的。
Web 按键的解决方案是检查keyKeyEvent 上的属性。尽管每个人都说了很多,但可以通过针对上述 unicode regex 对其进行测试来测试该文本属性。如果匹配,则该键可能实际上已在键盘上按下。这种不考虑像组合键ctrl + c以及ctrl + v用于复制和粘贴。这些功能是微不足道的,由读者决定如何实现这些功能。
少数例外是箭头键:“ArrowLeft”、“ArrowRight”等。这些键实际上修改了控件的状态,并改变了它的功能。重要的是要记住,键事件应该只由当前focused控件处理。这意味着您应该检查并确保控件在文本输入期间获得焦点。这当然发生在比我在我的库中编码更高的级别,所以这是微不足道的。
下一个需要解决的问题是每个字符输入应该如何修改控件的状态。该keyDown方法识别selectionState并根据其状态调用不同的函数。这不是优化的伪代码,而是为了清晰起见,非常适合我们描述行为的目的。
selectionStart,并将新键插入到文本数组中Normal或CaretselectionStatetoNormal0和text.length索引
caretIndex再次从caretIndex - 1caretIndex0text.lengthcaretIndexCaret模式中向左或向右移动插入符号时,您应该重新启动闪烁机制,以便每次插入符号移动时它都能准确显示它们的位置ctx.measureText插入符号索引来测量插入符号沿文本的距离,方法是将文本切片到插入符号位置,除非模式为SelectionSelection,因为我们总是希望文本选择的结尾对用户可见ctx.save()(基本画布)textScroll应该是负数的 x值midline值,它应该是垂直文本框的中间middle并通过调用text.join("")文本数组来填充文本由于canvas标签的性质,无法选择在canvas元素中绘制的文本.但是有一些解决方法,比如在typefaceJS中使用的解决方法.
另一种解决方案是添加带有定位div元素的文本,而不是使用strokeText或fillText.
| 归档时间: |
|
| 查看次数: |
16613 次 |
| 最近记录: |