Open cwchou2016 opened 4 years ago
先解決一下作文問題,順便夾帶一些背景知識,畢竟要搞畫面的話,這些搞清楚還是比較好的:
請問一下,GF-draw 有辦法讓滑鼠游標移到某個物件上,然後顯示另一個物件嗎?
在這裡用「物件」會讓人很恐慌,尤其你又是在寫 Java...... XD。用 sprite(基本上電腦繪圖領域可能都通用)或是 GF-Draw 裡頭的 Layer
都比較好。當然如果 GF-Draw 是一個 physical engine 說不定講 object 又沒問題(甚至是必要的 XD)。只能說在資訊領域的名詞定義實在很痛苦......
「游標 / 鼠標(對岸用法)移到某個物件上」這個可以直接說「mouse over」,基本上這也是通用詞彙了
你描述的這個需求,常見的學名是 tooltip、但是講 popup 其實也可以,這兩個區別就(尤其是網頁環境)底層來說區別不是很大。因為撇開一些 HTML tag 內建的功能(例如 <a>
的 title
),要能有統一的外觀跟程式控制能力,通常都是 UI library 另外畫出來然後控制它的出現時機以及位置(包括漂浮在最上層)。不過呢,如果講究一點的話,通常會有這些區別:
alert()
/ GWT 的 Window.alert()
也可以稱之為 popup),出現位置也不一定相關。簡單地說就只是在描述「一個會跳出來的顯示區域」順便扯一個有點遙遠,但其實也常常(跟 popup)混在一起(因為還是那個原因,底層區別不大)就是 modal / dialog。modal 通常還具備了「modal 底下的東西都不給使用者操作」的特性,很多時候 modal 也被當成 dialog 的屬性來用...... blahblah
如果你看完這一堆還沒昏的話,再給你最後一擊 :dancer: ,就是各家 UI component / library provider 的名詞定義都不太一樣,上面講得就只是個通俗的概念,不一定能對應到各家的命名....... [死]
以下「顯示另一個物件」的這玩意,我先用「tooltip」這個字。
好,終於要來回答你的問題了,答案是:好像沒辦法...... :skull: 這也是為什麼我那個 ftl.html 會讓他卡在最下面的原因...... (艸
更仔細地說,應該這樣講:「沒辦法讓 tooltip 的 layer / sprite 都屬於同一個 LayerContainer
。」
其實學理上應該是可行的(GXT 的 chart 好像也有類似功能),就是 onSpriteOver()
的時候把 tooltip 作 Layer.setHidden(false)
然後 onSpriteLeave()
的時候 setHidden(true)
,但是實際上 tooltip 那個 layer 會一直閃爍還是消失之類的狀況(忘記細節 XD),總之無法正常顯示。當時有點懶得去抓這問題...... Orz(謎之聲:難道現在就不懶的意思 [飛踢]),應該是 LayerContainer.handleEvent()
裡頭塞了一個 redrawSurface()
炸的問題....... (ry
這裡先提供一個(理論上的) workaround,就是另外生一個 Popup
來顯示,因為那是獨立於 LayerContainer
的 widget,所以不會受到影響,但相對的就得生出另一個 GXT Component 來塞到 Popup
裡頭去.........
暫時先這樣....... [逃]
後來找到解法、後來想要寫成 API、後來又發現這事情很大條短時間寫不完....... (ry
所以先講很受局限的解法:
public class WTF extends LayerContainer {
public WTF() {
TextButton textbutton = new TextButton("over me!");
textbutton.addSpriteOverHandler(new SpriteOverHandler() {
@Override
public void onSpriteOver(SpriteOverEvent event) {
Event be = event.getBrowserEvent();
tooltip.setHidden(false);
tooltip.setLX(be.getClientX() - WTF.this.getAbsoluteLeft() + 10);
tooltip.setLY(be.getClientY() - WTF.this.getAbsoluteTop() + 10);
}
});
textbutton.addSpriteOutHandler(new SpriteOutHandler() {
@Override
public void onSpriteLeave(SpriteOutEvent event) {
tooltip.setHidden(true);
}
});
//一些設定位置大小等等的細節就略
//總之記得把 textbutton / tooltip 加到 WTF 上頭去
//注意,`tooltip` 必須直接加在 LayerContainer 上,不然位置會出問題
}
}
class Tooltip extends LayerSprite {
Tooltip() {
LCircleSprite circle = new LCircleSprite(10);
circle.setFill(RGB.BLUE);
circle.setLX(30);
circle.setLY(30);
add(circle);
setBgColor(RGB.YELLOW);
setLZIndex(30000);
setHidden(true);
resize(200, 80);
}
}
之前會出現閃爍 / 消失的問題,其實是滑鼠(在短時間內)移動到剛剛出現的 tooltip 上,程式會觸發 textButton 的 onSpriteLeave(),然後觸發 tooltip 的 onSpriteOver()(這裡是簡化後的講法,實際上會囉唆一點 Orz)。所以最簡單的方法就是加上個 offset(例如上面的 +10),這樣滑鼠就很難在短時間內移動到還未消失的 tooltip 上。也許更確實的方法是在 textbutton.onSpriteLeave() 把 tooltip 的位置移到很遠的地方,不過還沒測就是了。
至於要寫成 API,目前還在便秘當中。這牽扯的問題有點多,光「是 LayerSprite 才提供 setTooltip()、還是 LSprite 都提供 setTooltip()」就讓我傷透腦筋,所以先 FYI 一下 有個交代。
畢竟你現在是 GF-Draw 的最大客戶
最近試了一下,你的範例顯示不出來,
不過把 Tooltip
的 setLZindex()
改成 0 的話就可以。
是不是 hide 的屬性只是讓 Sprite 不顯示,但是還是存在在位置上?
O.o 我的測試程式碼還在,除了是 gf-test 的架構之外,其他(至少 Tooltip
的部份)是一樣的,所以我不太確定為啥你的得改那樣才行(而且 z-index 設成 0 這超級不合理的阿)
至於你說的問題,答案是:是,最終就只是把 svg 的 attribute 改掉,其他值都不會變。(CSS 大抵上也通常是類似作法)。不過理論上應該不會因此觸發相關 event 才對。
我覺得你還是把時間花在「你希望看到什麼 API」這上頭。當然你要繼續尋根究底那也行,開個 gist 或是 repo 給我一下你炸掉的 code。
z-index 設定為 0 ,讓 tooltip 設定在最下面,有需要顯示的時候再把它移上來,要不然 tooltip 會擋住觸發的 sprite。
此外,我遇到的另一個問題是,我把 tooltip extend VerticalLayoutLayer
,在 onSpriteLeave()
被觸發之後,會有部分的 sprite 不會被 hide。
程式碼如下: https://gist.github.com/cwchou2016/654636243a121d86071207c5fd1d33e7
裡面的 ExhibitionInfoLayerSprite
就是 tooltip
那個 bg 仍然會顯示在化面上,還真他 X 的是個謎,我完全無法解釋,這很有可能是 GXT 底層的 bug....... :scream:
我現在終於瞭解你說的那個 z-index 導致 line
無法觸發的問題,這的確是之前沒遇過也沒想過的問題。不過呢,我的解法不會是用 z-index,主要原因是效能問題(當然你踩出來的那個雷會是很重要的支持理由 lol)。
z-index 應該會造成較多的計算(至於是 JS 還是 browser rendering engine.... 這部份細節略,應該都有)。z-index 不是一個實際存在 svg 當中的屬性。佐以觀察 DOM 結構的結果來說(aka 這不是 source code 的定論,可能會有例外 XD),GXT 會根據 z-index 重新調整 svg 當中的 element 先後順序,整個看起來就不是什麼快樂的事情,尤其是 tooltip 上頭的東西很多的時候。
所以我會這樣搞......
//in Chart 的 constructor
//除了排整齊一點之外,就是調回我原本的 z-index 寫法
//跟(重點)tooltip.setLX() / setLY()
Line line = new Line(100, 1000);
addLayer(line);
tooltip.setLZIndex(3000); //游標移到 sprite 上再把 tooltip 移到最前面
tooltip.setInfo("test", "adfadfadf");
tooltip.setLX(-10000); //你指不到我~你指不到我~ [達叔調]
tooltip.setLY(-10000);
addLayer(tooltip);
line.addSpriteOverHandler(new SpriteOverEvent.SpriteOverHandler() {
@Override
public void onSpriteOver(SpriteOverEvent event) {
Event be = event.getBrowserEvent();
tooltip.setLX(be.getClientX() - Chart.this.getAbsoluteLeft() + 10);
tooltip.setLY(be.getClientY() - Chart.this.getAbsoluteTop() + 10);
tooltip.setHidden(false);
}
});
line.addSpriteOutHandler(new SpriteOutEvent.SpriteOutHandler() {
@Override
public void onSpriteLeave(SpriteOutEvent event) {
tooltip.setHidden(true);
}
});
這樣就不會動到 z-index 值,而且反正 tooltip 的位置本來就是要調整的.....
gist 那邊我也有寫一些 comment,記得過去看......
我最近在開新的 副本亂搞,因為總總因素覺得上面取得 event 座標的方式太 白痴 麻煩囉唆又不保險,前端工程師不太可能到現在還容忍這種事情,所以仔細看一下 event 有沒有什麼其他資訊可以使用...... 還真的有...... 就是 layerX, layerY。各種 X, Y 的差別可以看這篇(這篇看起來挺嚴謹的,應該不會再被陰.....)
不過呢.... 這玩意在 GWT 的 API 沒有提供(主要大概是因為不是 standard 沒有 cross-browser 所以選擇不實做?)。所以就只好自己來......
public static native double eventLayerX(NativeEvent evt) /*-{
return evt.layerX || 0;
}-*/;
public static native double eventLayerY(NativeEvent evt) /*-{
return evt.layerY || 0;
}-*/;
如此一來,改寫我上一個 comment 的 code 就會變成
Event be = event.getBrowserEvent();
tooltip.setLX(eventLayerX(be) + 10);
tooltip.setLY(eventLayerY(be) + 10);
tooltip.setHidden(false);
那兩個 utility method 應該會在 遙遠的 未來寫進 GF 裡頭, 趕快過來報大腿誠心許願就會早點上阿 [指], 你如果有需要可以自己先弄一個頂一下 XD
我剛剛又炸了一輪 sprite 的 mouse over / out 的問題,因為這次功能更單純,所以測試的也更詳細,還整理了一個 SSCCE 在這裡: https://gist.github.com/MontyPan/892d20ceb046740ee87f25332dc2433c
(恩... 這可能不夠 SSCCE,因為還用了 GF-draw,真要搞就要弄純 GXT 的版本.... 😱 )
用比較正式的講法,當兩個 LayerSprite
A、B 同時符合兩個條件:
就有機率(移動緩慢時基本上 100%)出現滑鼠從 A 移動到 B 的時候,不會出現 A 的 SpriteOutEvent
,反而會出現 B 的 SpriteOutEvent
。
目前看起來,這不是 GF-draw 機制出的問題,而是 GXT 本來的行為就這樣... 理論上 GF 可能也不會幫 GXT 做 workaround...... 🙈
我記得你在超前部屬 tooltip 的時候靠腰過 tooltip 不會消失的問題(我現在還是沒打算理你那段啦... [被毆飛]),你可以看一下是不是同樣是這個 pattern,說不定會讓你開心 / 對 GF 有信心一點點 XDDD
其實我只是要找個地方作筆記而已
請問一下,GF-draw 有辦法讓滑鼠游標移到某個物件上,然後顯示另一個物件嗎?
有點像是 FTL 下面那條顯示資訊的 rectangle,不過這個 rectangle 在滑鼠移開的時候整個物件會消失,而且位置不固定(根據游標的位置決定顯示位置)。