文本冲突检测 [英] Text Collision Detection

查看:156
本文介绍了文本冲突检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个web应用程序,它使用 fillText 在HTML 5上绘制一组不同字体的字母 Canvas >。用户将点击画布上的某处,我需要检查他们点击了哪个字母(或者如果他们点击了一个字母)。



我想我需要to:


  1. 获取每个字母的向量路径(我不知道如何做到这一点)。

  2. 使用一些简单的碰撞检测算法检查点击点是否在字母路径内。

有一些简单的功能做这个我失踪?或者可能是这样的图书馆?如果没有任何库,我如何得到一个特定字体的字母的路径做自我检查?



我需要使用实际形状字母,而不仅仅是它的边框,因为我不希望用户能够点击 O 的中间并注册为点击。

编辑

em>



我正在建立一个CAD类型的应用程序,需要在一个画布上拥有我所有的形状。此外,我需要我的选择是准确的。我不认为抓取像素将是足够精确。有没有人知道一种方法来提取关于文本字符串的路径信息?

解决方案

逻辑



您不能在不提供自定义逻辑的情况下处理画布上的单独字母。绘制到画布上的所有内容都合并为一个像素点。



不幸的是,您不能将文本添加为​​纯路径,因此您必须检查像素值。否则,您可以简单地将文本添加到新路径,并对每个字母使用 isPointInPath 方法。





我们不能在SO上提供完整的解决方案,但这里是一个基础,你可以希望建立在提供基本的逻辑来点击画布上的单个字母: / p>


  • 每封信都以对象

  • 使用这些对象定义数组,然后将它们传递到渲染函数
  • $ b $ b
  • 当你注册一个点击迭代数组并测试矩形命中区域,如果里面检查像素(*)



*)要区分重叠的字母,您需要按优先级检查。您还可以将此字符渲染到单独的画布上,以便只获取此字符的像素。我不会在演示中显示这个,但你会得到的想法。



演示



  var ltrs = []; ///存储字母对象

///创建一些随机对象

for(; i <20; i ++){

/ //构建对象
var o = {char:alpha [((alpha.length - 1)* Math.random())| 0],
x:((w - 20) random())| 0,
y:((h - 20)* Math.random())| 0,
size:(50 * Math.random $ b font:fonts [((fonts.length - 1)* Math.random())| 0]};

///存储其他东西,如颜色等。

///存储在数组
ltrs.push(o);
}

然后我们有一些函数来渲染这些字符p>

当我们处理点击时,我们遍历对象数组,首先检查边界首先检查我们的字母(在这里选择一个像素不会使我们ID字母):

  demo.onclick = function(e){

///调整鼠标位置相对于画布
var rect = demo.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0 ,o;

/// iterate
for(; o = ltrs [i]; i ++){

///是在矩形? 旧的字母在这里具有更高的优先级...
if(x> ox&& x<(ox + o.rect [2])&&
y> oy& ;& y<(oy + o.rect [3])){

///它是,检查我们是否真的点击了一个字母
///这是你将会采用一个单独的画布...
if(checkPixel(x,y)=== true){
setLetterObject(o,'#f00')
return;
}
}
}
}

像素检查是直接的,它选择在x / y位置的单个像素,并检查其值(或颜色,如果你使用实心背景):

  function checkPixel(x,y){
var data = ctx.getImageData(x,y,1,1).data;
return(data [3]!== 0);
}

点击这里在线演示



更新检查像素功能



此更新的支票可以检查字母,即使它们在同一区域重叠。



创建一个单独的画布来绘制字母。这将孤立的字母,当我们选择一个像素,我们只能从该特定的字母得到一个像素。它也不重要什么背景颜色,因为我们的离屏画布只设置像素的字母,而不是背景的检查。

  function checkPixel(o,x,y){

///创建屏幕画布
var oc = document.createElement('canvas'),
octx = oc.getContext('2d'),
data,
oldX =
oldY = oy;

///默认画布为300x150,如果字母大小较大则调整)* b $ b //oc.width = oc.height = 200;

///这可以重构到更好的东西,但演示...
o.x = 0;
o.y = 0;

setLetterObject(octx,o,'#000');

o.x = oldX;
o.y = oldY;

data = octx.getImageData(x - oldX,y - oldY,1,1).data;
return(data [3]!== 0);
}

*)当我们创建一个画布时,默认大小为300x150。为了避免重新分配一个新的位图,我们只剩下它,因为内存已经为它分配,我们只需要从中选择一个像素。如果字母的像素大小大于默认大小,我们当然需要重新分配以使字母适合。



在本演示中,我们暂时覆盖x和y位置。对于生产你应该启用 setLetterObject 方法,以某种方式覆盖这一点,因为会更加优雅。但我会离开它在演示中,因为最重要的是要了解的原则。


