add bet slider for texas holdem
authorGeoffrey Allott <geoffrey@allott.email>
Mon, 15 Mar 2021 22:58:43 +0000 (22:58 +0000)
committerGeoffrey Allott <geoffrey@allott.email>
Mon, 15 Mar 2021 22:58:43 +0000 (22:58 +0000)
site/modules/poker.js
site/style/poker.css

index e9f128c2fb8e0da27680e10113e0f128a55ca6dc..60fbb28ec826b65c4753cf605f661b3d1d7a5243 100644 (file)
@@ -24,6 +24,9 @@ export class TexasHoldEm {
         this.svg = document.createElementNS(svgns, "svg");
         this.svg.classList.add("knock-out-whist");
         this.svg.setAttribute("viewBox", "0 0 500 500");
+        this.mouse_clicked = false;
+        this.svg.onmousedown = () => this.mouse_clicked = true;
+        this.svg.onmouseup = () => this.mouse_clicked = false;
 
         const background = document.createElementNS(svgns, "rect");
         background.setAttribute("width", "500");
@@ -49,13 +52,75 @@ export class TexasHoldEm {
 
         const controls = document.createElementNS(svgns, "rect");
         controls.setAttribute("x", "310");
-        controls.setAttribute("y", "435");
+        controls.setAttribute("y", "410");
         controls.setAttribute("width", "185");
-        controls.setAttribute("height", "60");
+        controls.setAttribute("height", "85");
         controls.setAttribute("rx", "15");
         controls.classList.add("controls");
         this.svg.append(controls);
 
+        this.bet_size_area = document.createElementNS(svgns, "rect");
+        this.bet_size_area.setAttribute("x", "317");
+        this.bet_size_area.setAttribute("y", "417");
+        this.bet_size_area.setAttribute("width", "38");
+        this.bet_size_area.setAttribute("height", "16");
+        this.bet_size_area.classList.add("bet-size-area");
+        this.svg.append(this.bet_size_area);
+
+        this.bet_size = document.createElementNS(svgns, "text");
+        this.bet_size.setAttribute("x", "336");
+        this.bet_size.setAttribute("y", "429");
+        this.bet_size.classList.add("bet-size");
+        this.bet_size_text = document.createTextNode("150");
+        this.bet_size.append(this.bet_size_text);
+        this.svg.append(this.bet_size);
+
+        this.bet_slider = document.createElementNS(svgns, "g");
+        this.bet_slider.classList.add("bet-slider");
+
+        this.bet_slider_track = document.createElementNS(svgns, "rect");
+        this.bet_slider_track.setAttribute("x", "360");
+        this.bet_slider_track.setAttribute("y", "422");
+        this.bet_slider_track.setAttribute("width", "125");
+        this.bet_slider_track.setAttribute("height", "6");
+        this.bet_slider_track.classList.add("bet-slider-track");
+        const point = this.svg.createSVGPoint();
+        this.bet_slider_track.onmousemove = e => {
+            if (this.mouse_clicked) {
+                point.x = e.clientX;
+                point.y = e.clientY;
+                const coords = point.matrixTransform(this.svg.getScreenCTM().inverse());
+                const x = Math.max(360, Math.min(475, coords.x - 5));
+                const p = Math.pow((x - 360) / 115, 2);
+                const bet = Math.round(this.min_bet() * (1 - p) + this.all_in_bet() * p);
+                this.bet_size_text.textContent = bet;
+                this.bet_slider_thumb.setAttribute("x", x);
+            }
+        };
+        this.bet_slider_track.onclick = e => {
+            point.x = e.clientX;
+            point.y = e.clientY;
+            const coords = point.matrixTransform(this.svg.getScreenCTM().inverse());
+            const x = Math.max(360, Math.min(475, coords.x - 5));
+            const p = Math.pow((x - 360) / 115, 2);
+            const bet = Math.round(this.min_bet() * (1 - p) + this.all_in_bet() * p);
+            this.bet_size_text.textContent = bet;
+            this.bet_slider_thumb.setAttribute("x", x);
+        };
+        this.bet_slider.append(this.bet_slider_track);
+
+        this.bet_slider_thumb = document.createElementNS(svgns, "rect");
+        this.bet_slider_thumb.setAttribute("x", "360");
+        this.bet_slider_thumb.setAttribute("y", "419");
+        this.bet_slider_thumb.setAttribute("width", "10");
+        this.bet_slider_thumb.setAttribute("height", "12");
+        this.bet_slider_thumb.classList.add("bet-slider-thumb");
+        this.bet_slider_thumb.onmousemove = this.bet_slider_track.onmousemove;
+        this.bet_slider_thumb.onclick = this.bet_slider_track.onclick;
+        this.bet_slider.append(this.bet_slider_thumb);
+
+        this.svg.append(this.bet_slider);
+
         this.fold_control = document.createElementNS(svgns, "rect");
         this.fold_control.setAttribute("x", "315");
         this.fold_control.setAttribute("y", "440");
@@ -99,7 +164,7 @@ export class TexasHoldEm {
         this.bet_control.setAttribute("height", "50");
         this.bet_control.setAttribute("rx", "10");
         this.bet_control.onclick = () => {
-            const chips = prompt("Chips to bet", this.chips_to_call() + this.min_raise());
+            const chips = +this.bet_size_text.textContent;
             if (chips !== null && !isNaN(Number(chips))) {
                 this.send({type: "TakeAction", action: {action: "Bet", chips: Number(chips)}});
             }
@@ -130,6 +195,10 @@ export class TexasHoldEm {
         this.call_control.classList.toggle("active", this.active === this.username);
         this.call_control_text.textContent = this.active === this.username && this.chips_to_call() == 0 ? "Check" : "Call";
         this.bet_control.classList.toggle("active", this.active === this.username);
+        this.bet_size_area.classList.toggle("active", this.active === this.username);
+        this.bet_slider.classList.toggle("active", this.active === this.username);
+        this.bet_size_text.textContent = this.min_bet();
+        this.bet_slider_thumb.setAttribute("x", 360);
         for (const [username, [user, stack, active, bet]] of this.user_icons) {
             if (!this.seats.has(username)) {
                 this.svg.removeChild(user);
@@ -254,6 +323,14 @@ export class TexasHoldEm {
         }
     }
 
+    min_bet() {
+        return this.chips_to_call(); /* + this.min_raise() TODO */
+    }
+
+    all_in_bet() {
+        return this.stacks.get(this.username) || 0;
+    }
+
     min_raise() {
         if (this.community.length === 0) {
             return Math.max(this.big_blind, Math.max(...this.bets.values()) - this.big_blind);
@@ -393,7 +470,7 @@ export class TexasHoldEm {
                 new CongratulateWinner(this.svg, user_action.username);
                 break;
             default:
-                console.error("Unhandled action for knock-out whist", user_action);
+                console.error("Unhandled action for texas hold'em", user_action);
                 break;
         }
     }
index 045f36dd685d4c35b2354b19a254f15df3af3f6d..fb69b7d29de03b878b5604a938aa5b4b0984246a 100644 (file)
     pointer-events: none;
     text-anchor: middle;
 }
+
+.bet-size {
+    pointer-events: none;
+    text-anchor: middle;
+    font-size: 8pt;
+}
+
+.bet-size-area {
+    fill: #808080;
+    stroke: black;
+    stroke-width: 1px;
+    transition: fill 0.5s;
+}
+
+.bet-size-area.active {
+    fill: #ffffff;
+}
+
+.bet-slider-track {
+    fill: black;
+    stroke: #808080;
+    stroke-width: 1px;
+    transition: stroke 0.5s;
+    pointer-events: none;
+    cursor: pointer;
+}
+
+.bet-slider.active > .bet-slider-track {
+    stroke: #8080ff;
+    pointer-events: auto;
+}
+
+.bet-slider.active:hover > .bet-slider-track {
+    stroke: #a0a0ff;
+}
+
+.bet-slider-thumb {
+    fill: #808080;
+    stroke: black;
+    stroke-width: 1px;
+    transition: fill 0.5s;
+    pointer-events: none;
+    cursor: pointer;
+}
+
+.bet-slider.active > .bet-slider-thumb {
+    fill: #8080ff;
+    pointer-events: auto;
+}
+
+.bet-slider.active > .bet-slider-thumb:hover {
+    fill: #a0a0ff;
+}