@@ -15,26 +15,32 @@ $(function () {
1515 detectionRate : 0.5 ,
1616 panSpeed : 3 ,
1717 tiltSpeed : 3 ,
18- deadzoneX : 12 ,
19- deadzoneY : 12
18+ deadzoneX : 15 ,
19+ deadzoneY : 15 ,
20+ outerDeadzoneX : 35 ,
21+ outerDeadzoneY : 35
2022 } ,
2123 precise : {
2224 name : 'Precise Centering' ,
2325 description : 'Tight centering for presentations' ,
2426 detectionRate : 1.5 ,
2527 panSpeed : 6 ,
2628 tiltSpeed : 6 ,
27- deadzoneX : 2 ,
28- deadzoneY : 2
29+ deadzoneX : 4 ,
30+ deadzoneY : 4 ,
31+ outerDeadzoneX : 12 ,
32+ outerDeadzoneY : 12
2933 } ,
3034 balanced : {
3135 name : 'Balanced' ,
3236 description : 'Good balance for general use' ,
3337 detectionRate : 1.0 ,
3438 panSpeed : 5 ,
3539 tiltSpeed : 5 ,
36- deadzoneX : 5 ,
37- deadzoneY : 5
40+ deadzoneX : 10 ,
41+ deadzoneY : 10 ,
42+ outerDeadzoneX : 25 ,
43+ outerDeadzoneY : 25
3844 } ,
3945 fast : {
4046 name : 'Fast Response' ,
@@ -43,19 +49,22 @@ $(function () {
4349 panSpeed : 8 ,
4450 tiltSpeed : 8 ,
4551 deadzoneX : 8 ,
46- deadzoneY : 8
52+ deadzoneY : 8 ,
53+ outerDeadzoneX : 20 ,
54+ outerDeadzoneY : 20
4755 } ,
4856 minimal : {
4957 name : 'Minimal Movement' ,
5058 description : 'Reduce API usage and camera movement' ,
5159 detectionRate : 0.3 ,
5260 panSpeed : 4 ,
5361 tiltSpeed : 4 ,
54- deadzoneX : 15 ,
55- deadzoneY : 15
62+ deadzoneX : 20 ,
63+ deadzoneY : 20 ,
64+ outerDeadzoneX : 40 ,
65+ outerDeadzoneY : 40
5666 }
5767 } ;
58-
5968 let settings = {
6069 moondreamApiKey : localStorage . getItem ( 'moondreamApiKey' ) || '' ,
6170 cameraIP : localStorage . getItem ( 'cameraIP' ) || '192.168.1.19' ,
@@ -69,8 +78,10 @@ $(function () {
6978 tiltSpeed : parseInt ( localStorage . getItem ( 'tiltSpeed' ) ) || 5 ,
7079 centerOffsetX : parseFloat ( localStorage . getItem ( 'centerOffsetX' ) ) || 50 ,
7180 centerOffsetY : parseFloat ( localStorage . getItem ( 'centerOffsetY' ) ) || 50 ,
72- deadzoneX : parseFloat ( localStorage . getItem ( 'deadzoneX' ) ) || 5 ,
73- deadzoneY : parseFloat ( localStorage . getItem ( 'deadzoneY' ) ) || 5 ,
81+ deadzoneX : parseFloat ( localStorage . getItem ( 'deadzoneX' ) ) || 10 ,
82+ deadzoneY : parseFloat ( localStorage . getItem ( 'deadzoneY' ) ) || 10 ,
83+ outerDeadzoneX : parseFloat ( localStorage . getItem ( 'outerDeadzoneX' ) ) || 25 ,
84+ outerDeadzoneY : parseFloat ( localStorage . getItem ( 'outerDeadzoneY' ) ) || 25 ,
7485 autoZoomEnabled : localStorage . getItem ( 'autoZoomEnabled' ) === 'true' ,
7586 minHeadroom : parseFloat ( localStorage . getItem ( 'minHeadroom' ) ) || 10 ,
7687 maxHeadroom : parseFloat ( localStorage . getItem ( 'maxHeadroom' ) ) || 30 ,
@@ -164,6 +175,10 @@ $(function () {
164175 $ ( '#deadzoneXValue' ) . text ( settings . deadzoneX ) ;
165176 $ ( '#deadzoneY' ) . val ( settings . deadzoneY ) ;
166177 $ ( '#deadzoneYValue' ) . text ( settings . deadzoneY ) ;
178+ $ ( '#outerDeadzoneX' ) . val ( settings . outerDeadzoneX ) ;
179+ $ ( '#outerDeadzoneXValue' ) . text ( settings . outerDeadzoneX ) ;
180+ $ ( '#outerDeadzoneY' ) . val ( settings . outerDeadzoneY ) ;
181+ $ ( '#outerDeadzoneYValue' ) . text ( settings . outerDeadzoneY ) ;
167182
168183 $ ( '#autoZoomEnabled' ) . prop ( 'checked' , settings . autoZoomEnabled ) ;
169184 $ ( '#minHeadroom' ) . val ( settings . minHeadroom ) ;
@@ -192,6 +207,10 @@ $(function () {
192207 horizontal : settings . deadzoneX ,
193208 vertical : settings . deadzoneY
194209 } ) ;
210+ ptzController . setOuterDeadzone ( {
211+ horizontal : settings . outerDeadzoneX ,
212+ vertical : settings . outerDeadzoneY
213+ } ) ;
195214
196215 setupEventListeners ( ) ;
197216
@@ -331,6 +350,26 @@ $(function () {
331350 switchToCustomMode ( ) ;
332351 renderDeadzone ( ) ;
333352 } ) ;
353+
354+ $ ( '#outerDeadzoneX' ) . on ( 'input' , function ( ) {
355+ const val = parseFloat ( $ ( this ) . val ( ) ) ;
356+ settings . outerDeadzoneX = val ;
357+ $ ( '#outerDeadzoneXValue' ) . text ( val ) ;
358+ localStorage . setItem ( 'outerDeadzoneX' , val . toString ( ) ) ;
359+ ptzController . setOuterDeadzone ( { horizontal : val } ) ;
360+ switchToCustomMode ( ) ;
361+ renderDeadzone ( ) ;
362+ } ) ;
363+
364+ $ ( '#outerDeadzoneY' ) . on ( 'input' , function ( ) {
365+ const val = parseFloat ( $ ( this ) . val ( ) ) ;
366+ settings . outerDeadzoneY = val ;
367+ $ ( '#outerDeadzoneYValue' ) . text ( val ) ;
368+ localStorage . setItem ( 'outerDeadzoneY' , val . toString ( ) ) ;
369+ ptzController . setOuterDeadzone ( { vertical : val } ) ;
370+ switchToCustomMode ( ) ;
371+ renderDeadzone ( ) ;
372+ } ) ;
334373
335374 $ ( '#autoZoomEnabled' ) . on ( 'change' , function ( ) {
336375 settings . autoZoomEnabled = $ ( this ) . is ( ':checked' ) ;
@@ -436,6 +475,18 @@ $(function () {
436475 $ ( '#deadzoneYValue' ) . text ( preset . deadzoneY ) ;
437476 localStorage . setItem ( 'deadzoneY' , preset . deadzoneY . toString ( ) ) ;
438477 ptzController . setDeadzone ( { vertical : preset . deadzoneY } ) ;
478+
479+ settings . outerDeadzoneX = preset . outerDeadzoneX ;
480+ $ ( '#outerDeadzoneX' ) . val ( preset . outerDeadzoneX ) ;
481+ $ ( '#outerDeadzoneXValue' ) . text ( preset . outerDeadzoneX ) ;
482+ localStorage . setItem ( 'outerDeadzoneX' , preset . outerDeadzoneX . toString ( ) ) ;
483+ ptzController . setOuterDeadzone ( { horizontal : preset . outerDeadzoneX } ) ;
484+
485+ settings . outerDeadzoneY = preset . outerDeadzoneY ;
486+ $ ( '#outerDeadzoneY' ) . val ( preset . outerDeadzoneY ) ;
487+ $ ( '#outerDeadzoneYValue' ) . text ( preset . outerDeadzoneY ) ;
488+ localStorage . setItem ( 'outerDeadzoneY' , preset . outerDeadzoneY . toString ( ) ) ;
489+ ptzController . setOuterDeadzone ( { vertical : preset . outerDeadzoneY } ) ;
439490
440491 if ( isTracking ) {
441492 clearInterval ( detectionInterval ) ;
@@ -641,28 +692,58 @@ $(function () {
641692
642693 const centerX = ( settings . centerOffsetX / 100 ) * video . videoWidth ;
643694 const centerY = ( settings . centerOffsetY / 100 ) * video . videoHeight ;
644- const halfDeadzoneW = ( settings . deadzoneX / 100 ) * video . videoWidth / 2 ;
645- const halfDeadzoneH = ( settings . deadzoneY / 100 ) * video . videoHeight / 2 ;
646-
647- ctx . strokeStyle = 'rgba(42, 157, 143, 0.6)' ;
695+
696+ // Outer deadzone (larger zone — 50% speed reduction beyond this)
697+ const halfOuterW = ( settings . outerDeadzoneX / 100 ) * video . videoWidth / 2 ;
698+ const halfOuterH = ( settings . outerDeadzoneY / 100 ) * video . videoHeight / 2 ;
699+
700+ // Draw outer deadzone — amber/yellow dashed
701+ ctx . strokeStyle = 'rgba(230, 176, 50, 0.5)' ;
702+ ctx . lineWidth = 1 ;
703+ ctx . setLineDash ( [ 12 , 6 ] ) ;
704+ ctx . strokeRect (
705+ centerX - halfOuterW ,
706+ centerY - halfOuterH ,
707+ halfOuterW * 2 ,
708+ halfOuterH * 2
709+ ) ;
710+ ctx . setLineDash ( [ ] ) ;
711+
712+ // Fill outer zone (between inner and outer) — faint amber
713+ ctx . fillStyle = 'rgba(230, 176, 50, 0.05)' ;
714+ ctx . fillRect (
715+ centerX - halfOuterW ,
716+ centerY - halfOuterH ,
717+ halfOuterW * 2 ,
718+ halfOuterH * 2
719+ ) ;
720+
721+ // Inner deadzone (smaller zone — camera STOPS here)
722+ const halfInnerW = ( settings . deadzoneX / 100 ) * video . videoWidth / 2 ;
723+ const halfInnerH = ( settings . deadzoneY / 100 ) * video . videoHeight / 2 ;
724+
725+ // Draw inner deadzone — green solid
726+ ctx . strokeStyle = 'rgba(42, 157, 143, 0.7)' ;
648727 ctx . lineWidth = 2 ;
649728 ctx . setLineDash ( [ 8 , 4 ] ) ;
650729 ctx . strokeRect (
651- centerX - halfDeadzoneW ,
652- centerY - halfDeadzoneH ,
653- halfDeadzoneW * 2 ,
654- halfDeadzoneH * 2
730+ centerX - halfInnerW ,
731+ centerY - halfInnerH ,
732+ halfInnerW * 2 ,
733+ halfInnerH * 2
655734 ) ;
656735 ctx . setLineDash ( [ ] ) ;
657-
736+
737+ // Fill inner deadzone — faint green
658738 ctx . fillStyle = 'rgba(42, 157, 143, 0.1)' ;
659739 ctx . fillRect (
660- centerX - halfDeadzoneW ,
661- centerY - halfDeadzoneH ,
662- halfDeadzoneW * 2 ,
663- halfDeadzoneH * 2
740+ centerX - halfInnerW ,
741+ centerY - halfInnerH ,
742+ halfInnerW * 2 ,
743+ halfInnerH * 2
664744 ) ;
665-
745+
746+ // Center crosshair
666747 ctx . strokeStyle = 'rgba(147, 204, 234, 0.5)' ;
667748 ctx . lineWidth = 1 ;
668749 ctx . beginPath ( ) ;
@@ -672,11 +753,15 @@ $(function () {
672753 ctx . lineTo ( centerX , centerY + 20 ) ;
673754 ctx . stroke ( ) ;
674755
675- ctx . fillStyle = 'rgba(147, 204, 234, 0.7)' ;
676- ctx . font = '12px sans-serif' ;
756+ // Labels
757+ ctx . fillStyle = 'rgba(42, 157, 143, 0.8)' ;
758+ ctx . font = '11px sans-serif' ;
677759 ctx . textAlign = 'left' ;
678760 ctx . textBaseline = 'top' ;
679- ctx . fillText ( 'Deadzone' , centerX - halfDeadzoneW + 4 , centerY - halfDeadzoneH + 4 ) ;
761+ ctx . fillText ( 'Inner (stop)' , centerX - halfInnerW + 4 , centerY - halfInnerH + 4 ) ;
762+
763+ ctx . fillStyle = 'rgba(230, 176, 50, 0.8)' ;
764+ ctx . fillText ( 'Outer (slow)' , centerX - halfOuterW + 4 , centerY - halfOuterH + 4 ) ;
680765 }
681766
682767 function renderDetection ( detection ) {
0 commit comments