Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Canvasでピアノロールを作る Canvasでスクロールを扱う際の 座標計算と苦労 / ng...
Search
OKUNOKENTARO
January 18, 2019
Technology
0
1.2k
Canvasでピアノロールを作る Canvasでスクロールを扱う際の 座標計算と苦労 / ng-kyoto Angular Meetup #9
2019/1/18、ng-kyoto Angular Meetup #9 にて発表した資料です。
OKUNOKENTARO
January 18, 2019
Tweet
Share
More Decks by OKUNOKENTARO
See All by OKUNOKENTARO
トレタO/X アーキテクチャ移行記 Next.js App Router化への道のり / TORETA TECH UPDATE 1
okunokentaro
5
11k
Podcastを継続する技術 / refactoradio-240119
okunokentaro
1
190
Webアプリケーション設計の第一歩は ディレクトリの整理から / Encraft 1
okunokentaro
34
10k
JSONとJSON Schemaを改めて理解する / tokyo_study
okunokentaro
9
2.4k
それでもどうしてRecoilを使うのか / Harajuku.ts Meetup Recoil
okunokentaro
19
5.6k
TypeScriptは10年でこんなに進化しました / TechFeed Experts Night 11
okunokentaro
6
1.8k
Hasura.io RDBをサクサク作る方法はARやO/RMだけじゃなくなりました/hasura-io
okunokentaro
5
690
コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2
okunokentaro
14
6.4k
10年と3ヶ月でWebサービスを作った話 / Piyogrammer Conference 2021
okunokentaro
2
1.1k
Other Decks in Technology
See All in Technology
How to achieve interoperable digital identity across Asian countries
fujie
0
150
能登半島災害現場エンジニアクロストーク 【JAWS FESTA 2025 in 金沢】
ditccsugii
0
540
綺麗なデータマートをつくろう_データ整備を前向きに考える会 / Let's create clean data mart
brainpadpr
3
420
ACA でMAGI システムを社内で展開しようとした話
mappie_kochi
1
310
速習AGENTS.md:5分で精度を上げる "3ブロック" テンプレ
ismk
6
1k
Vibe Coding Year in Review. From Karpathy to Real-World Agents by Niels Rolland, CEO Paatch
vcoisne
0
130
[Keynote] What do you need to know about DevEx in 2025
salaboy
0
160
Where will it converge?
ibknadedeji
0
210
PHPからはじめるコンピュータアーキテクチャ / From Scripts to Silicon: A Journey Through the Layers of Computing Hiroshima 2025 Edition
tomzoh
0
130
Geospatialの世界最前線を探る [2025年版]
dayjournal
1
220
小学4年生夏休みの自由研究「ぼくと Copilot エージェント」
taichinakamura
0
660
LLM時代にデータエンジニアの役割はどう変わるか?
ikkimiyazaki
6
1.2k
Featured
See All Featured
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.5k
Making Projects Easy
brettharned
119
6.4k
Practical Orchestrator
shlominoach
190
11k
Building Better People: How to give real-time feedback that sticks.
wjessup
369
20k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.9k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
970
RailsConf 2023
tenderlove
30
1.2k
Site-Speed That Sticks
csswizardry
11
900
Code Review Best Practice
trishagee
72
19k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
Git: the NoSQL Database
bkeepers
PRO
431
66k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Transcript
$BOWBTͰϐΞϊϩʔϧΛ࡞Δ $BOWBTͰεΫϩʔϧΛѻ͏ࡍͷ ࠲ඪܭࢉͱۤ࿑ +BO OHLZPUP"OHVMBS.FFUVQ !PLVOPLFOUBSP
୭ w Ԟݡଠ!PLVOPLFOUBSP w ΫϨεΣΞද w ΞϓϦέʔγϣϯ ɾ ΤϯδχΞ
࠷ۙͬͨ͜ͱ w 8FC.VTJDͰԿ͕Ͱ͖Δͷ͔ '30/5&/%$0/'&3&/$& w ͷ τϥΠΤϥʔ͔Βੜ·Εͨେنઃܭϊϋ 'SPOUFOE$POGFSFODF'VLVPLB w ࣍ੈ8FCΧϯϑΝϨϯε8FC.VTJDηογϣϯ
࣍ੈ8FCΧϯϑΝϨϯε
ࠓ͢͜ͱ w $BOWBTͰϐΞϊϩʔϧΛ࣮͢Δ w 3FBDU)PPLTͱԿ͔ w $BOWBTΛѻ͏্Ͱͷۤ࿑
ϐΞϊϩʔϧͱ
ϐΞϊϩʔϧ ͍͍ͩͨͲͷԻ੍ָ࡞༻ͷιϑ τΣΞʹ࣮͞Ε͍ͯΔ ϝϩσΟ Λೖྗ͢ΔͨΊͷΤσΟ λը໘
%FNP
Ͱ͖Δ͜ͱ Ϋ Ϧ οΫͰͷԻූͷೖྗ υϥ οάͰͷԻූͷมߋ ϐΞϊϩʔϧදࣔͷ9ํɺ :ํͷ֦େॖখɺ εΫϩʔϧ ʢσϞͯ͠ͳ͍͚Ͳɺ
ԻූͷίϐϖআͨΓલʹͰ͖Δʣ
ͳʹ͛ʹߴػೳ w Ի੍ָ࡞༻ιϑ τ %"8 ઐੑ͕ߴ͍ͨΊಛԽͨ͠ػೳ͕ଟ͍ w ςΩε τΤσΟ λʹൺΔͱང͔ʹಛघͳ࣮
w (6*࣮Λੜۀͱ͢Δϑϩϯ τΤϯ υ ɾ ΤϯδχΞͱͯ͠ ͜ΕΛͪΌΜͱ࣮Ͱ͖ΔͱεΩϧΞοϓ͢ΔͷͰ
ͬͯΈͨ
3FBDU $BOWBT w OHLZPUP"OHVMBS.FFUVQͰൃදͯ͠Δ͚Ͳ3FBDUΛͬͨ w $BOWBTΛ͏͚ͩͳͷͰ7BOJMMB+4Ͱ͍͍͕3FBDUΛͬͨ w )PPLTͷ࿅श͔ͨͬͨ͠ͷͰ3FBDUΛͬͨ
3FBDU)PPLT w ݄ɺ 3FBDU$POGʹͯൃද͞Εͨ3FBDUͷ৽͍͠"1*܈ w 4UBCMFͰ͏ ͜ͱ͕Ͱ͖ͣnpm i react@next͢Δ͜ͱͰ ࣮ࡁΈϦ
ϦʔεΛΠϯε τʔϧͰ͖Δ
3FBDU)PPLT w ͔ͭͯ3FBDUͷίϯϙʔωϯ τ class Something extends React.Component ͷΑ ͏ʹΫϥεͱ
ͯ͠هड़͢Δ͔ SFDPNQPTFΛͬͯ)JHIFSPSEFS$PNQPOFOU )0$ ͱͯ͠هड़ͨ͠ w )0$ͱίϯϙʔωϯ τΛҾͱ ͯ͠ίϯϙʔωϯ τΛฦؔ͢ͷ͜ͱ w ͭ· Γ Ϋϥεͱͯ͠Ͱͳ͘ɺ ؔͱ ͯ͠هड़͢Δͱ͍͏ ͜ͱ
3FBDU)PPLT w SFDPNQPTFͷ࡞ऀ͕'BDFCPPLʹࢀՃͨ͠ w SFDPNQPTF͕ղܾ͠Α ͏ ͱ ͍ͯͨ͠Λ 3FBDUຊମͰ݁ͯ͠վળͰ͖ΔΑ ͏ʹͳͬͨ
w ͦ͏ͬͯੜ·Εͨͷ͕)PPLT w SFDPNQPTFσΟ είϯͱͳͬͨ
ͳͥΫϥεͰμϝ͔ w ΫϥεUIJTʹঢ়ଶΛ࣋ͨͤΔ͜ͱ͕Ͱ͖Δ ʢεςʔ τϑϧɺ ෭࡞༻ʣ w componentDidMount componentDidUpdateͱ͍ͬͨ
ϥΠ ϑαΠΫϧϝ ιο υʹΑͬͯUIJT͕ॻ͖͑ΒΕ֎෦͔Βͷςε τ͕ࠔ w ϥΠ ϑαΠΫϧϝ ιο υʹɺ ίϯϙʔωϯ τͷ ʮΛඳը͢Δʯ ͱ͍͏Λ͑ͨ ෳࡶͳॲཧ͕ॻ͔Ε͕ͪ ʢGFUDIॲཧͱ͔ʣ w ෳࡶੑ͕૿͢ͱݕূ͕ࠔʹͳΓόά͕૿͑Δ 3FBDUυΩϡϝϯ τͷϞνϕʔγϣϯͷทΑ Γҙ༁ͯ͠Ҿ༻
'VODUJPOBM$PNQPOFOU w 3FBDU)PPLTΛ͏ ͜ͱͰίϯϙʔωϯ τΛؔͱͯ͠هड़ͭͭ͠ ͞Βʹঢ়ଶΛѻ͏ ͜ͱ͕Ͱ͖ΔΑ ͏ʹͳΔ w 3FBDUIPPLTOPUNBHJD
KVTUBSSBZT https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e w ैདྷͷϥΠ ϑαΠΫϧϝ ιο υuseEffect() ͱ͍͏ 3FBDU)PPLTͷҰछΛ͍ɺ ؔͱ ͯ͠هड़͢Δ
%FNP
ίʔ υͷߏ 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> ); }
υϥοάϋϯ υ Ϧ ϯάͷ࣮ݱ w ϚεΫ Ϧ οΫΛͯͦ͠ͷ··ͣ͞υϥ οάͱ͍͏࣮͕ຯʹ͍͠ w
ondragͦ͏͍࣮ͬͨͷͨΊͷΠϕϯ τͰͳ͍ w onmousemoveͰev.button === 1ͷͱ͖ υϥοάͱஅ͢ΔΑ ͏ʹذ
εΫϩʔϧόʔͷϋϯ υ Ϧ ϯά w εΫϩʔϧόʔ͕Ϋ Ϧ οΫ͞Ε͍ͯΔ͔Ͳ͏͔ɺ શͯࣗྗͰ࠲ඪܭࢉ ͠ͳ͚ΕͳΒͳ͍
w ϊ ϒͷࠨ্࠲ඪͱӈԼ࠲ඪΛuseState()Ͱ ֨ೲ͓͖ͯ͠onmousedownͰ ຖճɺ ྖҬ͔ఆ͢Δ
ԻූͷઃஔͱԻූͷมߋ w Ϛεͷ࠲ඪ͔Βx - 5, y - 10ͷҐஔΛجʹۣܗ ʢԻූʣ Λඳը
w Ϛε࠲ඪΛجʹ͢ΔͱԻූ͕ΧʔιϧͰӅΕͯ͠·͍ඇײత w ຖճ66*%Λൃߦͯ͠Իූʹ༩ w mousedown࣌ʹهԱͨ͠66*%͕mousemove࣌ʹ༗ޮͳΒ Իූมߋͱఆ͢Δ w Ϣʔβʹී௨ʹΫ Ϧ οΫͯ͠ υϥ οάͯ͠Δײ֮
ॳظඳը w 3FBDU)PPLTʹuseRef()͕͋ΔͷͰͦΕΛͬͯ$BOWBT3FGΛऔಘ w CanvasRef.currentͰωΠςΟ ϒͳ$BOWBTཁૉͷࢀরΛಘΔ w canvasEl.getContext('2d')ͰίϯςΩε τΛಘ͔ͯΒ$BOWBT"1* ௨ΓʹਐΊΕ0,
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`;
εΫϩʔϧରԠ w Ϋ Ϧ οΫͰͷԻූඳը࣌ʹ ͋Β͔͡ΊxʹscrollLeftΛɺ yʹscrollTopΛ͢ w εΫϩʔϧόʔͷ υϥ
οά࣌ʹ࠶ඳըॲཧͰ ͯ͢ͷԻූ࠲ඪ͔ΒscrollLeftͱscrollTopΛҾ͍ͯ࠶ඳը w ͨͿΜݱࡏͷ࣮ͷ··Ͱ·ͣ͘ ͯ ཧతʹΫ Ϧ οΫ͞Ε࣮ͨࡍͷ࠲ඪͱϐΞϊϩʔϧશମ͔ΒΈͨԾ࠲ඪΛ ܥ౷ཧ͠ͳ͍ͱɺ ॎԣ֦େॖখͳͲͰࢮ͵
ۤ࿑ͨ͠ ʢ3FBDUฤʣ w useEffect()͕૿͑Δ ΒΉ w Πϕϯ τϋϯ υ Ϧ
ϯάʹԠͨ͡࠶ඳըͷछྨ͕ଟ͍͍ͤ͋Δ͚Ͳ ෳͷuseEffect()ʹΑͬͯίϯϙʔωϯ τ͕ؔංେԽͨ͠ w Իූυϥ οά࣌ͱεΫϩʔϧόʔ ɾ υϥ οά࣌Ͱ࠶ඳըॲཧ͕ҧ͏ w useEffect(cb, [])ͷୈೋҾʹࢀরΛྻڍ͢Δ͜ͱͰ ͦͷࢀর͕มԽͨ͠ͱ͖ͷΈuseEffectΛ࣮ߦ͢Δ͜ͱ͕Ͱ͖Δ ʢuseEffect(() => {}, [scrollLeft]) ͳͲʣ
ۤ࿑ͨ͠ ʢ3FBDUฤʣ w 3FBDUͷϚεૢ࡞࣌ͷϋϯ υ Ϧ ϯάҾMouseEventܕͰͳ͍ w 3FBDUख़࿅ऀʹͨΓલͷ͔ w
SyntheticEventͱ͍͏ܗࣜͰΔͷͰnativeEventऔಘͷͨΊʹ ev.persist(); const nativeEv = ev.nativeEvent; ͷΑ ͏ʹҰ୴persist͢Δඞཁ͕͋Δ w ͜͏ ͠ͳ͍ͱoffsetX offsetY͕औΕͳ͍ͷͰҙ
ۤ࿑ͨ͠ ʢ$BOWBTฤʣ w ͻͨ͢Β࠲ඪܭࢉͱͷઓ͍ͱͳΔ w fillRect()ͳͲͯ͢ͷඳըॲཧޙউͪͳͷͰίʔϧॱͰ݁Ռ͕มΘΔ w ։ൃதԻූ͕εΫϩʔϧόʔΛಥ͖ൈ͚Δͱ͔βϥ w ϨΠϠʔͳΜͯ֓೦ແ͍
ʢؤு࣮ͬͯ͢Δ͔$BOWBTϥούʔϥΠ ϒϥ ϦʹཔΔʣ w ͻͨ͢ΒԚ͍ίʔ υͱ ϒϥβ্ͷखಈσόοάΛ܁Γฦͯ͠ ͧ͜͜ͱ͍͏ ͱ͜ΖͰϦ ϑΝΫλ Ϧ ϯά
ۤ࿑ͨ͠ ʢ$BOWBTฤʣ w 3FBDUͷίϯϙʔωϯ τ͔ؔΒ$BOWBTʹؔ͢Δॲཧ͍ͯ͢ग़ͨ͠ w CanvasMediatorͱ͍͏தؒҕৡ༻ͷγϯάϧ τϯΛ࡞ͬͯ ඳըܥͱ࠲ඪऔಘܥͯͦͬͪ͢ʹ࣮͢ΔΑ ͏
Ϧ ϑΝΫλ Ϧ ϯά w Իූ͚ͩͳΒ؆୯ͩͬͨ w εΫϩʔϧόʔͷ࣮Λ࢝ΊͨลΓ͔Βࠞಱͱ ࢝͠Ίͯ ϒϥβͷΠϯ υ࣮ͷ༷ͱ͔ړΓ࢝Ίͨ w 04ͷΠϯ υγεςϜΛ࣮ͨ͠ਓϚδͰҒେͩͱࢥ͏
ࠓޙ͍͖͍ͬͯͨػೳ w Ϋ Ϧ οΫͯ͠ஔ͍ͨԻූͷҠಈ ɾ আ w Ͳͷۣܗ͕Ϋ Ϧ
οΫ͞Ε͔͕ͨऔΕͦ͏ʹͳ͍ͷͰ εΫϩʔϧόʔͱಉ͡Ͱɺ ͯ͢ྖҬܭࢉͰදݱ͢Δ͔͠ͳ͍͔ wυϥοάͨ͠··$BOWBT֎ʹϚεΛಈ͔ͨ͠ΒࣗಈͰεΫϩʔϧ w ࠲ඪऔΕΔͬΆ͍ɺ ࠶ඳըܭࢉ͕ͨΒ໘ͬΆ͍ w ࣮ࡍʹ࠶ੜϘλϯΛ͚ͯԻΛ໐Β͢ w ເͷ·ͨເ
͜͜·Ͱۤ࿑ͯ͠ࢥͬͨ͜ͱ w "OHVMBSͰେنΞϓϦΛ࡞Εͯ$BOWBTશવ࡞Εͳ͍ w 3FBDU͡Όͳ͘ ͍͍ͯ w $VTUPN&MFNFOUTͱ૬ੑΑͦ͞͏
5IBOLZPV %0.ʹײँ͠ͳ͕Β$BOWBTͰ(6*ͷԞਂ͞ʹ৮ΕΑ ͏ ʂ