แสดงบทความที่มีป้ายกำกับ vaadin แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ vaadin แสดงบทความทั้งหมด

วันจันทร์ที่ 28 มีนาคม พ.ศ. 2559

Vaadin: How to listen to animation end part 3 (end)

>> เข้าประเด็นกันเลย
- ผมไม่ต้องการคลาส EndAnimatorWidget เพราะคลาส EndAnimator ไม่จำเป็นต้องมีหน้าตาใดๆ
- ผมไม่ต้องการอินเตอร์เฟส EndAnimatorClientRpc เพราะไม่มีงานของหน้าบ้านที่ต้องคุยกับหลังบ้านด้วย rpc ของหน้าบ้าน (ขอโทษครับเรื่องศัพท์แปลกๆของผม)
- ผมไม่ต้องการคลาส EndAnimatorState เพราะจะไม่มีการรับส่งค่าใดๆผ่านตัวแปร
- ผมต้องการ ให้คลาส EndAnimator ลงทะเบียนอินเตอร์เฟส EndAnimatorServerRpc เพื่อคอยรับสัญญาณจากคลาส EndAnimatorConnector แค่นั้น
- ผมต้องการ ให้อินเตอร์เฟส EndAnimatorServerRpc ใช้ rpc คอยรับการทำงานจาก EndAnimatorConnector เมื่อจาวาสคริปต์ทำงาน 'animationend' ของ animation ใดๆ
- ผมต้องการ ให้คลาส EndAnimatorConnector มีบริการลงทะเบียน 'animationend' สำหรับ component ใดๆที่ต้องการให้เล่น animation
- และเมื่อ 'animationend' ปรากฏ นั่นหมายความว่า EndAnimatorServerRpc จะต้องทำงานและส่งการทำงานนี้ให้กับอินเตอร์เฟสที่ทำหน้าที่เสมือนรับฟังเหตุการณ์เล่น animation เสร็จสิ้น
- ผมขอตั้งชื่ออินเตอร์เฟสที่ทำหน้าที่เสมือนรับฟังเหตุการณ์เล่น animation เสร็จสิ้นนี้ว่า AnimationEndListener ซึ่งมีบริการ onAnimationEnd สำหรับทุก component ที่เรียกใช้คลาส EndAnimator ครับ

>> ดังนั้นคลาส EndAnimator หรือก็คือหัวใจของเรื่องนี้จึงต้องมี AnimationEndListener บังคับให้ใช้อยู่ภายใน, สำหรับทุก component ที่มันรับฟัง (listen) การเล่น animation จนเสร็จสิ้นจะถูกบังคับทำ onAnimationEnd จาก EndAnimatorServerRpc อีกทอดหนึ่ง รายละเอียดทั้งหมดดังรูป

- เพื่อที่จะให้คลาสนี้ส่ง component ใดๆไปให้คลาส EndAnimatorConnector จึงต้องให้สืบทอด com.vaadin.server.AbstractExtension, เช่นเดียวกับคลาส EndAnimatorConnector ที่ต้องเป็นลูกของ com.vaadin.client.extensions.AbstractExtensionConnector มิเช่นนั้นมันจะคุยกันไม่รู้เรื่อง

>> คลาส EndAnimatorConnector เมื่อเป็นลูกของ com.vaadin.client.extensions.AbstractExtensionConnector จึงถูก override เมธอด extend เพื่อที่จะนำ component ที่รับมาจากคลาส EndAnimator มาเพิ่มการฟัง 'animationend' (ชื่อมาตราฐาน) ด้วยการเรียก registerCssCallback ที่ทำงาน native javascript code จับเหตุการณ์การเล่น animation เสร็จสิ้นของแต่ละ browser, เมื่อ callback function ถูกเรียกก็จะส่งผลให้ onAnimationEnd ของอินเตอร์เฟส AnimationEndEventHandler ทำงาน มันจะส่งสัญญาณไปบอกต่อ EndAnimatorServerRpc ซึ่งจะกลับไปที่คลาส EndAnimator เพื่อทำงาน onAnimationEnd ของอินเตอร์เฟส AnimationEndListener นั่นเอง



>> ทีนี้มาดูกันว่าใช้งานอย่างไร และเหตุใดผมจึงต้องหาวิธีการอย่างนี้มาจัดการกับเหตุการณ์ end animation
- ปรับปรุงคลาส MyUI ให้สร้างสี่เหลี่ยมขนาด 300 x 300 px ออกมา ให้ชื่อมันว่า animateLayout
- ใส่ style sheet พื้นหลังสีเหลือง ให้เล่น animation ของไลบรารีตัวนี้ http://daneden.github.io/animate.css/ มันก็จะหมุนติ้วๆ
- และเมื่อ animation เล่นจบลง ผมก็ให้เปลี่ยนพื้นหลังเป็นสีเขียว (อย่างที่เพื่อนๆชาว css ทราบกันดีอยู่แล้วว่าจะเกิดการ override สีพื้นหลัง) พร้อมกับลบ animation หมุนติ้วๆนี้ออก




