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.7k
Hasura.io RDBをサクサク作る方法はARやO/RMだけじゃなくなりました/hasura-io
okunokentaro
5
680
コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2
okunokentaro
14
6.4k
10年と3ヶ月でWebサービスを作った話 / Piyogrammer Conference 2021
okunokentaro
2
1.1k
Other Decks in Technology
See All in Technology
Autonomous Database - Dedicated 技術詳細 / adb-d_technical_detail_jp
oracle4engineer
PRO
4
10k
大「個人開発サービス」時代に僕たちはどう生きるか
sotarok
20
9.9k
250905 大吉祥寺.pm 2025 前夜祭 「プログラミングに出会って20年、『今』が1番楽しい」
msykd
PRO
1
820
COVESA VSSによる車両データモデルの標準化とAWS IoT FleetWiseの活用
osawa
1
270
5分でカオスエンジニアリングを分かった気になろう
pandayumi
0
240
Snowflake Intelligenceにはこうやって立ち向かう!クラシルが考えるAI Readyなデータ基盤と活用のためのDataOps
gappy50
0
180
ZOZOマッチのアーキテクチャと技術構成
zozotech
PRO
3
1.5k
CDK CLIで使ってたあの機能、CDK Toolkit Libraryではどうやるの?
smt7174
4
160
EncryptedSharedPreferences が deprecated になっちゃった!どうしよう! / Oh no! EncryptedSharedPreferences has been deprecated! What should I do?
yanzm
0
270
allow_retry と Arel.sql / allow_retry and Arel.sql
euglena1215
1
160
AWSで始める実践Dagster入門
kitagawaz
1
610
新アイテムをどう使っていくか?みんなであーだこーだ言ってみよう / 20250911-rpi-jam-tokyo
akkiesoft
0
240
Featured
See All Featured
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Intergalactic Javascript Robots from Outer Space
tanoku
272
27k
What's in a price? How to price your products and services
michaelherold
246
12k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3k
A Modern Web Designer's Workflow
chriscoyier
696
190k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
Embracing the Ebb and Flow
colly
87
4.8k
Music & Morning Musume
bryan
46
6.8k
4 Signs Your Business is Dying
shpigford
184
22k
Code Review Best Practice
trishagee
70
19k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
6k
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*ͷԞਂ͞ʹ৮ΕΑ ͏ ʂ