任何建议都受到高度赞赏。
答案 0 :(得分:22)
文本选择有许多组件,有些是视觉的,有些是非视觉的。
首先,使文本可选择必须保留数组,文本所在的位置,文本的内容以及使用的字体。您将在Canvas函数measureText中使用此信息。
通过使用measureText和文本字符串,您可以识别单击图像时光标应该落在哪个字母上。
ctx.fillText("My String", 100, 100);
textWidth = ctx.measureText("My String").width;
您仍然需要从“font”属性解析字体高度, 因为它目前未包含在文本指标中。画布文本已对齐 默认为基线。
使用此信息,您现在有一个边界框,您可以检查。 如果光标在边界框内,您现在有一个不幸的推断任务 有意选择哪一封信;应该放置光标的开头。这可能涉及多次调用measureText。
此时你知道光标应该去哪里;你需要存储你的 当然,文本字符串作为文本字符串,在变量中。
一旦定义了范围的起点和终点,就必须绘制 选择指标。这可以在新图层(第二个画布元素)中完成, 或者使用XOR合成模式绘制矩形。它也可以通过 只需清除并重新填充填充矩形顶部的文本即可。
总而言之,Canvas中的文本选择,文本编辑都很难编程,重新使用已经编写的组件是明智的,Bespin是一个很好的例子。
如果我遇到其他公开示例,我会编辑我的帖子。我相信Bespin使用基于网格的选择方法,可能需要等宽字体。字体渲染的连字,字距调整,双向性和其他高级功能需要额外的编程;这是一个复杂的问题。
答案 1 :(得分:5)
由于canvas标签的性质,无法选择在canvas元素中绘制的文本。但是有一些解决方法,例如typefaceJS中使用的解决方法。
另一种解决方案是添加带有定位div元素的文本,而不是使用strokeText或fillText。
答案 2 :(得分:3)
如果你需要有可选择的文本,那么创建一个div或者其他东西要容易得多,并将它放在你希望文本显示的画布上。
canvas没有任何用于选择文本的内置机制,因此您必须推出自己的文本呈现并选择代码 - 这可能相当棘手。
答案 3 :(得分:3)
答案 4 :(得分:3)
我建议使用EaselJS库,您可以将每个字母添加为子项,甚至可以将鼠标事件添加到该对象,这是一个了不起的库,请查看它!
答案 5 :(得分:3)
首先让我说我不是文本控件方面的专家,但是现在我确定这无关紧要,因为我可以帮助您安全地出入树林。这些事物本质上很复杂,需要对事物如何运作有足够的直觉和知识。但是,您可以检查在senpai-js/senpai-stage
存储库here中运行的代码。
我们应该预先定义一些内容:
/^.$/u
Insert
,Selection
,Basic
(我在库中使用了SelectionState
枚举,并检查了insertMode
舞台上的媒体资源)textScroll
,它始终是负数现在,我将遍历每个函数以描述其行为,以准确描述文本框控件应如何工作。
碰撞检测是一个怪物。标准化鼠标和触摸事件之间的点移动是本文中未涉及的复杂野兽。一旦处理了点事件,就必须对矩形执行某种常规的碰撞检测。这意味着要进行AABB碰撞。如果文本框精灵本身已旋转,则必须“取消旋转”该点本身。但是,如果鼠标/触摸点已经位于文本框上方,则我们绕过此检查。这是因为一旦开始选择文本,就希望此函数始终返回true
。然后,我们移至arrowingPhase冲突,该冲突实际上将检查“未变换”的鼠标/触摸点是否在文本框的填充范围内。如果是,或者文本框处于活动状态,我们将在此处返回一个真实值。
一旦我们知道鼠标/触摸点在文本框的范围内,就可以将画布的CSS视觉上更改为cursor: text;
。
当我们在文本框上按下鼠标按钮时,我们需要计算插入符号的移动位置。插入符号的范围为0
至text.length
(含)。请注意,这并不完全正确,因为Unicode字符的长度可以为2
。您必须跟踪数组中添加到文本的每个字符,以断言您没有在测量错误的Unicode字符。计算目标索引意味着循环遍历当前文本的每个字符,并将其附加到临时字符串上,每次进行测量,直到所测量的宽度大于当前textScroll +所测量的textWidth。
一旦我们断言该点已落在文本框顶部并设置了起点,就可以启动“选择”模式。拖动点应将选择从起始插入索引移动到新计算出的结束索引。这是双向的。
here显示了一个示例。
Web按键的解决方案是检查KeyEvent的key
属性。尽管每个人都说了很多,但是可以通过对上述unicode regex进行测试来测试该文本属性。如果匹配,则可能是实际上已在键盘上按下过该键。这不考虑用于复制和粘贴的ctrl + c
和ctrl + v
之类的组合键。这些功能微不足道,由读者自己决定如何实现。
少数几个例外是箭头键:“ ArrowLeft”,“ ArrowRight”等。这些键实际上会修改控件的状态并更改其功能。重要的是要记住,键事件只能由当前的focused
控件处理。这意味着您应该检查并确保控件在文本输入过程中聚焦。当然,这发生在比我在库中编写的代码更高的级别上,所以这很简单。
下一个需要解决的问题是每个字符输入应如何修改控件的状态。 keyDown
方法识别selectionState
并根据其状态调用其他函数。这不是经过优化的伪代码,而是用于清楚起见,非常适合我们描述行为的目的。
selectionStart
拼接出来,然后将新键插入文本数组Normal
或Caret
selectionState
再次返回到Normal
0
和text.length
索引
caretIndex
扩展选择范围caretIndex - 1
处索引之前的一个字符caretIndex
处索引后的一个字符0
text.length
caretIndex
处选择的字符Caret
模式下向左或向右移动插入符号时,您应该重新启动闪光机制,以便每次插入符号移动时都能准确显示它们的位置ctx.measureText
,否则使用Selection
到插入符号索引来测量插入符号沿文本的距离,方法是将文本切成插入符号的位置
Selection
中测量文本沿多远仍然有用,因为我们一直希望文本选择的结尾对用户可见ctx.save()
(基本画布)textScroll
值,该值应为负数midline
值,该值应垂直位于文本框的中间middle
,并通过在文本数组上调用text.join("")
填充文本是的,任务很艰巨,但是有时候您只是想给世界一个视觉新颖的引擎,或者是一个具有各种功能的精灵舞台。如果您想让senpai注意到您,请访问senpai-stage
回购并提交请求请求。祝您一切顺利!
〜恶魔战队
答案 6 :(得分:2)
FabricJS现在能够与canvas元素之外的对象进行交互 - 例如this demo显示一个链接到canvas元素中加载的图像的按钮。
通过挂钩任何移动事件,获取元素的边界框并重新定位HTML元素,可以在Raphael等其他库中使用相同的方法。
答案 7 :(得分:1)
画布只是一个绘图表面。你渲染,结果是像素。因此,您需要在鼠标事件期间处理的某种数据结构中跟踪已渲染到画布的所有文本的位置。
答案 8 :(得分:1)
一个简单的答案是:使用HTML或SVG而不是画布。除非你真的需要低级控制画布的程度。