- เพื่อนๆจะเห็นว่า css class names ที่ถูกเพิ่มเข้าไปเมื่อไม่ลบออกก็จะฝังอยู่ในแท็ก html (ได้แก่ .background-yellow และ .background-green) ซึ่งงานของผมไม่ต้องการให้ css class names ของ animation ฝังอยู่จึงสั่งให้ลบออกไปหลังจาก animation เล่นจบลง ทีนี้เวลาผมกดปุ่ม F5 หรือเคลื่อนย้าย dom ก็จะไม่เกิดการเล่น animation เหล่านี้อีก เป็นว่าบรรลุเป้าหมายครับผม (ยิ้ม)

>> และนี่คือโครงสร้างทั้งหมดของโปรเจ็กต์และการ include css animation ดังข้างต้นเข้าไป


*** ผมสังเกตว่า
- หากแก้ไข (รวมถึง เพิ่มไฟล์ ลบไฟล์) widgetset ก็ต้อง compile มันใหม่ ผมจะคลิกขวาที่โปรเจ็กต์แล้วเลือกคำสั่ง Build
- หากแก้ไข vaadin หลังบ้าน (ในที่นี้ได้แก่คลาส EndAnimator และ MyUI) ให้คลิกขวาที่โปรเจ็กต์แล้วเลือกคำสั่ง Run ได้เลย (มันจะ compile กับ deploy ให้อัตโนมัติ)

>> ใครที่สนใจ gwt อยากลองมาเขียน vaadin ผมขอบอกว่ามันแจ่มมาก! เป็น open source เพื่อทำงานกับ JEE เหมือนกันแต่ compile ไวกว่า ลองไปเยี่ยมชมพวกเขาสิครับ
https://vaadin.com/home
คืนนี้ฝันดีจ้า

วันอาทิตย์ที่ 27 มีนาคม พ.ศ. 2559

Vaadin: How to listen to animation end part 2

>> มาสร้างโปรเจ็กต์แรกกันเถอะ ด้วย netbeans เวอร์ชัน 8.1 กับ jdk เวอร์ชัน 1.8.0_65

1) เลือกสร้างโปรเจ็กต์จาก maven ด้วยวิธีการ project from archetype

2) ที่หน้าต่าง maven archetype ให้เพื่อนๆค้นหาแม่แบบที่เป็น vaadin-archetype-application (อ่านเพิ่มเติมสำหรับแม่แบบอื่นๆ)

3) ตั้งชื่อโปรเจ็กต์, กำหนดที่อยู่ของโปรเจ็กต์, ตั้งชื่อ group id รวมไปถึงรายละเอียดปลีกย่อยด้านล่าง ได้แก่ ชื่อของ widgetset และชื่อของคลาสหลัก

4) เสร็จแล้วโปรดคอยสักครู่ เจ้า maven นี้จะตามไปโหลดไฟล์จาร์ที่เกี่ยวข้องกับแม่แบบที่เราได้เลือกไว้มาให้ และหลังจากนั้นก็เปิดเข้าไปดูหน้าตาของ source code ที่มันเขียนไว้ให้กันเลย

5) เดี๋ยวผมจึงจะอธิบายว่ามันเขียนอะไรมาให้บ้าง ตอนนี้อยากให้ลองรันโปรเจ็กตนี้กันก่อนครับ ด้วยการคลิกขวาที่ชื่อโปรเจ็กต์แล้วเลือก run มันจะถามว่าจะรันบน server ตัวไหน ผมเลือกเป็น glassfish server เวอร์ชัน 4.1.1 จากนั้นกดปุ่ม ok

6) เข้าใจว่ามันจะ compile สิ่งที่เรียกว่า widgetset ด้วย (ถ้ามี) รวมไปถึงสร้าง .war และ deploy ขึ้นสู่ server

7) และปรากฏสู่สายตา


>> มาทำความเข้าใจโค้ดกันเถอะ นี่ก็เพื่อมิตรอันดีระหว่างผมกับผู้เริ่มต้นใหม่ที่ใช้ netbeans มาสร้างโปรเจ็กต์ตามผม ทว่าโพสต์นี้ก็ไม่ได้สอนพื้นฐานเพื่อที่จะเข้าใจ vaadin หรอกนะครับ หลังจากนี้ผมจะมุ่งไปที่การจับเหตุการณ์เมื่อ animation เล่นจบแล้วหรือก็คือตามวัตถุประสงค์ของโพสต์นี้นั่นเอง

- บรรทัดที่ 24 บอกว่าเราใช้ theme ชื่อ mytheme ซึ่งอยู่ ณ end_animator\src\main\webapp\VAADIN\themes
- บรรทัดที่ 25 บอกว่าเรามีไฟล์ .gwt.xml หรือก็คือ widgetset อยู่ที่ end_animator\src\main\resources\com\pros\endanimator


