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.1k
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.3k
それでもどうしてRecoilを使うのか / Harajuku.ts Meetup Recoil
okunokentaro
19
5.5k
TypeScriptは10年でこんなに進化しました / TechFeed Experts Night 11
okunokentaro
6
1.7k
Hasura.io RDBをサクサク作る方法はARやO/RMだけじゃなくなりました/hasura-io
okunokentaro
5
670
コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2
okunokentaro
14
6.4k
10年と3ヶ月でWebサービスを作った話 / Piyogrammer Conference 2021
okunokentaro
2
1.1k
Other Decks in Technology
See All in Technology
新規プロダクト開発、AIでどう変わった? #デザインエンジニアMeetup
bengo4com
0
490
DroidKnights 2025 - Jetpack XR 살펴보기: XR 개발은 어떻게 이루어지는가?
heesung6701
1
160
_第3回__AIxIoTビジネス共創ラボ紹介資料_20250617.pdf
iotcomjpadmin
0
140
Definition of Done
kawaguti
PRO
6
440
從四件事帶你見識見識 事件驅動架構設計 (EDA)
line_developers_tw
PRO
0
920
生成AIでwebアプリケーションを作ってみた
tajimon
2
110
Oracle Audit Vault and Database Firewall 20 概要
oracle4engineer
PRO
2
1.6k
Claude Code Actionを使ったコード品質改善の取り組み
potix2
PRO
1
170
監視のこれまでとこれから/sakura monitoring seminar 2025
fujiwara3
10
2.6k
LinkX_GitHubを基点にした_AI時代のプロジェクトマネジメント.pdf
iotcomjpadmin
0
150
SFTPコンテナからファイルをダウンロードする
dip
0
550
Amazon Q Developer for GitHubとAmplify Hosting でサクッとデジタル名刺を作ってみた
kmiya84377
0
3.5k
Featured
See All Featured
Unsuck your backbone
ammeep
671
58k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
35
2.3k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.8k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Git: the NoSQL Database
bkeepers
PRO
430
65k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
A Modern Web Designer's Workflow
chriscoyier
693
190k
Producing Creativity
orderedlist
PRO
346
40k
Build The Right Thing And Hit Your Dates
maggiecrowley
36
2.7k
Automating Front-end Workflow
addyosmani
1370
200k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
20
1.3k
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*ͷԞਂ͞ʹ৮ΕΑ ͏ ʂ