Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Canvasでピアノロールを作る Canvasでスクロールを扱う際の
座標計算と苦労 / ng-kyoto Angular Meetup #9

Canvasでピアノロールを作る Canvasでスクロールを扱う際の
座標計算と苦労 / ng-kyoto Angular Meetup #9

2019/1/18、ng-kyoto Angular Meetup #9 にて発表した資料です。

OKUNOKENTARO

January 18, 2019
Tweet

More Decks by OKUNOKENTARO

Other Decks in Technology

Transcript

  1. ͳʹ͛ʹߴػೳ w Ի੍ָ࡞༻ιϑ τ %"8 ͸ઐ໳ੑ͕ߴ͍ͨΊಛԽͨ͠ػೳ͕ଟ͍ w ςΩε τΤσΟ λʹൺ΂Δͱང͔ʹಛघͳ࣮૷

    w (6*࣮૷Λੜۀͱ͢Δϑϩϯ τΤϯ υ ɾ ΤϯδχΞͱͯ͠
 ͜ΕΛͪΌΜͱ࣮૷Ͱ͖ΔͱεΩϧΞοϓ͢ΔͷͰ͸
  2. 3FBDU)PPLT w ͔ͭͯ3FBDUͷίϯϙʔωϯ τ͸
 class Something extends React.Component
 ͷΑ ͏ʹΫϥεͱ

    ͯ͠هड़͢Δ͔
 SFDPNQPTFΛ࢖ͬͯ)JHIFSPSEFS$PNQPOFOU )0$ ͱͯ͠هड़ͨ͠ w )0$ͱ͸ίϯϙʔωϯ τΛҾ਺ͱ ͯ͠ίϯϙʔωϯ τΛฦؔ͢਺ͷ͜ͱ w ͭ· Γ Ϋϥεͱͯ͠Ͱ͸ͳ͘ɺ ؔ਺ͱ ͯ͠هड़͢Δͱ͍͏ ͜ͱ
  3. ͳͥΫϥεͰ͸μϝ͔ w Ϋϥε͸UIJTʹঢ়ଶΛ࣋ͨͤΔ͜ͱ͕Ͱ͖Δ ʢεςʔ τϑϧɺ ෭࡞༻ʣ  w componentDidMount componentDidUpdateͱ͍ͬͨ


    ϥΠ ϑαΠΫϧϝ ιο υʹΑͬͯUIJT಺͕ॻ͖׵͑ΒΕ֎෦͔Βͷςε τ͕ࠔ೉ w ϥΠ ϑαΠΫϧϝ ιο υʹɺ ίϯϙʔωϯ τͷ ʮ஋Λඳը͢Δʯ ͱ͍͏੹຿Λ௒͑ͨ ෳࡶͳॲཧ͕ॻ͔Ε͕ͪ ʢGFUDIॲཧͱ͔ʣ  w ෳࡶੑ͕૿͢ͱݕূ͕ࠔ೉ʹͳΓόά͕૿͑Δ 3FBDUυΩϡϝϯ τͷϞνϕʔγϣϯͷทΑ Γҙ༁ͯ͠Ҿ༻
  4. 'VODUJPOBM$PNQPOFOU w 3FBDU)PPLTΛ࢖͏ ͜ͱͰίϯϙʔωϯ τΛؔ਺ͱͯ͠هड़ͭͭ͠
 ͞Βʹঢ়ଶΛѻ͏ ͜ͱ͕Ͱ͖ΔΑ ͏ʹͳΔ w 3FBDUIPPLTOPUNBHJD

    KVTUBSSBZT
 https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e  w ैདྷͷϥΠ ϑαΠΫϧϝ ιο υ΋useEffect() ͱ͍͏
 3FBDU)PPLTͷҰछΛ࢖͍ɺ ؔ਺ͱ ͯ͠هड़͢Δ
  5. ίʔ υͷߏ଄ export default function App() { // ͻͨ͢Β useState()

    const canvasRef = useRef < HTMLCanvasElement > null; useEffect(() => { // ॳظඳը࣌ॲཧ }, []); useEffect(() => { // Իූ௥Ճ࣌ͷॲཧ }, [notes]); useEffect(() => { // εΫϩʔϧҐஔมߋ࣌ͷॲཧ }, [scrollLeft, scrollTop]); const onDragHorizontalScrollBarKnob = useCallback((ev: React.MouseEvent) => { // ਫฏεΫϩʔϧόʔυϥοά࣌ͷϋϯυϦϯά }, [originXY, mediator]); const onDragVerticalScrollBarKnob = useCallback((ev: React.MouseEvent) => { // ਨ௚εΫϩʔϧόʔυϥοά࣌ͷϋϯυϦϯά }, [originXY, mediator]); const onDragScreen = useCallback((ev: React.MouseEvent) => { // Canvas಺υϥοά࣌ͷૢ࡞ʢԻූ௕ͷมߋʣ }, [scrollBarCoord, currentUuid, originXY, notes]); const onMouseDown = useCallback((ev: React.MouseEvent) => { // Canvas಺ͰͷmousedownϋϯυϦϯά }, [ currentUuid, originXY, notes, scrollBarCoord, isDraggingHorizontalScrollBarKnob, isDraggingVerticalScrollBarKnob ]); const onMouseMove = useCallback((ev: React.MouseEvent) => { // canvas಺ͰͷmousemoveϋϯυϦϯά }, [ currentUuid, originXY, notes, isDraggingHorizontalScrollBarKnob, isDraggingVerticalScrollBarKnob ]); return ( <div className="App"> <canvas onMouseDown={ev => onMouseDown(ev)} onMouseMove={ev => onMouseMove(ev)} ref={canvasRef} width="600" height="400" /> </div> ); }
  6. υϥοάϋϯ υ Ϧ ϯάͷ࣮ݱ w Ϛ΢εΫ Ϧ οΫΛͯͦ͠ͷ··཭ͣ͞υϥ οάͱ͍͏࣮૷͕஍ຯʹ೉͍͠ w

    ondrag͸ͦ͏͍࣮ͬͨ૷ͷͨΊͷΠϕϯ τͰ͸ͳ͍ w onmousemoveͰev.button === 1ͷͱ͖ υϥοάͱ൑அ͢ΔΑ ͏ʹ෼ذ
  7. εΫϩʔϧόʔͷϋϯ υ Ϧ ϯά w εΫϩʔϧόʔ͕Ϋ Ϧ οΫ͞Ε͍ͯΔ͔Ͳ͏͔͸ɺ શͯࣗྗͰ࠲ඪܭࢉ
 ͠ͳ͚Ε͹ͳΒͳ͍

    w ϊ ϒͷࠨ্࠲ඪͱӈԼ࠲ඪΛuseState()Ͱ
 ֨ೲ͓͖ͯ͠onmousedownͰ
 ຖճɺ ྖҬ಺͔൑ఆ͢Δ
  8. ԻූͷઃஔͱԻූ௕ͷมߋ w Ϛ΢εͷ࠲ඪ͔Βx - 5, y - 10ͷҐஔΛج఺ʹۣܗ ʢԻූʣ Λඳը

    w Ϛ΢ε࠲ඪΛج఺ʹ͢ΔͱԻූ͕ΧʔιϧͰӅΕͯ͠·͍ඇ௚ײత w ຖճ66*%Λൃߦͯ͠Իූʹ෇༩ w mousedown࣌ʹهԱͨ͠66*%͕mousemove࣌ʹ༗ޮͳΒ͹
 Իූ௕มߋͱ൑ఆ͢Δ w Ϣʔβʹ͸ී௨ʹΫ Ϧ οΫͯ͠ υϥ οάͯ͠Δײ֮
  9. 3FUJOBରԠ w window.devicePixelRatioͰ3FUJOBͳͲͷഒ཰ΛऔಘՄೳ w canvasCtx.scale(dpr, dpr)Ͱഒ཰ઃఆ͕Մೳ w fillRect(x * dpr,

    y * dpr, width * dpr, height * dpr)
 ͱ͔ຖճॻ͔ͳ͘ ͯࡁΉ w ߴEQSදࣔ࣌ʹδϟΪʔ͕ग़ͳ͍Α ͏ʹɺ ຐ๏ͷߦΛ௥Ճ canvasEl.width *= dpr; canvasEl.height *= dpr; canvasEl.style.width = `${canvasEl.width / dpr}px`; canvasEl.style.height = `${canvasEl.height / dpr}px`;
  10. εΫϩʔϧରԠ w Ϋ Ϧ οΫͰͷԻූඳը࣌ʹ
 ͋Β͔͡ΊxʹscrollLeftΛɺ yʹscrollTopΛ଍͢ w εΫϩʔϧόʔͷ υϥ

    οά࣌ʹ࠶ඳըॲཧͰ
 ͢΂ͯͷԻූ࠲ඪ͔ΒscrollLeftͱscrollTopΛҾ͍ͯ࠶ඳը w ͨͿΜݱࡏͷ࣮૷ͷ··Ͱ͸·ͣ͘ ͯ
 ཧ૝తʹ͸Ϋ Ϧ οΫ͞Ε࣮ͨࡍͷ࠲ඪͱϐΞϊϩʔϧશମ͔ΒΈͨԾ૝࠲ඪΛ
 ܥ౷؅ཧ͠ͳ͍ͱɺ ॎԣ֦େॖখͳͲͰࢮ͵
  11. ۤ࿑ͨ͠఺ ʢ3FBDUฤʣ w useEffect()͕૿͑Δ ๲ΒΉ w Πϕϯ τϋϯ υ Ϧ

    ϯάʹԠͨ͡࠶ඳըͷछྨ͕ଟ͍͍ͤ΋͋Δ͚Ͳ
 ෳ਺ͷuseEffect()ʹΑͬͯίϯϙʔωϯ τؔ਺͕ංେԽͨ͠ w Իූυϥ οά࣌ͱεΫϩʔϧόʔ ɾ υϥ οά࣌Ͱ࠶ඳըॲཧ͕ҧ͏ w useEffect(cb, [])ͷୈೋҾ਺ʹࢀরΛྻڍ͢Δ͜ͱͰ
 ͦͷࢀর͕มԽͨ͠ͱ͖ͷΈuseEffectΛ࣮ߦ͢Δ͜ͱ͕Ͱ͖Δ
 ʢuseEffect(() => {}, [scrollLeft]) ͳͲʣ
  12. ۤ࿑ͨ͠఺ ʢ3FBDUฤʣ w 3FBDUͷϚ΢εૢ࡞࣌ͷϋϯ υ Ϧ ϯάҾ਺͸MouseEventܕͰ͸ͳ͍ w 3FBDUख़࿅ऀʹ͸౰ͨΓલͷ࿩͔΋ w

    SyntheticEventͱ͍͏ܗࣜͰ౉ΔͷͰnativeEventऔಘͷͨΊʹ͸
 ev.persist();
 const nativeEv = ev.nativeEvent;
 ͷΑ ͏ʹҰ୴persist͢Δඞཁ͕͋Δ w ͜͏ ͠ͳ͍ͱoffsetX offsetY͕औΕͳ͍ͷͰ஫ҙ
  13. ۤ࿑ͨ͠఺ ʢ$BOWBTฤʣ w ͻͨ͢Β࠲ඪܭࢉͱͷઓ͍ͱͳΔ w fillRect()ͳͲ͢΂ͯͷඳըॲཧ͸ޙউͪͳͷͰίʔϧॱͰ݁Ռ͕มΘΔ w ։ൃத͸Իූ͕εΫϩʔϧόʔΛಥ͖ൈ͚Δͱ͔βϥ w ϨΠϠʔͳΜͯ֓೦͸ແ͍

    ʢؤு࣮ͬͯ૷͢Δ͔$BOWBTϥούʔϥΠ ϒϥ ϦʹཔΔʣ  w ͻͨ͢ΒԚ͍ίʔ υͱ ϒϥ΢β্ͷखಈσόοάΛ܁Γฦͯ͠
 ͧ͜͜ͱ͍͏ ͱ͜ΖͰϦ ϑΝΫλ Ϧ ϯά
  14. ۤ࿑ͨ͠఺ ʢ$BOWBTฤʣ w 3FBDUͷίϯϙʔωϯ τؔ਺͔Β$BOWBTʹؔ͢Δॲཧ͸͢΂ͯ௥͍ग़ͨ͠ w CanvasMediatorͱ͍͏தؒҕৡ༻ͷγϯάϧ τϯΛ࡞ͬͯ
 ඳըܥͱ࠲ඪऔಘܥ͸͢΂ͯͦͬͪʹ࣮૷͢ΔΑ ͏

    Ϧ ϑΝΫλ Ϧ ϯά w Իූ͚ͩͳΒ؆୯ͩͬͨ w εΫϩʔϧόʔͷ࣮૷Λ࢝ΊͨลΓ͔Βࠞಱͱ ࢝͠Ίͯ
 ϒϥ΢βͷ΢Πϯ υ΢࣮૷ͷ࢓༷ͱ͔ړΓ࢝Ίͨ w 04ͷ΢Πϯ υ΢γεςϜΛ࣮૷ͨ͠ਓ͸ϚδͰҒେͩͱࢥ͏
  15. ࠓޙ΍͍͖͍ͬͯͨػೳ w Ϋ Ϧ οΫͯ͠ஔ͍ͨԻූͷҠಈ ɾ ࡟আ w Ͳͷۣܗ͕Ϋ Ϧ

    οΫ͞Ε͔͕ͨऔΕͦ͏ʹͳ͍ͷͰ
 εΫϩʔϧόʔͱಉ͡Ͱɺ ͢΂ͯྖҬܭࢉͰදݱ͢Δ͔͠ͳ͍͔΋ wυϥοάͨ͠··$BOWBT֎ʹϚ΢εΛಈ͔ͨ͠ΒࣗಈͰεΫϩʔϧ w ࠲ඪ͸औΕΔͬΆ͍ɺ ࠶ඳըܭࢉ͕΍ͨΒ໘౗ͬΆ͍ w ࣮ࡍʹ࠶ੜϘλϯΛ෇͚ͯԻΛ໐Β͢ w ເͷ·ͨເ