- บรรทัดที่ 29 นี่เป็นเมธอดแรกที่ vaadin จะเข้ามาทำงาน
- บรรทัดที่ 30 คือ layout แบบ vertical เหมือนกับจานที่ตั้งซ้อนกันขึ้นไป เพียงแต่ความจริงแล้วการเพิ่ม component จะเป็นการเรียงลงมาด้านล่าง หากแกะดู html code ก็จะพบว่ามันคือแท็ก div ที่วางเรียงต่อกันจากบนลงล่างครับ
- บรรทัดที่ 32 สร้างช่องรับข้อมูลหรือก็คือ text field ขึ้นมา จากนั้นระบุ caption ว่า Type your name here:
- บรรทัดที่ 35 สร้างปุ่มหรือก็คือ button โดยระบุ caption ว่า Click Me จากนั้นกำหนด click event ให้กับปุ่ม ประมาณว่ากดปุ่มแล้วอยากจะให้ทำอะไรด้วยวิธีการเขียนของจาวา 1.8 ที่เรียกว่า lambda expressions (อ่านเพิ่มเติม) ซึ่งต้องการให้เพิ่ม label เข้าไปใหม่ทุกครั้งที่กดปุ่ม โดยให้ label นี้มีค่าเป็น Thanks ตามด้วยข้อความที่เราได้กรอกเข้าไปในช่อง text field ตามด้วย , it works!
- บรรทัดที่ 41 เพิ่ม text field กับ button เข้าไปใน layout
- บรรทัดที่ 42 กำหนด padding ใหักับ layout (ระบบ margin ของ vaadin ก็คือ padding ครับ)
- บรรทัดที่ 43 กำหนดพื้นที่ว่างระหว่าง text field กับ button ให้แลดูสวยงาม
- สุดท้ายบรรทัดที่ 45 ก็กำหนด layout ให้กับ panel หลักหรือก็คือพื้นที่ที่ใช้แสดงผลนั่นเอง (แท็ก body) หากขาดบรรทัดนี้ไป เราก็จะมองไม่เห็นอะไรเลย (เห็นหน้าเปล่าๆ)