I am building a web application that draws a set of letters in different fonts on an HTML 5 Canvas using fillText. The user will click somewhere on that canvas and I need to check which letter they clicked on (or if they clicked on a letter at all).

I think I will need to:

  1. Get the vector path for each letter (I have no clue how to do this).
  2. Check if the click point is inside the letter path using some simple collision-detection algorithm.

Is there some easy function to do this that I am missing? Or maybe a library for things like this? If there aren't any libraries, how do I get the path for the letter in a specific font to do the checking myself?

I need to use the actual shape of the letter and not just its bounding box as I don't want the user to be able to click in the middle of an O and it register as a hit.

Any hint in this direction would be appreciated.

Edit:

I am building a CAD-type application and need to have all of my shapes on one canvas. Furthermore, I need my selection to be accurate. I don't think grabbing pixels will be precise enough. Does anyone know of a way to extract path information about a string of text?

解决方案

Logic

You can't handle separate letters on canvas without providing custom logic for it. Everything drawn to the canvas is merged to a soup of pixels.

And unfortunately you can't add text as pure path so you will have to check pixel values. Otherwise you could simply add the text to a new path and use the isPointInPath method for each letter.

One approach

We can't provide full solutions here on SO but here is a basis you can hopefully built on top of to provide basic logic to click single letters on a canvas:

  • Each letter is stored as object incl. its position, size, font and char, but also with a rectangle hit region (see below)
  • Define an array with these objects and then pass them to a render function
  • When you register a click iterate through the array and test against the rectangular hit-region and if inside check the pixel (*)

*) To distinguish between overlapping letters you need to check by priority. You can also render this char onto a separate canvas so you get pixels of only this char. I am not showing this in the demo but you'll get the idea.

Demo

var ltrs = []; /// stores the letter objects

/// Create some random objects

for(;i < 20; i++) {

    /// build the object
    var o = {char: alpha[((alpha.length - 1) * Math.random())|0],
             x:    ((w - 20) * Math.random())|0,
             y:    ((h - 20) * Math.random())|0,
             size: (50 * Math.random() + 16)|0,
             font: fonts[((fonts.length - 1) * Math.random())|0]};

             /// store other things such as color etc.

    /// store it in array
    ltrs.push(o);
}

Then we have some function to render these characters (see demo).

When we then handle clicks we iterate through the object array and check by boundary first to check what letter we are at (picking just a pixel here won't enable us to ID the letter):

demo.onclick = function(e) {

    /// adjust mouse position to be relative to canvas
    var rect = demo.getBoundingClientRect(),
        x = e.clientX - rect.left,
        y = e.clientY - rect.top,
        i = 0, o;

    /// iterate
    for(;o = ltrs[i]; i++) {

        /// is in rectangle? "Older" letters has higher priority here...
        if (x > o.x && x < (o.x + o.rect[2]) &&
            y > o.y && y < (o.y + o.rect[3])) {

            /// it is, check if we actually clicked a letter
            /// This is what you would adopt to be on a separate canvas...    
            if (checkPixel(x, y) === true) {
                setLetterObject(o, '#f00')
                return;
            }
        }
    }
}

The pixel check is straight forward, it picks a single pixel at x/y position and checks its alpha value (or color if you use solid backgrounds):

function checkPixel(x, y) {
    var data = ctx.getImageData(x, y, 1, 1).data;
    return (data[3] !== 0);
}

CLICK HERE FOR ONLINE DEMO

Updated check pixel function:

This updated check is capable of checking letters even if they are overlapping in the same region.

We create a separate canvas to draw the letter in. This isolates the letter and when we pick a pixel we can only get a pixel from that specific letter. It also doesn't matter what background color is as we our off-screen canvas only set pixels for the letter and not background during the check. The overhead is minimal.

function checkPixel(o, x, y) {

    /// create off-screen canvas        
    var oc = document.createElement('canvas'),
        octx = oc.getContext('2d'),
        data,
        oldX = o.x,
        oldY = o.y;

    /// default canvas is 300x150, adjust if letter size is larger *)
    //oc.width = oc.height = 200;

    /// this can be refactored to something better but for demo...
    o.x = 0;
    o.y = 0;

    setLetterObject(octx, o, '#000');

    o.x = oldX;
    o.y = oldY;

    data = octx.getImageData(x - oldX, y - oldY, 1, 1).data;
    return (data[3] !== 0);
}

*) When we create a canvas the default size is 300x150. To avoid re-allocating a new bitmap we just leave it as it is as the memory is already allocated for it and we only need to pick a single pixel from it. If letters has larger pixel size than the default size we will of course need to re-allocate to make the letter fit.

In this demo we temporary override the x and y position. For production you should enable the setLetterObject method to somehow override this as that would be more elegant. But I'll leave it as-is here in the demo as the most important thing is to understand the principle.

这篇关于文本冲突检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