網頁版幾何畫板開發筆記(七) 關於點擊測試

點擊測試(hit_test), 用於查找(檢測)指定鼠標點(x, y) 位置有什麼對象, 以及若是存在
多個對象的狀況下, 以什麼樣的策略進行處理. 如今先看如何檢測到有哪一個對象. 數組

爲檢測而提供的函數當前爲 GeoPad.hit_test(x, y, mode). 其中參數 x,y 表示鼠標位置,
mode 是一個對象或null, 表示一些選項. 函數

做爲 hit_test() 函數的返回結果, 也是一個對象, 並且因爲有多重需求, 這一返回須要仔細
分析. 下面先列出對 hit_test() 函數有哪些需求: 工具

1. 當鼠標移動的時候, 未按下, 將根據在當前鼠標可進行的操做(通常是選中), 或在何種對象
  上面, 須要給出 a)新的鼠標指針樣式; b)可能的statusText,根據鼠標下對象和操做.
  此時須要檢測到鼠標位置有哪一個(或哪些)對象, 並判斷有哪些可能的操做. 測試

2. 當選中某一工具操做時, 如畫點, 畫線, 畫圓等工具時, 區分爲鼠標按下, 移動, 彈起幾種
  不一樣事件, 對鼠標當前位置的對象進行檢測. 將根據檢測結果產生不一樣操做. 優化

3. 新的需求, 如近期想作的移動標籤(Label)功能, 也與 hit_test 有關, 具體如何作, 與原有
  功能如何結合是須要仔細考慮的. 指針

若是以類來描述 hit_test 返回結果, 假設稱之爲 HitTestResult 類, 則僞代碼可以下: 對象

class HitTestResult {
  int length;  // 這次 hit_test 找到的對象數.
  operator [];  // 經過索引 0..length-1 能夠訪問到被點擊中的第 i 個對象.
     // 至關於用對象模擬數組的訪問方式, 緣由是(過去)此對象是當一個數組用的.
  Point[] points;  // 全部被點擊中的點的數組.
  Object[] hit_ret; // 經過此數組可訪問到第 i 個對象的 hit_test() 返回值.
} 索引

當前使用這樣的(相對有點冗餘有點亂)的結構是爲了知足多個不一樣地方的需求, 也許將這個
返回的對象真的變成類以及重構, 能夠減小點這種混亂的. 事件

(*) HitTestResult 類中數據的產生.
  在函數 GeoPad.hit_test() 中, 遍歷全部對象(不含 tmp 的, 這是一個問題), 對它們調用
  各自的 hit_test() 函數, 返回非空(非假)值的, 就認爲被擊中, 放入 [] 數組中; 返回值
  放入 hit_ret[] 數組中; 若是此對象是一個點(Point), 則還放入 points[] 數組中. it

好比說, 若是一次點擊測試, 鼠標在兩條線l1,l2和一個點p1上面, 則這個對象看起來應以下:

{ length:3, 0:l1, 1:l2, 2:p1, points: [p1], hit_ret[true,true,true] ... }

的確是有點亂... 若是不包裝爲一個更清晰的對象, 彷佛很差再改進或增長什麼新功能了.

 

(*) hit_test() 的使用.

1. 在 def_mouse_move() ---  缺省的鼠標移動處理, 此時未選中任何工具, 或稱是缺省
 SELECT 工具也可. 此時:
    var hit_objs = pad.hit_test(x, y, ...); // 執行點擊測試.
    if (hit_objs.length > 0)  // 有至少一個對象在當前鼠標位置.
      pad.set_cursor(pointer) -- 鼠標切換爲手形(表示可選擇,移動等操做)

2. def_mouse_down() --- 缺省鼠標按下, 未選中任何工具時.
    var hit_objs = pad.hit_test(x, y, ...);  // 點擊測試.
    if (hit_objs.length > 0)
      根據被點擊中的對象執行... 選中,取消選中 操做
    else
      表示點到空白位置, 此時取消全部對象的選中.

TODO: 因爲鼠標各類狀況下的處理比較多樣和複雜, 分解它們到合適的類中.   而後優化 hit_test(), 爲移動 Label 作準備.

相關文章
相關標籤/搜索