* Center tile dragging (client-side rearrangement) *
*****************************************************/
+ _drop_on_rack(clientX, clientY, tile) {
+ if (!this.state.claim_active) return false;
+ const rack = document.querySelector(".claim-rack");
+ if (!rack) return false;
+ const r = rack.getBoundingClientRect();
+ if (clientX >= r.left && clientX <= r.right
+ && clientY >= r.top && clientY <= r.bottom) {
+ this.take_letter(tile);
+ return true;
+ }
+ return false;
+ }
+
on_center_mouse_down(e, tile) {
- /* Only allow rearranging when not in claim mode. */
- if (this.state.claim_active) return;
if (e.button !== 0) return;
const pool = e.target.closest(".center-pool");
if (!pool) return;
const rect = pool.getBoundingClientRect();
+ const startX = e.clientX;
+ const startY = e.clientY;
this._drag_offset = {
x: e.clientX - (this.state.tile_positions[tile.id].x / 100 * rect.width),
y: e.clientY - (this.state.tile_positions[tile.id].y / 100 * rect.height)
};
this._drag_pool_rect = rect;
- this.setState({ dragging_center_tile: tile.id });
+ let dragging = false;
const onMove = (me) => {
+ const dx = me.clientX - startX;
+ const dy = me.clientY - startY;
+ if (!dragging) {
+ if (dx * dx + dy * dy < 25) return;
+ dragging = true;
+ this.setState({ dragging_center_tile: tile.id });
+ }
const x = ((me.clientX - this._drag_offset.x) / rect.width) * 100;
const y = ((me.clientY - this._drag_offset.y) / rect.height) * 100;
this.setState(prev => ({
}));
};
- const onUp = () => {
+ const onUp = (me) => {
document.removeEventListener("mousemove", onMove);
document.removeEventListener("mouseup", onUp);
- this.setState({ dragging_center_tile: null });
+ if (dragging) {
+ this.setState({ dragging_center_tile: null });
+ this._drop_on_rack(me.clientX, me.clientY, tile);
+ } else if (this.state.claim_active && !this.state.revealing[tile.id]) {
+ this.take_letter(tile);
+ }
};
document.addEventListener("mousemove", onMove);
}
on_center_touch_start(e, tile) {
- if (this.state.claim_active) return;
if (e.touches.length !== 1) return;
const pool = e.target.closest(".center-pool");
const touch = e.touches[0];
const rect = pool.getBoundingClientRect();
+ this._drag_start = { x: touch.clientX, y: touch.clientY };
this._drag_offset = {
x: touch.clientX - (this.state.tile_positions[tile.id].x / 100 * rect.width),
y: touch.clientY - (this.state.tile_positions[tile.id].y / 100 * rect.height)
};
this._drag_pool_rect = rect;
- this._touch_moved = false;
- this.setState({ dragging_center_tile: tile.id });
+ this._drag_dragging = false;
+ this._drag_tile = tile;
e.preventDefault();
}
on_center_touch_move(e) {
- if (this.state.dragging_center_tile === null) return;
+ if (!this._drag_tile) return;
const touch = e.touches[0];
+ this._drag_last_touch = { x: touch.clientX, y: touch.clientY };
const rect = this._drag_pool_rect;
- this._touch_moved = true;
+
+ if (!this._drag_dragging) {
+ const dx = touch.clientX - this._drag_start.x;
+ const dy = touch.clientY - this._drag_start.y;
+ if (dx * dx + dy * dy < 25) return;
+ this._drag_dragging = true;
+ this.setState({ dragging_center_tile: this._drag_tile.id });
+ }
const x = ((touch.clientX - this._drag_offset.x) / rect.width) * 100;
const y = ((touch.clientY - this._drag_offset.y) / rect.height) * 100;
this.setState(prev => ({
tile_positions: {
...prev.tile_positions,
- [this.state.dragging_center_tile]: {
+ [this._drag_tile.id]: {
x: Math.max(0, Math.min(90, x)),
y: Math.max(0, Math.min(85, y))
}
}
on_center_touch_end(e) {
- if (this.state.dragging_center_tile === null) return;
- this.setState({ dragging_center_tile: null });
+ const tile = this._drag_tile;
+ if (!tile) return;
+
+ if (this._drag_dragging) {
+ this.setState({ dragging_center_tile: null });
+ /* Use last known touch position for drop detection. */
+ if (this._drag_last_touch) {
+ this._drop_on_rack(this._drag_last_touch.x, this._drag_last_touch.y, tile);
+ }
+ } else if (this.state.claim_active && !this.state.revealing[tile.id]) {
+ this.take_letter(tile);
+ }
+
+ this._drag_tile = null;
+ this._drag_dragging = false;
}
/*****************************************************
left: pos.x + "%",
top: pos.y + "%",
zIndex: is_dragging ? 10 : 1,
- cursor: claim_active && !is_revealing ? "pointer" :
- !claim_active && !is_revealing ? "grab" : "default"
+ cursor: claim_active ? "pointer" : "grab"
};
let className = "";
<div key={tile.id}
className={"tile" + (className ? " " + className : "")}
style={style}
- onMouseDown={!claim_active && !is_revealing
- ? (e) => this.on_center_mouse_down(e, tile) : null}
- onTouchStart={!claim_active && !is_revealing
- ? (e) => this.on_center_touch_start(e, tile) : null}
- onClick={claim_active && !is_revealing
- ? () => this.take_letter(tile) : null}>
+ onMouseDown={(e) => this.on_center_mouse_down(e, tile)}
+ onTouchStart={(e) => this.on_center_touch_start(e, tile)}>
{is_revealing
? <span style={{opacity: rev.opacity}}>{rev.seconds}</span>
: tile.letter}