-
Notifications
You must be signed in to change notification settings - Fork 116
[stale] Improve off-screen waypoint visibility and clarity #416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
# 🎯 Waypoint System Improvements | ||
|
||
## Overview | ||
This document outlines the improvements made to the waypoint system in the Minecraft Web Client, focusing on better visibility when out of sight and enhanced text clarity. | ||
|
||
## ✨ Key Improvements | ||
|
||
### 1. Directional Arrows When Out of Sight | ||
- **Before**: Simple triangle arrows when waypoints were off-screen | ||
- **After**: Full waypoint sprites with directional arrow overlays pointing toward the waypoint | ||
- **Benefit**: Players can see the complete waypoint information even when out of sight, with clear directional guidance | ||
|
||
### 2. Enhanced Text Clarity | ||
- **Font Sizes**: | ||
- Title font increased from 8% to 12% of canvas height | ||
- Distance font increased from 6% to 9% of canvas height | ||
- **Resolution**: Canvas size increased from 256x256 to 512x512 pixels | ||
- **Scaling**: Canvas scale factor increased from 2x to 3x for device pixel ratio | ||
- **Text Outlines**: Enhanced stroke width for better visibility and contrast | ||
|
||
### 3. Improved Resolution | ||
- **Canvas Size**: Doubled from 256x256 to 512x512 pixels | ||
- **Scale Factor**: Increased from 2x to 3x for sharper text rendering | ||
- **Result**: Much crisper, more readable text on all devices | ||
|
||
## 🔧 Technical Changes | ||
|
||
### Files Modified | ||
1. **`renderer/viewer/three/waypointSprite.ts`** | ||
- Updated `WAYPOINT_CONFIG` with higher resolution and scale | ||
- Enhanced `ensureArrow()` function to show full waypoint sprite with directional overlay | ||
- Improved `drawCombinedCanvas()` function with larger fonts and better outlines | ||
- Modified arrow rotation logic to point in the correct direction | ||
|
||
2. **`renderer/viewer/three/waypoints.ts`** | ||
- Enabled offscreen arrows by default for all waypoints | ||
|
||
3. **`renderer/viewer/three/graphicsBackend.ts`** | ||
- Added global testing functions for easier waypoint testing | ||
|
||
### Configuration Changes | ||
```typescript | ||
export const WAYPOINT_CONFIG = { | ||
TARGET_SCREEN_PX: 150, // Unchanged | ||
CANVAS_SIZE: 512, // Increased from 256 | ||
CANVAS_SCALE: 3, // Increased from 2 | ||
LAYOUT: { /* unchanged */ }, | ||
ARROW: { | ||
enabledDefault: true, // Changed from false | ||
pixelSize: 30, // Unchanged | ||
paddingPx: 50, // Unchanged | ||
}, | ||
} | ||
``` | ||
|
||
### Font Size Improvements | ||
```typescript | ||
// Before | ||
const nameFontPx = Math.round(size * 0.08) // 8% of canvas height | ||
const distanceFontPx = Math.round(size * 0.06) // 6% of canvas height | ||
|
||
// After | ||
const nameFontPx = Math.round(size * 0.12) // 12% of canvas height | ||
const distanceFontPx = Math.round(size * 0.09) // 9% of canvas height | ||
``` | ||
|
||
## 🧪 Testing | ||
|
||
### Console Commands | ||
The following functions are now available in the browser console for testing: | ||
|
||
```javascript | ||
// Add test waypoints (green, yellow, blue) | ||
testWaypoints() | ||
|
||
// Add custom waypoint | ||
addTestWaypoint('Home', 0, 70, 0, 0xFF0000, 'My Home') | ||
|
||
// Remove specific waypoint | ||
removeWaypoint('Test Point') | ||
|
||
// List all active waypoints | ||
listWaypoints() | ||
``` | ||
|
||
### Test Instructions | ||
1. Open the Minecraft Web Client | ||
2. Wait for the world to load completely | ||
3. Open browser console (F12 → Console) | ||
4. Use the console commands above to test waypoints | ||
5. Move around so waypoints go out of sight | ||
6. Observe the improved directional arrows and text clarity | ||
|
||
## 🎨 Visual Improvements | ||
|
||
### Before vs After | ||
- **Visibility**: Waypoints now maintain full appearance when off-screen | ||
- **Direction**: Clear arrows indicate which way to go | ||
- **Text**: Much more readable with larger fonts | ||
- **Quality**: Higher resolution ensures crisp rendering | ||
- **Contrast**: Better text outlines for improved visibility | ||
|
||
### Arrow Design | ||
- Shows the complete waypoint sprite (dot, name, distance) | ||
- Overlays a white directional arrow with black outline | ||
- Arrow size is 15% of canvas for good visibility | ||
- Automatically rotates to point toward the waypoint | ||
|
||
## 📱 Device Compatibility | ||
- Higher resolution ensures crisp rendering on high-DPI displays | ||
- Improved scaling handles various device pixel ratios | ||
- Larger fonts remain readable on smaller screens | ||
- Enhanced outlines provide better contrast in all lighting conditions | ||
|
||
## 🚀 Performance Impact | ||
- Minimal performance impact from increased canvas size | ||
- Efficient texture management with proper disposal | ||
- Optimized rendering with consistent scaling | ||
- No additional memory overhead for arrow overlays | ||
|
||
## 🔮 Future Enhancements | ||
Potential areas for further improvement: | ||
- Configurable arrow styles and colors | ||
- Animated directional indicators | ||
- Distance-based arrow sizing | ||
- Custom waypoint icons | ||
- Waypoint grouping and organization | ||
|
||
## 📋 Summary | ||
The waypoint system now provides: | ||
1. **Better Navigation**: Clear directional guidance when out of sight | ||
2. **Improved Readability**: Larger, sharper text with better contrast | ||
3. **Enhanced Quality**: Higher resolution rendering for all devices | ||
4. **Consistent Experience**: Same visual style whether visible or off-screen | ||
5. **Easy Testing**: Built-in console commands for development and testing | ||
|
||
These improvements make waypoints much more useful for navigation and provide a better user experience across all devices and viewing conditions. |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -5,17 +5,17 @@ export const WAYPOINT_CONFIG = { | |||||||||||||||||||||||||||||||||||||||||||
// Target size in screen pixels (this controls the final sprite size) | ||||||||||||||||||||||||||||||||||||||||||||
TARGET_SCREEN_PX: 150, | ||||||||||||||||||||||||||||||||||||||||||||
// Canvas size for internal rendering (keep power of 2 for textures) | ||||||||||||||||||||||||||||||||||||||||||||
CANVAS_SIZE: 256, | ||||||||||||||||||||||||||||||||||||||||||||
CANVAS_SIZE: 512, // Increased from 256 for better resolution | ||||||||||||||||||||||||||||||||||||||||||||
// Relative positions in canvas (0-1) | ||||||||||||||||||||||||||||||||||||||||||||
LAYOUT: { | ||||||||||||||||||||||||||||||||||||||||||||
DOT_Y: 0.3, | ||||||||||||||||||||||||||||||||||||||||||||
NAME_Y: 0.45, | ||||||||||||||||||||||||||||||||||||||||||||
DISTANCE_Y: 0.55, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
// Multiplier for canvas internal resolution to keep text crisp | ||||||||||||||||||||||||||||||||||||||||||||
CANVAS_SCALE: 2, | ||||||||||||||||||||||||||||||||||||||||||||
CANVAS_SCALE: 3, // Increased from 2 for sharper text | ||||||||||||||||||||||||||||||||||||||||||||
ARROW: { | ||||||||||||||||||||||||||||||||||||||||||||
enabledDefault: false, | ||||||||||||||||||||||||||||||||||||||||||||
enabledDefault: true, // Changed from false to true | ||||||||||||||||||||||||||||||||||||||||||||
pixelSize: 30, | ||||||||||||||||||||||||||||||||||||||||||||
paddingPx: 50, | ||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -125,22 +125,45 @@ export function createWaypointSprite (options: { | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
function ensureArrow () { | ||||||||||||||||||||||||||||||||||||||||||||
if (arrowSprite) return | ||||||||||||||||||||||||||||||||||||||||||||
const size = 128 | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Create a canvas with the same waypoint sprite but with directional arrow overlay | ||||||||||||||||||||||||||||||||||||||||||||
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1) | ||||||||||||||||||||||||||||||||||||||||||||
const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale | ||||||||||||||||||||||||||||||||||||||||||||
const canvas = document.createElement('canvas') | ||||||||||||||||||||||||||||||||||||||||||||
canvas.width = size | ||||||||||||||||||||||||||||||||||||||||||||
canvas.height = size | ||||||||||||||||||||||||||||||||||||||||||||
const ctx = canvas.getContext('2d')! | ||||||||||||||||||||||||||||||||||||||||||||
ctx.clearRect(0, 0, size, size) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Draw the same waypoint sprite as the main one | ||||||||||||||||||||||||||||||||||||||||||||
drawCombinedCanvas(color, currentLabel, '0m', ctx, size) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Add directional arrow overlay in the center | ||||||||||||||||||||||||||||||||||||||||||||
const arrowSize = Math.round(size * 0.15) // Arrow takes up ~15% of canvas | ||||||||||||||||||||||||||||||||||||||||||||
const centerX = size / 2 | ||||||||||||||||||||||||||||||||||||||||||||
const centerY = size / 2 | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Draw arrow pointing right (will be rotated based on direction) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.save() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.translate(centerX, centerY) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Arrow shape (pointing right) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.beginPath() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.moveTo(size * 0.2, size * 0.5) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(size * 0.8, size * 0.5) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(size * 0.5, size * 0.2) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.moveTo(-arrowSize * 0.3, 0) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(arrowSize * 0.3, 0) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(arrowSize * 0.1, -arrowSize * 0.2) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(arrowSize * 0.3, 0) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineTo(arrowSize * 0.1, arrowSize * 0.2) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.closePath() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineWidth = 4 | ||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.stroke() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Fill with white and black outline | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillStyle = 'white' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fill() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineWidth = Math.max(3, Math.round(4 * scale)) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.stroke() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
ctx.restore() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const texture = new THREE.CanvasTexture(canvas) | ||||||||||||||||||||||||||||||||||||||||||||
const material = new THREE.SpriteMaterial({ map: texture, transparent: true, depthTest: false, depthWrite: false }) | ||||||||||||||||||||||||||||||||||||||||||||
arrowSprite = new THREE.Sprite(material) | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -240,13 +263,18 @@ export function createWaypointSprite (options: { | |||||||||||||||||||||||||||||||||||||||||||
arrowSprite.visible = true | ||||||||||||||||||||||||||||||||||||||||||||
arrowSprite.position.copy(pos) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Angle for rotation relative to screen right/up (derived from camera up vector) | ||||||||||||||||||||||||||||||||||||||||||||
const angle = Math.atan2(ry, rx) | ||||||||||||||||||||||||||||||||||||||||||||
arrowSprite.material.rotation = angle - Math.PI / 2 | ||||||||||||||||||||||||||||||||||||||||||||
// Calculate the direction vector from camera to waypoint | ||||||||||||||||||||||||||||||||||||||||||||
const direction = new THREE.Vector3(group.position.x, group.position.y, group.position.z).sub(camPos).normalize() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Calculate the angle in the XZ plane (horizontal direction) | ||||||||||||||||||||||||||||||||||||||||||||
const horizontalAngle = Math.atan2(direction.x, direction.z) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Rotate the arrow to point in the direction of the waypoint | ||||||||||||||||||||||||||||||||||||||||||||
arrowSprite.material.rotation = horizontalAngle | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||
// Constant pixel size for arrow (use fixed placement distance) | ||||||||||||||||||||||||||||||||||||||||||||
// Use the same scale as the main waypoint sprite for consistency | ||||||||||||||||||||||||||||||||||||||||||||
const worldUnitsPerScreenHeightAtDist = Math.tan(vFovRad / 2) * 2 * placeDist | ||||||||||||||||||||||||||||||||||||||||||||
const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.ARROW.pixelSize / viewportHeightPx) | ||||||||||||||||||||||||||||||||||||||||||||
const sPx = worldUnitsPerScreenHeightAtDist * (WAYPOINT_CONFIG.TARGET_SCREEN_PX / viewportHeightPx) | ||||||||||||||||||||||||||||||||||||||||||||
arrowSprite.scale.set(sPx, sPx, 1) | ||||||||||||||||||||||||||||||||||||||||||||
return false | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -299,60 +327,60 @@ export function createWaypointSprite (options: { | |||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Internal helpers | ||||||||||||||||||||||||||||||||||||||||||||
function drawCombinedCanvas (color: number, id: string, distance: string): HTMLCanvasElement { | ||||||||||||||||||||||||||||||||||||||||||||
function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement { | ||||||||||||||||||||||||||||||||||||||||||||
const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1) | ||||||||||||||||||||||||||||||||||||||||||||
const size = WAYPOINT_CONFIG.CANVAS_SIZE * scale | ||||||||||||||||||||||||||||||||||||||||||||
const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale | ||||||||||||||||||||||||||||||||||||||||||||
const canvas = document.createElement('canvas') | ||||||||||||||||||||||||||||||||||||||||||||
canvas.width = size | ||||||||||||||||||||||||||||||||||||||||||||
canvas.height = size | ||||||||||||||||||||||||||||||||||||||||||||
const ctx = canvas.getContext('2d')! | ||||||||||||||||||||||||||||||||||||||||||||
canvas.width = sizeCanvas | ||||||||||||||||||||||||||||||||||||||||||||
canvas.height = sizeCanvas | ||||||||||||||||||||||||||||||||||||||||||||
const ctxCanvas = ctx || canvas.getContext('2d')! | ||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+389
to
+395
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainTexture size can exceed common GPU limits (DPR-multiplied 512×3 → 4608 on DPR=3). Clamp and cap DPR to prevent perf/alloc spikes. Multiplying CANVAS_SIZE (512) by CANVAS_SCALE (3) and devicePixelRatio produces >4K canvases on high-DPR displays, risking stalls and OOM on some GPUs. Cap DPR and clamp to a safe max size: -function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
- const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
- const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
+function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
+ const deviceScale = Math.min(globalThis.devicePixelRatio || 1, 2) // cap DPR impact
+ const scale = WAYPOINT_CONFIG.CANVAS_SCALE * deviceScale
+ const baseSize = WAYPOINT_CONFIG.CANVAS_SIZE * scale
+ const MAX_TEX = 2048
+ const sizeCanvas = size || Math.min(baseSize, MAX_TEX) Optionally consider reducing CANVAS_SCALE to 2 for mobile profiles. Also applies to: 8-8, 16-16, 21-23 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Searching repository for drawCombinedCanvas, WAYPOINT_CONFIG, CANVAS_SIZE, CANVAS_SCALE, devicePixelRatio..."
if command -v rg >/dev/null 2>&1; then
rg -n --hidden --no-ignore-vcs -S "drawCombinedCanvas|WAYPOINT_CONFIG|CANVAS_SIZE|CANVAS_SCALE|devicePixelRatio" || true
else
echo "rg (ripgrep) not found; using find+grep fallback"
find . -type f -name '*.ts' -o -name '*.js' -o -name '*.tsx' -o -name '*.jsx' | xargs grep -nH -E "drawCombinedCanvas|WAYPOINT_CONFIG|CANVAS_SIZE|CANVAS_SCALE|devicePixelRatio" || true
fi
# Show the waypointSprite file if present
WSP=$(rg -n --hidden --no-ignore-vcs -S "waypointSprite.ts" -l || true)
if [ -n "$WSP" ]; then
echo "Found waypointSprite file(s):"
echo "$WSP"
for f in $WSP; do
echo "---- $f (first 400 lines) ----"
sed -n '1,400p' "$f" | nl -ba
done
else
echo "No waypointSprite.ts file found by name; trying to locate files containing drawCombinedCanvas..."
FILES=$(rg -n --hidden --no-ignore-vcs -S "drawCombinedCanvas" -l || true)
if [ -n "$FILES" ]; then
echo "Files with drawCombinedCanvas:"
echo "$FILES"
for f in $FILES; do
echo "---- $f (first 400 lines) ----"
sed -n '1,400p' "$f" | nl -ba
done
else
echo "No files contain drawCombinedCanvas."
fi
fi
echo "Searching for definitions/values of CANVAS_SIZE / CANVAS_SCALE / WAYPOINT_CONFIG..."
CFGFILES=$(rg -n --hidden --no-ignore-vcs -S "CANVAS_SIZE|CANVAS_SCALE|WAYPOINT_CONFIG" -l || true)
if [ -n "$CFGFILES" ]; then
for f in $CFGFILES; do
echo "---- $f ----"
rg -n --hidden --no-ignore-vcs -S "CANVAS_SIZE|CANVAS_SCALE|WAYPOINT_CONFIG" "$f" -n -C3 || true
echo "File head:"
sed -n '1,200p' "$f" | nl -ba
done
else
echo "No files found defining CANVAS_SIZE/CANVAS_SCALE/WAYPOINT_CONFIG."
fi
echo "Searching for raw uses of canvas.width/height and getContext..."
rg -n --hidden --no-ignore-vcs -S "canvas.width|canvas.height|getContext\\(" || true
echo "Done." Length of output: 3105 Clamp DPR and cap canvas size to avoid >4K textures WAYPOINT_CONFIG.CANVAS_SIZE = 512 and CANVAS_SCALE = 3 are multiplied by devicePixelRatio in drawCombinedCanvas — DPR=3 → 51233 = 4608px, which can cause GPU stalls/OOM. Cap DPR and clamp the computed canvas size. Location: renderer/viewer/three/waypointSprite.ts (drawCombinedCanvas at ~lines 389–395; WAYPOINT_CONFIG at top ~lines 4–16) -function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
- const scale = WAYPOINT_CONFIG.CANVAS_SCALE * (globalThis.devicePixelRatio || 1)
- const sizeCanvas = size || WAYPOINT_CONFIG.CANVAS_SIZE * scale
+function drawCombinedCanvas (color: number, id: string, distance: string, ctx?: CanvasRenderingContext2D, size?: number): HTMLCanvasElement {
+ const deviceScale = Math.min(globalThis.devicePixelRatio || 1, 2) // cap DPR impact
+ const scale = WAYPOINT_CONFIG.CANVAS_SCALE * deviceScale
+ const baseSize = WAYPOINT_CONFIG.CANVAS_SIZE * scale
+ const MAX_TEX = 2048
+ const sizeCanvas = size || Math.min(baseSize, MAX_TEX) Also review other drawCombinedCanvas call sites in this file to ensure they don’t force oversized textures. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Clear canvas | ||||||||||||||||||||||||||||||||||||||||||||
ctx.clearRect(0, 0, size, size) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.clearRect(0, 0, sizeCanvas, sizeCanvas) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Draw dot | ||||||||||||||||||||||||||||||||||||||||||||
const centerX = size / 2 | ||||||||||||||||||||||||||||||||||||||||||||
const dotY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DOT_Y) | ||||||||||||||||||||||||||||||||||||||||||||
const radius = Math.round(size * 0.05) // Dot takes up ~12% of canvas height | ||||||||||||||||||||||||||||||||||||||||||||
const centerX = sizeCanvas / 2 | ||||||||||||||||||||||||||||||||||||||||||||
const dotY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.DOT_Y) | ||||||||||||||||||||||||||||||||||||||||||||
const radius = Math.round(sizeCanvas * 0.05) // Dot takes up ~12% of canvas height | ||||||||||||||||||||||||||||||||||||||||||||
const borderWidth = Math.max(2, Math.round(4 * scale)) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Outer border (black) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.beginPath() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.arc(centerX, dotY, radius + borderWidth, 0, Math.PI * 2) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fill() | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.beginPath() | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.arc(centerX, dotY, radius + borderWidth, 0, Math.PI * 2) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fill() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Inner circle (colored) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.beginPath() | ||||||||||||||||||||||||||||||||||||||||||||
ctx.arc(centerX, dotY, radius, 0, Math.PI * 2) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillStyle = `#${color.toString(16).padStart(6, '0')}` | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fill() | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.beginPath() | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.arc(centerX, dotY, radius, 0, Math.PI * 2) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillStyle = `#${color.toString(16).padStart(6, '0')}` | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fill() | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Text properties | ||||||||||||||||||||||||||||||||||||||||||||
ctx.textAlign = 'center' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.textBaseline = 'middle' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.textAlign = 'center' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.textBaseline = 'middle' | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Title | ||||||||||||||||||||||||||||||||||||||||||||
const nameFontPx = Math.round(size * 0.08) // ~8% of canvas height | ||||||||||||||||||||||||||||||||||||||||||||
const distanceFontPx = Math.round(size * 0.06) // ~6% of canvas height | ||||||||||||||||||||||||||||||||||||||||||||
ctx.font = `bold ${nameFontPx}px mojangles` | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineWidth = Math.max(2, Math.round(3 * scale)) | ||||||||||||||||||||||||||||||||||||||||||||
const nameY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.NAME_Y) | ||||||||||||||||||||||||||||||||||||||||||||
const nameFontPx = Math.round(sizeCanvas * 0.12) // Increased from 0.08 (~12% of canvas height) | ||||||||||||||||||||||||||||||||||||||||||||
const distanceFontPx = Math.round(sizeCanvas * 0.09) // Increased from 0.06 (~9% of canvas height) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.font = `bold ${nameFontPx}px mojangles` | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.lineWidth = Math.max(3, Math.round(4 * scale)) // Increased line width for better text outline | ||||||||||||||||||||||||||||||||||||||||||||
const nameY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.NAME_Y) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeText(id, centerX, nameY) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillStyle = 'white' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillText(id, centerX, nameY) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.strokeText(id, centerX, nameY) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillStyle = 'white' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillText(id, centerX, nameY) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
// Distance | ||||||||||||||||||||||||||||||||||||||||||||
ctx.font = `bold ${distanceFontPx}px mojangles` | ||||||||||||||||||||||||||||||||||||||||||||
ctx.lineWidth = Math.max(2, Math.round(2 * scale)) | ||||||||||||||||||||||||||||||||||||||||||||
const distanceY = Math.round(size * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.strokeText(distance, centerX, distanceY) | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillStyle = '#CCCCCC' | ||||||||||||||||||||||||||||||||||||||||||||
ctx.fillText(distance, centerX, distanceY) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.font = `bold ${distanceFontPx}px mojangles` | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.lineWidth = Math.max(3, Math.round(3 * scale)) // Increased line width for better text outline | ||||||||||||||||||||||||||||||||||||||||||||
const distanceY = Math.round(sizeCanvas * WAYPOINT_CONFIG.LAYOUT.DISTANCE_Y) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.strokeStyle = 'black' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.strokeText(distance, centerX, distanceY) | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillStyle = '#CCCCCC' | ||||||||||||||||||||||||||||||||||||||||||||
ctxCanvas.fillText(distance, centerX, distanceY) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return canvas | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.