- บรรทัดที่ 48 กำหนดให้มี servlet (อย่างที่เพื่อนๆทราบ พื้นฐานของจาวาเว็บก็คือ servlet) ตัวหนึ่งมีหน้าที่รับผิดชอบต่อประดา request ที่ถูกยิงเข้ามาหาโปรเจ็กต์นี้ (สำหรับ /* คือทุก request)
- บรรทัดที่ 49 กำหนดให้ MyUI เป็นคลาสหลักที่สืบทอดจากคลาส com.vaadin.ui.UI (vaadin ตั้งแต่เวอร์ชัน 7 เป็นต้นมาคลาสหลักต้องเป็นลูกของคลาส UI) ทั้งกำหนดโปรเจ็กต์นี้ถูกจัดการหน่วยความจำแบบ dev mode (หรือก็คือการกำหนดว่า production mode มีค่าเป็น false)
- บรรทัดที่ 50 พูดถึงบรรทัดที่ 48 เจ้า servlet ที่รับผิดชอบต่อทุก request ของโปรเจ็กต์นี้ก็คือคลาสชื่อ MyUIServlet ที่เป็นลูกของ VaadinServlet นั่นเองครับ

>> ที่กล่าวมานี้ก็เพื่อมือใหม่ที่หัดใช้ netbeans มาทำงาน vaadin ว่าอย่างน้อยๆเราก็เป็นมือใหม่หัดใช้เหมือนกัน (โพสต์นี้ real time เลยก็ว่าได้) และต่อไปผมขอนำเข้าสู่เนื้อหาแท้จริงที่ต้องการนำเสนอเลยนะครับ

>> ผมต้องการสร้าง widgetset เพื่อทำงาน javascript กับ rpc, ผมพบอยู่ 2 วิธีครับ
1) สร้างทีละคลาสเอง (= =) อื่ม... ก็ทำได้อยู่ หรือ
2) ติดตั้ง vaadin plugin ตามขั้นตอนต่อไปนี้ (ผมเลือกวิธีนี้นะ)
จาก https://www.youtube.com/watch?v=P9YupaOpsMk
- เลือกเมนู Tools ตามด้วย Plugins

- เลือกแท็บ Available Plugins และค้นหาด้วยคีย์ว่า vaadin

- พบ plugin ชื่อดังรูปด้านล่างนี้ (เวอร์ชันอาจต่างกัน) ก็ติดตั้งเลยครับ


- เมื่อติดตั้งเสร็จเรียบร้อยแล้ว (รวมถึงหลังจากที่เจ้า netbeans ขอ restart) เพื่อนๆจะสามารถสร้างโปรเจ็กต์ vaadin ได้ โดย netbeans รู้จักวิธีการดังกล่าวแสดงอยู่ในช่อง Categories และมีรูปแบบย่อยให้เลือกสร้างในช่อง Projects (ทดลองสร้างโปรเจ็กต์ใหม่อีกสักรอบ ต้องเห็นดังรูปด้านล่างนี้)


>> ทีนี้เรากก็ขอให้ netbeans สร้าง widgetset ให้ได้แล้วล่ะ คลิกขวาที่โปรเจ็กต์เลย แล้วเลือก New > Other... > มองหา Vaadin แล้วเลือก File Types เป็น Vaadin Widget กดปุ่ม Next

- ผมตั้งชื่อ Class Name: เป็น EndAnimator และคลาสนี้อยู่ฝั่งหลังบ้านหรือก็คือ vaadin
- ให้สังกัด Package: เป็น com.pros.endanimator
- ตัวเลือกด้านล่าง เลืก Server side component / Client side connector with shared state and RPC, including custom widget. เดี๋ยวอันไหนไม่ได้ใช้ค่อยลบออก
- กด Next เลย

- โดยปกติแล้ว หลังบ้าน (vaadin) กับ หน้าบ้าน (gwt) จะติดต่อกันผ่าน interface ที่ระบบนี้สามารถเข้าใจกันได้ และโดยปกติแล้วหลังบ้านจะใช้ com.vaadin.ui.AbstractComponent interface แต่ครั้งนี้ผมขอเปลี่ยนเป็น com.vaadin.server.AbstractExtension ทว่าไม่มีให้เลือก ? โอเค งั้นก็ใช้ com.vaadin.ui.AbstractComponent ไปก่อน เดี๋ยวค่อยไปแก้ไขเอาทีหลัง กดปุ่ม Finish

- netbeans ก็จะสร้างคลาสและอินเตอร์เฟสต่างๆออกมา อย่างที่ผมได้รับตามนี้ครับ


>> เป็นว่าตอนนี้ผมให้ netbeans เตรียม widgetset ให้เสร็จแล้ว แต่มันไม่ได้ทำงานตามที่ผมต้องการ แต่ผมก็อยากจะอธิบายเสียหน่อยว่า widget ใหม่ที่เพิ่งได้มานี้ เขาเขียนโค้ดให้มันทำงานอะไร เรามาดูแต่ละคลาสแต่ละอินเตอร์เฟสที่สำคัญกันก่อนนะ ซึ่งแบ่งออกเป็นสองฝั่ง
- ฝั่งหลังบ้าน ตอนนี้มีคลาส EndAnimator กับ MyUI
- ฝั่งหน้าบ้าน คือทั้งหมดใน package ชื่อ com.pros.endanimator.client นั่นแหละ ประกอบด้วย EndAnimatorClientRpc, EndAnimatorConnector, EndAnimatorServerRpc, EndAnimatorState และ EndAnimatorWidget

>> คลาส EndAnimator (หลังบ้าน) มี constructor ทำงาน register ออบเจ็กต์ rpc หลังบ้านไว้ตัวหนึ่ง พร้อมกับบริการ getState ที่สามารถให้ค่าของตัวแปรชื่อ text ออกมาได้, มองไปที่ตัวออบเจ็กต์ rpc มันคือ EndAnimatorServerRpc ที่เป็น interface โดยจะรอสัญญาณ (จากหน้าบ้าน) เพื่อทำงานเมธอด clicked และมี MouseEventDetails เป็นพารามิเตอร์ (อ่านทั้งหมดนี้ด้วยตัวเอง) ดูรูปประกอบ

- หมายความว่าอย่างไรสำหรับสิ่งที่ออบเจ็กต์ rpc นี้ทำ หมายความว่า ทุกครั้งที่เมธอด clicked นี้ถูกเรียก ค่าของตัวแปร clickCount จะเพิ่มขึ้นหนึ่งทุกครั้งไป และเมื่อไรก็ตามที่ค่าของมันเอาไปหารเอาเศษด้วย 5 แล้วได้ค่าเป็น 0 มันจะเรียกไปที่ rpc อีกตัวที่อยู่ฝั่งหน้าบ้าน (ซึ่งตอนนี้เรายังไม่รู้จัก) โดยบอกให้ rpc ฝั่งหน้าบ้านนี้ทำงานเมธอด alert แสดงข้อความ Ok, that's enough! ออกมา
- โดยทุกรอบที่เมธอด clicked นี้ทำงานก็จะเปลี่ยนค่าตัวแปร text ที่ถูกสร้างไว้ในคลาส EndAnimatorState เป็น You have clicked ตามด้วยค่า clickCount และตามด้วย times (ประมาณว่านับครั้งให้)
- เพื่อนๆมือใหม่จะเห็นว่าคลาส EndAnimator นี้ไม่มีหน้าตาใดๆเลย มันไปอยู่ไหนนะ?

>> คลาส EndAnimatorConnector (หน้าบ้าน) มี constructor ทำงาน register ออบเจ็กต์ rpc หน้าบ้านไว้ตัวหนึ่ง, บริการ getState ที่สามารถให้ค่าของตัวแปรชื่อ text ออกมาได้, บริการ getWidget คือช่องทางที่ connector จะสื่อสารกับ gwt, กลไก onStateChanged ที่ทำงานอัตโนมัติเมื่อมีการเปลี่ยนค่าของตัวแปร text จากหลังบ้านมายังหน้าบ้าน (ปกติแล้ว vaadin สามารถคุยกับ gwt ได้ก็ผ่าน onStateChanged นี้ครับ แต่ถ้า gwt จะคุยกลับไปที่ vaadin จะต้องใช้ rpc มาช่วย), มองไปที่ตัวออบเจ็กต์ rpc มันคือ EndAnimatorClientRpc ที่เป็น interface โดยจะรอสัญญาณ (จากหลังบ้าน) เพื่อทำงานเมธอด alert และก็จะใช้ javascript เขียน message แบบกล่องข้อความออกไป ซึ่งก็คือข้อความว่า Ok, that's enough! นั่นเอง

- คำถามคือ แล้วเมื่อไรที่ rpc ฝั่งหลังบ้านจะถูกเรียกล่ะ? เพราะเท่าที่อธิบายมา ดูเหมือนว่า logic นี้จะคอยให้มีการส่งสัญญาณไปหา rpc ฝั่งหลังบ้านก่อน จากนั้นฝั่งหน้าบ้านจึงจะ alert ข้อความออกมาได้ ฮั่นแน่!เพื่อนๆที่ตาไวตอบผมได้ทันควัน บรรทัดที่ 33 ในรูปข้างต้นนั่นไงที่จะผลิตสัญญาณหรือก็คือการเรียกเมธอด clicked ของฝั่งหลังบ้านให้ทำงานตาม logic นี้โดยส่งพารามิเตอร์ที่มันต้องการให้ด้วย นั่นคือออบเจ็กต์ MouseEventDetails ครับ
- เรื่องของเรื่องจะเริ่มจากผู้ใช้ต้องเห็นหน้าตาของ widget ที่ browser ก่อนจากนั้นทำอะไรกับมันสักอย่าง ฮั่นแน่!เพื่อนตาไวคนเดิมตอบผมทันทีว่า คลิก ผู้ใช้คลิกอะไรสักอย่างไง! ใช่ครับบรรทัดที่ 28 เราได้ขอ widget จาก getWidget เพื่อคอยฟัง ClickHandler (ฟังการคลิกจากผู้ใช้) เพราะเมื่อคลิกเข้ามา onClick จะทำงาน เกิดการสร้างออบเจ็กต์ MouseEventDetails ด้วยกลวิธีดังในรูป แล้วส่งให้กับ rpc หลังบ้านทำงานในที่สุด เย้! เป็นว่าเพื่อนๆกับผมเข้าใจหัวใจการทำงานของระบบ rpc นี้แล้วนะครับ

>> สุดท้ายที่จะอธิบายก็คือคลาส EndAnimatorWidget หรือก็คือ widget เจ้ากรรมที่ผู้ใช้จะมองเห็นหน้าตาของมันนั่นเอง คลาสนี้เป็นลูกของ com.google.gwt.user.client.ui.Label ดังนั้นหน้าตาที่จะเห็นก็ต้องเป็น label ที่ถูกกำหนดค่ามาให้

ฮั่นแน่! เพื่อนตาไวอีกคนรู้เลยว่าค่าของมันก็คือ
"You have clicked " + clickCount + " times"
ที่ถูกกำหนดมาตั้งแต่แรกที่คลาสหลังบ้าน EndAnimator นั่นแล้ว (ลองกลับไปดูบรรทัดที่ 21 ของคลาส EndAnimator) แต่ผิดครับ ไม่ใช่ข้อความ "You have..." มันคือข้อความว่า "This is EndAnimator" นั่นเพราะว่ามันคือค่าแรกที่กำหนดให้กับตัวแปร text ในคลาส EndAnimatorState (ลองเปิดดูสิ) ถือว่าเป็นเสน่ห์ของ EndAnimatorState ที่สามารถส่งค่าของตัวแปรใดๆ (ต้องมีชนิดตามที่ระบบของทั้งสองฝั่งรู้จักนะ) ออกไปได้ผ่านบริการ getState ของทั้งฝั่งหลังบ้านและหน้าบ้านครับ

>> เอาล่ะ เรามาทดลองรันมันกันเถอะ โดยกลับไปแก้ไขคลาส MyUI ให้เรียกมันออกมาก่อน ตามนี้

- เพื่อนๆควรทราบว่า หากเราได้เคยลองรันมาแล้วแล้วรันใหม่ ผลลัพธ์ที่ได้จะไม่เปลี่ยนแปลง เนื่องจากว่า server ยังคงใช้ .war อันเก่า เราต้องหาวิธีการให้ server มันรู้ว่าต้องใช้ .war ใหม่นะ (เพราะ source code เราได้เปลี่ยนแปลงไปแล้ว)
- ให้คลิกขวาที่โปรเจ็กต์ เลือก Build หรือ Clean and Build เพื่อ compile ทุกสิ่งใหม่ จากนั้นจึงคลิกขวาที่โปรเจ็กต์อีกครั้งแล้วสั่ง run ก็จะเป็นการ deploy .war ใหม่ขึ้นสู่ server ครับ (ใครมีวิธีดีกว่านี้ช่วยบอกผมหน่อยก็ได้นะ)

- ทดสอบคลิกไปที่ข้อความ

- และคลิกครั้งที่ 5 ซึ่งหารเอาเศษกับ 5 จะมีค่าเท่ากับ 0


>> อ๊! อธิบายเพลินจนลืมตัว มันยาวอีกแล้ว (= =) ไว้ต่อ part หน้านะครับ ดึกแล้วฝันดี

วันเสาร์ที่ 26 มีนาคม พ.ศ. 2559

Vaadin: How to listen to animation end part 1

>> เนื่องจากผมกำลังศึกษาการเขียน vaadin ด้วย netbeans ซึ่งแท้จริงแล้วผมเขียนมันด้วย eclipse เสมอมา (สังเกตได้จากตัวอย่างก่อนหน้านี้ที่ได้นำเสนอไป) ก็เพราะว่าคราวนี้ผมมีงานที่จำเป็นต้องใส่ animation ให้กับ component บางชิ้น ผมจึงต้องถามตัวเองว่า เทคโนโลยีในขณะนี้ในเรื่องของ animation (โดยเฉพาะกับเว็บเนี่ย) เขาใช้อะไรกัน? คำตอบก็คือ...

>> ใช้ css เวอร์ชัน 3 น่าจะดีที่สุดและง่ายที่สุดสำหรับผมในตอนนี้ครับ

แน่นอนว่า browser ใหม่ๆรองรับมาตราฐานนี้กันหมดแล้ว (เยี่ยมชม)

>> มาฟังปัญหาของผมกันก่อนนะ แท้จริงแล้ว component (รากฐานของ ui ของ vaadin แต่ละชิ้นมาจาก interface ที่ชื่อ Component) เพียงนำมาจับใส่ css class name พวกมันก็สามารถเล่น animation ได้ด้วยดี แต่ทว่า...เมื่อพวกมันเล่น animation จบสิ้นไปแล้ว พวกมันก็ยังคงติดแหง่กฝังอยู่ในแท็ก html (= =) ใครฟังมาถึงตอนนี้ก็ต้องบอกผมว่า แหม มันก็เป็นธรรมชาติของการใส่ style sheet อยู่แล้วนี่ (css ย่อมาจาก Cascading Style Sheets) ก็เหมือนตอนใส่สีพื้นหลังไง background-color: yellow; มันก็ต้องได้สีเหลืองอยู่อย่างนั้นแหละ แต่ๆๆแต่ผมไม่ต้องการแบบนั้น เพราะงานของผมเจ้าชิ้นที่ใส่ animation ไปนั้นน่ะเมื่อมันถูกลากหรือย้ายตำแหน่ง (ตำแหน่งของ dom เปลี่ยนไป) มันจะกลับไปเล่น animation ซ้ำอีกรอบ เพื่อนคนเดิมก็บอกมาอีกว่า ก็ใช้ animation fill mode กำหนดให้มันเล่นไปข้างหน้า (forwards) อย่างเดียวเลยก็ได้นี่ ผมก็ขอบคุณเขานะ แต่ๆๆแต่เมื่อผมกดปุ่ม F5 (refresh page) เท่านั้นแหละ เจ้ากรรม animation ก็จะกลับมาเล่นใหม่เหมือนเดิม คำตอบที่ผมต้องการคือ เมื่อพวกมันเล่นจบผมจะลบพวกมันทิ้งไปเลย! (เอาออกจากแท็ก html)

เหตุที่ต้องทำเช่นนี้ก็เพราะว่า เว็บนี้มีกลุ่มลูกค้าที่จะเข้ามาซื้อสินค้า (เล่นเว็บเราอะนะ) ในแต่ละช่วงเวลาต่างกัน บ้างก็จะเอากระเป๋า บ้างก็จะเอารองเท้า เป็นต้น ตัวอย่างพฤติกรรมการซื้อสินค้าเช่น คนไหนที่คลิกซื้อกระเป๋า เจ้ากระเป๋านี่จะต้องหมุนติ้วๆสามรอบภายในเวลา 1 วินาทีก่อนจะถูกโยนใส่ตะกร้าของเขา และเมื่อพวกเขาเข้าไปดูของในตะกร้า พวกเขาจะยังไม่จ่ายเงิน พวกเขาสามารถจัดของในตะกร้าได้ (เหมือนกับการจัดกระเป๋าไอเทมในเกมออนไลน์) ทำให้สินค้าสามารถถูกย้ายตำแหน่ง เป็นเหตุให้โครงสร้างของ html ในส่วนนั้นเปลี่ยนแปลงและผลคือ animation หมุนติ้วๆกลับมาเล่นซ้ำอีก ทีนี้ถ้าลูกค้ากดปุ่ม F5 สินค้าทุกชิ้นที่เขาได้เลือกไว้ในตะกร้าก็จะหมุนติ้วๆกันทุกชิ้น เฮ้!

เพราะผมเองก็ไม่คล่อง javascript หนักเลยคือรู้เรื่อง animation ของ css น้อยมากเมื่อเที่ยบกับการเขียนโปรแกรมนี้ด้วย vaadin ในเมื่อผมเป็น java และตอนนี้ต้องใช้ css มาทำ animation, ผมจึงอยากทราบว่า ผมจะรู้ได้อย่างไรว่า animation เหล่านั้นได้เล่นจนเสร็จสิ้นไปแล้วครับ?

และผมก็มีคำตอบ นั่นคือเรื่อง animation end event (อ่านเพิ่มเติม) ซึ่งต้องใช้ javascript มาดักฟัง ...ห๊ะ?...นี่ต้องมาเขียนจาวาสคริปต์อีกแล้วหรือ ก็ใช่ไง

>> เอาล่ะในเมื่อหนีมันไม่พ้นก็พุ่งชนเสียเลย, ผมรู้ว่า vaadin สามารถเข้าใจ javascript เพียวๆได้ (อ่านเพิ่มเติม) ด้วยการกำหนด function ก่อนจากนั้นค่อยเรียกใช้ แต่แนวทางนี้สำหรับสินค้าแต่ละชิ้นของเว็บดูเหมือนว่าจะต้องส่งค่า id ให้กับ function ด้วย เพื่อที่ function จะได้แยกแยะสินค้าแต่ละชิ้นได้ แล้วยังไงต่อ...ก็ต้องหาทางผูก id เข้ากับ animation end event อย่างนั้นสินะ โอ้ย~คิดไม่ออก อ่อนแอจาวาสคริปต์

มีวิธีอื่นอีกไหมที่สามารถเอาชนะปัญหานี้ได้ (แน่นอนว่ายังต้องพึ่งพา javascript) อ้อ การเขียน vaadin แบบ native ไง (คำเรียกของผมเอง) ซึ่งจะเรียกให้ถูกต้องคือการเขียน gwt ขึ้นมาเองโดยวิธีการที่เรียกว่า widgetset (อ่านเพิ่มเติม) พร้อมกับใช้วิธี rpc ในการสื่อสารระหว่าง vaadin (ฝั่งหลังบ้าน) กับ gwt (ฝั่งหน้าบ้าน) ดังกล่าว (อ่านเพิ่มเติม) เพื่อนๆจะเห็นว่าผมต้องอ่านเยอะ ยิ่งความรู้ไม่มี ผมก็ต้องอ่านให้มากเข้าไว้ (ไม่นับว่าอ่านแล้วตีความผิดอีก อะโด่~) เอาล่ะครับมาลงมือทำกันเถอะ

>> เครื่องมือที่ผมจะใช้สร้างงานชิ้นนี้
- NetBeans IDE 8.1
- และวิธีทำให้ netbeans นี้สร้าง vaadin project ให้ผมได้
(คลิกไปอ่านพร้อมกันเลย: https://vaadin.com/docs/-/part/framework/getting-started/getting-started-netbeans.html)

>> อุ้ย!ยาวไปแล้วขอตัดจบก่อน (เล่นตัว) ให้เพื่อนๆลองสร้างโปรเจ็กต์แรกพลางกันไปก่อน เดี๋ยวพรุ่งนี้ผมมาคุยให้ฟังต่อ

>> ขอบคุณยิ่งสำหรับแหล่งความรู้เหล่านี้ที่แชร์กันในโลกออนไลน์ ซึ่งทำให้ผมสามารถเอาชนะปัญหานี้ได้ โดยเพื่อนๆสามารถอ่านเพิ่มเติมเองได้ครับ
- How to Capture CSS3 Animation Events in JavaScript
- Client-server connector and onStateChanged
- How to add CSS AnimationEnd event handler to GWT widget?
- Navigator userAgent Property
- Delayed Client -> Server RPC call when using JSNI -> Java callbacks
- Component and UI Extensions
- Animate.css

>> และนี่คืองานที่ผมทำสำเร็จแล้วบน eclipse ครับ


วันอาทิตย์ที่ 21 กุมภาพันธ์ พ.ศ. 2559

Vaadin with Map by JavaScript part 2

>> สามสิ่งที่เราจะต้องใช้จาก part ที่ผ่านมา (ทบทวน) ได้แก่
1. com.vaadin.ui.AbstractJavaScriptComponent หรือก็คือ หลังบ้าน
2. com.vaadin.shared.ui.JavaScriptComponentState หรือก็คือ share พื้นที่
3. จาวาสคริปต์ที่ทำหน้าที่เป็น Connector ซึ่งถูกเขียนรวมกับฟังก์ชันของแผนที่ที่เป็นงานของ หน้าบ้าน

>> ภาพด้านล่างนี้คือ main โปรแกรม

- บรรทัดที่ 5 และ 6 ระบุว่าเราจะเขียนคลาสแผนที่เพิ่มอีกสองคลาส ได้แก่ GoogleMap และ LongdoMap
- ส่วนบรรทัดที่ 24 คือจุดเริ่มต้นการทำงาน


- บรรทัดที่ 26 แบ่งหน้าจอออกเป็นสองด้าน ด้านซ้ายจะให้แสดง Google map ส่วนด้านขวาจะให้แสดง Longdo map
- บรรทัดที่ 29 และ 30 กำหนดพิกัดเริ่มต้น (ประเทศไทย)
- บรรทัดที่ 34 ถึง 37 อธิบายได้ว่า สร้าง Google map กำหนดพิกัดให้ จากนั้นกำหนดความกว้างและยาว 100 เปอร์เซ็นต์
- บรรทัดที่ 39 ถึง 41 อธิบายได้ว่า ให้วาด Google map ข้างต้น กำหนด caption กำหนดความกว้างและยาว 100 เปอร์เซ็นต์
- บรรทัดที่ 43 ให้ Google map ที่ได้แสดงยังพื้นที่ด้านซ้าย (ดังคำอธิบายในบรรทัดที่ 26)


- บรรทัดที่ 48 ถึง 51 อธิบายได้ว่า สร้าง Longdo map กำหนดพิกัดให้ จากนั้นกำหนดความกว้างและยาว 100 เปอร์เซ็นต์
- บรรทัดที่ 53 ถึง 55 อธิบายได้ว่า ให้วาด Longdo map ข้างต้น กำหนด caption กำหนดความกว้างและยาว 100 เปอร์เซ็นต์
- บรรทัดที่ 57 ให้ Longdo map ที่ได้แสดงยังพื้นที่ด้านขวา (ดังคำอธิบายในบรรทัดที่ 26)

>> ต่อที่คลาส DrawMap ครับ

- บรรทัดที่ 13 ให้คลาสนี้สืบทอดมาจาก VerticalLayout
- บรรทัดที่ 15 ถึง 18 ประกาศว่าคลาสนี้ประกอบไปด้วย component สำคัญใดบ้าง
- บรรทัดที่ 20 ให้ constructor ของคลาสรับพารามิเตอร์ที่มีชนิดเป็น Map interface เท่านั้น (เราเขียนขึ้นเองครับ) ทั้งนี้เพราะผมจะกำหนดให้คลาส GoogleMap และ LongdoMap เป็น Map ด้วย
- บรรทัดที่ 30 และ 31 เมื่อใดก็ตามที่เกิดการกดปุ่ม ค่าที่กำหนดไว้ใน text field จะถูกอ่านและนำมากำหนดให้กับ Map ออบเจ็กต์ทุกครั้ง ซึ่งจะเป็นผลให้เกิดการทำงาน onStateChange โดยอัตโนมัติดังที่ได้เล่าไป
- บรรทัดที่ 35 ถึง 47 เป็นการจัด layout เพื่อให้ประดา component ทั้งหลายเป็นไปตามตำแหน่งที่เราต้องการครับ


- บรรทัดที่ 52 ถึง 66 เขียนบริการ getter methods เอาไว้ส่งออก component สำคัญที่อนุญาตให้เรียกใช้ ณ คลาสอื่นๆ

>> และนี่คือ Map interface ครับผม


>> ก่อนที่จะไปต่อ ภาพด้านล่างคือโครงสร้างทั้งหมดของโปรเจ็กต์นี้


>> คลาส GoogleMap ที่จัดว่าเป็น server-side component และเป็น Map

- หัวใจสำคัญของคลาสนี้มี 3 ตำแหน่งนะ ได้แก่ 1. บรรทัดที่ 7 @JavaScript เพื่อเรียกใช้ไฟล์จาวาสคริปต์ใดๆ ทั้งจากภายนอกและภายในโปรเจ็กต์
-- ภายนอกเรียกไปยัง https://maps.googleapis.com เพื่อใช้ google map api เวอร์ชัน 3 (เท่าที่ทราบในตอนนี้)
-- ภายในเรียกไปยัง JavaScript Connector
2. บรรทัดที่ 11 ระบุว่าคลาสนี้สืบทอดจาก AbstractJavaScriptComponent และเป็น Map
3. บรรทัดที่ 14 เชื่อมโยงตนเองกับ share ในที่นี้คือ State ซึ่งจะได้รับผลการเปลี่ยนแปลงทุกครั้งที่มีการกำหนดพิกัดเข้ามาใหม่

>> คลาส GoogleMapState


>> JavaScript Connector ของ Google map

- บรรทัดที่ 1 ระบุที่อยู่ตาม package ของไฟล์นี้ โดยแทนที่ . (dot) หลังจาก window object ด้วยเครื่องหมาย _ (underscores) ไม่อย่างนั้นจะหาไฟล์นี้ไม่พบ
- บรรทัดที่ 3 บอกว่าพื้นที่ที่เป็นของคลาส GoogleMap นี้แหละคือ DOM ที่จะใช้ผูกเป็นหน้าตาบน browser
- บรรทัดที่ 5 ถึง 16 คือฟังก์ชัน onStateChange (ชื่อต้องตั้งตามนี้เลย) เพราะเมื่อกำหนดค่าพิกัดใหม่ฉันใด ฟังก์ชันนี้จะทำงานทันทีฉันนั้น ผมก็ตั้งใจให้มันไปเรียกใช้ google map api วาดแผนที่ออกมาให้ครับ :)

>> จบไปแล้วกับ Google map คราวนี้มาดู Longdo map กันบ้าง เพื่อนๆจะเห็นว่าวิธีการเหมือนเดิม ต่างกันแค่ api ของตัววาดแผนที่เท่านั้น








>> และลิงค์ด้านล่างนี้คือเอกสารทั้งหมดที่ผมอ่านแล้วลองประยุกต์ทำเอง (ลอกมาว่างั้นเถอะ หัวเราะ) ขอบคุณสำหรับความรู้ครับผม
- Vaadin 7 Loves JavaScript Components
https://vaadin.com/blog/-/blogs/vaadin-7-loves-javascript-components
- Integrating a JavaScript component
https://vaadin.com/wiki/-/wiki/Main/Integrating+a+JavaScript+component
- Integrating JavaScript Components and Extensions
https://vaadin.com/book/vaadin7/-/page/gwt.javascript.html
- Longdo map api (v.2)
http://map.longdo.com/longdo-map-api
- Longdo map api tutorial example (not v.2)
http://map.longdo.com/api/docs/tutorial-mmmap-api-beginners
- Google Maps JavaScript API v3 example
http://www.daydev.com/developer/s6-programming-language/google-maps-javascript-api-v3.html